forked from github/server
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
1f5a31b817
404 changed files with 26584 additions and 22543 deletions
|
@ -9,7 +9,7 @@ end_of_line = lf
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
|
|
||||||
# 4 space indentation
|
# 4 space indentation
|
||||||
[*.{c,h,lua}]
|
[*.{c,h,lua,py}]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -42,3 +42,4 @@ tests/data/185.dat
|
||||||
/quicklist/
|
/quicklist/
|
||||||
/cutest/
|
/cutest/
|
||||||
/critbit/
|
/critbit/
|
||||||
|
*.mo
|
||||||
|
|
|
@ -13,9 +13,13 @@ include(MSVC)
|
||||||
set (HAVE_STRDUP 0)
|
set (HAVE_STRDUP 0)
|
||||||
set (HAVE_STRLCAT 0)
|
set (HAVE_STRLCAT 0)
|
||||||
set (HAVE_LIBBSD 0)
|
set (HAVE_LIBBSD 0)
|
||||||
|
set (HAVE_SIGNAL_H 0)
|
||||||
|
set (HAVE_EXECINFO_H 0)
|
||||||
else (MSVC)
|
else (MSVC)
|
||||||
|
|
||||||
INCLUDE (CheckIncludeFile)
|
INCLUDE (CheckIncludeFile)
|
||||||
|
CHECK_INCLUDE_FILE(signal.h HAVE_SIGNAL_H)
|
||||||
|
CHECK_INCLUDE_FILE(execinfo.h HAVE_EXECINFO_H)
|
||||||
CHECK_INCLUDE_FILE(bsd/string.h HAVE_LIBBSD)
|
CHECK_INCLUDE_FILE(bsd/string.h HAVE_LIBBSD)
|
||||||
|
|
||||||
INCLUDE (CheckFunctionExists)
|
INCLUDE (CheckFunctionExists)
|
||||||
|
@ -46,7 +50,7 @@ else()
|
||||||
find_package (SQLite3 REQUIRED QUIET)
|
find_package (SQLite3 REQUIRED QUIET)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package (LibXml2 REQUIRED)
|
find_package(EXPAT REQUIRED)
|
||||||
find_package (ToLua REQUIRED)
|
find_package (ToLua REQUIRED)
|
||||||
if (TOLUA_FOUND)
|
if (TOLUA_FOUND)
|
||||||
if (${TOLUA_VERSION_STRING} VERSION_EQUAL "5.2")
|
if (${TOLUA_VERSION_STRING} VERSION_EQUAL "5.2")
|
||||||
|
@ -66,6 +70,7 @@ add_subdirectory (process)
|
||||||
add_subdirectory (src eressea)
|
add_subdirectory (src eressea)
|
||||||
|
|
||||||
install(DIRECTORY etc DESTINATION ${CMAKE_INSTALL_PREFIX} FILES_MATCHING PATTERN "*.txt")
|
install(DIRECTORY etc DESTINATION ${CMAKE_INSTALL_PREFIX} FILES_MATCHING PATTERN "*.txt")
|
||||||
|
install(DIRECTORY res conf DESTINATION ${CMAKE_INSTALL_PREFIX} FILES_MATCHING PATTERN "*.po")
|
||||||
install(DIRECTORY res conf DESTINATION ${CMAKE_INSTALL_PREFIX} FILES_MATCHING PATTERN "*.xml")
|
install(DIRECTORY res conf DESTINATION ${CMAKE_INSTALL_PREFIX} FILES_MATCHING PATTERN "*.xml")
|
||||||
install(DIRECTORY res conf DESTINATION ${CMAKE_INSTALL_PREFIX} FILES_MATCHING PATTERN "*.json")
|
install(DIRECTORY res conf DESTINATION ${CMAKE_INSTALL_PREFIX} FILES_MATCHING PATTERN "*.json")
|
||||||
install(DIRECTORY scripts DESTINATION ${CMAKE_INSTALL_PREFIX} FILES_MATCHING PATTERN "*.lua")
|
install(DIRECTORY scripts DESTINATION ${CMAKE_INSTALL_PREFIX} FILES_MATCHING PATTERN "*.lua")
|
||||||
|
|
|
@ -18,3 +18,6 @@ This repository relies heavily on the use of submodules, and it pulls in most of
|
||||||
./s/build
|
./s/build
|
||||||
|
|
||||||
If you got this far and all went well, you have built a server (it is linked from the `game` subdirectory), and it will have passed some basic functionality tests.
|
If you got this far and all went well, you have built a server (it is linked from the `game` subdirectory), and it will have passed some basic functionality tests.
|
||||||
|
|
||||||
|
* [![Static Analysis](https://scan.coverity.com/projects/6742/badge.svg?flat=1)](https://scan.coverity.com/projects/6742/)
|
||||||
|
* [![Build Status](https://api.travis-ci.org/eressea/server.svg?branch=develop)](https://travis-ci.org/eressea/server)
|
||||||
|
|
2
clibs
2
clibs
|
@ -1 +1 @@
|
||||||
Subproject commit 7eb6713ff73d29e67d2bc87fb037a9c738c2c512
|
Subproject commit f9842e07a442c5453c270badf25ab72633b4edf5
|
|
@ -1,15 +1,31 @@
|
||||||
{
|
{
|
||||||
"include": [
|
"include": [
|
||||||
"keywords.json",
|
"config://conf/keywords.json",
|
||||||
"calendar.json",
|
"config://conf/calendar.json",
|
||||||
"prefixes.json",
|
"config://conf/prefixes.json",
|
||||||
"e2/terrains.json"
|
"config://conf/e2/locales.json",
|
||||||
|
"config://conf/e2/terrains.json",
|
||||||
|
"config://conf/e2/items.json",
|
||||||
|
"config://res/core/ships.xml",
|
||||||
|
"config://res/core/common/buildings.xml",
|
||||||
|
"config://res/eressea/buildings.xml",
|
||||||
|
"config://res/buildings/castle.xml",
|
||||||
|
"config://res/eressea/races.xml",
|
||||||
|
"config://res/eressea/artrewards.xml",
|
||||||
|
"config://res/eressea/spells.xml",
|
||||||
|
"config://res/eressea/spellbooks/gray.xml",
|
||||||
|
"config://res/eressea/spellbooks/gwyrrd.xml",
|
||||||
|
"config://res/eressea/spellbooks/draig.xml",
|
||||||
|
"config://res/eressea/spellbooks/illaun.xml",
|
||||||
|
"config://res/eressea/spellbooks/cerddor.xml",
|
||||||
|
"config://res/eressea/spellbooks/tybied.xml"
|
||||||
],
|
],
|
||||||
"disabled": [
|
"disabled": [
|
||||||
"jsreport"
|
"jsreport"
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"game.name" : "Eressea",
|
"game.name" : "Eressea",
|
||||||
|
"game.mailcmd" : "ERESSEA",
|
||||||
"game.id" : 2,
|
"game.id" : 2,
|
||||||
"orders.default": "work",
|
"orders.default": "work",
|
||||||
"NewbieImmunity": 8,
|
"NewbieImmunity": 8,
|
||||||
|
|
50
conf/e2/items.json
Normal file
50
conf/e2/items.json
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
"include": [
|
||||||
|
"config://res/core/spoils.xml",
|
||||||
|
"config://res/core/common/herbs.xml",
|
||||||
|
"config://res/core/common/items.xml",
|
||||||
|
"config://res/core/common/luxuries.xml",
|
||||||
|
"config://res/core/common/potions.xml",
|
||||||
|
"config://res/core/armor/chainmail.xml",
|
||||||
|
"config://res/core/armor/laenmail.xml",
|
||||||
|
"config://res/core/armor/laenshield.xml",
|
||||||
|
"config://res/core/armor/plate.xml",
|
||||||
|
"config://res/core/armor/rustychainmail.xml",
|
||||||
|
"config://res/core/armor/rustyshield.xml",
|
||||||
|
"config://res/core/armor/shield.xml",
|
||||||
|
"config://res/core/resources/cart.xml",
|
||||||
|
"config://res/core/resources/horse.xml",
|
||||||
|
"config://res/core/resources/hp.xml",
|
||||||
|
"config://res/core/resources/iron.xml",
|
||||||
|
"config://res/core/resources/laen.xml",
|
||||||
|
"config://res/core/resources/log.xml",
|
||||||
|
"config://res/core/resources/mallorn.xml",
|
||||||
|
"config://res/core/resources/mallornseed.xml",
|
||||||
|
"config://res/core/resources/seed.xml",
|
||||||
|
"config://res/core/resources/peasant.xml",
|
||||||
|
"config://res/core/resources/stone.xml",
|
||||||
|
"config://res/core/weapons/axe.xml",
|
||||||
|
"config://res/core/weapons/bow.xml",
|
||||||
|
"config://res/core/weapons/catapult.xml",
|
||||||
|
"config://res/core/weapons/crossbow.xml",
|
||||||
|
"config://res/core/weapons/firesword.xml",
|
||||||
|
"config://res/core/weapons/greatbow.xml",
|
||||||
|
"config://res/core/weapons/greatsword.xml",
|
||||||
|
"config://res/core/weapons/halberd.xml",
|
||||||
|
"config://res/core/weapons/laensword.xml",
|
||||||
|
"config://res/core/weapons/lance.xml",
|
||||||
|
"config://res/core/weapons/mallornbow.xml",
|
||||||
|
"config://res/core/weapons/mallorncrossbow.xml",
|
||||||
|
"config://res/core/weapons/mallornlance.xml",
|
||||||
|
"config://res/core/weapons/mallornspear.xml",
|
||||||
|
"config://res/core/weapons/runesword.xml",
|
||||||
|
"config://res/core/weapons/rustyaxe.xml",
|
||||||
|
"config://res/core/weapons/rustygreatsword.xml",
|
||||||
|
"config://res/core/weapons/rustyhalberd.xml",
|
||||||
|
"config://res/core/weapons/rustysword.xml",
|
||||||
|
"config://res/core/weapons/spear.xml",
|
||||||
|
"config://res/core/weapons/sword.xml",
|
||||||
|
"config://res/eressea/items.xml",
|
||||||
|
"config://res/adamantium.xml"
|
||||||
|
]
|
||||||
|
}
|
9
conf/e2/locales.json
Normal file
9
conf/e2/locales.json
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"include": [
|
||||||
|
"config://res/translations/strings.de.po",
|
||||||
|
"config://res/translations/strings.en.po",
|
||||||
|
"config://res/translations/messages.de.po",
|
||||||
|
"config://res/translations/messages.en.po",
|
||||||
|
"config://res/core/messages.xml"
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,13 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<eressea xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
||||||
<xi:include href="config://core/messages.xml"/>
|
|
||||||
<xi:include href="config://core/de/strings.xml"/>
|
|
||||||
<xi:include href="config://core/en/strings.xml"/>
|
|
||||||
<xi:include href="config://game/strings.xml"/>
|
|
||||||
<xi:include href="config://game/spellinfo.xml" />
|
|
||||||
<xi:include href="config://default/names-undead.xml"/>
|
|
||||||
<xi:include href="config://default/names-skeletons.xml"/>
|
|
||||||
<xi:include href="config://default/names-zombies.xml"/>
|
|
||||||
<xi:include href="config://default/names-ghouls.xml"/>
|
|
||||||
<xi:include href="config://default/names-dragons.xml"/>
|
|
||||||
</eressea>
|
|
|
@ -1,45 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<eressea xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
||||||
|
|
||||||
<xi:include href="config://core/common/items.xml" />
|
|
||||||
<xi:include href="config://core/common/armor.xml" />
|
|
||||||
<xi:include href="config://core/common/weapons.xml" />
|
|
||||||
<xi:include href="config://core/common/resources.xml" />
|
|
||||||
<xi:include href="config://core/common/luxuries.xml" />
|
|
||||||
<xi:include href="config://core/common/herbs.xml" />
|
|
||||||
<xi:include href="config://core/common/potions.xml" />
|
|
||||||
<xi:include href="config://core/spoils.xml"/>
|
|
||||||
<xi:include href="config://game/races.xml"/>
|
|
||||||
<xi:include href="config://core/ships.xml"/>
|
|
||||||
<xi:include href="config://core/common/buildings.xml"/>
|
|
||||||
<xi:include href="config://game/familiars.xml"/>
|
|
||||||
<xi:include href="config://game/artrewards.xml"/>
|
|
||||||
<xi:include href="config://game/buildings.xml"/>
|
|
||||||
<xi:include href="config://game/equipment.xml"/>
|
|
||||||
<xi:include href="config://game/items.xml"/>
|
|
||||||
<xi:include href="config://game/spells.xml"/>
|
|
||||||
<xi:include href="config://default/adamantium.xml"/>
|
|
||||||
<equipment>
|
|
||||||
<set name="first_unit">
|
|
||||||
<item name="money" amount="2500"/>
|
|
||||||
<item name="log" amount="10"/>
|
|
||||||
<item name="stone" amount="4"/>
|
|
||||||
</set>
|
|
||||||
<set name="seed_unit">
|
|
||||||
<item name="log" amount="50"/>
|
|
||||||
<item name="stone" amount="50"/>
|
|
||||||
<item name="iron" amount="50"/>
|
|
||||||
<item name="laen" amount="10"/>
|
|
||||||
<item name="sword" amount="1"/>
|
|
||||||
<item name="mallorn" amount="10"/>
|
|
||||||
<item name="skillpotion" amount="5"/>
|
|
||||||
<item name="p2" amount="5"/>
|
|
||||||
<item name="money" amount="20000"/>
|
|
||||||
<skill name="perception" level="30"/>
|
|
||||||
<skill name="melee" level="1"/>
|
|
||||||
</set>
|
|
||||||
<set name="seed_faction">
|
|
||||||
<item name="adamantium" amount="1"/>
|
|
||||||
</set>
|
|
||||||
</equipment>
|
|
||||||
</eressea>
|
|
|
@ -1,9 +1,23 @@
|
||||||
{
|
{
|
||||||
"include": [
|
"include": [
|
||||||
"keywords.json",
|
"config://conf/keywords.json",
|
||||||
"calendar.json",
|
"config://conf/calendar.json",
|
||||||
"prefixes.json",
|
"config://conf/prefixes.json",
|
||||||
"e3/terrains.json"
|
"config://conf/e3/locales.json",
|
||||||
|
"config://conf/e3/terrains.json",
|
||||||
|
"config://conf/e3/items.json",
|
||||||
|
"config://conf/e3/races.json",
|
||||||
|
"config://res/e3a/ships.xml",
|
||||||
|
"config://res/e3a/buildings.xml",
|
||||||
|
"config://res/e3a/spells.xml",
|
||||||
|
"config://res/e3a/spellbooks/gray.xml",
|
||||||
|
"config://res/e3a/spellbooks/gwyrrd.xml",
|
||||||
|
"config://res/e3a/spellbooks/draig.xml",
|
||||||
|
"config://res/e3a/spellbooks/illaun.xml",
|
||||||
|
"config://res/e3a/spellbooks/cerddor.xml",
|
||||||
|
"config://res/e3a/spellbooks/common.xml",
|
||||||
|
"config://res/core/common/buildings.xml",
|
||||||
|
"config://res/buildings/castle-2.xml"
|
||||||
],
|
],
|
||||||
"disabled": [
|
"disabled": [
|
||||||
"herbalism",
|
"herbalism",
|
||||||
|
@ -27,6 +41,7 @@
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"game.name" : "Eressea",
|
"game.name" : "Eressea",
|
||||||
|
"game.mailcmd" : "ERESSEA",
|
||||||
"game.id" : 3,
|
"game.id" : 3,
|
||||||
"orders.default": "work",
|
"orders.default": "work",
|
||||||
"database.gameid": 7,
|
"database.gameid": 7,
|
||||||
|
@ -77,7 +92,6 @@
|
||||||
"rules.region_owners": true,
|
"rules.region_owners": true,
|
||||||
"rules.cavalry.skill": 2,
|
"rules.cavalry.skill": 2,
|
||||||
"rules.cavalry.mode": 1,
|
"rules.cavalry.mode": 1,
|
||||||
"rules.magic.multipotion": true,
|
|
||||||
"rules.magic.wol_effect": 5,
|
"rules.magic.wol_effect": 5,
|
||||||
"rules.magic.factionlist": true,
|
"rules.magic.factionlist": true,
|
||||||
"rules.magic.wol_type": 2,
|
"rules.magic.wol_type": 2,
|
||||||
|
|
29
conf/e3/items.json
Normal file
29
conf/e3/items.json
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"include": [
|
||||||
|
"config://res/core/spoils.xml",
|
||||||
|
"config://res/core/common/herbs.xml",
|
||||||
|
"config://res/core/common/items.xml",
|
||||||
|
"config://res/core/common/luxuries.xml",
|
||||||
|
"config://res/core/resources/cart.xml",
|
||||||
|
"config://res/core/resources/horse.xml",
|
||||||
|
"config://res/core/resources/hp.xml",
|
||||||
|
"config://res/core/resources/laen.xml",
|
||||||
|
"config://res/core/resources/log.xml",
|
||||||
|
"config://res/core/resources/mallorn.xml",
|
||||||
|
"config://res/core/resources/peasant.xml",
|
||||||
|
"config://res/core/weapons/bow.xml",
|
||||||
|
"config://res/core/weapons/catapult.xml",
|
||||||
|
"config://res/core/weapons/mallornbow.xml",
|
||||||
|
"config://res/core/weapons/mallornspear.xml",
|
||||||
|
"config://res/core/weapons/runesword.xml",
|
||||||
|
"config://res/core/weapons/rustyaxe.xml",
|
||||||
|
"config://res/core/weapons/rustysword.xml",
|
||||||
|
"config://res/core/weapons/spear.xml",
|
||||||
|
"config://res/core/weapons/sword.xml",
|
||||||
|
"config://res/core/weapons/firesword.xml",
|
||||||
|
"config://res/e3a/weapons.xml",
|
||||||
|
"config://res/e3a/armor.xml",
|
||||||
|
"config://res/e3a/items.xml",
|
||||||
|
"config://res/adamantium.xml"
|
||||||
|
]
|
||||||
|
}
|
11
conf/e3/locales.json
Normal file
11
conf/e3/locales.json
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"include": [
|
||||||
|
"config://res/translations/strings.de.po",
|
||||||
|
"config://res/translations/strings-e3.de.po",
|
||||||
|
"config://res/translations/messages.de.po",
|
||||||
|
"config://res/translations/strings.en.po",
|
||||||
|
"config://res/translations/strings-e3.en.po",
|
||||||
|
"config://res/translations/messages.en.po",
|
||||||
|
"config://res/core/messages.xml"
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,12 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<eressea xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
||||||
<xi:include href="config://core/messages.xml"/>
|
|
||||||
<xi:include href="config://core/de/strings.xml"/>
|
|
||||||
<xi:include href="config://core/en/strings.xml"/>
|
|
||||||
<xi:include href="config://game/strings.xml"/>
|
|
||||||
<xi:include href="config://default/names-undead.xml"/>
|
|
||||||
<xi:include href="config://default/names-skeletons.xml"/>
|
|
||||||
<xi:include href="config://default/names-zombies.xml"/>
|
|
||||||
<xi:include href="config://default/names-ghouls.xml"/>
|
|
||||||
<xi:include href="config://default/names-dragons.xml"/>
|
|
||||||
</eressea>
|
|
9
conf/e3/races.json
Normal file
9
conf/e3/races.json
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"include": [
|
||||||
|
"config://res/races/goblin-3.xml",
|
||||||
|
"config://res/races/wyrm.xml",
|
||||||
|
"config://res/races/dragon.xml",
|
||||||
|
"config://res/races/youngdragon.xml",
|
||||||
|
"config://res/e3a/races.xml"
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,28 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<eressea xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
||||||
<xi:include href="config://core/common/items.xml"/>
|
|
||||||
<xi:include href="config://core/common/herbs.xml" />
|
|
||||||
<xi:include href="config://core/spoils.xml"/>
|
|
||||||
<xi:include href="config://core/common/buildings.xml"/>
|
|
||||||
<xi:include href="config://game/familiars.xml"/>
|
|
||||||
|
|
||||||
<xi:include href="config://default/adamantium.xml" />
|
|
||||||
|
|
||||||
<xi:include href="config://game/ships.xml"/>
|
|
||||||
<xi:include href="config://game/shipnames.xml"/>
|
|
||||||
<xi:include href="config://game/items.xml" />
|
|
||||||
<xi:include href="config://game/races.xml"/>
|
|
||||||
<xi:include href="config://game/buildings.xml"/>
|
|
||||||
<xi:include href="config://game/equipment.xml"/>
|
|
||||||
<xi:include href="config://game/spells.xml"/>
|
|
||||||
<xi:include href="config://game/luxuries.xml" />
|
|
||||||
<xi:include href="config://game/weapons.xml" />
|
|
||||||
<xi:include href="config://game/armor.xml" />
|
|
||||||
<xi:include href="config://game/resources.xml" />
|
|
||||||
|
|
||||||
<xi:include href="config://default/names-undead.xml"/>
|
|
||||||
<xi:include href="config://default/names-skeletons.xml"/>
|
|
||||||
<xi:include href="config://default/names-zombies.xml"/>
|
|
||||||
<xi:include href="config://default/names-ghouls.xml"/>
|
|
||||||
<xi:include href="config://default/names-dragons.xml"/>
|
|
||||||
</eressea>
|
|
|
@ -1,5 +1,6 @@
|
||||||
install(PROGRAMS create-orders backup-eressea run-turn send-zip-report
|
install(PROGRAMS create-orders backup-eressea run-turn send-zip-report
|
||||||
send-bz2-report compress.py compress.sh epasswd.py orders-process
|
send-bz2-report compress.py compress.sh epasswd.py orders-process
|
||||||
|
process-orders.py accept-orders.py
|
||||||
checkpasswd.py sendreport.sh sendreports.sh orders-accept DESTINATION bin)
|
checkpasswd.py sendreport.sh sendreports.sh orders-accept DESTINATION bin)
|
||||||
|
|
||||||
install(DIRECTORY cron/ DESTINATION bin USE_SOURCE_PERMISSIONS
|
install(DIRECTORY cron/ DESTINATION bin USE_SOURCE_PERMISSIONS
|
||||||
|
|
377
process/accept-orders.py
Executable file
377
process/accept-orders.py
Executable file
|
@ -0,0 +1,377 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from email.Utils import parseaddr
|
||||||
|
from email.Parser import Parser
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import ConfigParser
|
||||||
|
from re import compile, IGNORECASE
|
||||||
|
from stat import ST_MTIME
|
||||||
|
from string import upper, split, replace
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
from sys import stdin
|
||||||
|
from time import ctime, sleep, time
|
||||||
|
from socket import gethostname
|
||||||
|
from rfc822 import parsedate_tz, mktime_tz
|
||||||
|
|
||||||
|
if 'ERESSEA' in os.environ:
|
||||||
|
dir = os.environ['ERESSEA']
|
||||||
|
elif 'HOME' in os.environ:
|
||||||
|
dir = os.path.join(os.environ['HOME'], 'eressea')
|
||||||
|
else: # WTF? No HOME?
|
||||||
|
dir = "/home/eressea/eressea"
|
||||||
|
if not os.path.isdir(dir):
|
||||||
|
print "please set the ERESSEA environment variable to the install path"
|
||||||
|
sys.exit(1)
|
||||||
|
rootdir = dir
|
||||||
|
|
||||||
|
game = int(sys.argv[1])
|
||||||
|
gamedir = os.path.join(rootdir, "game-%d" % (game, ))
|
||||||
|
frommail = 'eressea-server@kn-bremen.de'
|
||||||
|
gamename = 'Eressea'
|
||||||
|
sender = '%s Server <%s>' % (gamename, frommail)
|
||||||
|
|
||||||
|
inifile = os.path.join(gamedir, 'eressea.ini')
|
||||||
|
if not os.path.exists(inifile):
|
||||||
|
print "no such file: " . inifile
|
||||||
|
else:
|
||||||
|
config = ConfigParser.ConfigParser()
|
||||||
|
config.read(inifile)
|
||||||
|
if config.has_option('game', 'email'):
|
||||||
|
frommail = config.get('game', 'email')
|
||||||
|
if config.has_option('game', 'name'):
|
||||||
|
gamename = config.get('game', 'name')
|
||||||
|
if config.has_option('game', 'sender'):
|
||||||
|
sender = config.get('game', 'sender')
|
||||||
|
else:
|
||||||
|
sender = "%s Server <%s>" % (gamename, frommail)
|
||||||
|
config = None
|
||||||
|
prefix = 'turn-'
|
||||||
|
hostname = gethostname()
|
||||||
|
orderbase = "orders.dir"
|
||||||
|
sendmail = True
|
||||||
|
# maximum number of reports per sender:
|
||||||
|
maxfiles = 20
|
||||||
|
# write headers to file?
|
||||||
|
writeheaders = True
|
||||||
|
# reject all html email?
|
||||||
|
rejecthtml = True
|
||||||
|
|
||||||
|
def unlock_file(filename):
|
||||||
|
try:
|
||||||
|
os.unlink(filename+".lock")
|
||||||
|
except:
|
||||||
|
print "could not unlock %s.lock, file not found" % filename
|
||||||
|
|
||||||
|
def lock_file(filename):
|
||||||
|
i = 0
|
||||||
|
wait = 1
|
||||||
|
if not os.path.exists(filename):
|
||||||
|
file=open(filename, "w")
|
||||||
|
file.close()
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
os.symlink(filename, filename+".lock")
|
||||||
|
return
|
||||||
|
except:
|
||||||
|
i = i+1
|
||||||
|
if i == 5: unlock_file(filename)
|
||||||
|
sleep(wait)
|
||||||
|
wait = wait*2
|
||||||
|
|
||||||
|
messages = {
|
||||||
|
"multipart-en" :
|
||||||
|
"ERROR: The orders you sent contain no plaintext. " \
|
||||||
|
"The Eressea server cannot process orders containing HTML " \
|
||||||
|
"or invalid attachments, which are the reasons why this " \
|
||||||
|
"usually happens. Please change the settings of your mail " \
|
||||||
|
"software and re-send the orders.",
|
||||||
|
|
||||||
|
"multipart-de" :
|
||||||
|
"FEHLER: Die von dir eingeschickte Mail enthält keinen " \
|
||||||
|
"Text. Evtl. hast Du den Zug als HTML oder als anderweitig " \
|
||||||
|
"ungültig formatierte Mail ingeschickt. Wir können ihn " \
|
||||||
|
"deshalb nicht berücksichtigen. Schicke den Zug nochmals " \
|
||||||
|
"als reinen Text ohne Formatierungen ein.",
|
||||||
|
|
||||||
|
"maildate-de":
|
||||||
|
"Es erreichte uns bereits ein Zug mit einem späteren " \
|
||||||
|
"Absendedatum (%s > %s). Entweder ist deine " \
|
||||||
|
"Systemzeit verstellt, oder ein Zug hat einen anderen Zug von " \
|
||||||
|
"dir auf dem Transportweg überholt. Entscheidend für die " \
|
||||||
|
"Auswertungsreihenfolge ist das Absendedatum, d.h. der Date:-Header " \
|
||||||
|
"deiner Mail.",
|
||||||
|
|
||||||
|
"maildate-en":
|
||||||
|
"The server already received an order file that was sent at a later " \
|
||||||
|
"date (%s > %s). Either your system clock is wrong, or two messages have " \
|
||||||
|
"overtaken each other on the way to the server. The order of " \
|
||||||
|
"execution on the server is always according to the Date: header in " \
|
||||||
|
"your mail.",
|
||||||
|
|
||||||
|
"nodate-en":
|
||||||
|
"Your message did not contain a valid Date: header in accordance with RFC2822.",
|
||||||
|
|
||||||
|
"nodate-de":
|
||||||
|
"Deine Nachricht enthielt keinen gueltigen Date: header nach RFC2822.",
|
||||||
|
|
||||||
|
"error-de":
|
||||||
|
"Fehler",
|
||||||
|
|
||||||
|
"error-en":
|
||||||
|
"Error",
|
||||||
|
|
||||||
|
"warning-de":
|
||||||
|
"Warnung",
|
||||||
|
|
||||||
|
"warning-en":
|
||||||
|
"Warning",
|
||||||
|
|
||||||
|
"subject-de":
|
||||||
|
"Befehle angekommen",
|
||||||
|
|
||||||
|
"subject-en":
|
||||||
|
"orders received"
|
||||||
|
}
|
||||||
|
|
||||||
|
# return 1 if addr is a valid email address
|
||||||
|
def valid_email(addr):
|
||||||
|
rfc822_specials = '/()<>@,;:\\"[]'
|
||||||
|
# First we validate the name portion (name@domain)
|
||||||
|
c = 0
|
||||||
|
while c < len(addr):
|
||||||
|
if addr[c] == '"' and (not c or addr[c - 1] == '.' or addr[c - 1] == '"'):
|
||||||
|
c = c + 1
|
||||||
|
while c < len(addr):
|
||||||
|
if addr[c] == '"': break
|
||||||
|
if addr[c] == '\\' and addr[c + 1] == ' ':
|
||||||
|
c = c + 2
|
||||||
|
continue
|
||||||
|
if ord(addr[c]) < 32 or ord(addr[c]) >= 127: return 0
|
||||||
|
c = c + 1
|
||||||
|
else: return 0
|
||||||
|
if addr[c] == '@': break
|
||||||
|
if addr[c] != '.': return 0
|
||||||
|
c = c + 1
|
||||||
|
continue
|
||||||
|
if addr[c] == '@': break
|
||||||
|
if ord(addr[c]) <= 32 or ord(addr[c]) >= 127: return 0
|
||||||
|
if addr[c] in rfc822_specials: return 0
|
||||||
|
c = c + 1
|
||||||
|
if not c or addr[c - 1] == '.': return 0
|
||||||
|
|
||||||
|
# Next we validate the domain portion (name@domain)
|
||||||
|
domain = c = c + 1
|
||||||
|
if domain >= len(addr): return 0
|
||||||
|
count = 0
|
||||||
|
while c < len(addr):
|
||||||
|
if addr[c] == '.':
|
||||||
|
if c == domain or addr[c - 1] == '.': return 0
|
||||||
|
count = count + 1
|
||||||
|
if ord(addr[c]) <= 32 or ord(addr[c]) >= 127: return 0
|
||||||
|
if addr[c] in rfc822_specials: return 0
|
||||||
|
c = c + 1
|
||||||
|
return count >= 1
|
||||||
|
|
||||||
|
# return the replyto or from address in the header
|
||||||
|
def get_sender(header):
|
||||||
|
replyto = header.get("Reply-To")
|
||||||
|
if replyto is None:
|
||||||
|
replyto = header.get("From")
|
||||||
|
if replyto is None: return None
|
||||||
|
x = parseaddr(replyto)
|
||||||
|
return x[1]
|
||||||
|
|
||||||
|
# return first available filename basename,[0-9]+
|
||||||
|
def available_file(dirname, basename):
|
||||||
|
ver = 0
|
||||||
|
maxdate = 0
|
||||||
|
filename = "%s/%s,%s,%d" % (dirname, basename, hostname, ver)
|
||||||
|
while os.path.exists(filename):
|
||||||
|
maxdate = max(os.stat(filename)[ST_MTIME], maxdate)
|
||||||
|
ver = ver + 1
|
||||||
|
filename = "%s/%s,%s,%d" % (dirname, basename, hostname, ver)
|
||||||
|
if ver >= maxfiles:
|
||||||
|
return None, None
|
||||||
|
return maxdate, filename
|
||||||
|
|
||||||
|
def formatpar(string, l=76, indent=2):
|
||||||
|
words = split(string)
|
||||||
|
res = ""
|
||||||
|
ll = 0
|
||||||
|
first = 1
|
||||||
|
|
||||||
|
for word in words:
|
||||||
|
if first == 1:
|
||||||
|
res = word
|
||||||
|
first = 0
|
||||||
|
ll = len(word)
|
||||||
|
else:
|
||||||
|
if ll + len(word) > l:
|
||||||
|
res = res + "\n"+" "*indent+word
|
||||||
|
ll = len(word) + indent
|
||||||
|
else:
|
||||||
|
res = res+" "+word
|
||||||
|
ll = ll + len(word) + 1
|
||||||
|
|
||||||
|
return res+"\n"
|
||||||
|
|
||||||
|
def store_message(message, filename):
|
||||||
|
outfile = open(filename, "w")
|
||||||
|
outfile.write(message.as_string())
|
||||||
|
outfile.close()
|
||||||
|
return
|
||||||
|
|
||||||
|
def write_part(outfile, part):
|
||||||
|
charset = part.get_content_charset()
|
||||||
|
payload = part.get_payload(decode=True)
|
||||||
|
|
||||||
|
if charset is None:
|
||||||
|
charset = "latin1"
|
||||||
|
try:
|
||||||
|
msg = payload.decode(charset, "ignore")
|
||||||
|
except:
|
||||||
|
msg = payload
|
||||||
|
charset = None
|
||||||
|
try:
|
||||||
|
utf8 = msg.encode("utf-8", "ignore")
|
||||||
|
outfile.write(utf8)
|
||||||
|
except:
|
||||||
|
outfile.write(msg)
|
||||||
|
return False
|
||||||
|
outfile.write("\n");
|
||||||
|
return True
|
||||||
|
|
||||||
|
def copy_orders(message, filename, sender):
|
||||||
|
# print the header first
|
||||||
|
if writeheaders:
|
||||||
|
from os.path import split
|
||||||
|
dirname, basename = split(filename)
|
||||||
|
dirname = dirname + '/headers'
|
||||||
|
if not os.path.exists(dirname): os.mkdir(dirname)
|
||||||
|
outfile = open(dirname + '/' + basename, "w")
|
||||||
|
for name, value in message.items():
|
||||||
|
outfile.write(name + ": " + value + "\n")
|
||||||
|
outfile.close()
|
||||||
|
|
||||||
|
found = False
|
||||||
|
outfile = open(filename, "w")
|
||||||
|
if message.is_multipart():
|
||||||
|
for part in message.get_payload():
|
||||||
|
content_type = part.get_content_type()
|
||||||
|
logger.debug("found content type %s for %s" % (content_type, sender))
|
||||||
|
if content_type=="text/plain":
|
||||||
|
if write_part(outfile, part):
|
||||||
|
found = True
|
||||||
|
else:
|
||||||
|
charset = part.get_content_charset()
|
||||||
|
logger.error("could not write text/plain part (charset=%s) for %s" % (charset, sender))
|
||||||
|
|
||||||
|
else:
|
||||||
|
if write_part(outfile, message):
|
||||||
|
found = True
|
||||||
|
else:
|
||||||
|
charset = message.get_content_charset()
|
||||||
|
logger.error("could not write text/plain message (charset=%s) for %s" % (charset, sender))
|
||||||
|
outfile.close()
|
||||||
|
return found
|
||||||
|
|
||||||
|
# create a file, containing:
|
||||||
|
# game=0 locale=de file=/path/to/filename email=rcpt@domain.to
|
||||||
|
def accept(game, locale, stream, extend=None):
|
||||||
|
global rootdir, orderbase, gamedir, gamename, sender
|
||||||
|
if extend is not None:
|
||||||
|
orderbase = orderbase + ".pre-" + extend
|
||||||
|
savedir = os.path.join(gamedir, orderbase)
|
||||||
|
# check if it's one of the pre-sent orders.
|
||||||
|
# create the save-directories if they don't exist
|
||||||
|
if not os.path.exists(gamedir): os.mkdir(gamedir)
|
||||||
|
if not os.path.exists(savedir): os.mkdir(savedir)
|
||||||
|
# parse message
|
||||||
|
message = Parser().parse(stream)
|
||||||
|
email = get_sender(message)
|
||||||
|
logger = logging.getLogger(email)
|
||||||
|
# write syslog
|
||||||
|
if email is None or valid_email(email)==0:
|
||||||
|
logger.warning("invalid email address: " + str(email))
|
||||||
|
return -1
|
||||||
|
logger.info("received orders from " + email)
|
||||||
|
# get an available filename
|
||||||
|
lock_file(gamedir + "/orders.queue")
|
||||||
|
maxdate, filename = available_file(savedir, prefix + email)
|
||||||
|
if filename is None:
|
||||||
|
logger.warning("more than " + str(maxfiles) + " orders from " + email)
|
||||||
|
return -1
|
||||||
|
# copy the orders to the file
|
||||||
|
text_ok = copy_orders(message, filename, email)
|
||||||
|
unlock_file(gamedir + "/orders.queue")
|
||||||
|
|
||||||
|
warning, msg, fail = None, "", False
|
||||||
|
maildate = message.get("Date")
|
||||||
|
if maildate != None:
|
||||||
|
turndate = mktime_tz(parsedate_tz(maildate))
|
||||||
|
os.utime(filename, (turndate, turndate))
|
||||||
|
logger.debug("mail date is '%s' (%d)" % (maildate, turndate))
|
||||||
|
if False and turndate < maxdate:
|
||||||
|
logger.warning("inconsistent message date " + email)
|
||||||
|
warning = " (" + messages["warning-" + locale] + ")"
|
||||||
|
msg = msg + formatpar(messages["maildate-" + locale] % (ctime(maxdate),ctime(turndate)), 76, 2) + "\n"
|
||||||
|
else:
|
||||||
|
logger.warning("missing message date " + email)
|
||||||
|
warning = " (" + messages["warning-" + locale] + ")"
|
||||||
|
msg = msg + formatpar(messages["nodate-" + locale], 76, 2) + "\n"
|
||||||
|
|
||||||
|
if not text_ok:
|
||||||
|
warning = " (" + messages["error-" + locale] + ")"
|
||||||
|
msg = msg + formatpar(messages["multipart-" + locale], 76, 2) + "\n"
|
||||||
|
logger.warning("rejected - no text/plain in orders from " + email)
|
||||||
|
os.unlink(filename)
|
||||||
|
savedir = savedir + "/rejected"
|
||||||
|
if not os.path.exists(savedir): os.mkdir(savedir)
|
||||||
|
lock_file(gamedir + "/orders.queue")
|
||||||
|
maxdate, filename = available_file(savedir, prefix + email)
|
||||||
|
store_message(message, filename)
|
||||||
|
unlock_file(gamedir + "/orders.queue")
|
||||||
|
fail = True
|
||||||
|
|
||||||
|
if sendmail and warning is not None:
|
||||||
|
subject = gamename + " " + messages["subject-"+locale] + warning
|
||||||
|
print("mail " + subject)
|
||||||
|
ps = subprocess.Popen(['mutt', '-s', subject, email], stdin=subprocess.PIPE)
|
||||||
|
ps.communicate(msg)
|
||||||
|
|
||||||
|
if not sendmail:
|
||||||
|
print text_ok, fail, email
|
||||||
|
print filename
|
||||||
|
|
||||||
|
if not fail:
|
||||||
|
lock_file(gamedir + "/orders.queue")
|
||||||
|
queue = open(gamedir + "/orders.queue", "a")
|
||||||
|
queue.write("email=%s file=%s locale=%s game=%s\n" % (email, filename, locale, game))
|
||||||
|
queue.close()
|
||||||
|
unlock_file(gamedir + "/orders.queue")
|
||||||
|
|
||||||
|
logger.info("done - accepted orders from " + email)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# the main body of the script:
|
||||||
|
try:
|
||||||
|
os.mkdir(os.path.join(rootdir, 'log'))
|
||||||
|
except:
|
||||||
|
pass # already exists?
|
||||||
|
LOG_FILENAME=os.path.join(rootdir, 'log/orders.log')
|
||||||
|
logging.basicConfig(level=logging.DEBUG, filename=LOG_FILENAME)
|
||||||
|
logger = logging
|
||||||
|
delay = None # TODO: parse the turn delay
|
||||||
|
locale = sys.argv[2]
|
||||||
|
infile = stdin
|
||||||
|
if len(sys.argv)>3:
|
||||||
|
infile = open(sys.argv[3], "r")
|
||||||
|
retval = accept(game, locale, infile, delay)
|
||||||
|
if infile!=stdin:
|
||||||
|
infile.close()
|
||||||
|
sys.exit(retval)
|
|
@ -9,7 +9,7 @@ if [ -e ${ERESSEA}/build/.preview ]; then
|
||||||
fi
|
fi
|
||||||
SRC=${ERESSEA}/git
|
SRC=${ERESSEA}/git
|
||||||
${SRC}/s/preview build ${branch} || exit $?
|
${SRC}/s/preview build ${branch} || exit $?
|
||||||
for game in 2 3 ; do
|
for game in 2 3 4 ; do
|
||||||
${SRC}/s/preview -g ${game} run && \
|
${SRC}/s/preview -g ${game} run && \
|
||||||
${SRC}/s/preview -g ${game} send
|
${SRC}/s/preview -g ${game} send
|
||||||
done
|
done
|
||||||
|
|
|
@ -1,378 +1,5 @@
|
||||||
#!/usr/bin/env python
|
#!/bin/sh
|
||||||
# -*- coding: iso-8859-1 -*-
|
SCRIPT=$(readlink -f $0)
|
||||||
|
cd $(dirname $SCRIPT)
|
||||||
|
python accept-orders.py "$@"
|
||||||
|
|
||||||
from email.Utils import parseaddr
|
|
||||||
from email.Parser import Parser
|
|
||||||
import os
|
|
||||||
import os.path
|
|
||||||
import ConfigParser
|
|
||||||
from re import compile, IGNORECASE
|
|
||||||
from stat import ST_MTIME
|
|
||||||
from string import upper, split, replace
|
|
||||||
import logging
|
|
||||||
import sys
|
|
||||||
from sys import stdin
|
|
||||||
from time import ctime, sleep, time
|
|
||||||
from socket import gethostname
|
|
||||||
from rfc822 import parsedate_tz, mktime_tz
|
|
||||||
|
|
||||||
if 'ERESSEA' in os.environ:
|
|
||||||
dir = os.environ['ERESSEA']
|
|
||||||
elif 'HOME' in os.environ:
|
|
||||||
dir = os.path.join(os.environ['HOME'], '/eressea')
|
|
||||||
else: # WTF? No HOME?
|
|
||||||
dir = "/home/eressea/eressea"
|
|
||||||
if not os.path.isdir(dir):
|
|
||||||
print "please set the ERESSEA environment variable to the install path"
|
|
||||||
sys.exit(1)
|
|
||||||
rootdir = dir
|
|
||||||
|
|
||||||
game = int(sys.argv[1])
|
|
||||||
gamedir = os.path.join(rootdir, "game-%d" % (game, ))
|
|
||||||
frommail = 'eressea-server@kn-bremen.de'
|
|
||||||
gamename = 'Eressea'
|
|
||||||
sender = '%s Server <%s>' % (gamename, frommail)
|
|
||||||
|
|
||||||
inifile = os.path.join(gamedir, 'eressea.ini')
|
|
||||||
if not os.path.exists(inifile):
|
|
||||||
print "no such file: " . inifile
|
|
||||||
else:
|
|
||||||
config = ConfigParser.ConfigParser()
|
|
||||||
config.read(inifile)
|
|
||||||
if config.has_option('game', 'email'):
|
|
||||||
frommail = config.get('game', 'email')
|
|
||||||
if config.has_option('game', 'name'):
|
|
||||||
gamename = config.get('game', 'name')
|
|
||||||
if config.has_option('game', 'sender'):
|
|
||||||
sender = config.get('game', 'sender')
|
|
||||||
else:
|
|
||||||
sender = "%s Server <%s>" % (gamename, frommail)
|
|
||||||
config = None
|
|
||||||
prefix = 'turn-'
|
|
||||||
hostname = gethostname()
|
|
||||||
orderbase = "orders.dir"
|
|
||||||
sendmail = True
|
|
||||||
# maximum number of reports per sender:
|
|
||||||
maxfiles = 20
|
|
||||||
# write headers to file?
|
|
||||||
writeheaders = True
|
|
||||||
# reject all html email?
|
|
||||||
rejecthtml = True
|
|
||||||
|
|
||||||
def unlock_file(filename):
|
|
||||||
try:
|
|
||||||
os.unlink(filename+".lock")
|
|
||||||
except:
|
|
||||||
print "could not unlock %s.lock, file not found" % filename
|
|
||||||
|
|
||||||
def lock_file(filename):
|
|
||||||
i = 0
|
|
||||||
wait = 1
|
|
||||||
if not os.path.exists(filename):
|
|
||||||
file=open(filename, "w")
|
|
||||||
file.close()
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
os.symlink(filename, filename+".lock")
|
|
||||||
return
|
|
||||||
except:
|
|
||||||
i = i+1
|
|
||||||
if i == 5: unlock_file(filename)
|
|
||||||
sleep(wait)
|
|
||||||
wait = wait*2
|
|
||||||
|
|
||||||
messages = {
|
|
||||||
"multipart-en" :
|
|
||||||
"ERROR: The orders you sent contain no plaintext. " \
|
|
||||||
"The Eressea server cannot process orders containing HTML " \
|
|
||||||
"or invalid attachments, which are the reasons why this " \
|
|
||||||
"usually happens. Please change the settings of your mail " \
|
|
||||||
"software and re-send the orders.",
|
|
||||||
|
|
||||||
"multipart-de" :
|
|
||||||
"FEHLER: Die von dir eingeschickte Mail enth<74>lt keinen " \
|
|
||||||
"Text. Evtl. hast Du den Zug als HTML oder als anderweitig " \
|
|
||||||
"ung<6E>ltig formatierte Mail ingeschickt. Wir k<>nnen ihn " \
|
|
||||||
"deshalb nicht ber<65>cksichtigen. Schicke den Zug nochmals " \
|
|
||||||
"als reinen Text ohne Formatierungen ein.",
|
|
||||||
|
|
||||||
"maildate-de":
|
|
||||||
"Es erreichte uns bereits ein Zug mit einem sp<73>teren " \
|
|
||||||
"Absendedatum (%s > %s). Entweder ist deine " \
|
|
||||||
"Systemzeit verstellt, oder ein Zug hat einen anderen Zug von " \
|
|
||||||
"dir auf dem Transportweg <20>berholt. Entscheidend f<>r die " \
|
|
||||||
"Auswertungsreihenfolge ist das Absendedatum, d.h. der Date:-Header " \
|
|
||||||
"deiner Mail.",
|
|
||||||
|
|
||||||
"maildate-en":
|
|
||||||
"The server already received an order file that was sent at a later " \
|
|
||||||
"date (%s > %s). Either your system clock is wrong, or two messages have " \
|
|
||||||
"overtaken each other on the way to the server. The order of " \
|
|
||||||
"execution on the server is always according to the Date: header in " \
|
|
||||||
"your mail.",
|
|
||||||
|
|
||||||
"nodate-en":
|
|
||||||
"Your message did not contain a valid Date: header in accordance with RFC2822.",
|
|
||||||
|
|
||||||
"nodate-de":
|
|
||||||
"Deine Nachricht enthielt keinen gueltigen Date: header nach RFC2822.",
|
|
||||||
|
|
||||||
"error-de":
|
|
||||||
"Fehler",
|
|
||||||
|
|
||||||
"error-en":
|
|
||||||
"Error",
|
|
||||||
|
|
||||||
"warning-de":
|
|
||||||
"Warnung",
|
|
||||||
|
|
||||||
"warning-en":
|
|
||||||
"Warning",
|
|
||||||
|
|
||||||
"subject-de":
|
|
||||||
"Befehle angekommen",
|
|
||||||
|
|
||||||
"subject-en":
|
|
||||||
"orders received"
|
|
||||||
}
|
|
||||||
|
|
||||||
# return 1 if addr is a valid email address
|
|
||||||
def valid_email(addr):
|
|
||||||
rfc822_specials = '/()<>@,;:\\"[]'
|
|
||||||
# First we validate the name portion (name@domain)
|
|
||||||
c = 0
|
|
||||||
while c < len(addr):
|
|
||||||
if addr[c] == '"' and (not c or addr[c - 1] == '.' or addr[c - 1] == '"'):
|
|
||||||
c = c + 1
|
|
||||||
while c < len(addr):
|
|
||||||
if addr[c] == '"': break
|
|
||||||
if addr[c] == '\\' and addr[c + 1] == ' ':
|
|
||||||
c = c + 2
|
|
||||||
continue
|
|
||||||
if ord(addr[c]) < 32 or ord(addr[c]) >= 127: return 0
|
|
||||||
c = c + 1
|
|
||||||
else: return 0
|
|
||||||
if addr[c] == '@': break
|
|
||||||
if addr[c] != '.': return 0
|
|
||||||
c = c + 1
|
|
||||||
continue
|
|
||||||
if addr[c] == '@': break
|
|
||||||
if ord(addr[c]) <= 32 or ord(addr[c]) >= 127: return 0
|
|
||||||
if addr[c] in rfc822_specials: return 0
|
|
||||||
c = c + 1
|
|
||||||
if not c or addr[c - 1] == '.': return 0
|
|
||||||
|
|
||||||
# Next we validate the domain portion (name@domain)
|
|
||||||
domain = c = c + 1
|
|
||||||
if domain >= len(addr): return 0
|
|
||||||
count = 0
|
|
||||||
while c < len(addr):
|
|
||||||
if addr[c] == '.':
|
|
||||||
if c == domain or addr[c - 1] == '.': return 0
|
|
||||||
count = count + 1
|
|
||||||
if ord(addr[c]) <= 32 or ord(addr[c]) >= 127: return 0
|
|
||||||
if addr[c] in rfc822_specials: return 0
|
|
||||||
c = c + 1
|
|
||||||
return count >= 1
|
|
||||||
|
|
||||||
# return the replyto or from address in the header
|
|
||||||
def get_sender(header):
|
|
||||||
replyto = header.get("Reply-To")
|
|
||||||
if replyto is None:
|
|
||||||
replyto = header.get("From")
|
|
||||||
if replyto is None: return None
|
|
||||||
x = parseaddr(replyto)
|
|
||||||
return x[1]
|
|
||||||
|
|
||||||
# return first available filename basename,[0-9]+
|
|
||||||
def available_file(dirname, basename):
|
|
||||||
ver = 0
|
|
||||||
maxdate = 0
|
|
||||||
filename = "%s/%s,%s,%d" % (dirname, basename, hostname, ver)
|
|
||||||
while os.path.exists(filename):
|
|
||||||
maxdate = max(os.stat(filename)[ST_MTIME], maxdate)
|
|
||||||
ver = ver + 1
|
|
||||||
filename = "%s/%s,%s,%d" % (dirname, basename, hostname, ver)
|
|
||||||
if ver >= maxfiles:
|
|
||||||
return None, None
|
|
||||||
return maxdate, filename
|
|
||||||
|
|
||||||
def formatpar(string, l=76, indent=2):
|
|
||||||
words = split(string)
|
|
||||||
res = ""
|
|
||||||
ll = 0
|
|
||||||
first = 1
|
|
||||||
|
|
||||||
for word in words:
|
|
||||||
if first == 1:
|
|
||||||
res = word
|
|
||||||
first = 0
|
|
||||||
ll = len(word)
|
|
||||||
else:
|
|
||||||
if ll + len(word) > l:
|
|
||||||
res = res + "\n"+" "*indent+word
|
|
||||||
ll = len(word) + indent
|
|
||||||
else:
|
|
||||||
res = res+" "+word
|
|
||||||
ll = ll + len(word) + 1
|
|
||||||
|
|
||||||
return res+"\n"
|
|
||||||
|
|
||||||
def store_message(message, filename):
|
|
||||||
outfile = open(filename, "w")
|
|
||||||
outfile.write(message.as_string())
|
|
||||||
outfile.close()
|
|
||||||
return
|
|
||||||
|
|
||||||
def write_part(outfile, part):
|
|
||||||
charset = part.get_content_charset()
|
|
||||||
payload = part.get_payload(decode=True)
|
|
||||||
|
|
||||||
if charset is None:
|
|
||||||
charset = "latin1"
|
|
||||||
try:
|
|
||||||
msg = payload.decode(charset, "ignore")
|
|
||||||
except:
|
|
||||||
msg = payload
|
|
||||||
charset = None
|
|
||||||
try:
|
|
||||||
utf8 = msg.encode("utf-8", "ignore")
|
|
||||||
outfile.write(utf8)
|
|
||||||
except:
|
|
||||||
outfile.write(msg)
|
|
||||||
return False
|
|
||||||
outfile.write("\n");
|
|
||||||
return True
|
|
||||||
|
|
||||||
def copy_orders(message, filename, sender):
|
|
||||||
# print the header first
|
|
||||||
if writeheaders:
|
|
||||||
from os.path import split
|
|
||||||
dirname, basename = split(filename)
|
|
||||||
dirname = dirname + '/headers'
|
|
||||||
if not os.path.exists(dirname): os.mkdir(dirname)
|
|
||||||
outfile = open(dirname + '/' + basename, "w")
|
|
||||||
for name, value in message.items():
|
|
||||||
outfile.write(name + ": " + value + "\n")
|
|
||||||
outfile.close()
|
|
||||||
|
|
||||||
found = False
|
|
||||||
outfile = open(filename, "w")
|
|
||||||
if message.is_multipart():
|
|
||||||
for part in message.get_payload():
|
|
||||||
content_type = part.get_content_type()
|
|
||||||
logger.debug("found content type %s for %s" % (content_type, sender))
|
|
||||||
if content_type=="text/plain":
|
|
||||||
if write_part(outfile, part):
|
|
||||||
found = True
|
|
||||||
else:
|
|
||||||
charset = part.get_content_charset()
|
|
||||||
logger.error("could not write text/plain part (charset=%s) for %s" % (charset, sender))
|
|
||||||
|
|
||||||
else:
|
|
||||||
if write_part(outfile, message):
|
|
||||||
found = True
|
|
||||||
else:
|
|
||||||
charset = message.get_content_charset()
|
|
||||||
logger.error("could not write text/plain message (charset=%s) for %s" % (charset, sender))
|
|
||||||
outfile.close()
|
|
||||||
return found
|
|
||||||
|
|
||||||
# create a file, containing:
|
|
||||||
# game=0 locale=de file=/path/to/filename email=rcpt@domain.to
|
|
||||||
def accept(game, locale, stream, extend=None):
|
|
||||||
global rootdir, orderbase, gamedir, gamename, sender
|
|
||||||
if extend is not None:
|
|
||||||
orderbase = orderbase + ".pre-" + extend
|
|
||||||
savedir = os.path.join(gamedir, orderbase)
|
|
||||||
# check if it's one of the pre-sent orders.
|
|
||||||
# create the save-directories if they don't exist
|
|
||||||
if not os.path.exists(gamedir): os.mkdir(gamedir)
|
|
||||||
if not os.path.exists(savedir): os.mkdir(savedir)
|
|
||||||
# parse message
|
|
||||||
message = Parser().parse(stream)
|
|
||||||
email = get_sender(message)
|
|
||||||
logger = logging.getLogger(email)
|
|
||||||
# write syslog
|
|
||||||
if email is None or valid_email(email)==0:
|
|
||||||
logger.warning("invalid email address: " + str(email))
|
|
||||||
return -1
|
|
||||||
logger.info("received orders from " + email)
|
|
||||||
# get an available filename
|
|
||||||
lock_file(gamedir + "/orders.queue")
|
|
||||||
maxdate, filename = available_file(savedir, prefix + email)
|
|
||||||
if filename is None:
|
|
||||||
logger.warning("more than " + str(maxfiles) + " orders from " + email)
|
|
||||||
return -1
|
|
||||||
# copy the orders to the file
|
|
||||||
text_ok = copy_orders(message, filename, email)
|
|
||||||
unlock_file(gamedir + "/orders.queue")
|
|
||||||
|
|
||||||
warning, msg, fail = None, "", False
|
|
||||||
maildate = message.get("Date")
|
|
||||||
if maildate != None:
|
|
||||||
turndate = mktime_tz(parsedate_tz(maildate))
|
|
||||||
os.utime(filename, (turndate, turndate))
|
|
||||||
logger.debug("mail date is '%s' (%d)" % (maildate, turndate))
|
|
||||||
if turndate < maxdate:
|
|
||||||
logger.warning("inconsistent message date " + email)
|
|
||||||
warning = " (" + messages["warning-" + locale] + ")"
|
|
||||||
msg = msg + formatpar(messages["maildate-" + locale] % (ctime(maxdate),ctime(turndate)), 76, 2) + "\n"
|
|
||||||
else:
|
|
||||||
logger.warning("missing message date " + email)
|
|
||||||
warning = " (" + messages["warning-" + locale] + ")"
|
|
||||||
msg = msg + formatpar(messages["nodate-" + locale], 76, 2) + "\n"
|
|
||||||
|
|
||||||
if not text_ok:
|
|
||||||
warning = " (" + messages["error-" + locale] + ")"
|
|
||||||
msg = msg + formatpar(messages["multipart-" + locale], 76, 2) + "\n"
|
|
||||||
logger.warning("rejected - no text/plain in orders from " + email)
|
|
||||||
os.unlink(filename)
|
|
||||||
savedir = savedir + "/rejected"
|
|
||||||
if not os.path.exists(savedir): os.mkdir(savedir)
|
|
||||||
lock_file(gamedir + "/orders.queue")
|
|
||||||
maxdate, filename = available_file(savedir, prefix + email)
|
|
||||||
store_message(message, filename)
|
|
||||||
unlock_file(gamedir + "/orders.queue")
|
|
||||||
fail = True
|
|
||||||
|
|
||||||
if sendmail and warning is not None:
|
|
||||||
subject = gamename + " " + messages["subject-"+locale] + warning
|
|
||||||
mail = "Subject: %s\nFrom: %s\nTo: %s\n\n" % (subject, sender, email) + msg
|
|
||||||
from smtplib import SMTP
|
|
||||||
server = SMTP("localhost")
|
|
||||||
server.sendmail(sender, email, mail)
|
|
||||||
server.close()
|
|
||||||
|
|
||||||
if not sendmail:
|
|
||||||
print text_ok, fail, email
|
|
||||||
print filename
|
|
||||||
|
|
||||||
if not fail:
|
|
||||||
lock_file(gamedir + "/orders.queue")
|
|
||||||
queue = open(gamedir + "/orders.queue", "a")
|
|
||||||
queue.write("email=%s file=%s locale=%s game=%s\n" % (email, filename, locale, game))
|
|
||||||
queue.close()
|
|
||||||
unlock_file(gamedir + "/orders.queue")
|
|
||||||
|
|
||||||
logger.info("done - accepted orders from " + email)
|
|
||||||
|
|
||||||
return 0
|
|
||||||
|
|
||||||
# the main body of the script:
|
|
||||||
try:
|
|
||||||
os.mkdir(os.path.join(rootdir, 'log'))
|
|
||||||
except:
|
|
||||||
pass # already exists?
|
|
||||||
LOG_FILENAME=os.path.join(rootdir, 'log/orders.log')
|
|
||||||
logging.basicConfig(level=logging.DEBUG, filename=LOG_FILENAME)
|
|
||||||
logger = logging
|
|
||||||
delay=None # TODO: parse the turn delay
|
|
||||||
locale = sys.argv[2]
|
|
||||||
infile = stdin
|
|
||||||
if len(sys.argv)>3:
|
|
||||||
infile = open(sys.argv[3], "r")
|
|
||||||
retval = accept(game, locale, infile, delay)
|
|
||||||
if infile!=stdin:
|
|
||||||
infile.close()
|
|
||||||
sys.exit(retval)
|
|
||||||
|
|
|
@ -1,242 +1,5 @@
|
||||||
#!/usr/bin/env python
|
#!/bin/sh
|
||||||
# -*- coding: iso-8859-1 -*-
|
SCRIPT=$(readlink -f $0)
|
||||||
|
cd $(dirname $SCRIPT)
|
||||||
|
python process-orders.py "$@"
|
||||||
|
|
||||||
from os import unlink, symlink, rename, popen, tmpfile
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import os.path
|
|
||||||
import ConfigParser
|
|
||||||
from re import compile, IGNORECASE
|
|
||||||
from string import split, join, upper, strip
|
|
||||||
from sys import argv, exit
|
|
||||||
from time import sleep, time, ctime
|
|
||||||
from syslog import openlog, closelog, syslog
|
|
||||||
|
|
||||||
from epasswd import EPasswd
|
|
||||||
|
|
||||||
def pwd_get_email(faction, pwd, pwdfile=None):
|
|
||||||
return None
|
|
||||||
|
|
||||||
def split_filename(filename):
|
|
||||||
return os.path.split(filename)
|
|
||||||
|
|
||||||
def unlock_file(filename):
|
|
||||||
try:
|
|
||||||
unlink(filename+".lock")
|
|
||||||
except:
|
|
||||||
print "could not unlock %s.lock, file not found" % filename
|
|
||||||
raise
|
|
||||||
|
|
||||||
def lock_file(filename):
|
|
||||||
i = 0
|
|
||||||
wait = 1
|
|
||||||
if not os.path.exists(filename):
|
|
||||||
file=open(filename, "w")
|
|
||||||
file.close()
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
symlink(filename, filename+".lock")
|
|
||||||
return
|
|
||||||
except:
|
|
||||||
i = i+1
|
|
||||||
if i == 5:
|
|
||||||
raise
|
|
||||||
sleep(wait)
|
|
||||||
wait = wait*2
|
|
||||||
|
|
||||||
messages = {
|
|
||||||
"subject-de": "Befehle angekommen",
|
|
||||||
"subject-en": "orders received",
|
|
||||||
|
|
||||||
"validate-en": "Validating",
|
|
||||||
"validate-de": "Verarbeite",
|
|
||||||
|
|
||||||
"faction-en": "Faction",
|
|
||||||
"faction-de": "Partei",
|
|
||||||
|
|
||||||
"unknown-de": "WARNUNG: Die Partei ist nicht bekannt, oder das Passwort falsch!",
|
|
||||||
"unknown-en": "WARNING: This faction is unknown, or the password is incorrect!",
|
|
||||||
|
|
||||||
"warning-de": "Warnung",
|
|
||||||
"warning-en": "Warning",
|
|
||||||
|
|
||||||
"error-de": "Fehler",
|
|
||||||
"error-en": "Error",
|
|
||||||
}
|
|
||||||
|
|
||||||
game = int(sys.argv[1])
|
|
||||||
echeck_cmd = "/home/eressea/echeck/echeck.sh"
|
|
||||||
maxlines = 25
|
|
||||||
|
|
||||||
# base directory for all your games:
|
|
||||||
install_dir = "/home/eressea/eressea"
|
|
||||||
if 'ERESSEA' in os.environ:
|
|
||||||
install_dir = os.environ['ERESSEA']
|
|
||||||
elif 'HOME' in os.environ:
|
|
||||||
install_dir = os.path.join(os.environ['HOME'], '/eressea')
|
|
||||||
if not os.path.isdir(install_dir):
|
|
||||||
print "please set the ERESSEA environment variable to the install path"
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
game_dir = os.path.join(install_dir, "game-%d" % (game, ))
|
|
||||||
frommail = 'eressea-server@kn-bremen.de'
|
|
||||||
gamename = 'Eressea'
|
|
||||||
sender = '%s Server <%s>' % (gamename, frommail)
|
|
||||||
|
|
||||||
inifile = os.path.join(game_dir, 'eressea.ini')
|
|
||||||
if not os.path.exists(inifile):
|
|
||||||
print "no such file: " . inifile
|
|
||||||
else:
|
|
||||||
config = ConfigParser.ConfigParser()
|
|
||||||
config.read(inifile)
|
|
||||||
if config.has_option('game', 'email'):
|
|
||||||
frommail = config.get('game', 'email')
|
|
||||||
if config.has_option('game', 'name'):
|
|
||||||
gamename = config.get('game', 'name')
|
|
||||||
if config.has_option('game', 'sender'):
|
|
||||||
sender = config.get('game', 'sender')
|
|
||||||
else:
|
|
||||||
sender = "%s Server <%s>" % (gamename, frommail)
|
|
||||||
config = None
|
|
||||||
|
|
||||||
queue_file = os.path.join(game_dir, "orders.queue")
|
|
||||||
if not os.path.exists(queue_file):
|
|
||||||
exit(0)
|
|
||||||
|
|
||||||
# regular expression that finds the start of a faction
|
|
||||||
fact_re = compile("^\s*(eressea|partei|faction)\s+([a-zA-Z0-9]+)\s+\"?([^\"]*)\"?", IGNORECASE)
|
|
||||||
|
|
||||||
def check_pwd(filename, email, pw_data):
|
|
||||||
results = []
|
|
||||||
try:
|
|
||||||
file = open(filename, "r")
|
|
||||||
except:
|
|
||||||
print "could not open file", filename
|
|
||||||
return results
|
|
||||||
for line in file.readlines():
|
|
||||||
mo = fact_re.search(strip(line))
|
|
||||||
if mo != None:
|
|
||||||
fact_nr = str(mo.group(2))
|
|
||||||
fact_pw = str(mo.group(3))
|
|
||||||
if pw_data.fac_exists(fact_nr):
|
|
||||||
if not pw_data.check(fact_nr, fact_pw):
|
|
||||||
game_email = pw_data.get_email(fact_nr)
|
|
||||||
results = results + [ (fact_nr, game_email, False, fact_pw) ]
|
|
||||||
else:
|
|
||||||
game_email = pw_data.get_email(fact_nr)
|
|
||||||
results = results + [ (fact_nr, game_email, True, fact_pw) ]
|
|
||||||
else:
|
|
||||||
results = results + [ (fact_nr, None, False, fact_pw) ]
|
|
||||||
return results
|
|
||||||
|
|
||||||
def echeck(filename, locale, rules):
|
|
||||||
dirname, filename = split_filename(filename)
|
|
||||||
stream = popen("%s %s %s %s %s" % (echeck_cmd, locale, filename, dirname, rules), 'r')
|
|
||||||
lines = stream.readlines()
|
|
||||||
if len(lines)==0:
|
|
||||||
stream.close()
|
|
||||||
return None
|
|
||||||
if len(lines)>maxlines:
|
|
||||||
mail = join(lines[:maxlines-3] + ["...", "\n"] + lines[-3:], '')
|
|
||||||
else:
|
|
||||||
mail = join(lines[:maxlines], '')
|
|
||||||
stream.close()
|
|
||||||
return mail
|
|
||||||
|
|
||||||
# parse the queue file -
|
|
||||||
#print "connecting to SMTP..."
|
|
||||||
from smtplib import SMTP
|
|
||||||
try:
|
|
||||||
server = SMTP("localhost")
|
|
||||||
except:
|
|
||||||
print "could not connect to SMTP server"
|
|
||||||
exit(0)
|
|
||||||
|
|
||||||
#print "reading password file..."
|
|
||||||
pw_data = EPasswd(os.path.join(game_dir,"passwd"))
|
|
||||||
|
|
||||||
#print "reading orders.queue..."
|
|
||||||
# move the queue file to a save space while locking it:
|
|
||||||
try:
|
|
||||||
lock_file(queue_file)
|
|
||||||
except:
|
|
||||||
exit(0)
|
|
||||||
queuefile = open(queue_file, "r")
|
|
||||||
lines = queuefile.readlines()
|
|
||||||
queuefile.close()
|
|
||||||
|
|
||||||
# copy to a temp file
|
|
||||||
|
|
||||||
tname="/tmp/orders.queue.%s" % str(time())
|
|
||||||
try:
|
|
||||||
lock_file(tname)
|
|
||||||
except:
|
|
||||||
exit(0)
|
|
||||||
tmpfile=open(tname, "w")
|
|
||||||
for line in lines:
|
|
||||||
tmpfile.write(line)
|
|
||||||
tmpfile.close()
|
|
||||||
|
|
||||||
openlog("orders")
|
|
||||||
|
|
||||||
unlink(queue_file)
|
|
||||||
try:
|
|
||||||
unlock_file(queue_file)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
for line in lines:
|
|
||||||
tokens = split(line[:-1], ' ')
|
|
||||||
dict = {}
|
|
||||||
for token in tokens:
|
|
||||||
name, value = split(token, '=')
|
|
||||||
dict[name] = value
|
|
||||||
|
|
||||||
email = dict["email"]
|
|
||||||
locale = dict["locale"]
|
|
||||||
game = int(dict["game"])
|
|
||||||
infile = dict["file"]
|
|
||||||
gamename='[E%d]' % game
|
|
||||||
rules='e%d' % game
|
|
||||||
warning = ""
|
|
||||||
failed = True
|
|
||||||
results = check_pwd(infile, email, pw_data)
|
|
||||||
logfile = open(os.path.join(game_dir, "zug.log"), "a")
|
|
||||||
dirname, filename = split_filename(infile)
|
|
||||||
msg = messages["validate-"+locale] + " " + infile + "\n\n"
|
|
||||||
for faction, game_email, success, pwd in results:
|
|
||||||
msg = msg + messages["faction-"+locale] + " " + faction + "\n"
|
|
||||||
if success: failed = False
|
|
||||||
else: msg = msg + messages["unknown-"+locale] + "\n"
|
|
||||||
msg = msg + "\n"
|
|
||||||
logfile.write("%s:%s:%s:%s:%s:%s\n" % (ctime(time()), email, game_email, faction, pwd, success))
|
|
||||||
logfile.close()
|
|
||||||
|
|
||||||
if failed:
|
|
||||||
warning = " (" + messages["warning-" + locale] + ")"
|
|
||||||
syslog("failed - no valid password in " + infile)
|
|
||||||
else:
|
|
||||||
result = None
|
|
||||||
if os.path.exists(echeck_cmd):
|
|
||||||
result = echeck(infile, locale, rules)
|
|
||||||
if result is None:
|
|
||||||
# echeck did not finish
|
|
||||||
msg = msg + "Echeck is broken. Your turn was accepted, but could not be verified.\n"
|
|
||||||
warning = " (" + messages["warning-" + locale] + ")"
|
|
||||||
syslog("process - echeck broken, " + infile)
|
|
||||||
else:
|
|
||||||
msg = msg + result
|
|
||||||
syslog("process - checked orders in " + infile)
|
|
||||||
|
|
||||||
subject = gamename + " " + messages["subject-" + locale] + warning
|
|
||||||
msg = "Subject: %s\nFrom: %s\nTo: %s\nContent-Type: text/plain; charset=utf-8\n\n" % (subject, sender, email) + msg
|
|
||||||
try:
|
|
||||||
server.sendmail(sender, email, msg)
|
|
||||||
except:
|
|
||||||
syslog("failed - cannot send to " + email)
|
|
||||||
|
|
||||||
server.close()
|
|
||||||
|
|
||||||
closelog()
|
|
||||||
unlink(tname)
|
|
||||||
unlock_file(tname)
|
|
||||||
|
|
215
process/process-orders.py
Executable file
215
process/process-orders.py
Executable file
|
@ -0,0 +1,215 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from os import unlink, symlink, rename, popen, tmpfile
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import ConfigParser
|
||||||
|
import subprocess
|
||||||
|
from re import compile, IGNORECASE
|
||||||
|
from string import split, join, upper, strip
|
||||||
|
from sys import argv, exit
|
||||||
|
from time import sleep, time, ctime
|
||||||
|
from syslog import openlog, closelog, syslog
|
||||||
|
|
||||||
|
from epasswd import EPasswd
|
||||||
|
|
||||||
|
def pwd_get_email(faction, pwd, pwdfile=None):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def split_filename(filename):
|
||||||
|
return os.path.split(filename)
|
||||||
|
|
||||||
|
def unlock_file(filename):
|
||||||
|
try:
|
||||||
|
unlink(filename+".lock")
|
||||||
|
except:
|
||||||
|
print "could not unlock %s.lock, file not found" % filename
|
||||||
|
raise
|
||||||
|
|
||||||
|
def lock_file(filename):
|
||||||
|
i = 0
|
||||||
|
wait = 1
|
||||||
|
if not os.path.exists(filename):
|
||||||
|
file=open(filename, "w")
|
||||||
|
file.close()
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
symlink(filename, filename+".lock")
|
||||||
|
return
|
||||||
|
except:
|
||||||
|
i = i+1
|
||||||
|
if i == 5:
|
||||||
|
raise
|
||||||
|
sleep(wait)
|
||||||
|
wait = wait*2
|
||||||
|
|
||||||
|
messages = {
|
||||||
|
"subject-de": "Befehle angekommen",
|
||||||
|
"subject-en": "orders received",
|
||||||
|
|
||||||
|
"validate-en": "Validating",
|
||||||
|
"validate-de": "Verarbeite",
|
||||||
|
|
||||||
|
"faction-en": "Faction",
|
||||||
|
"faction-de": "Partei",
|
||||||
|
|
||||||
|
"unknown-de": "WARNUNG: Die Partei ist nicht bekannt, oder das Passwort falsch!",
|
||||||
|
"unknown-en": "WARNING: This faction is unknown, or the password is incorrect!",
|
||||||
|
|
||||||
|
"warning-de": "Warnung",
|
||||||
|
"warning-en": "Warning",
|
||||||
|
|
||||||
|
"error-de": "Fehler",
|
||||||
|
"error-en": "Error",
|
||||||
|
}
|
||||||
|
|
||||||
|
game = int(sys.argv[1])
|
||||||
|
echeck_cmd = "/home/eressea/echeck/echeck.sh"
|
||||||
|
maxlines = 25
|
||||||
|
|
||||||
|
# base directory for all your games:
|
||||||
|
install_dir = "/home/eressea/eressea"
|
||||||
|
if 'ERESSEA' in os.environ:
|
||||||
|
install_dir = os.environ['ERESSEA']
|
||||||
|
elif 'HOME' in os.environ:
|
||||||
|
install_dir = os.path.join(os.environ['HOME'], 'eressea')
|
||||||
|
if not os.path.isdir(install_dir):
|
||||||
|
print "please set the ERESSEA environment variable to the install path"
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
game_dir = os.path.join(install_dir, "game-%d" % (game, ))
|
||||||
|
gamename = 'Eressea'
|
||||||
|
|
||||||
|
inifile = os.path.join(game_dir, 'eressea.ini')
|
||||||
|
queue_file = os.path.join(game_dir, "orders.queue")
|
||||||
|
if not os.path.exists(queue_file):
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
# regular expression that finds the start of a faction
|
||||||
|
fact_re = compile("^\s*(eressea|partei|faction)\s+([a-zA-Z0-9]+)\s+\"?([^\"]*)\"?", IGNORECASE)
|
||||||
|
|
||||||
|
def check_pwd(filename, email, pw_data):
|
||||||
|
results = []
|
||||||
|
try:
|
||||||
|
file = open(filename, "r")
|
||||||
|
except:
|
||||||
|
print "could not open file", filename
|
||||||
|
return results
|
||||||
|
for line in file.readlines():
|
||||||
|
mo = fact_re.search(strip(line))
|
||||||
|
if mo != None:
|
||||||
|
fact_nr = str(mo.group(2))
|
||||||
|
fact_pw = str(mo.group(3))
|
||||||
|
if pw_data.fac_exists(fact_nr):
|
||||||
|
if not pw_data.check(fact_nr, fact_pw):
|
||||||
|
game_email = pw_data.get_email(fact_nr)
|
||||||
|
results = results + [ (fact_nr, game_email, False, fact_pw) ]
|
||||||
|
else:
|
||||||
|
game_email = pw_data.get_email(fact_nr)
|
||||||
|
results = results + [ (fact_nr, game_email, True, fact_pw) ]
|
||||||
|
else:
|
||||||
|
results = results + [ (fact_nr, None, False, fact_pw) ]
|
||||||
|
return results
|
||||||
|
|
||||||
|
def echeck(filename, locale, rules):
|
||||||
|
dirname, filename = split_filename(filename)
|
||||||
|
stream = popen("%s %s %s %s %s" % (echeck_cmd, locale, filename, dirname, rules), 'r')
|
||||||
|
lines = stream.readlines()
|
||||||
|
if len(lines)==0:
|
||||||
|
stream.close()
|
||||||
|
return None
|
||||||
|
if len(lines)>maxlines:
|
||||||
|
mail = join(lines[:maxlines-3] + ["...", "\n"] + lines[-3:], '')
|
||||||
|
else:
|
||||||
|
mail = join(lines[:maxlines], '')
|
||||||
|
stream.close()
|
||||||
|
return mail
|
||||||
|
|
||||||
|
#print "reading password file..."
|
||||||
|
pw_data = EPasswd(os.path.join(game_dir,"passwd"))
|
||||||
|
|
||||||
|
#print "reading orders.queue..."
|
||||||
|
# move the queue file to a save space while locking it:
|
||||||
|
try:
|
||||||
|
lock_file(queue_file)
|
||||||
|
except:
|
||||||
|
exit(0)
|
||||||
|
queuefile = open(queue_file, "r")
|
||||||
|
lines = queuefile.readlines()
|
||||||
|
queuefile.close()
|
||||||
|
|
||||||
|
# copy to a temp file
|
||||||
|
|
||||||
|
tname="/tmp/orders.queue.%s" % str(time())
|
||||||
|
try:
|
||||||
|
lock_file(tname)
|
||||||
|
except:
|
||||||
|
exit(0)
|
||||||
|
tmpfile=open(tname, "w")
|
||||||
|
for line in lines:
|
||||||
|
tmpfile.write(line)
|
||||||
|
tmpfile.close()
|
||||||
|
|
||||||
|
openlog("orders")
|
||||||
|
|
||||||
|
unlink(queue_file)
|
||||||
|
try:
|
||||||
|
unlock_file(queue_file)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
tokens = split(line[:-1], ' ')
|
||||||
|
dict = {}
|
||||||
|
for token in tokens:
|
||||||
|
name, value = split(token, '=')
|
||||||
|
dict[name] = value
|
||||||
|
|
||||||
|
email = dict["email"]
|
||||||
|
locale = dict["locale"]
|
||||||
|
game = int(dict["game"])
|
||||||
|
infile = dict["file"]
|
||||||
|
gamename='[E%d]' % game
|
||||||
|
rules='e%d' % game
|
||||||
|
warning = ""
|
||||||
|
failed = True
|
||||||
|
results = check_pwd(infile, email, pw_data)
|
||||||
|
logfile = open(os.path.join(game_dir, "zug.log"), "a")
|
||||||
|
dirname, filename = split_filename(infile)
|
||||||
|
msg = messages["validate-"+locale] + " " + infile + "\n\n"
|
||||||
|
for faction, game_email, success, pwd in results:
|
||||||
|
msg = msg + messages["faction-"+locale] + " " + faction + "\n"
|
||||||
|
if success: failed = False
|
||||||
|
else: msg = msg + messages["unknown-"+locale] + "\n"
|
||||||
|
msg = msg + "\n"
|
||||||
|
logfile.write("%s:%s:%s:%s:%s:%s\n" % (ctime(time()), email, game_email, faction, pwd, success))
|
||||||
|
logfile.close()
|
||||||
|
|
||||||
|
if failed:
|
||||||
|
warning = " (" + messages["warning-" + locale] + ")"
|
||||||
|
syslog("failed - no valid password in " + infile)
|
||||||
|
else:
|
||||||
|
result = None
|
||||||
|
if os.path.exists(echeck_cmd):
|
||||||
|
result = echeck(infile, locale, rules)
|
||||||
|
if result is None:
|
||||||
|
# echeck did not finish
|
||||||
|
msg = msg + "Echeck is broken. Your turn was accepted, but could not be verified.\n"
|
||||||
|
warning = " (" + messages["warning-" + locale] + ")"
|
||||||
|
syslog("process - echeck broken, " + infile)
|
||||||
|
else:
|
||||||
|
msg = msg + result
|
||||||
|
syslog("process - checked orders in " + infile)
|
||||||
|
|
||||||
|
subject = gamename + " " + messages["subject-" + locale] + warning
|
||||||
|
try:
|
||||||
|
sp = subprocess.Popen(['mutt', '-s', subject, email], stdin=subprocess.PIPE)
|
||||||
|
sp.communicate(msg)
|
||||||
|
except:
|
||||||
|
syslog("failed - cannot send to " + email)
|
||||||
|
|
||||||
|
closelog()
|
||||||
|
unlink(tname)
|
||||||
|
unlock_file(tname)
|
|
@ -1,12 +1,13 @@
|
||||||
<?xml version="1.0" encoding="utf-8" ?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<eressea>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<resource name="adamantium" limited="yes" material="yes">
|
<resource name="adamantium" limited="yes" material="yes">
|
||||||
<item weight="200" score="200">
|
<item weight="200" score="200">
|
||||||
<construction skill="mining" minskill="8"/>
|
<construction skill="mining" minskill="8"/>
|
||||||
</item>
|
</item>
|
||||||
<modifier building="mine" type="skill" value="1"/>
|
<modifier building="mine" type="skill" value="1"/>
|
||||||
<modifier type="require" building="mine"/>
|
<modifier type="require" building="mine"/>
|
||||||
</resource>
|
</resource>
|
||||||
|
|
||||||
<resource name="adamantiumaxe">
|
<resource name="adamantiumaxe">
|
||||||
|
@ -15,7 +16,7 @@
|
||||||
<requirement type="adamantium" quantity="1"/>
|
<requirement type="adamantium" quantity="1"/>
|
||||||
<requirement type="log" quantity="1"/>
|
<requirement type="log" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
<weapon cut="true" skill="melee" offmod="2" defmod="-2" magres="0.30">
|
<weapon cut="true" magical="true" skill="melee" offmod="2" defmod="-2" magres="0.30">
|
||||||
<damage type="rider" value="3d4+15"/>
|
<damage type="rider" value="3d4+15"/>
|
||||||
<damage type="footman" value="3d4+15"/>
|
<damage type="footman" value="3d4+15"/>
|
||||||
</weapon>
|
</weapon>
|
||||||
|
@ -32,3 +33,4 @@
|
||||||
</resource>
|
</resource>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<buildings>
|
||||||
<building name="castle" fort="yes" taxes="100">
|
<building name="castle" fort="yes" taxes="100">
|
||||||
<construction skill="building" minskill="1" maxsize="10" name="site">
|
<construction skill="building" minskill="1" maxsize="10" name="site">
|
||||||
<requirement type="stone" quantity="1"/>
|
<requirement type="stone" quantity="1"/>
|
||||||
|
@ -19,3 +21,5 @@
|
||||||
<requirement type="stone" quantity="1"/>
|
<requirement type="stone" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
</building>
|
</building>
|
||||||
|
</buildings>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<buildings>
|
||||||
<building name="castle" fort="yes">
|
<building name="castle" fort="yes">
|
||||||
<construction skill="building" minskill="1" maxsize="2" name="site">
|
<construction skill="building" minskill="1" maxsize="2" name="site">
|
||||||
<requirement type="stone" quantity="1"/>
|
<requirement type="stone" quantity="1"/>
|
||||||
|
@ -22,3 +24,5 @@
|
||||||
<requirement type="stone" quantity="1"/>
|
<requirement type="stone" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
</building>
|
</building>
|
||||||
|
</buildings>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea><resources>
|
||||||
<resource name="chainmail">
|
<resource name="chainmail">
|
||||||
<item weight="200" score="90">
|
<item weight="200" score="90">
|
||||||
<construction skill="armorer" minskill="3">
|
<construction skill="armorer" minskill="3">
|
||||||
|
@ -7,3 +8,4 @@
|
||||||
<armor ac="3" penalty="0.15" magres="0.0"/>
|
<armor ac="3" penalty="0.15" magres="0.0"/>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources></eressea>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea><resources>
|
||||||
<resource name="laenmail">
|
<resource name="laenmail">
|
||||||
<item weight="100" score="1000">
|
<item weight="100" score="1000">
|
||||||
<construction skill="armorer" minskill="9">
|
<construction skill="armorer" minskill="9">
|
||||||
|
@ -7,3 +8,4 @@
|
||||||
<armor ac="6" penalty="0.0" magres="0.3" laen="yes" />
|
<armor ac="6" penalty="0.0" magres="0.3" laen="yes" />
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources></eressea>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea><resources>
|
||||||
<resource name="laenshield">
|
<resource name="laenshield">
|
||||||
<item weight="0" score="1000">
|
<item weight="0" score="1000">
|
||||||
<construction skill="armorer" minskill="7">
|
<construction skill="armorer" minskill="7">
|
||||||
|
@ -7,3 +8,4 @@
|
||||||
<armor ac="2" penalty="-0.25" magres="0.3" laen="yes" shield="yes" />
|
<armor ac="2" penalty="-0.25" magres="0.3" laen="yes" shield="yes" />
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources></eressea>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea><resources>
|
||||||
<resource name="plate">
|
<resource name="plate">
|
||||||
<item weight="400" score="150">
|
<item weight="400" score="150">
|
||||||
<construction skill="armorer" minskill="4">
|
<construction skill="armorer" minskill="4">
|
||||||
|
@ -7,3 +8,4 @@
|
||||||
<armor ac="5" penalty="0.30" magres="0.0"/>
|
<armor ac="5" penalty="0.30" magres="0.0"/>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources></eressea>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea><resources>
|
||||||
<resource name="rustychainmail">
|
<resource name="rustychainmail">
|
||||||
<item weight="200" score="30">
|
<item weight="200" score="30">
|
||||||
<construction skill="armorer" minskill="3">
|
<construction skill="armorer" minskill="3">
|
||||||
|
@ -7,4 +8,4 @@
|
||||||
<armor ac="2" penalty="0.30" magres="0.0"/>
|
<armor ac="2" penalty="0.30" magres="0.0"/>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources></eressea>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea><resources>
|
||||||
<resource name="rustyshield">
|
<resource name="rustyshield">
|
||||||
<item weight="100" score="10">
|
<item weight="100" score="10">
|
||||||
<construction skill="armorer" minskill="2">
|
<construction skill="armorer" minskill="2">
|
||||||
|
@ -7,3 +8,4 @@
|
||||||
<armor ac="1" penalty="0.0" magres="0.0" shield="yes"/>
|
<armor ac="1" penalty="0.0" magres="0.0" shield="yes"/>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources></eressea>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea><resources>
|
||||||
<resource name="shield">
|
<resource name="shield">
|
||||||
<item weight="100" score="30">
|
<item weight="100" score="30">
|
||||||
<construction skill="armorer" minskill="2">
|
<construction skill="armorer" minskill="2">
|
||||||
|
@ -7,3 +8,4 @@
|
||||||
<armor ac="1" penalty="-0.15" magres="0.0" shield="yes"/>
|
<armor ac="1" penalty="-0.15" magres="0.0" shield="yes"/>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources></eressea>
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<resources xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
||||||
<xi:include href="../armor/chainmail.xml"/>
|
|
||||||
<xi:include href="../armor/laenmail.xml"/>
|
|
||||||
<xi:include href="../armor/laenshield.xml"/>
|
|
||||||
<xi:include href="../armor/plate.xml"/>
|
|
||||||
<xi:include href="../armor/rustychainmail.xml"/>
|
|
||||||
<xi:include href="../armor/rustyshield.xml"/>
|
|
||||||
<xi:include href="../armor/shield.xml"/>
|
|
||||||
</resources>
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
<buildings>
|
<buildings>
|
||||||
<building name="wormhole" maxsize="4" maxcapacity="4" nobuild="yes" nodestroy="yes" unique="yes" />
|
<building name="wormhole" maxsize="4" maxcapacity="4" nobuild="yes" nodestroy="yes" unique="yes" />
|
||||||
<building name="illusioncastle" capacity="0" maxcapacity="0" maxsize="0" nobuild="yes"/>
|
<building name="illusioncastle" capacity="0" maxcapacity="0" maxsize="0" nobuild="yes"/>
|
||||||
|
@ -167,4 +168,4 @@
|
||||||
</building>
|
</building>
|
||||||
|
|
||||||
</buildings>
|
</buildings>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<!-- TODO: this does not work yet -->
|
|
||||||
<production>
|
|
||||||
<construction resource="laenshield" skill="armorer" minskill="7">
|
|
||||||
<requirement type="laen" quantity="1"/>
|
|
||||||
</construction>
|
|
||||||
<construction resource="laenmail" skill="armorer" minskill="9">
|
|
||||||
<requirement type="laen" quantity="3"/>
|
|
||||||
</construction>
|
|
||||||
</production>
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
<resources>
|
<resources>
|
||||||
<!-- this file contains herbs that are part of the alchemy system -->
|
<!-- this file contains herbs that are part of the alchemy system -->
|
||||||
|
|
||||||
|
@ -87,3 +88,4 @@
|
||||||
</resource>
|
</resource>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<resource name="money">
|
<resource name="money">
|
||||||
|
@ -33,8 +34,8 @@
|
||||||
<item weight="0" score="6000"/>
|
<item weight="0" score="6000"/>
|
||||||
</resource>
|
</resource>
|
||||||
|
|
||||||
<resource name="presspass" cursed="yes">
|
<resource name="presspass">
|
||||||
<item weight="0" score="6000"/>
|
<item weight="0" score="6000" cursed="yes"/>
|
||||||
</resource>
|
</resource>
|
||||||
|
|
||||||
<resource name="aurafocus">
|
<resource name="aurafocus">
|
||||||
|
@ -133,3 +134,4 @@
|
||||||
</resource>
|
</resource>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
<resources>
|
<resources>
|
||||||
<!-- this file contains luxury items that are part of the trade system -->
|
<!-- this file contains luxury items that are part of the trade system -->
|
||||||
<resource name="balm">
|
<resource name="balm">
|
||||||
|
@ -24,3 +25,4 @@
|
||||||
</resource>
|
</resource>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
<resources>
|
<resources>
|
||||||
<!-- this file contains potions that are part of the alchemy system -->
|
<!-- this file contains potions that are part of the alchemy system -->
|
||||||
|
|
||||||
|
@ -33,7 +34,7 @@
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
|
||||||
<resource name="p2" appearance="vial">
|
<resource name="lifepotion" appearance="vial">
|
||||||
<item weight="0" score="30" use="yes">
|
<item weight="0" score="30" use="yes">
|
||||||
<potion level="1"/>
|
<potion level="1"/>
|
||||||
<construction skill="alchemy" minskill="2">
|
<construction skill="alchemy" minskill="2">
|
||||||
|
@ -166,7 +167,7 @@
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
|
||||||
<resource name="p14" appearance="vial">
|
<resource name="healing" appearance="vial">
|
||||||
<item weight="0" score="120" use="yes">
|
<item weight="0" score="120" use="yes">
|
||||||
<potion level="4"/>
|
<potion level="4"/>
|
||||||
<construction skill="alchemy" minskill="8">
|
<construction skill="alchemy" minskill="8">
|
||||||
|
@ -180,3 +181,4 @@
|
||||||
</resource>
|
</resource>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<resources xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
||||||
<!--
|
|
||||||
this file contains the most important items and resources any game will
|
|
||||||
want to use. Or maybe you just have to roll your own file.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<xi:include href="../resources/cart.xml"/>
|
|
||||||
<xi:include href="../resources/horse.xml"/>
|
|
||||||
<xi:include href="../resources/hp.xml"/>
|
|
||||||
<xi:include href="../resources/iron.xml"/>
|
|
||||||
<xi:include href="../resources/laen.xml"/>
|
|
||||||
<xi:include href="../resources/log.xml"/>
|
|
||||||
<xi:include href="../resources/mallorn.xml"/>
|
|
||||||
<xi:include href="../resources/mallornseed.xml"/>
|
|
||||||
<xi:include href="../resources/seed.xml"/>
|
|
||||||
<xi:include href="../resources/peasant.xml"/>
|
|
||||||
<xi:include href="../resources/stone.xml"/>
|
|
||||||
</resources>
|
|
|
@ -1,24 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<resources xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
||||||
<xi:include href="../weapons/axe.xml"/>
|
|
||||||
<xi:include href="../weapons/bow.xml"/>
|
|
||||||
<xi:include href="../weapons/catapult.xml"/>
|
|
||||||
<xi:include href="../weapons/crossbow.xml"/>
|
|
||||||
<xi:include href="../weapons/firesword.xml"/>
|
|
||||||
<xi:include href="../weapons/greatbow.xml"/>
|
|
||||||
<xi:include href="../weapons/greatsword.xml"/>
|
|
||||||
<xi:include href="../weapons/halberd.xml"/>
|
|
||||||
<xi:include href="../weapons/laensword.xml"/>
|
|
||||||
<xi:include href="../weapons/lance.xml"/>
|
|
||||||
<xi:include href="../weapons/mallornbow.xml"/>
|
|
||||||
<xi:include href="../weapons/mallorncrossbow.xml"/>
|
|
||||||
<xi:include href="../weapons/mallornlance.xml"/>
|
|
||||||
<xi:include href="../weapons/mallornspear.xml"/>
|
|
||||||
<xi:include href="../weapons/runesword.xml"/>
|
|
||||||
<xi:include href="../weapons/rustyaxe.xml"/>
|
|
||||||
<xi:include href="../weapons/rustygreatsword.xml"/>
|
|
||||||
<xi:include href="../weapons/rustyhalberd.xml"/>
|
|
||||||
<xi:include href="../weapons/rustysword.xml"/>
|
|
||||||
<xi:include href="../weapons/spear.xml"/>
|
|
||||||
<xi:include href="../weapons/sword.xml"/>
|
|
||||||
</resources>
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="cart">
|
<resource name="cart">
|
||||||
<item capacity="14000" weight="4000" score="60" vehicle="yes" big="yes">
|
<item capacity="14000" weight="4000" score="60" vehicle="yes" big="yes">
|
||||||
<construction skill="cartmaking" minskill="1">
|
<construction skill="cartmaking" minskill="1">
|
||||||
|
@ -6,3 +8,5 @@
|
||||||
</construction>
|
</construction>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="horse" limited="yes">
|
<resource name="horse" limited="yes">
|
||||||
<item big="yes" weight="5000" score="10" capacity="7000" animal="yes">
|
<item big="yes" weight="5000" score="10" capacity="7000" animal="yes">
|
||||||
<construction skill="training" minskill="1" />
|
<construction skill="training" minskill="1" />
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="hp" pooled="false">
|
<resource name="hp" pooled="false">
|
||||||
<function name="change" value="lua_changeresource"/>
|
<function name="change" value="lua_changeresource"/>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="iron" limited="yes" material="yes">
|
<resource name="iron" limited="yes" material="yes">
|
||||||
<item weight="500" score="10">
|
<item weight="500" score="10">
|
||||||
<construction skill="mining" minskill="1"/>
|
<construction skill="mining" minskill="1"/>
|
||||||
|
@ -6,5 +8,7 @@
|
||||||
<modifier building="smithy" type="save" value="2"/>
|
<modifier building="smithy" type="save" value="2"/>
|
||||||
<modifier building="mine" type="skill" value="1"/>
|
<modifier building="mine" type="skill" value="1"/>
|
||||||
<modifier building="mine" type="material" value="0.5"/>
|
<modifier building="mine" type="material" value="0.5"/>
|
||||||
<modifier race="dwarf" type="material" value="0.6"/>
|
<modifier races="dwarf" type="material" value="0.6"/>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="laen" limited="yes" material="yes">
|
<resource name="laen" limited="yes" material="yes">
|
||||||
<item weight="200" score="100">
|
<item weight="200" score="100">
|
||||||
<construction skill="mining" minskill="7"/>
|
<construction skill="mining" minskill="7"/>
|
||||||
</item>
|
</item>
|
||||||
<modifier building="mine" type="skill" value="1"/>
|
<modifier building="mine" type="skill" value="1"/>
|
||||||
<modifier type="require" building="mine"/>
|
<modifier type="require" building="mine"/>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="log" limited="yes">
|
<resource name="log" limited="yes">
|
||||||
<item weight="500" score="10">
|
<item weight="500" score="10">
|
||||||
<construction skill="forestry" minskill="1"/>
|
<construction skill="forestry" minskill="1"/>
|
||||||
|
@ -6,3 +8,5 @@
|
||||||
<modifier building="sawmill" type="skill" value="1"/>
|
<modifier building="sawmill" type="skill" value="1"/>
|
||||||
<modifier building="sawmill" type="material" value="0.5"/>
|
<modifier building="sawmill" type="material" value="0.5"/>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="mallorn" limited="yes">
|
<resource name="mallorn" limited="yes">
|
||||||
<item weight="500" score="30">
|
<item weight="500" score="30">
|
||||||
<construction skill="forestry" minskill="2"/>
|
<construction skill="forestry" minskill="2"/>
|
||||||
|
@ -6,3 +8,5 @@
|
||||||
<modifier building="sawmill" type="skill" value="1"/>
|
<modifier building="sawmill" type="skill" value="1"/>
|
||||||
<modifier building="sawmill" type="material" value="0.5"/>
|
<modifier building="sawmill" type="material" value="0.5"/>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="mallornseed" limited="yes">
|
<resource name="mallornseed" limited="yes">
|
||||||
<item weight="10" score="100">
|
<item weight="10" score="100">
|
||||||
<construction skill="herbalism" minskill="4"/>
|
<construction skill="herbalism" minskill="4"/>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="peasant" pooled="false">
|
<resource name="peasant" pooled="false">
|
||||||
<function name="change" value="lua_changeresource"/>
|
<function name="change" value="lua_changeresource"/>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="seed" limited="yes">
|
<resource name="seed" limited="yes">
|
||||||
<item weight="10" score="50">
|
<item weight="10" score="50">
|
||||||
<construction skill="herbalism" minskill="3"/>
|
<construction skill="herbalism" minskill="3"/>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="stone" limited="yes" material="yes">
|
<resource name="stone" limited="yes" material="yes">
|
||||||
<item weight="6000" score="10" big="yes">
|
<item weight="6000" score="10" big="yes">
|
||||||
<construction skill="quarrying" minskill="1"/>
|
<construction skill="quarrying" minskill="1"/>
|
||||||
</item>
|
</item>
|
||||||
<modifier building="quarry" type="skill" value="1"/>
|
<modifier building="quarry" type="skill" value="1"/>
|
||||||
<modifier building="quarry" type="material" value="0.5"/>
|
<modifier building="quarry" type="material" value="0.5"/>
|
||||||
<modifier race="troll" type="material" value="0.75"/>
|
<modifier races="troll" type="material" value="0.75"/>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
<ships>
|
<ships>
|
||||||
<ship name="trireme" range="7" storm="1.00" damage="1.00" cargo="200000" cptskill="4" minskill="1" sumskill="120" opensea="yes">
|
<ship name="trireme" range="7" storm="1.00" damage="1.00" cargo="200000" cptskill="4" minskill="1" sumskill="120" opensea="yes">
|
||||||
<coast terrain="plain"/>
|
<coast terrain="plain"/>
|
||||||
|
@ -73,4 +74,4 @@
|
||||||
</ship>
|
</ship>
|
||||||
|
|
||||||
</ships>
|
</ships>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
<?xml version="1.0" ?>
|
|
||||||
<spellbook name="cerddor">
|
|
||||||
<entry spell="create_roi" level="6" />
|
|
||||||
<entry spell="earn_silver#cerddor" level="1" />
|
|
||||||
<entry spell="create_aots" level="6" />
|
|
||||||
<entry spell="create_roqf" level="11" />
|
|
||||||
</spellbook>
|
|
|
@ -1,8 +0,0 @@
|
||||||
<?xml version="1.0" ?>
|
|
||||||
<spellbook name="draig">
|
|
||||||
<entry spell="create_roi" level="6" />
|
|
||||||
<entry spell="earn_silver#draig" level="1" />
|
|
||||||
<entry spell="create_aots" level="6" />
|
|
||||||
<entry spell="create_firesword" level="12" />
|
|
||||||
<entry spell="create_trollbelt" level="9" />
|
|
||||||
</spellbook>
|
|
|
@ -1,7 +0,0 @@
|
||||||
<?xml version="1.0" ?>
|
|
||||||
<spellbook name="gray">
|
|
||||||
<entry spell="create_runesword" level="6" />
|
|
||||||
<entry spell="create_chastitybelt" level="7" />
|
|
||||||
<entry spell="create_focus" level="9" />
|
|
||||||
<entry spell="create_ror" level="9" />
|
|
||||||
</spellbook>
|
|
|
@ -1,7 +0,0 @@
|
||||||
<?xml version="1.0" ?>
|
|
||||||
<spellbook name="gwyrrd">
|
|
||||||
<entry spell="create_roi" level="6" />
|
|
||||||
<entry spell="earn_silver#gwyrrd" level="1" />
|
|
||||||
<entry spell="create_aots" level="6" />
|
|
||||||
<entry spell="create_magicherbbag" level="5" />
|
|
||||||
</spellbook>
|
|
|
@ -1,8 +0,0 @@
|
||||||
<?xml version="1.0" ?>
|
|
||||||
<spellbook name="illaun">
|
|
||||||
<entry spell="create_roi" level="6" />
|
|
||||||
<entry spell="earn_silver#illaun" level="1" />
|
|
||||||
<entry spell="create_aots" level="6" />
|
|
||||||
<entry spell="create_dreameye" level="14" />
|
|
||||||
<entry spell="create_invisibility_sphere" level="13" />
|
|
||||||
</spellbook>
|
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0" ?>
|
|
||||||
<spellbook name="tybied">
|
|
||||||
<entry spell="create_roi" level="6" />
|
|
||||||
<entry spell="earn_silver#tybied" level="1" />
|
|
||||||
<entry spell="create_aots" level="6" />
|
|
||||||
<entry spell="create_antimagic" level="7" />
|
|
||||||
<entry spell="create_rop" level="9" />
|
|
||||||
<entry spell="create_bagofholding" level="10" />
|
|
||||||
</spellbook>
|
|
|
@ -1,123 +1,116 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<spells xmlns:xi="http://www.w3.org/2001/XInclude">
|
<spells>
|
||||||
|
|
||||||
<xi:include href="spellbooks/gray.xml"/>
|
|
||||||
<xi:include href="spellbooks/gwyrrd.xml"/>
|
|
||||||
<xi:include href="spellbooks/draig.xml"/>
|
|
||||||
<xi:include href="spellbooks/illaun.xml"/>
|
|
||||||
<xi:include href="spellbooks/cerddor.xml"/>
|
|
||||||
<xi:include href="spellbooks/tybied.xml"/>
|
|
||||||
|
|
||||||
<!-- shared spells -->
|
<!-- shared spells -->
|
||||||
<spell name="create_roi" ship="true" rank="5" index="130">
|
<spell name="create_roi" ship="true" rank="5">
|
||||||
<resource name="aura" amount="50" cost="fixed"/>
|
<resource name="aura" amount="50" cost="fixed"/>
|
||||||
<resource name="money" amount="3000" cost="fixed"/>
|
<resource name="money" amount="3000" cost="fixed"/>
|
||||||
<resource name="permaura" amount="1" cost="fixed"/>
|
<resource name="permaura" amount="1" cost="fixed"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
||||||
<spell name="create_aots" ship="true" rank="5" index="125">
|
<spell name="create_aots" ship="true" rank="5">
|
||||||
<resource name="aura" amount="50" cost="fixed"/>
|
<resource name="aura" amount="50" cost="fixed"/>
|
||||||
<resource name="money" amount="3000" cost="fixed"/>
|
<resource name="money" amount="3000" cost="fixed"/>
|
||||||
<resource name="permaura" amount="1" cost="fixed"/>
|
<resource name="permaura" amount="1" cost="fixed"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
||||||
<!-- draig spells -->
|
<!-- draig spells -->
|
||||||
<spell name="earn_silver#draig" ship="true" variable="true" rank="5" index="159">
|
<spell name="earn_silver#draig" ship="true" variable="true" rank="5">
|
||||||
<resource name="aura" amount="1" cost="level"/>
|
<resource name="aura" amount="1" cost="level"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
||||||
<spell name="create_firesword" ship="true" rank="5" index="148">
|
<spell name="create_firesword" ship="true" rank="5">
|
||||||
<resource name="aura" amount="100" cost="fixed"/>
|
<resource name="aura" amount="100" cost="fixed"/>
|
||||||
<resource name="p10" amount="1" cost="fixed"/>
|
<resource name="p10" amount="1" cost="fixed"/>
|
||||||
<resource name="sword" amount="1" cost="fixed"/>
|
<resource name="sword" amount="1" cost="fixed"/>
|
||||||
<resource name="permaura" amount="1" cost="fixed"/>
|
<resource name="permaura" amount="1" cost="fixed"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
||||||
<spell name="create_trollbelt" ship="true" rank="5" index="48">
|
<spell name="create_trollbelt" ship="true" rank="5">
|
||||||
<resource name="aura" amount="20" cost="fixed"/>
|
<resource name="aura" amount="20" cost="fixed"/>
|
||||||
<resource name="permaura" amount="1" cost="fixed"/>
|
<resource name="permaura" amount="1" cost="fixed"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
||||||
<!-- gwyrrd spells -->
|
<!-- gwyrrd spells -->
|
||||||
<spell name="earn_silver#gwyrrd" ship="true" variable="true" rank="5" index="159">
|
<spell name="earn_silver#gwyrrd" ship="true" variable="true" rank="5">
|
||||||
<resource name="aura" amount="1" cost="level"/>
|
<resource name="aura" amount="1" cost="level"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
||||||
<spell name="create_magicherbbag" ship="true" rank="5" index="165">
|
<spell name="create_magicherbbag" ship="true" rank="5">
|
||||||
<resource name="aura" amount="30" cost="fixed"/>
|
<resource name="aura" amount="30" cost="fixed"/>
|
||||||
<resource name="permaura" amount="1" cost="fixed"/>
|
<resource name="permaura" amount="1" cost="fixed"/>
|
||||||
<resource name="p2" amount="1" cost="fixed"/>
|
<resource name="lifepotion" amount="1" cost="fixed"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
||||||
<!-- illaun spells -->
|
<!-- illaun spells -->
|
||||||
<spell name="earn_silver#illaun" ship="true" variable="true" rank="5" index="159">
|
<spell name="earn_silver#illaun" ship="true" variable="true" rank="5">
|
||||||
<resource name="aura" amount="1" cost="level"/>
|
<resource name="aura" amount="1" cost="level"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
||||||
<spell name="create_dreameye" ship="true" rank="5" index="149">
|
<spell name="create_dreameye" ship="true" rank="5">
|
||||||
<resource name="dragonhead" amount="1" cost="fixed"/>
|
<resource name="dragonhead" amount="1" cost="fixed"/>
|
||||||
<resource name="permaura" amount="5" cost="fixed"/>
|
<resource name="permaura" amount="5" cost="fixed"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
||||||
<spell name="create_invisibility_sphere" ship="true" rank="5" index="178">
|
<spell name="create_invisibility_sphere" ship="true" rank="5">
|
||||||
<resource name="aura" amount="150" cost="fixed"/>
|
<resource name="aura" amount="150" cost="fixed"/>
|
||||||
<resource name="money" amount="30000" cost="fixed"/>
|
<resource name="money" amount="30000" cost="fixed"/>
|
||||||
<resource name="permaura" amount="3" cost="fixed"/>
|
<resource name="permaura" amount="3" cost="fixed"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
||||||
<!-- cerddor spells -->
|
<!-- cerddor spells -->
|
||||||
<spell name="earn_silver#cerddor" ship="true" variable="true" rank="5" index="159">
|
<spell name="earn_silver#cerddor" ship="true" variable="true" rank="5">
|
||||||
<resource name="aura" amount="1" cost="level"/>
|
<resource name="aura" amount="1" cost="level"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
||||||
<spell name="create_roqf" ship="true" rank="5" index="63">
|
<spell name="create_roqf" ship="true" rank="5">
|
||||||
<resource name="aura" amount="20" cost="fixed"/>
|
<resource name="aura" amount="20" cost="fixed"/>
|
||||||
<resource name="money" amount="1000" cost="fixed"/>
|
<resource name="money" amount="1000" cost="fixed"/>
|
||||||
<resource name="permaura" amount="1" cost="fixed"/>
|
<resource name="permaura" amount="1" cost="fixed"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
||||||
<!-- tybied spells -->
|
<!-- tybied spells -->
|
||||||
<spell name="earn_silver#tybied" ship="true" variable="true" rank="5" index="159">
|
<spell name="earn_silver#tybied" ship="true" variable="true" rank="5">
|
||||||
<resource name="aura" amount="1" cost="level"/>
|
<resource name="aura" amount="1" cost="level"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
||||||
<spell name="create_antimagic" ship="true" rank="5" index="38">
|
<spell name="create_antimagic" ship="true" rank="5">
|
||||||
<resource name="aura" amount="50" cost="fixed"/>
|
<resource name="aura" amount="50" cost="fixed"/>
|
||||||
<resource name="money" amount="3000" cost="fixed"/>
|
<resource name="money" amount="3000" cost="fixed"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
||||||
<spell name="create_rop" ship="true" rank="5" index="1">
|
<spell name="create_rop" ship="true" rank="5">
|
||||||
<resource name="aura" amount="100" cost="fixed"/>
|
<resource name="aura" amount="100" cost="fixed"/>
|
||||||
<resource name="permaura" amount="1" cost="fixed"/>
|
<resource name="permaura" amount="1" cost="fixed"/>
|
||||||
<resource name="money" amount="4000" cost="fixed"/>
|
<resource name="money" amount="4000" cost="fixed"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
||||||
<spell name="create_bagofholding" ship="true" rank="5" index="155">
|
<spell name="create_bagofholding" ship="true" rank="5">
|
||||||
<resource name="aura" amount="30" cost="fixed"/>
|
<resource name="aura" amount="30" cost="fixed"/>
|
||||||
<resource name="permaura" amount="1" cost="fixed"/>
|
<resource name="permaura" amount="1" cost="fixed"/>
|
||||||
<resource name="money" amount="5000" cost="fixed"/>
|
<resource name="money" amount="5000" cost="fixed"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
||||||
<!-- gray magic -->
|
<!-- gray magic -->
|
||||||
<spell name="create_runesword" ship="true" rank="5" index="135">
|
<spell name="create_runesword" ship="true" rank="5">
|
||||||
<resource name="aura" amount="100" cost="fixed"/>
|
<resource name="aura" amount="100" cost="fixed"/>
|
||||||
<resource name="permaura" amount="1" cost="fixed"/>
|
<resource name="permaura" amount="1" cost="fixed"/>
|
||||||
<resource name="money" amount="1000" cost="fixed"/>
|
<resource name="money" amount="1000" cost="fixed"/>
|
||||||
<resource name="laensword" amount="1" cost="fixed"/>
|
<resource name="laensword" amount="1" cost="fixed"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
||||||
<spell name="create_chastitybelt" ship="true" rank="5" index="134">
|
<spell name="create_chastitybelt" ship="true" rank="5">
|
||||||
<resource name="aura" amount="50" cost="fixed"/>
|
<resource name="aura" amount="50" cost="fixed"/>
|
||||||
<resource name="permaura" amount="1" cost="fixed"/>
|
<resource name="permaura" amount="1" cost="fixed"/>
|
||||||
<resource name="money" amount="3000" cost="fixed"/>
|
<resource name="money" amount="3000" cost="fixed"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
||||||
<spell name="create_focus" ship="true" rank="5" index="2">
|
<spell name="create_focus" ship="true" rank="5">
|
||||||
<resource name="aura" amount="100" cost="fixed"/>
|
<resource name="aura" amount="100" cost="fixed"/>
|
||||||
<resource name="permaura" amount="1" cost="fixed"/>
|
<resource name="permaura" amount="1" cost="fixed"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
||||||
<spell name="create_ror" ship="true" rank="5" index="3">
|
<spell name="create_ror" ship="true" rank="5">
|
||||||
<resource name="aura" amount="100" cost="fixed"/>
|
<resource name="aura" amount="100" cost="fixed"/>
|
||||||
<resource name="permaura" amount="1" cost="fixed"/>
|
<resource name="permaura" amount="1" cost="fixed"/>
|
||||||
</spell>
|
</spell>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<resource name="elfspoil">
|
<resource name="elfspoil">
|
||||||
|
@ -57,3 +58,4 @@
|
||||||
</resource>
|
</resource>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="axe">
|
<resource name="axe">
|
||||||
<item weight="200">
|
<item weight="200">
|
||||||
<construction skill="weaponsmithing" minskill="3">
|
<construction skill="weaponsmithing" minskill="3">
|
||||||
|
@ -11,3 +13,5 @@
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="bow">
|
<resource name="bow">
|
||||||
<item weight="100">
|
<item weight="100">
|
||||||
<construction skill="weaponsmithing" minskill="2">
|
<construction skill="weaponsmithing" minskill="2">
|
||||||
|
@ -11,3 +13,5 @@
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="catapult">
|
<resource name="catapult">
|
||||||
<item weight="10000" big="yes">
|
<item weight="10000" big="yes">
|
||||||
<construction skill="cartmaking" minskill="5">
|
<construction skill="cartmaking" minskill="5">
|
||||||
|
@ -12,3 +14,5 @@
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="crossbow">
|
<resource name="crossbow">
|
||||||
<item weight="100">
|
<item weight="100">
|
||||||
<construction skill="weaponsmithing" minskill="3">
|
<construction skill="weaponsmithing" minskill="3">
|
||||||
|
@ -11,3 +13,5 @@
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="firesword">
|
<resource name="firesword">
|
||||||
<item weight="100">
|
<item weight="100">
|
||||||
<weapon magres="0.3" cut="true" skill="melee" offmod="1" defmod="1">
|
<weapon magres="0.3" cut="true" magical="true" skill="melee" offmod="1" defmod="1">
|
||||||
<function name="attack" value="attack_firesword"/>
|
<function name="attack" value="attack_firesword"/>
|
||||||
<damage type="rider" value="3d6+10"/>
|
<damage type="rider" value="3d6+10"/>
|
||||||
<damage type="footman" value="3d6+10"/>
|
<damage type="footman" value="3d6+10"/>
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="greatbow">
|
<resource name="greatbow">
|
||||||
<modifier type="require" race="elf"/>
|
<modifier type="require" races="elf"/>
|
||||||
<item weight="100">
|
<item weight="100">
|
||||||
<construction skill="weaponsmithing" minskill="5">
|
<construction skill="weaponsmithing" minskill="5">
|
||||||
<requirement type="mallorn" quantity="2"/>
|
<requirement type="mallorn" quantity="2"/>
|
||||||
|
@ -9,9 +11,9 @@
|
||||||
<damage type="rider" value="2d6+4"/>
|
<damage type="rider" value="2d6+4"/>
|
||||||
<damage type="footman" value="2d6+4"/>
|
<damage type="footman" value="2d6+4"/>
|
||||||
<modifier type="missile_target" value="2"/>
|
<modifier type="missile_target" value="2"/>
|
||||||
<modifier type="damage" value="1">
|
<modifier type="damage" value="1" races="elf"/>
|
||||||
<race name="elf"/>
|
|
||||||
</modifier>
|
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="greatsword">
|
<resource name="greatsword">
|
||||||
<item weight="200" score="30">
|
<item weight="200" score="30">
|
||||||
<construction skill="weaponsmithing" minskill="4">
|
<construction skill="weaponsmithing" minskill="4">
|
||||||
|
@ -10,3 +12,5 @@
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="halberd">
|
<resource name="halberd">
|
||||||
<item weight="200">
|
<item weight="200">
|
||||||
<construction skill="weaponsmithing" minskill="3">
|
<construction skill="weaponsmithing" minskill="3">
|
||||||
|
@ -12,3 +14,5 @@
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="laensword">
|
<resource name="laensword">
|
||||||
<item weight="100" score="400">
|
<item weight="100" score="400">
|
||||||
<construction skill="weaponsmithing" minskill="8">
|
<construction skill="weaponsmithing" minskill="8">
|
||||||
<requirement type="laen" quantity="1"/>
|
<requirement type="laen" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
<weapon cut="true" skill="melee" offmod="1" defmod="1" magres="0.30">
|
<weapon cut="true" magical="true" skill="melee" offmod="1" defmod="1" magres="0.30">
|
||||||
<damage type="rider" value="3d6+10"/>
|
<damage type="rider" value="3d6+10"/>
|
||||||
<damage type="footman" value="3d6+10"/>
|
<damage type="footman" value="3d6+10"/>
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="lance">
|
<resource name="lance">
|
||||||
<item weight="200">
|
<item weight="200">
|
||||||
<construction skill="weaponsmithing" minskill="2">
|
<construction skill="weaponsmithing" minskill="2">
|
||||||
|
@ -10,3 +12,5 @@
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="mallornbow">
|
<resource name="mallornbow">
|
||||||
<item weight="100">
|
<item weight="100">
|
||||||
<construction skill="weaponsmithing" minskill="5">
|
<construction skill="weaponsmithing" minskill="5">
|
||||||
|
@ -8,9 +10,9 @@
|
||||||
<damage type="rider" value="1d11+2"/>
|
<damage type="rider" value="1d11+2"/>
|
||||||
<damage type="footman" value="1d11+2"/>
|
<damage type="footman" value="1d11+2"/>
|
||||||
<modifier type="missile_target" value="2"/>
|
<modifier type="missile_target" value="2"/>
|
||||||
<modifier type="damage" value="1">
|
<modifier type="damage" value="1" races="elf"/>
|
||||||
<race name="elf"/>
|
|
||||||
</modifier>
|
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="mallorncrossbow">
|
<resource name="mallorncrossbow">
|
||||||
<item weight="100">
|
<item weight="100">
|
||||||
<construction skill="weaponsmithing" minskill="5">
|
<construction skill="weaponsmithing" minskill="5">
|
||||||
|
@ -11,3 +13,5 @@
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="mallornlance">
|
<resource name="mallornlance">
|
||||||
<item weight="100">
|
<item weight="100">
|
||||||
<construction skill="weaponsmithing" minskill="5">
|
<construction skill="weaponsmithing" minskill="5">
|
||||||
|
@ -10,3 +12,5 @@
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="mallornspear">
|
<resource name="mallornspear">
|
||||||
<item weight="100">
|
<item weight="100">
|
||||||
<construction skill="weaponsmithing" minskill="5">
|
<construction skill="weaponsmithing" minskill="5">
|
||||||
|
@ -12,3 +14,5 @@
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="runesword">
|
<resource name="runesword">
|
||||||
<item weight="100" score="2000">
|
<item weight="100" score="2000">
|
||||||
<weapon cut="true" magical="yes" skill="melee" offmod="2" defmod="2">
|
<weapon cut="true" magical="yes" skill="melee" offmod="2" defmod="2">
|
||||||
|
@ -8,3 +10,5 @@
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="rustyaxe">
|
<resource name="rustyaxe">
|
||||||
<item weight="200">
|
<item weight="200">
|
||||||
<construction skill="weaponsmithing" minskill="3">
|
<construction skill="weaponsmithing" minskill="3">
|
||||||
|
@ -11,3 +13,5 @@
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="rustygreatsword">
|
<resource name="rustygreatsword">
|
||||||
<item weight="200" score="20">
|
<item weight="200" score="20">
|
||||||
<construction skill="weaponsmithing" minskill="4">
|
<construction skill="weaponsmithing" minskill="4">
|
||||||
|
@ -10,3 +12,5 @@
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="rustyhalberd">
|
<resource name="rustyhalberd">
|
||||||
<item weight="200" score="20">
|
<item weight="200" score="20">
|
||||||
<construction skill="weaponsmithing" minskill="3">
|
<construction skill="weaponsmithing" minskill="3">
|
||||||
|
@ -12,3 +14,5 @@
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="rustysword">
|
<resource name="rustysword">
|
||||||
<item weight="100" score="10">
|
<item weight="100" score="10">
|
||||||
<construction skill="weaponsmithing" minskill="3">
|
<construction skill="weaponsmithing" minskill="3">
|
||||||
|
@ -10,3 +12,5 @@
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="spear">
|
<resource name="spear">
|
||||||
<item weight="100">
|
<item weight="100">
|
||||||
<construction skill="weaponsmithing" minskill="2">
|
<construction skill="weaponsmithing" minskill="2">
|
||||||
|
@ -12,3 +14,5 @@
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
<eressea>
|
||||||
|
<resources>
|
||||||
<resource name="sword">
|
<resource name="sword">
|
||||||
<item weight="100" score="30">
|
<item weight="100" score="30">
|
||||||
<construction skill="weaponsmithing" minskill="3">
|
<construction skill="weaponsmithing" minskill="3">
|
||||||
|
@ -10,3 +12,5 @@
|
||||||
</weapon>
|
</weapon>
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,12 +1,79 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<resources xmlns:xi="http://www.w3.org/2001/XInclude">
|
<eressea>
|
||||||
<xi:include href="armor/chainmail.xml"/>
|
<resources>
|
||||||
<xi:include href="armor/laenmail.xml"/>
|
<resource name="towershield">
|
||||||
<xi:include href="armor/laenshield.xml"/>
|
<modifier type="require" races="dwarf irongolem"/>
|
||||||
<xi:include href="armor/plate.xml"/>
|
<item weight="200" score="60" allow="dwarf">
|
||||||
<xi:include href="armor/rustychainmail.xml"/>
|
<construction skill="armorer" minskill="4">
|
||||||
<xi:include href="armor/rustyshield.xml"/>
|
<requirement type="iron" quantity="1"/>
|
||||||
<xi:include href="armor/scale.xml"/>
|
</construction>
|
||||||
<xi:include href="armor/shield.xml"/>
|
<armor ac="0" penalty="-0.15" projectile="0.25" magres="0.0" shield="yes"/>
|
||||||
<xi:include href="armor/towershield.xml"/>
|
</item>
|
||||||
|
</resource>
|
||||||
|
<resource name="shield">
|
||||||
|
<item weight="100" score="30">
|
||||||
|
<construction skill="armorer" minskill="2">
|
||||||
|
<requirement type="iron" quantity="1"/>
|
||||||
|
</construction>
|
||||||
|
<armor ac="0" penalty="-0.10" magres="0.0" shield="yes"/>
|
||||||
|
</item>
|
||||||
|
</resource>
|
||||||
|
<resource name="scale">
|
||||||
|
<modifier type="require" races="dwarf irongolem"/>
|
||||||
|
<item weight="300" score="150" allow="dwarf halfling">
|
||||||
|
<construction skill="armorer" minskill="5">
|
||||||
|
<requirement type="iron" quantity="2"/>
|
||||||
|
</construction>
|
||||||
|
<armor ac="3" penalty="0.10" projectile="0.05" magres="0.0"/>
|
||||||
|
</item>
|
||||||
|
</resource>
|
||||||
|
<resource name="rustyshield">
|
||||||
|
<item weight="100" score="10">
|
||||||
|
<construction skill="armorer" minskill="2">
|
||||||
|
<requirement type="iron" quantity="1"/>
|
||||||
|
</construction>
|
||||||
|
<armor ac="0" penalty="-0.05" magres="0.0" shield="yes"/>
|
||||||
|
</item>
|
||||||
|
</resource>
|
||||||
|
<resource name="rustychainmail">
|
||||||
|
<item weight="200" score="30">
|
||||||
|
<construction skill="armorer" minskill="3">
|
||||||
|
<requirement type="iron" quantity="3"/>
|
||||||
|
</construction>
|
||||||
|
<armor ac="1" penalty="0.20" magres="0.0"/>
|
||||||
|
</item>
|
||||||
|
</resource>
|
||||||
|
<resource name="plate">
|
||||||
|
<item weight="400" score="150" deny="goblin">
|
||||||
|
<construction skill="armorer" minskill="4">
|
||||||
|
<requirement type="iron" quantity="4"/>
|
||||||
|
</construction>
|
||||||
|
<armor ac="3" penalty="0.15" projectile="0.10" magres="0.0"/>
|
||||||
|
</item>
|
||||||
|
</resource>
|
||||||
|
<resource name="laenshield">
|
||||||
|
<item weight="0" score="1000">
|
||||||
|
<construction skill="armorer" minskill="7">
|
||||||
|
<requirement type="laen" quantity="1"/>
|
||||||
|
</construction>
|
||||||
|
<armor ac="1" penalty="-0.10" magres="0.3" laen="yes" shield="yes" />
|
||||||
|
</item>
|
||||||
|
</resource>
|
||||||
|
<resource name="laenmail">
|
||||||
|
<item weight="100" score="1000">
|
||||||
|
<construction skill="armorer" minskill="9">
|
||||||
|
<requirement type="laen" quantity="2"/>
|
||||||
|
</construction>
|
||||||
|
<armor ac="3" penalty="0.0" projectile="0.10" magres="0.3" laen="yes" />
|
||||||
|
</item>
|
||||||
|
</resource>
|
||||||
|
<resource name="chainmail">
|
||||||
|
<item weight="200" score="90">
|
||||||
|
<construction skill="armorer" minskill="3">
|
||||||
|
<requirement type="iron" quantity="2"/>
|
||||||
|
</construction>
|
||||||
|
<armor ac="2" penalty="0.10" projectile="0.0" magres="0.0"/>
|
||||||
|
</item>
|
||||||
|
</resource>
|
||||||
</resources>
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<resource name="chainmail">
|
|
||||||
<item weight="200" score="90">
|
|
||||||
<construction skill="armorer" minskill="3">
|
|
||||||
<requirement type="iron" quantity="2"/>
|
|
||||||
</construction>
|
|
||||||
<armor ac="2" penalty="0.10" projectile="0.0" magres="0.0"/>
|
|
||||||
</item>
|
|
||||||
</resource>
|
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<resource name="laenmail">
|
|
||||||
<item weight="100" score="1000">
|
|
||||||
<construction skill="armorer" minskill="9">
|
|
||||||
<requirement type="laen" quantity="2"/>
|
|
||||||
</construction>
|
|
||||||
<armor ac="3" penalty="0.0" projectile="0.10" magres="0.3" laen="yes" />
|
|
||||||
</item>
|
|
||||||
</resource>
|
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<resource name="laenshield">
|
|
||||||
<item weight="0" score="1000">
|
|
||||||
<construction skill="armorer" minskill="7">
|
|
||||||
<requirement type="laen" quantity="1"/>
|
|
||||||
</construction>
|
|
||||||
<armor ac="1" penalty="-0.10" magres="0.3" laen="yes" shield="yes" />
|
|
||||||
</item>
|
|
||||||
</resource>
|
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<resource name="plate">
|
|
||||||
<item weight="400" score="150" deny="goblin">
|
|
||||||
<construction skill="armorer" minskill="4">
|
|
||||||
<requirement type="iron" quantity="4"/>
|
|
||||||
</construction>
|
|
||||||
<armor ac="3" penalty="0.15" projectile="0.10" magres="0.0"/>
|
|
||||||
</item>
|
|
||||||
</resource>
|
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<resource name="rustychainmail">
|
|
||||||
<item weight="200" score="30">
|
|
||||||
<construction skill="armorer" minskill="3">
|
|
||||||
<requirement type="iron" quantity="3"/>
|
|
||||||
</construction>
|
|
||||||
<armor ac="1" penalty="0.20" magres="0.0"/>
|
|
||||||
</item>
|
|
||||||
</resource>
|
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<resource name="rustyshield">
|
|
||||||
<item weight="100" score="10">
|
|
||||||
<construction skill="armorer" minskill="2">
|
|
||||||
<requirement type="iron" quantity="1"/>
|
|
||||||
</construction>
|
|
||||||
<armor ac="0" penalty="-0.05" magres="0.0" shield="yes"/>
|
|
||||||
</item>
|
|
||||||
</resource>
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<resource name="scale">
|
|
||||||
<modifier type="require" race="dwarf"/>
|
|
||||||
<modifier type="require" race="irongolem"/>
|
|
||||||
<item weight="300" score="150" allow="dwarf halfling">
|
|
||||||
<construction skill="armorer" minskill="5">
|
|
||||||
<requirement type="iron" quantity="2"/>
|
|
||||||
</construction>
|
|
||||||
<armor ac="3" penalty="0.10" projectile="0.05" magres="0.0"/>
|
|
||||||
</item>
|
|
||||||
</resource>
|
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<resource name="shield">
|
|
||||||
<item weight="100" score="30">
|
|
||||||
<construction skill="armorer" minskill="2">
|
|
||||||
<requirement type="iron" quantity="1"/>
|
|
||||||
</construction>
|
|
||||||
<armor ac="0" penalty="-0.10" magres="0.0" shield="yes"/>
|
|
||||||
</item>
|
|
||||||
</resource>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<resource name="towershield">
|
|
||||||
<modifier type="require" race="dwarf"/>
|
|
||||||
<modifier type="require" race="irongolem"/>
|
|
||||||
<item weight="200" score="60" allow="dwarf">
|
|
||||||
<construction skill="armorer" minskill="4">
|
|
||||||
<requirement type="iron" quantity="1"/>
|
|
||||||
</construction>
|
|
||||||
<armor ac="0" penalty="-0.15" projectile="0.25" magres="0.0" shield="yes">
|
|
||||||
<modifier type="canuse" function="mod_dwarves_only"/>
|
|
||||||
</armor>
|
|
||||||
</item>
|
|
||||||
</resource>
|
|
|
@ -1,7 +1,6 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<buildings xmlns:xi="http://www.w3.org/2001/XInclude">
|
<eressea>
|
||||||
|
<buildings>
|
||||||
<xi:include href="config://default/buildings/castle-2.xml" />
|
|
||||||
|
|
||||||
<building name="watch" maxsize="10" fort="yes" taxes="200">
|
<building name="watch" maxsize="10" fort="yes" taxes="200">
|
||||||
<construction skill="building" minskill="1" maxsize="5" name="scaffolding">
|
<construction skill="building" minskill="1" maxsize="5" name="scaffolding">
|
||||||
|
@ -24,4 +23,4 @@
|
||||||
</building>
|
</building>
|
||||||
|
|
||||||
</buildings>
|
</buildings>
|
||||||
|
</eressea>
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<equipment>
|
|
||||||
|
|
||||||
<set name="spo_seaserpent">
|
|
||||||
<item name="dragonblood" amount="2"/>
|
|
||||||
<item name="seaserpenthead" amount="1"/>
|
|
||||||
</set>
|
|
||||||
|
|
||||||
</equipment>
|
|
|
@ -1,104 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<equipment>
|
|
||||||
|
|
||||||
<!-- equipment given to familiars -->
|
|
||||||
<set name="fam_lynx">
|
|
||||||
<skill name="magic" level="1"/>
|
|
||||||
</set>
|
|
||||||
|
|
||||||
<set name="fam_tunnelworm">
|
|
||||||
<skill name="magic" level="1"/>
|
|
||||||
<skill name="mining" level="1"/>
|
|
||||||
<skill name="forestry" level="1"/>
|
|
||||||
<skill name="stamina" level="1"/>
|
|
||||||
</set>
|
|
||||||
|
|
||||||
<set name="fam_eagle">
|
|
||||||
<skill name="magic" level="1"/>
|
|
||||||
</set>
|
|
||||||
|
|
||||||
<set name="fam_rat">
|
|
||||||
<skill name="magic" level="1"/>
|
|
||||||
<skill name="stamina" level="6"/>
|
|
||||||
</set>
|
|
||||||
|
|
||||||
<set name="fam_songdragon">
|
|
||||||
<skill name="magic" level="1"/>
|
|
||||||
<!-- spells -->
|
|
||||||
<spell name="flee" level="2"/>
|
|
||||||
<spell name="sleep" level="7"/>
|
|
||||||
<spell name="frighten" level="8"/>
|
|
||||||
</set>
|
|
||||||
|
|
||||||
<set name="fam_nymph">
|
|
||||||
<skill name="magic" level="1"/>
|
|
||||||
<skill name="bow" level="1"/>
|
|
||||||
<skill name="training" level="1"/>
|
|
||||||
<skill name="riding" level="1"/>
|
|
||||||
<!-- spells -->
|
|
||||||
<spell name="seduction" level="6"/>
|
|
||||||
<spell name="calm_monster" level="6"/>
|
|
||||||
<spell name="song_of_confusion" level="4"/>
|
|
||||||
<spell name="appeasement" level="1"/>
|
|
||||||
</set>
|
|
||||||
|
|
||||||
<set name="fam_unicorn">
|
|
||||||
<skill name="magic" level="1"/>
|
|
||||||
<!-- spells -->
|
|
||||||
<spell name="resist_magic" level="3"/>
|
|
||||||
<spell name="song_of_peace" level="12"/>
|
|
||||||
<spell name="calm_monster" level="6"/>
|
|
||||||
<spell name="heroic_song" level="5"/>
|
|
||||||
<spell name="song_of_healing" level="2"/>
|
|
||||||
<spell name="appeasement" level="1"/>
|
|
||||||
</set>
|
|
||||||
|
|
||||||
<set name="fam_direwolf">
|
|
||||||
<skill name="magic" level="1"/>
|
|
||||||
</set>
|
|
||||||
|
|
||||||
<set name="fam_ghost">
|
|
||||||
<skill name="magic" level="1"/>
|
|
||||||
<!-- spells -->
|
|
||||||
<spell name="steal_aura" level="6"/>
|
|
||||||
<spell name="frighten" level="8"/>
|
|
||||||
<spell name="summonundead" level="6"/>
|
|
||||||
</set>
|
|
||||||
|
|
||||||
<set name="fam_imp">
|
|
||||||
<skill name="magic" level="1"/>
|
|
||||||
<!-- spells -->
|
|
||||||
<spell name="steal_aura" level="6"/>
|
|
||||||
<spell name="shapeshift" level="3"/>
|
|
||||||
<spell name="seduction" level="6"/>
|
|
||||||
</set>
|
|
||||||
|
|
||||||
<set name="fam_dreamcat">
|
|
||||||
<skill name="magic" level="1"/>
|
|
||||||
<!-- spells -->
|
|
||||||
<spell name="shapeshift" level="3"/>
|
|
||||||
<spell name="transferauratraum" level="3"/>
|
|
||||||
</set>
|
|
||||||
|
|
||||||
<set name="fam_fairy">
|
|
||||||
<skill name="magic" level="1"/>
|
|
||||||
<!-- spells -->
|
|
||||||
<spell name="appeasement" level="1"/>
|
|
||||||
<spell name="calm_monster" level="6"/>
|
|
||||||
<spell name="seduction" level="6"/>
|
|
||||||
</set>
|
|
||||||
|
|
||||||
<set name="fam_owl">
|
|
||||||
<skill name="magic" level="1"/>
|
|
||||||
</set>
|
|
||||||
|
|
||||||
<set name="fam_hellcat">
|
|
||||||
<skill name="magic" level="1"/>
|
|
||||||
</set>
|
|
||||||
|
|
||||||
<set name="fam_tiger">
|
|
||||||
<skill name="magic" level="1"/>
|
|
||||||
</set>
|
|
||||||
|
|
||||||
</equipment>
|
|
||||||
|
|
|
@ -1,6 +1,32 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<eressea>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
|
<resource name="stone" limited="yes" material="yes">
|
||||||
|
<item weight="6000" score="10" big="yes">
|
||||||
|
<construction skill="quarrying" minskill="1"/>
|
||||||
|
</item>
|
||||||
|
<modifier building="quarry" type="skill" value="1"/>
|
||||||
|
<modifier building="quarry" type="material" value="0.5"/>
|
||||||
|
</resource>
|
||||||
|
|
||||||
|
<resource name="iron" limited="yes" material="yes">
|
||||||
|
<item weight="500" score="10">
|
||||||
|
<construction skill="mining" minskill="1"/>
|
||||||
|
</item>
|
||||||
|
<modifier building="smithy" type="save" value="2"/>
|
||||||
|
<modifier building="mine" type="skill" value="1"/>
|
||||||
|
<modifier building="mine" type="material" value="0.5"/>
|
||||||
|
</resource>
|
||||||
|
|
||||||
|
<resource name="seed">
|
||||||
|
<item weight="10" score="50"/>
|
||||||
|
</resource>
|
||||||
|
|
||||||
|
<resource name="mallornseed">
|
||||||
|
<item weight="10" score="100"/>
|
||||||
|
</resource>
|
||||||
|
|
||||||
<resource name="rpg_item_1"><item weight="10"/></resource>
|
<resource name="rpg_item_1"><item weight="10"/></resource>
|
||||||
<resource name="rpg_item_2"><item weight="1"/></resource>
|
<resource name="rpg_item_2"><item weight="1"/></resource>
|
||||||
<resource name="rpg_item_3"><item weight="100"/></resource>
|
<resource name="rpg_item_3"><item weight="100"/></resource>
|
||||||
|
@ -26,7 +52,7 @@
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
|
||||||
<resource name="p14" appearance="vial">
|
<resource name="healing" appearance="vial">
|
||||||
<!-- Heiltrank -->
|
<!-- Heiltrank -->
|
||||||
<item weight="0" score="120" use="yes">
|
<item weight="0" score="120" use="yes">
|
||||||
<potion level="4"/>
|
<potion level="4"/>
|
||||||
|
@ -40,7 +66,7 @@
|
||||||
</item>
|
</item>
|
||||||
</resource>
|
</resource>
|
||||||
|
|
||||||
<resource name="p2" appearance="vial">
|
<resource name="lifepotion" appearance="vial">
|
||||||
<!-- Wasser des Lebens -->
|
<!-- Wasser des Lebens -->
|
||||||
<item weight="0" score="30" use="yes">
|
<item weight="0" score="30" use="yes">
|
||||||
<potion level="1"/>
|
<potion level="1"/>
|
||||||
|
@ -76,3 +102,4 @@
|
||||||
</resource>
|
</resource>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
</eressea>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue