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
|
||||
|
||||
# 4 space indentation
|
||||
[*.{c,h,lua}]
|
||||
[*.{c,h,lua,py}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -42,3 +42,4 @@ tests/data/185.dat
|
|||
/quicklist/
|
||||
/cutest/
|
||||
/critbit/
|
||||
*.mo
|
||||
|
|
|
@ -13,9 +13,13 @@ include(MSVC)
|
|||
set (HAVE_STRDUP 0)
|
||||
set (HAVE_STRLCAT 0)
|
||||
set (HAVE_LIBBSD 0)
|
||||
set (HAVE_SIGNAL_H 0)
|
||||
set (HAVE_EXECINFO_H 0)
|
||||
else (MSVC)
|
||||
|
||||
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)
|
||||
|
||||
INCLUDE (CheckFunctionExists)
|
||||
|
@ -46,7 +50,7 @@ else()
|
|||
find_package (SQLite3 REQUIRED QUIET)
|
||||
endif()
|
||||
|
||||
find_package (LibXml2 REQUIRED)
|
||||
find_package(EXPAT REQUIRED)
|
||||
find_package (ToLua REQUIRED)
|
||||
if (TOLUA_FOUND)
|
||||
if (${TOLUA_VERSION_STRING} VERSION_EQUAL "5.2")
|
||||
|
@ -66,6 +70,7 @@ add_subdirectory (process)
|
|||
add_subdirectory (src eressea)
|
||||
|
||||
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 "*.json")
|
||||
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
|
||||
|
||||
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": [
|
||||
"keywords.json",
|
||||
"calendar.json",
|
||||
"prefixes.json",
|
||||
"e2/terrains.json"
|
||||
"config://conf/keywords.json",
|
||||
"config://conf/calendar.json",
|
||||
"config://conf/prefixes.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": [
|
||||
"jsreport"
|
||||
],
|
||||
"settings": {
|
||||
"game.name" : "Eressea",
|
||||
"game.mailcmd" : "ERESSEA",
|
||||
"game.id" : 2,
|
||||
"orders.default": "work",
|
||||
"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": [
|
||||
"keywords.json",
|
||||
"calendar.json",
|
||||
"prefixes.json",
|
||||
"e3/terrains.json"
|
||||
"config://conf/keywords.json",
|
||||
"config://conf/calendar.json",
|
||||
"config://conf/prefixes.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": [
|
||||
"herbalism",
|
||||
|
@ -27,6 +41,7 @@
|
|||
],
|
||||
"settings": {
|
||||
"game.name" : "Eressea",
|
||||
"game.mailcmd" : "ERESSEA",
|
||||
"game.id" : 3,
|
||||
"orders.default": "work",
|
||||
"database.gameid": 7,
|
||||
|
@ -77,7 +92,6 @@
|
|||
"rules.region_owners": true,
|
||||
"rules.cavalry.skill": 2,
|
||||
"rules.cavalry.mode": 1,
|
||||
"rules.magic.multipotion": true,
|
||||
"rules.magic.wol_effect": 5,
|
||||
"rules.magic.factionlist": true,
|
||||
"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
|
||||
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)
|
||||
|
||||
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
|
||||
SRC=${ERESSEA}/git
|
||||
${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} send
|
||||
done
|
||||
|
|
|
@ -1,378 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: iso-8859-1 -*-
|
||||
#!/bin/sh
|
||||
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
|
||||
# -*- coding: iso-8859-1 -*-
|
||||
#!/bin/sh
|
||||
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" ?>
|
||||
<eressea>
|
||||
<resources>
|
||||
|
||||
<resource name="adamantium" limited="yes" material="yes">
|
||||
<item weight="200" score="200">
|
||||
<construction skill="mining" minskill="8"/>
|
||||
</item>
|
||||
<modifier building="mine" type="skill" value="1"/>
|
||||
<modifier type="require" building="mine"/>
|
||||
<modifier building="mine" type="skill" value="1"/>
|
||||
<modifier type="require" building="mine"/>
|
||||
</resource>
|
||||
|
||||
<resource name="adamantiumaxe">
|
||||
|
@ -15,7 +16,7 @@
|
|||
<requirement type="adamantium" quantity="1"/>
|
||||
<requirement type="log" quantity="1"/>
|
||||
</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="footman" value="3d4+15"/>
|
||||
</weapon>
|
||||
|
@ -32,3 +33,4 @@
|
|||
</resource>
|
||||
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<buildings>
|
||||
<building name="castle" fort="yes" taxes="100">
|
||||
<construction skill="building" minskill="1" maxsize="10" name="site">
|
||||
<requirement type="stone" quantity="1"/>
|
||||
|
@ -19,3 +21,5 @@
|
|||
<requirement type="stone" quantity="1"/>
|
||||
</construction>
|
||||
</building>
|
||||
</buildings>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<buildings>
|
||||
<building name="castle" fort="yes">
|
||||
<construction skill="building" minskill="1" maxsize="2" name="site">
|
||||
<requirement type="stone" quantity="1"/>
|
||||
|
@ -22,3 +24,5 @@
|
|||
<requirement type="stone" quantity="1"/>
|
||||
</construction>
|
||||
</building>
|
||||
</buildings>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea><resources>
|
||||
<resource name="chainmail">
|
||||
<item weight="200" score="90">
|
||||
<construction skill="armorer" minskill="3">
|
||||
|
@ -7,3 +8,4 @@
|
|||
<armor ac="3" penalty="0.15" magres="0.0"/>
|
||||
</item>
|
||||
</resource>
|
||||
</resources></eressea>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea><resources>
|
||||
<resource name="laenmail">
|
||||
<item weight="100" score="1000">
|
||||
<construction skill="armorer" minskill="9">
|
||||
|
@ -7,3 +8,4 @@
|
|||
<armor ac="6" penalty="0.0" magres="0.3" laen="yes" />
|
||||
</item>
|
||||
</resource>
|
||||
</resources></eressea>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea><resources>
|
||||
<resource name="laenshield">
|
||||
<item weight="0" score="1000">
|
||||
<construction skill="armorer" minskill="7">
|
||||
|
@ -7,3 +8,4 @@
|
|||
<armor ac="2" penalty="-0.25" magres="0.3" laen="yes" shield="yes" />
|
||||
</item>
|
||||
</resource>
|
||||
</resources></eressea>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea><resources>
|
||||
<resource name="plate">
|
||||
<item weight="400" score="150">
|
||||
<construction skill="armorer" minskill="4">
|
||||
|
@ -7,3 +8,4 @@
|
|||
<armor ac="5" penalty="0.30" magres="0.0"/>
|
||||
</item>
|
||||
</resource>
|
||||
</resources></eressea>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea><resources>
|
||||
<resource name="rustychainmail">
|
||||
<item weight="200" score="30">
|
||||
<construction skill="armorer" minskill="3">
|
||||
|
@ -7,4 +8,4 @@
|
|||
<armor ac="2" penalty="0.30" magres="0.0"/>
|
||||
</item>
|
||||
</resource>
|
||||
|
||||
</resources></eressea>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea><resources>
|
||||
<resource name="rustyshield">
|
||||
<item weight="100" score="10">
|
||||
<construction skill="armorer" minskill="2">
|
||||
|
@ -7,3 +8,4 @@
|
|||
<armor ac="1" penalty="0.0" magres="0.0" shield="yes"/>
|
||||
</item>
|
||||
</resource>
|
||||
</resources></eressea>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea><resources>
|
||||
<resource name="shield">
|
||||
<item weight="100" score="30">
|
||||
<construction skill="armorer" minskill="2">
|
||||
|
@ -7,3 +8,4 @@
|
|||
<armor ac="1" penalty="-0.15" magres="0.0" shield="yes"/>
|
||||
</item>
|
||||
</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"?>
|
||||
<eressea>
|
||||
<buildings>
|
||||
<building name="wormhole" maxsize="4" maxcapacity="4" nobuild="yes" nodestroy="yes" unique="yes" />
|
||||
<building name="illusioncastle" capacity="0" maxcapacity="0" maxsize="0" nobuild="yes"/>
|
||||
|
@ -167,4 +168,4 @@
|
|||
</building>
|
||||
|
||||
</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"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<!-- this file contains herbs that are part of the alchemy system -->
|
||||
|
||||
|
@ -87,3 +88,4 @@
|
|||
</resource>
|
||||
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
|
||||
<resource name="money">
|
||||
|
@ -33,8 +34,8 @@
|
|||
<item weight="0" score="6000"/>
|
||||
</resource>
|
||||
|
||||
<resource name="presspass" cursed="yes">
|
||||
<item weight="0" score="6000"/>
|
||||
<resource name="presspass">
|
||||
<item weight="0" score="6000" cursed="yes"/>
|
||||
</resource>
|
||||
|
||||
<resource name="aurafocus">
|
||||
|
@ -133,3 +134,4 @@
|
|||
</resource>
|
||||
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<!-- this file contains luxury items that are part of the trade system -->
|
||||
<resource name="balm">
|
||||
|
@ -24,3 +25,4 @@
|
|||
</resource>
|
||||
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<!-- this file contains potions that are part of the alchemy system -->
|
||||
|
||||
|
@ -33,7 +34,7 @@
|
|||
</item>
|
||||
</resource>
|
||||
|
||||
<resource name="p2" appearance="vial">
|
||||
<resource name="lifepotion" appearance="vial">
|
||||
<item weight="0" score="30" use="yes">
|
||||
<potion level="1"/>
|
||||
<construction skill="alchemy" minskill="2">
|
||||
|
@ -166,7 +167,7 @@
|
|||
</item>
|
||||
</resource>
|
||||
|
||||
<resource name="p14" appearance="vial">
|
||||
<resource name="healing" appearance="vial">
|
||||
<item weight="0" score="120" use="yes">
|
||||
<potion level="4"/>
|
||||
<construction skill="alchemy" minskill="8">
|
||||
|
@ -180,3 +181,4 @@
|
|||
</resource>
|
||||
|
||||
</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"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="cart">
|
||||
<item capacity="14000" weight="4000" score="60" vehicle="yes" big="yes">
|
||||
<construction skill="cartmaking" minskill="1">
|
||||
|
@ -6,3 +8,5 @@
|
|||
</construction>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="horse" limited="yes">
|
||||
<item big="yes" weight="5000" score="10" capacity="7000" animal="yes">
|
||||
<construction skill="training" minskill="1" />
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="hp" pooled="false">
|
||||
<function name="change" value="lua_changeresource"/>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="iron" limited="yes" material="yes">
|
||||
<item weight="500" score="10">
|
||||
<construction skill="mining" minskill="1"/>
|
||||
|
@ -6,5 +8,7 @@
|
|||
<modifier building="smithy" type="save" value="2"/>
|
||||
<modifier building="mine" type="skill" value="1"/>
|
||||
<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>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="laen" limited="yes" material="yes">
|
||||
<item weight="200" score="100">
|
||||
<construction skill="mining" minskill="7"/>
|
||||
</item>
|
||||
<item weight="200" score="100">
|
||||
<construction skill="mining" minskill="7"/>
|
||||
</item>
|
||||
<modifier building="mine" type="skill" value="1"/>
|
||||
<modifier type="require" building="mine"/>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="log" limited="yes">
|
||||
<item weight="500" score="10">
|
||||
<construction skill="forestry" minskill="1"/>
|
||||
|
@ -6,3 +8,5 @@
|
|||
<modifier building="sawmill" type="skill" value="1"/>
|
||||
<modifier building="sawmill" type="material" value="0.5"/>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="mallorn" limited="yes">
|
||||
<item weight="500" score="30">
|
||||
<construction skill="forestry" minskill="2"/>
|
||||
|
@ -6,3 +8,5 @@
|
|||
<modifier building="sawmill" type="skill" value="1"/>
|
||||
<modifier building="sawmill" type="material" value="0.5"/>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="mallornseed" limited="yes">
|
||||
<item weight="10" score="100">
|
||||
<construction skill="herbalism" minskill="4"/>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="peasant" pooled="false">
|
||||
<function name="change" value="lua_changeresource"/>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="seed" limited="yes">
|
||||
<item weight="10" score="50">
|
||||
<construction skill="herbalism" minskill="3"/>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<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"/>
|
||||
<modifier race="troll" type="material" value="0.75"/>
|
||||
<modifier races="troll" type="material" value="0.75"/>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<ships>
|
||||
<ship name="trireme" range="7" storm="1.00" damage="1.00" cargo="200000" cptskill="4" minskill="1" sumskill="120" opensea="yes">
|
||||
<coast terrain="plain"/>
|
||||
|
@ -73,4 +74,4 @@
|
|||
</ship>
|
||||
|
||||
</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"?>
|
||||
<spells xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<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"/>
|
||||
<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="money" amount="3000" cost="fixed"/>
|
||||
<resource name="permaura" amount="1" cost="fixed"/>
|
||||
</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="money" amount="3000" cost="fixed"/>
|
||||
<resource name="permaura" amount="1" cost="fixed"/>
|
||||
</spell>
|
||||
|
||||
<!-- 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"/>
|
||||
</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="p10" amount="1" cost="fixed"/>
|
||||
<resource name="sword" amount="1" cost="fixed"/>
|
||||
<resource name="permaura" amount="1" cost="fixed"/>
|
||||
</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="permaura" amount="1" cost="fixed"/>
|
||||
</spell>
|
||||
|
||||
<!-- 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"/>
|
||||
</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="permaura" amount="1" cost="fixed"/>
|
||||
<resource name="p2" amount="1" cost="fixed"/>
|
||||
<resource name="lifepotion" amount="1" cost="fixed"/>
|
||||
</spell>
|
||||
|
||||
<!-- 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"/>
|
||||
</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="permaura" amount="5" cost="fixed"/>
|
||||
</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="money" amount="30000" cost="fixed"/>
|
||||
<resource name="permaura" amount="3" cost="fixed"/>
|
||||
</spell>
|
||||
|
||||
<!-- 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"/>
|
||||
</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="money" amount="1000" cost="fixed"/>
|
||||
<resource name="permaura" amount="1" cost="fixed"/>
|
||||
</spell>
|
||||
|
||||
<!-- 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"/>
|
||||
</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="money" amount="3000" cost="fixed"/>
|
||||
</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="permaura" amount="1" cost="fixed"/>
|
||||
<resource name="money" amount="4000" cost="fixed"/>
|
||||
</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="permaura" amount="1" cost="fixed"/>
|
||||
<resource name="money" amount="5000" cost="fixed"/>
|
||||
</spell>
|
||||
|
||||
<!-- 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="permaura" amount="1" cost="fixed"/>
|
||||
<resource name="money" amount="1000" cost="fixed"/>
|
||||
<resource name="laensword" amount="1" cost="fixed"/>
|
||||
</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="permaura" amount="1" cost="fixed"/>
|
||||
<resource name="money" amount="3000" cost="fixed"/>
|
||||
</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="permaura" amount="1" cost="fixed"/>
|
||||
</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="permaura" amount="1" cost="fixed"/>
|
||||
</spell>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
|
||||
<resource name="elfspoil">
|
||||
|
@ -57,3 +58,4 @@
|
|||
</resource>
|
||||
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="axe">
|
||||
<item weight="200">
|
||||
<construction skill="weaponsmithing" minskill="3">
|
||||
|
@ -11,3 +13,5 @@
|
|||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="bow">
|
||||
<item weight="100">
|
||||
<construction skill="weaponsmithing" minskill="2">
|
||||
|
@ -11,3 +13,5 @@
|
|||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="catapult">
|
||||
<item weight="10000" big="yes">
|
||||
<construction skill="cartmaking" minskill="5">
|
||||
|
@ -12,3 +14,5 @@
|
|||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="crossbow">
|
||||
<item weight="100">
|
||||
<construction skill="weaponsmithing" minskill="3">
|
||||
|
@ -11,3 +13,5 @@
|
|||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="firesword">
|
||||
<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"/>
|
||||
<damage type="rider" value="3d6+10"/>
|
||||
<damage type="footman" value="3d6+10"/>
|
||||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="greatbow">
|
||||
<modifier type="require" race="elf"/>
|
||||
<modifier type="require" races="elf"/>
|
||||
<item weight="100">
|
||||
<construction skill="weaponsmithing" minskill="5">
|
||||
<requirement type="mallorn" quantity="2"/>
|
||||
|
@ -9,9 +11,9 @@
|
|||
<damage type="rider" value="2d6+4"/>
|
||||
<damage type="footman" value="2d6+4"/>
|
||||
<modifier type="missile_target" value="2"/>
|
||||
<modifier type="damage" value="1">
|
||||
<race name="elf"/>
|
||||
</modifier>
|
||||
<modifier type="damage" value="1" races="elf"/>
|
||||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="greatsword">
|
||||
<item weight="200" score="30">
|
||||
<construction skill="weaponsmithing" minskill="4">
|
||||
|
@ -10,3 +12,5 @@
|
|||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="halberd">
|
||||
<item weight="200">
|
||||
<construction skill="weaponsmithing" minskill="3">
|
||||
|
@ -12,3 +14,5 @@
|
|||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="laensword">
|
||||
<item weight="100" score="400">
|
||||
<construction skill="weaponsmithing" minskill="8">
|
||||
<requirement type="laen" quantity="1"/>
|
||||
</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="footman" value="3d6+10"/>
|
||||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="lance">
|
||||
<item weight="200">
|
||||
<construction skill="weaponsmithing" minskill="2">
|
||||
|
@ -10,3 +12,5 @@
|
|||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="mallornbow">
|
||||
<item weight="100">
|
||||
<construction skill="weaponsmithing" minskill="5">
|
||||
|
@ -8,9 +10,9 @@
|
|||
<damage type="rider" value="1d11+2"/>
|
||||
<damage type="footman" value="1d11+2"/>
|
||||
<modifier type="missile_target" value="2"/>
|
||||
<modifier type="damage" value="1">
|
||||
<race name="elf"/>
|
||||
</modifier>
|
||||
<modifier type="damage" value="1" races="elf"/>
|
||||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="mallorncrossbow">
|
||||
<item weight="100">
|
||||
<construction skill="weaponsmithing" minskill="5">
|
||||
|
@ -11,3 +13,5 @@
|
|||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="mallornlance">
|
||||
<item weight="100">
|
||||
<construction skill="weaponsmithing" minskill="5">
|
||||
|
@ -10,3 +12,5 @@
|
|||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="mallornspear">
|
||||
<item weight="100">
|
||||
<construction skill="weaponsmithing" minskill="5">
|
||||
|
@ -12,3 +14,5 @@
|
|||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="runesword">
|
||||
<item weight="100" score="2000">
|
||||
<weapon cut="true" magical="yes" skill="melee" offmod="2" defmod="2">
|
||||
|
@ -8,3 +10,5 @@
|
|||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="rustyaxe">
|
||||
<item weight="200">
|
||||
<construction skill="weaponsmithing" minskill="3">
|
||||
|
@ -11,3 +13,5 @@
|
|||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="rustygreatsword">
|
||||
<item weight="200" score="20">
|
||||
<construction skill="weaponsmithing" minskill="4">
|
||||
|
@ -10,3 +12,5 @@
|
|||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="rustyhalberd">
|
||||
<item weight="200" score="20">
|
||||
<construction skill="weaponsmithing" minskill="3">
|
||||
|
@ -12,3 +14,5 @@
|
|||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="rustysword">
|
||||
<item weight="100" score="10">
|
||||
<construction skill="weaponsmithing" minskill="3">
|
||||
|
@ -10,3 +12,5 @@
|
|||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="spear">
|
||||
<item weight="100">
|
||||
<construction skill="weaponsmithing" minskill="2">
|
||||
|
@ -12,3 +14,5 @@
|
|||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="sword">
|
||||
<item weight="100" score="30">
|
||||
<construction skill="weaponsmithing" minskill="3">
|
||||
|
@ -10,3 +12,5 @@
|
|||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
|
@ -1,12 +1,79 @@
|
|||
<?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/scale.xml"/>
|
||||
<xi:include href="armor/shield.xml"/>
|
||||
<xi:include href="armor/towershield.xml"/>
|
||||
<eressea>
|
||||
<resources>
|
||||
<resource name="towershield">
|
||||
<modifier type="require" races="dwarf 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"/>
|
||||
</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>
|
||||
</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"?>
|
||||
<buildings xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<xi:include href="config://default/buildings/castle-2.xml" />
|
||||
<eressea>
|
||||
<buildings>
|
||||
|
||||
<building name="watch" maxsize="10" fort="yes" taxes="200">
|
||||
<construction skill="building" minskill="1" maxsize="5" name="scaffolding">
|
||||
|
@ -24,4 +23,4 @@
|
|||
</building>
|
||||
|
||||
</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" ?>
|
||||
<eressea>
|
||||
<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_2"><item weight="1"/></resource>
|
||||
<resource name="rpg_item_3"><item weight="100"/></resource>
|
||||
|
@ -26,7 +52,7 @@
|
|||
</item>
|
||||
</resource>
|
||||
|
||||
<resource name="p14" appearance="vial">
|
||||
<resource name="healing" appearance="vial">
|
||||
<!-- Heiltrank -->
|
||||
<item weight="0" score="120" use="yes">
|
||||
<potion level="4"/>
|
||||
|
@ -40,7 +66,7 @@
|
|||
</item>
|
||||
</resource>
|
||||
|
||||
<resource name="p2" appearance="vial">
|
||||
<resource name="lifepotion" appearance="vial">
|
||||
<!-- Wasser des Lebens -->
|
||||
<item weight="0" score="30" use="yes">
|
||||
<potion level="1"/>
|
||||
|
@ -76,3 +102,4 @@
|
|||
</resource>
|
||||
|
||||
</resources>
|
||||
</eressea>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue