forked from github/server
Merge branch 'master' of github.com:eressea/server
This commit is contained in:
commit
465f3f7ce9
|
@ -27,3 +27,4 @@ game-e3/reports/
|
|||
*.log
|
||||
*.log.*
|
||||
tags
|
||||
Thumbs.db
|
||||
|
|
|
@ -4,7 +4,7 @@ require "resources"
|
|||
|
||||
function run_editor()
|
||||
local turn = get_turn()
|
||||
if turn==0 then
|
||||
if turn<0 then
|
||||
turn = read_turn()
|
||||
set_turn(turn)
|
||||
end
|
||||
|
@ -28,7 +28,7 @@ function run_turn()
|
|||
require(config.game .. ".main")
|
||||
|
||||
local turn = get_turn()
|
||||
if turn==0 then
|
||||
if turn<0 then
|
||||
turn = read_turn()
|
||||
set_turn(turn)
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
function kill_nonstarters()
|
||||
for f in factions() do
|
||||
if f.lastturn==1 then
|
||||
if f.lastturn==0 then
|
||||
kill_faction(f, true)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
# Eressea Rules
|
||||
|
||||
© Copyright Enno Rehling 2014
|
||||
|
||||
## Contents
|
||||
|
||||
1. Introduction
|
||||
2. First Turn by Example
|
||||
3. The Economy: Recruiting, Upkeep and Silver
|
||||
4. Studying Skills
|
||||
5. Movement and Seafaring
|
||||
6. Combat
|
||||
7. Alliances and Groups
|
||||
7. Resources and Production
|
||||
8. Magic and Alchemy
|
||||
9. Castles and other buildings
|
||||
10. Races
|
||||
11. List of Orders
|
||||
12. List of Skills
|
||||
13. List of Buildings
|
||||
14. List of Items
|
||||
15. Appendices and Tables
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
This game would not be possible without the work of Russell Wallace, who created the Atlantis PBEM in 1993. I would also like to thank Alex Schröder, who wrote the first German translation of Atlantis. Christian Schlittchen, Katja Zedel and Henning Peters started Eressea, and invited me to be a part of their team and become their friends in the process. Ingo Wilken, Benjamin Bärmann, Stefan Reich, and Martin Hershoff have contributed code and valuable design input to the server. Many advanced features are a direct result of entertaining debates on the eressea-kom and atlantisdev discussion lists, and I would like to thank them and the entire community for their support and encouragement over the years.
|
||||
|
||||
Enno Rehling, April 2014
|
|
@ -0,0 +1,79 @@
|
|||
# Introduction
|
||||
|
||||
Eressea is a play-by-email strategy role-playing game that simulates a fantasy world. Unlike most video games, there are are no fancy graphics, but everything that happens is communicated by text.
|
||||
|
||||
As a player, you are in control of a number of characters, which are referred to as units, which combine to make a faction. Your faction competes with other factions over the resources of the world that you explore together. Sometimes this leads to war, and sometimes to friendship between factions, and eventually it all adds up to a rich history of the world, with its own heroes and legends.
|
||||
|
||||
Eressea is different from most games in many respects, but most of all in that there is no declared winner. There is not even a goal, other than to enjoy yourself, and set your own goals. Do you want to monopolize a natural resource? Become the strongest military force? Create a democratic government for the factions in your part of the world? Collect trophies from slain dragons? Map the entire globe? Those are all valid goals to set for yourself, but you might find your own.
|
||||
|
||||
### How to play
|
||||
|
||||
Eressea is played in weekly turns. Every weekend, you receive a textual report containing your units, the part of the world that they can observe, and any events that happened since the last report.
|
||||
|
||||
Based on that report, players send an email to the game's server that contains orders for all of their units. A week later, the server evaluates the orders from all players, updates the state of the world, and sends out new reports.
|
||||
|
||||
A (slightly simplified) report may look like this:
|
||||
|
||||
Report for Eressea, Sunday, 13. April 2014, 23:25
|
||||
|
||||
It is the first week of the month of harvest moon in
|
||||
the 1. year of the fourth age. It is summer.
|
||||
|
||||
Guardians (xin8), elves/draig (guardian@gmx.de)
|
||||
|
||||
Your faction has 4 people in 1 unit.
|
||||
|
||||
Vetkan (10,1), highland, 1012 peasants, 13156 silver,
|
||||
17 horses. To the northwest lies the forests of
|
||||
Buviken (9,2), to the northeast the mountains of Rebus
|
||||
(10,2), to the east the plain of Setutvul (-9,1), to
|
||||
the southeast the mountains of Vithil (-9,0), to the
|
||||
southwest the forests of Posotmetid (10,0) and to the
|
||||
west the forests of Cesartapun (9,1)
|
||||
|
||||
The local market offers silk and mandrakes.
|
||||
|
||||
Statistics for Vetkan (10,1):
|
||||
|
||||
Peasant wages: 11 silver
|
||||
Recruits: 25 peasants
|
||||
|
||||
Pelenth (opw4), size 10, fortification.
|
||||
|
||||
* Fighters of Pelenth (r6b0), 4 elves,
|
||||
aggressive, skills: melee 5, has: platemail,
|
||||
sword, 500 silver.
|
||||
|
||||
+ Osswid the Destroyer (wtmj), Vikings (atnf), 1
|
||||
dwarf, has: 1 iron.
|
||||
|
||||
What you see here are two units, Osswid (wtmj) and the Fighters of Pelenth (r6b0). The fighters are our own unit, but Osswid belongs to the faction Vikings (atnf). Every unit, faction or other object in the game is identified by a four-letter code, and it is common to append it to the name in parentheses. The fort of Pelenth (opw4) is a building, and our fighters are inside, which causes them to be indented a little more, and gives them some benefits including additional protection in combat.
|
||||
|
||||
While Osswid is a single dwarf, our unit of fighters consists of several elves. Units can any number of men, which are always of the same race. Each unit can learn any number of skills, and our Fighters are skilled in melee combat at a respectable level 5. They own a sword and one platemail, which means that one of them will be well equipped when going into battle, while the other three will fight with their bare hands. The unit also has 500 pieces of silver, the currency of the game.
|
||||
|
||||
Since he isn't of our own faction, we cannot tell what skills Osswid has, but we can tell that he's unarmed.
|
||||
|
||||
We see all this because one of our units is in the region, the highland of Vetkan (10,1). Regions do not have a four-letter identifier, but are instead identified by their coordinates on the map, which makes it easier to visualize the world.
|
||||
|
||||
The region of Vetkan is surrounded by a number of other regions on six sides, since Eressea's Map uses a hexagonal grid. Every region has a terrain, and we can see highland, mountain, plain and forest regions in our vicinity. Each terrain has different qualities: For example, mountains are good for mining iron ore and quarries, while plains are fertile and forests produce lumber. Each region is inhabited by a peasant population, and you can see that Vetkan has a population of 1012. These peasants are the basis of the region's economy, and they own a combined 13,156 silver that we could try to acquire through taxation or other means.
|
||||
|
||||
Example orders for this faction may look like this:
|
||||
|
||||
ERESSEA xin8 "password"
|
||||
UNIT r6b0
|
||||
STUDY perception
|
||||
GIVE wtmj 100 silver
|
||||
GIVE TEMP 1 150 silver
|
||||
GIVE TEMP 2 150 silver
|
||||
MAKE TEMP 1
|
||||
RECRUIT 1
|
||||
MOVE W
|
||||
END
|
||||
MAKE TEMP 2
|
||||
RECRUIT 1
|
||||
MOVE E
|
||||
END
|
||||
|
||||
Every set of orders begins with the faction's id and password, and is followed by orders for one or more units. A unit's orders begin with the word UNIT followed by the unit's id, and one or more orders. In this case, we are giving the unit an order to STUDY the perception skill, and to GIVE silver to three other units. STUDY is a standard action, and each unit can perform exactly one per turn. If you do not specify a standard action, then the unit will usually repeat the action from the previous week. GIVE is a free action, and all units can perform as many free actions in a week as they like.
|
||||
|
||||
The MAKE TEMP order is special: It creates a new unit with a temporary id (in this case, we're calling them TEMP 1 and TEMP 2). The server will replace this with a unique id by the time it sends the next report, but until then, we can address the new unit by this temporary identifier, for example to give it the silver that it requires for recruiting new members. RECRUIT is another example of a free action, while MOVE is a standard action. The MAKE TEMP order is technically given by the unit whose orders preceded it, and the new unit's orders are finished with the END keyword.
|
|
@ -5,6 +5,12 @@
|
|||
|
||||
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
|
||||
<rewriteURI
|
||||
uriStartString="eressea:///core/"
|
||||
uriStartString="config:///game/"
|
||||
rewritePrefix="../res/eressea/" />
|
||||
<rewriteURI
|
||||
uriStartString="config:///default/"
|
||||
rewritePrefix="../res/" />
|
||||
<rewriteURI
|
||||
uriStartString="config:///core/"
|
||||
rewritePrefix="../core/res/" />
|
||||
</catalog>
|
|
@ -1,36 +1,37 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<xi:include href="eressea:///core/messages.xml"/>
|
||||
<xi:include href="config:///core/messages.xml"/>
|
||||
|
||||
<!-- Localization -->
|
||||
<xi:include href="eressea:///core/de/strings.xml"/>
|
||||
<xi:include href="eressea:///core/en/strings.xml"/>
|
||||
<xi:include href="eressea/spellinfo.xml" />
|
||||
<xi:include href="config:///core/de/strings.xml"/>
|
||||
<xi:include href="config:///core/en/strings.xml"/>
|
||||
<xi:include href="config:///game/spellinfo.xml" />
|
||||
|
||||
<xi:include href="eressea:///core/common/items.xml" />
|
||||
<xi:include href="eressea:///core/common/armor.xml" />
|
||||
<xi:include href="eressea:///core/common/weapons.xml" />
|
||||
<xi:include href="eressea:///core/common/resources.xml" />
|
||||
<xi:include href="eressea:///core/common/luxuries.xml" />
|
||||
<xi:include href="eressea:///core/common/herbs.xml" />
|
||||
<xi:include href="eressea:///core/common/potions.xml" />
|
||||
<xi:include href="eressea:///core/spoils.xml"/>
|
||||
<xi:include href="eressea/races.xml"/>
|
||||
<xi:include href="eressea:///core/prefixes.xml"/>
|
||||
<xi:include href="eressea:///core/ships.xml"/>
|
||||
<xi:include href="eressea:///core/common/buildings.xml"/>
|
||||
<xi:include href="eressea:///core/equipment.xml"/>
|
||||
<xi:include href="eressea:///core/terrains.xml"/>
|
||||
<xi:include href="eressea/terrains.xml"/>
|
||||
<xi:include href="directions.xml"/>
|
||||
<xi:include href="eressea/artrewards.xml"/>
|
||||
<xi:include href="eressea/buildings.xml"/>
|
||||
<xi:include href="eressea:///core/calendar.xml"/>
|
||||
<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/prefixes.xml"/>
|
||||
<xi:include href="config:///core/ships.xml"/>
|
||||
<xi:include href="config:///core/common/buildings.xml"/>
|
||||
<xi:include href="config:///core/equipment.xml"/>
|
||||
<xi:include href="config:///core/terrains.xml"/>
|
||||
<xi:include href="config:///game/terrains.xml"/>
|
||||
<xi:include href="config:///default/directions.xml"/>
|
||||
<xi:include href="config:///game/artrewards.xml"/>
|
||||
<xi:include href="config:///game/buildings.xml"/>
|
||||
<xi:include href="config:///core/calendar.xml"/>
|
||||
<calendar name="secondage" newyear="month_1" start="184"/>
|
||||
<xi:include href="eressea/equipment.xml"/>
|
||||
<xi:include href="eressea/items.xml"/>
|
||||
<xi:include href="eressea/spells.xml"/>
|
||||
<xi:include href="eressea/strings.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:///game/strings.xml"/>
|
||||
<xi:include href="config:///default/adamantium.xml"/>
|
||||
<equipment>
|
||||
<set name="first_unit">
|
||||
<item name="conquesttoken" amount="1"/>
|
||||
|
@ -43,11 +44,11 @@
|
|||
</set>
|
||||
</equipment>
|
||||
|
||||
<xi:include href="names-undead.xml"/>
|
||||
<xi:include href="names-skeletons.xml"/>
|
||||
<xi:include href="names-zombies.xml"/>
|
||||
<xi:include href="names-ghouls.xml"/>
|
||||
<xi:include href="names-dragons.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"/>
|
||||
|
||||
<game name="Eressea">
|
||||
<!-- Game specific settings -->
|
|
@ -1,6 +1,5 @@
|
|||
[eressea]
|
||||
base = .
|
||||
load = setup.lua
|
||||
report = reports
|
||||
verbose = 0
|
||||
lomem = 0
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
require "setup"
|
||||
run_tests()
|
|
@ -10,6 +10,5 @@ for idx, path in pairs(paths) do
|
|||
package.path = srcpath .. '/' .. path .. ';' .. package.path
|
||||
end
|
||||
|
||||
read_xml(respath..'/config-eressea.xml', respath..'/catalog-eressea.xml')
|
||||
|
||||
assert(read_xml())
|
||||
require "init"
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
"http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
|
||||
|
||||
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
|
||||
<rewriteURI
|
||||
uriStartString="config:///core/"
|
||||
rewritePrefix="../core/res/" />
|
||||
<rewriteURI
|
||||
uriStartString="config:///game/"
|
||||
rewritePrefix="../res/e3a/" />
|
||||
<rewriteURI
|
||||
uriStartString="config:///default/"
|
||||
rewritePrefix="../res/" />
|
||||
<rewriteURI
|
||||
uriStartString="config:///core/"
|
||||
rewritePrefix="../core/res/" />
|
||||
</catalog>
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
require "setup"
|
||||
run_tests()
|
|
@ -10,6 +10,5 @@ for idx, path in pairs(paths) do
|
|||
package.path = srcpath .. '/' .. path .. ';' .. package.path
|
||||
end
|
||||
|
||||
read_xml(respath..'/config-e3a.xml', respath..'/catalog-e3a.xml')
|
||||
|
||||
assert(read_xml())
|
||||
require "init"
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from sys import argv, exit
|
||||
from string import join
|
||||
from os import access, R_OK
|
||||
from os import system
|
||||
|
||||
gamename='Eressea'
|
||||
|
||||
if(len(argv) >= 3):
|
||||
gamename=argv[2]
|
||||
|
||||
template="""#!/bin/bash
|
||||
#PATH=$PATH:$HOME/bin
|
||||
|
||||
addr=%(email)s
|
||||
[ $# -ge 1 ] && addr=$1
|
||||
[ -z $addr ] || send-%(compression)s-report $addr '%(gamename)s Report #%(turn)s' %(files)s
|
||||
"""
|
||||
|
||||
turn = argv[1]
|
||||
try:
|
||||
infile = file("reports.txt", "r")
|
||||
except:
|
||||
print "%s: reports.txt file does not exist" % (argv[0], )
|
||||
exit(0)
|
||||
|
||||
for line in infile.readlines():
|
||||
settings = line[:-1].split(":")
|
||||
options = { "turn" : turn}
|
||||
options["gamename"] = gamename
|
||||
for setting in settings:
|
||||
try:
|
||||
key, value = setting.split("=")
|
||||
options[key] = value
|
||||
except:
|
||||
print "Invalid input line", line
|
||||
if not options.has_key("reports"):
|
||||
continue
|
||||
reports = options["reports"].split(",")
|
||||
# reports = reports + [ "iso.cr" ]
|
||||
prefix = "%(turn)s-%(faction)s." % options
|
||||
files=[]
|
||||
if options["compression"]=="zip":
|
||||
output = prefix+"zip"
|
||||
files = [output]
|
||||
if (access(output, R_OK)):
|
||||
pass
|
||||
else:
|
||||
parameters = []
|
||||
for extension in reports:
|
||||
filename = "%s%s" % (prefix, extension)
|
||||
if (access(filename, R_OK)):
|
||||
parameters = parameters + [ filename ]
|
||||
system("zip %s -q -m -j -1 %s" % (output, join(parameters," ")))
|
||||
else:
|
||||
for extension in reports:
|
||||
if extension!='':
|
||||
filename = "%s%s" % (prefix, extension)
|
||||
output = "%s%s.bz2" % (prefix, extension)
|
||||
files = files+[output]
|
||||
if access(filename, R_OK):
|
||||
if (access(output, R_OK)):
|
||||
#print output, "exists, skipping"
|
||||
continue
|
||||
system("bzip2 %s" % filename)
|
||||
#print files
|
||||
options["files"] = join(files, " ")
|
||||
batch = file("%s.sh" % options["faction"], "w")
|
||||
batch.write(template % options)
|
||||
batch.close()
|
||||
infile.close()
|
|
@ -0,0 +1,2 @@
|
|||
#/bin/.sh
|
||||
grep -v '>From' | $HOME/src/scripts/bin/orders-accept $*
|
|
@ -0,0 +1,218 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: iso-8859-1 -*-
|
||||
|
||||
from os import unlink, symlink, rename, popen, tmpfile
|
||||
from os.path import exists
|
||||
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 splitfilename(filename):
|
||||
from os.path import split
|
||||
return 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 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",
|
||||
}
|
||||
|
||||
|
||||
# base directory for all your games:
|
||||
rootdir = "/home/eressea/eressea"
|
||||
frommail = "Eressea Server <eressea-server@eressea.de>"
|
||||
orderbase = "orders.dir"
|
||||
sendmail = True
|
||||
maxlines = 25
|
||||
echeck_cmd = "/home/eressea/echeck/echeck.sh"
|
||||
|
||||
# regular expression that finds the start of a faction
|
||||
fact_re = compile("^\s*(eressea|vinyambar|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 pw_data.check(fact_nr, fact_pw) == 0:
|
||||
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 = splitfilename(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
|
||||
|
||||
## the main body of the script
|
||||
game = int(argv[1])
|
||||
|
||||
basedir = rootdir + "/game-%d" % (game, )
|
||||
queuename = basedir + "/orders.queue"
|
||||
if not exists(queuename):
|
||||
exit(0)
|
||||
|
||||
# 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(basedir + "/passwd")
|
||||
|
||||
#print "reading orders.queue..."
|
||||
# move the queue file to a save space while locking it:
|
||||
try:
|
||||
lock_file(queuename)
|
||||
except:
|
||||
exit(0)
|
||||
queuefile = open(queuename, "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(queuename)
|
||||
try:
|
||||
unlock_file(queuename)
|
||||
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"])
|
||||
file = dict["file"]
|
||||
gamename='[E%d]' % game
|
||||
rules='e%d' % game
|
||||
warning = ""
|
||||
failed = True
|
||||
results = check_pwd(file, email, pw_data)
|
||||
logfile = open(basedir+"/zug.log", "a")
|
||||
dirname, filename = splitfilename(file)
|
||||
msg = messages["validate-"+locale] + " " + filename + "\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 " + file)
|
||||
else:
|
||||
result = echeck(file, locale, rules)
|
||||
if email=='eressea':
|
||||
print result
|
||||
continue
|
||||
elif result is None:
|
||||
# echeck did not finish
|
||||
msg = msg + "Echeck was killed. Your turn was accepted, but could not be verified.\n"
|
||||
warning = " (" + messages["warning-" + locale] + ")"
|
||||
syslog("process - echeck got killed, " + file)
|
||||
else:
|
||||
msg = msg + result
|
||||
syslog("process - checked orders in " + file)
|
||||
|
||||
subject = gamename + " " + messages["subject-" + locale] + warning
|
||||
msg = "Subject: %s\nFrom: %s\nTo: %s\nContent-Type: text/plain; charset=utf-8\n\n" % (subject, frommail, email) + msg
|
||||
try:
|
||||
server.sendmail(frommail, email, msg)
|
||||
except:
|
||||
syslog("failed - cannot send to " + email)
|
||||
|
||||
server.close()
|
||||
|
||||
closelog()
|
||||
unlink(tname)
|
||||
unlock_file(tname)
|
|
@ -0,0 +1,16 @@
|
|||
#!/bin/bash
|
||||
|
||||
## this script processes incoming order files.
|
||||
# files are delivered into an incoming queue by procmail, then cron runs
|
||||
# this here script to make a non-blocking syntax check and reject or
|
||||
# accept the order file.
|
||||
|
||||
for GAME in $*
|
||||
do
|
||||
if [ "$GAME" == "eressea" ]; then GAME=2 ; fi
|
||||
if [ "$GAME" == "e3a" ]; then GAME=3 ; fi
|
||||
if [ -e $HOME/eressea/game-$GAME/orders.queue ]
|
||||
then
|
||||
$HOME/bin/orders-process $GAME
|
||||
fi
|
||||
done
|
|
@ -0,0 +1,35 @@
|
|||
#!/bin/bash
|
||||
if [ -z $ERESSEA ]; then
|
||||
echo "You have to define the \$ERESSEA environment variable to run $0"
|
||||
exit -2
|
||||
fi
|
||||
source $HOME/bin/functions.sh
|
||||
source $ERESSEA/etc/eressea.conf
|
||||
|
||||
TEMPLATE=report-mail.txt
|
||||
if [ "$1" == "-Lde" ]
|
||||
then
|
||||
TEMPLATE=report-mail.de.txt
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ "$1" == "-Lde" ]
|
||||
then
|
||||
TEMPLATE=report-mail.en.txt
|
||||
shift
|
||||
fi
|
||||
|
||||
EMAIL=$1
|
||||
SUBJECT=$2
|
||||
shift 2
|
||||
|
||||
ATTACHMENTS=""
|
||||
while [ $# -gt 0 ]
|
||||
do
|
||||
if [ -e "$1" ]; then
|
||||
ATTACHMENTS="-a $1 $ATTACHMENTS"
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
cat $ERESSEA/etc/$TEMPLATE | mutt -F $ERESSEA/etc/muttrc -s "$SUBJECT" $ATTACHMENTS -- $EMAIL
|
|
@ -0,0 +1,46 @@
|
|||
#!/bin/bash
|
||||
if [ -z $ERESSEA ]; then
|
||||
ERESSEA=`echo $PWD |sed -e 's/\/game.*//'`
|
||||
echo "Assuming that ERESSEA=$ERESSEA"
|
||||
fi
|
||||
if [ ! -f reports.txt ]; then
|
||||
echo "need to run $0 from the report direcory"
|
||||
exit -2
|
||||
fi
|
||||
|
||||
PWD=$(pwd)
|
||||
GAME=$(dirname $PWD)
|
||||
|
||||
TEMPLATE=report-mail.txt
|
||||
if [ "$1" == "-Lde" ]
|
||||
then
|
||||
TEMPLATE=report-mail.de.txt
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ "$1" == "-Len" ]
|
||||
then
|
||||
TEMPLATE=report-mail.en.txt
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ -e $GAME/$TEMPLATE ]; then
|
||||
TEMPLATE=$GAME/$TEMPLATE
|
||||
else
|
||||
TEMPLATE=$ERESSEA/etc/$TEMPLATE
|
||||
fi
|
||||
|
||||
if [ ! -e $TEMPLATE ]; then
|
||||
echo "no such email template: $TEMPLATE"
|
||||
exit -3
|
||||
fi
|
||||
|
||||
while [ -e /tmp/.stopped ] ; do
|
||||
echo "waiting 2 minutes for lockfile in /tmp/.stopped to clear"
|
||||
sleep 120
|
||||
done
|
||||
mutt -F $ERESSEA/etc/muttrc -s "$2" -a "$3" -- $1 < $TEMPLATE
|
||||
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Sending failed for email/report: $2/$3"
|
||||
fi
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1" ?>
|
||||
<resources>
|
||||
|
||||
<resource name="adamantium" limited="yes" material="rm_adamantium">
|
||||
<item weight="200" score="200">
|
||||
<construction skill="mining" minskill="8" reqsize="1"/>
|
||||
</item>
|
||||
<resourcelimit>
|
||||
<modifier type="require" building="mine"/>
|
||||
<guard flag="mining"/>
|
||||
</resourcelimit>
|
||||
</resource>
|
||||
|
||||
<resource name="adamantiumaxe">
|
||||
<item weight="100" score="500">
|
||||
<construction skill="weaponsmithing" minskill="8" reqsize="1">
|
||||
<requirement type="adamantium" quantity="1"/>
|
||||
<requirement type="log" quantity="1"/>
|
||||
</construction>
|
||||
<weapon cut="true" skill="melee" offmod="2" defmod="-2" magres="0.30">
|
||||
<damage type="rider" value="3d4+15"/>
|
||||
<damage type="footman" value="3d4+15"/>
|
||||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
|
||||
<resource name="adamantiumplate">
|
||||
<item weight="100" score="2000">
|
||||
<construction skill="armorer" minskill="10" reqsize="1">
|
||||
<requirement type="adamantium" quantity="3"/>
|
||||
</construction>
|
||||
<armor ac="7" penalty="0.1"/>
|
||||
</item>
|
||||
</resource>
|
||||
|
||||
</resources>
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE catalog
|
||||
PUBLIC "-//OASIS/DTD Entity Resolution XML Catalog V1.0//EN"
|
||||
"http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
|
||||
|
||||
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
|
||||
<rewriteURI
|
||||
uriStartString="eressea:///core/"
|
||||
rewritePrefix="../core/res/" />
|
||||
</catalog>
|
|
@ -1,189 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<eressea xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<xi:include href="eressea:///core/messages.xml"/>
|
||||
|
||||
<!-- Localization -->
|
||||
<xi:include href="eressea:///core/de/strings.xml"/>
|
||||
<xi:include href="eressea:///core/en/strings.xml"/>
|
||||
|
||||
<xi:include href="eressea:///core/common/items.xml"/>
|
||||
<xi:include href="eressea:///core/common/herbs.xml" />
|
||||
<xi:include href="eressea:///core/spoils.xml"/>
|
||||
<xi:include href="eressea:///core/prefixes.xml"/>
|
||||
<xi:include href="eressea:///core/common/buildings.xml"/>
|
||||
<xi:include href="eressea:///core/equipment.xml"/>
|
||||
<xi:include href="directions.xml"/>
|
||||
|
||||
<xi:include href="e3a/ships.xml"/>
|
||||
<xi:include href="e3a/shipnames.xml"/>
|
||||
<xi:include href="e3a/terrains.xml"/>
|
||||
<xi:include href="eressea:///core/calendar.xml"/>
|
||||
<calendar name="thirdage" newyear="month_1" start="1"/>
|
||||
<xi:include href="e3a/items.xml" />
|
||||
<xi:include href="e3a/strings.xml"/>
|
||||
<xi:include href="e3a/messages.xml"/>
|
||||
<xi:include href="e3a/races.xml"/>
|
||||
<xi:include href="e3a/buildings.xml"/>
|
||||
<xi:include href="e3a/equipment.xml"/>
|
||||
<xi:include href="e3a/spells.xml"/>
|
||||
<xi:include href="e3a/luxuries.xml" />
|
||||
<xi:include href="e3a/weapons.xml" />
|
||||
<xi:include href="e3a/armor.xml" />
|
||||
<xi:include href="e3a/resources.xml" />
|
||||
|
||||
<equipment>
|
||||
<set name="first_unit">
|
||||
<item name="conquesttoken" amount="1"/>
|
||||
<item name="log" amount="10"/>
|
||||
<item name="stone" amount="10"/>
|
||||
<item name="money" amount="5000"/>
|
||||
</set>
|
||||
</equipment>
|
||||
|
||||
<xi:include href="names-undead.xml"/>
|
||||
<xi:include href="names-skeletons.xml"/>
|
||||
<xi:include href="names-zombies.xml"/>
|
||||
<xi:include href="names-ghouls.xml"/>
|
||||
<xi:include href="names-dragons.xml"/>
|
||||
|
||||
<game name="E3">
|
||||
<!-- Game specific settings -->
|
||||
<param name="database.gameid" value="7"></param>
|
||||
|
||||
<order name="BETEN" disable="yes"/>
|
||||
<order name="BELAGERE" disable="yes"/>
|
||||
<order name="BEKLAUEN" disable="yes"/>
|
||||
<order name="FRIEDEN" disable="yes"/>
|
||||
<order name="GM" disable="yes"/>
|
||||
<order name="JIHAD" disable="yes"/>
|
||||
<order name="KRIEG" disable="yes"/>
|
||||
<order name="KAUFEN" disable="yes"/>
|
||||
<order name="LEHREN" disable="yes"/>
|
||||
<order name="LIEFERE" disable="yes"/>
|
||||
<order name="OPFERE" disable="yes"/>
|
||||
<order name="SABOTIEREN" disable="yes"/>
|
||||
<order name="SPIONIEREN" disable="yes"/>
|
||||
<order name="TREIBEN" disable="yes"/>
|
||||
<order name="UNTERHALTEN" disable="yes"/>
|
||||
<order name="VERKAUFEN" disable="yes"/>
|
||||
|
||||
<skill name="armorer" enable="true"/>
|
||||
<skill name="bow" enable="true"/>
|
||||
<skill name="building" enable="true"/>
|
||||
<skill name="cartmaking" enable="true"/>
|
||||
<skill name="catapult" enable="true"/>
|
||||
<skill name="crossbow" enable="true"/>
|
||||
<skill name="forestry" enable="true"/>
|
||||
<skill name="magic" enable="true"/>
|
||||
<skill name="melee" enable="true"/>
|
||||
<skill name="mining" enable="true"/>
|
||||
<skill name="polearm" enable="true"/>
|
||||
<skill name="quarrying" enable="true"/>
|
||||
<skill name="riding" enable="true"/>
|
||||
<skill name="roadwork" enable="true"/>
|
||||
<skill name="sailing" enable="true"/>
|
||||
<skill name="shipcraft" enable="true"/>
|
||||
<skill name="stamina" enable="true"/>
|
||||
<skill name="tactics" enable="true"/>
|
||||
<skill name="training" enable="true"/>
|
||||
<skill name="unarmed" enable="true"/>
|
||||
<skill name="weaponsmithing" enable="true"/>
|
||||
|
||||
<skill name="herbalism" enable="false"/>
|
||||
|
||||
<skill name="alchemy" enable="false"/>
|
||||
<skill name="entertainment" enable="false"/>
|
||||
<skill name="espionage" enable="false"/>
|
||||
<skill name="perception" enable="false"/>
|
||||
<skill name="stealth" enable="false"/>
|
||||
<skill name="taxation" enable="false"/>
|
||||
<skill name="trade" enable="false"/>
|
||||
|
||||
<param name="NewbieImmunity" value="9"/> <!-- ends after turn 9 -->
|
||||
|
||||
<param name="modules.astralspace" value="0"/>
|
||||
<param name="modules.wormholes" value="0"/>
|
||||
<param name="modules.markets" value="1"/>
|
||||
|
||||
<!-- resource limitations -->
|
||||
<param name="magic.regeneration" value="0.75"/>
|
||||
<param name="magic.power" value="0.5"/>
|
||||
<param name="resource.factor" value="0.25"/>
|
||||
|
||||
<param name="skills.cost.tactics" value="500"/>
|
||||
<param name="entertain.base" value="0"/>
|
||||
<param name="entertain.perlevel" value="20"/>
|
||||
<param name="nmr.timeout" value="5"/>
|
||||
<param name="nmr.removenewbie" value="0"/>
|
||||
<param name="GiveRestriction" value="3"/>
|
||||
<param name="hunger.long" value="0"/>
|
||||
<param name="hunger.demon.skill" value="1"/>
|
||||
<param name="hunger.damage" value="1d9+9"/>
|
||||
<param name="hunger.demons" value="1"/>
|
||||
<param name="init_spells" value="0"/>
|
||||
<param name="recruit.allow_merge" value="1"/>
|
||||
<param name="study.expensivemigrants" value="1"/>
|
||||
<param name="study.speedup" value="0"/>
|
||||
<param name="world.era" value="3"/>
|
||||
<param name="rules.migrants" value="0"/>
|
||||
<param name="rules.transfermen" value="0"/>
|
||||
<param name="rules.stealth.faction" value="1"/>
|
||||
<param name="rules.stealth.anon_battle" value="0"/>
|
||||
<param name="rules.check_overload" value="0"/>
|
||||
<param name="rules.combat.goblinbonus" value="3"/>
|
||||
<param name="rules.ship.damage_drift" value="0.00"/> <!-- percent damage from drifting-->
|
||||
<param name="rules.alliances" value="1"/>
|
||||
<param name="rules.combat.herospeed" value="3"/>
|
||||
<param name="rules.combat.demon_vampire" value="5"/> <!-- regen 1 hp per X points of damage done -->
|
||||
<param name="rules.combat.skill_bonus" value="0"/>
|
||||
<!--param name="rules.combat.loot" value="5"/--> <!-- only self + others - keeploot -->
|
||||
<param name="rules.items.loot_divisor" value="2"/> <!-- damage skims off 1/2 of goods transfers -->
|
||||
<param name="rules.items.give_divisor" value="2"/> <!-- corruption skims off 1/2 of goods transfers -->
|
||||
<param name="rules.move.owner_leave" value="1"/> <!-- owner must leave before moving -->
|
||||
<param name="rules.region_owners" value="1"/>
|
||||
<param name="rules.cavalry.skill" value="2"/>
|
||||
<param name="rules.cavalry.mode" value="1"/>
|
||||
<param name="rules.magic.multipotion" value="1"/>
|
||||
<param name="rules.magic.wol_effect" value="5"/>
|
||||
<param name="rules.magic.factionlist" value="1"/>
|
||||
<param name="rules.magic.wol_type" value="2"/>
|
||||
<param name="rules.magic.blessed_harvest" value="1"/>
|
||||
<param name="rules.magic.elfpower" value="1"/> <!-- elves get ring-of-power bonus in a forest -->
|
||||
<param name="rules.magic.playerschools" value="gwyrrd illaun draig cerddor"/>
|
||||
<param name="rules.build.other_buildings" value="1"/>
|
||||
<param name="rules.economy.taxation" value="1"/>
|
||||
<param name="rules.economy.food" value="2"/>
|
||||
<param name="rules.economy.wages" value="1"/>
|
||||
<param name="rules.economy.roqf" value="5"/>
|
||||
<param name="rules.economy.herbrot" value="0"/>
|
||||
<param name="rules.dwarf_castles" value="1"/>
|
||||
<!-- param name="rules.nmr.destroy" value="1"/ -->
|
||||
<param name="rules.limit.faction" value="250"/>
|
||||
<!--param name="rules.give" value="15"/ --> <!-- self + peasants + herbs + lux - goods -->
|
||||
<param name="rules.economy.grow" value="1"/>
|
||||
<param name="rules.tactics.formula" value="1"/> <!-- 10% per skilldiff -->
|
||||
<param name="rules.help.mask" value="fight guard money give"/>
|
||||
<param name="movement.shipspeed.skillbonus" value="6"/>
|
||||
<param name="alliance.auto" value="fight"/>
|
||||
<param name="alliance.restricted" value="fight"/>
|
||||
</game>
|
||||
<rules>
|
||||
<function name="wage" value="minimum_wage"/>
|
||||
</rules>
|
||||
<strings>
|
||||
<string name="mailto">
|
||||
<text locale="de">eressea-server@eressea.de</text>
|
||||
<text locale="en">eressea-server@eressea.de</text>
|
||||
</string>
|
||||
<string name="newbie_info_1">
|
||||
<text locale="de">Bitte denke daran, deine Befehle mit dem Betreff
|
||||
E3 BEFEHLE an eressea-server@eressea.de zu senden.</text>
|
||||
<text locale="en">Remember to send your orders to
|
||||
eressea-server@eressea.de with the subject E3 ORDERS.</text>
|
||||
</string>
|
||||
<string name="mailcmd">
|
||||
<text locale="de">E3 BEFEHLE</text>
|
||||
<text locale="en">E3 ORDERS</text>
|
||||
</string>
|
||||
</strings>
|
||||
</eressea>
|
|
@ -7,6 +7,37 @@
|
|||
_a: including article (ein Troll, a troll)
|
||||
-->
|
||||
|
||||
<string name="rm_adamantium">
|
||||
<text locale="de">Adamantium</text>
|
||||
<text locale="en">adamantium</text>
|
||||
</string>
|
||||
<string name="adamantium">
|
||||
<text locale="de">Adamantium</text>
|
||||
<text locale="en">adamantium</text>
|
||||
</string>
|
||||
<string name="adamantium_p">
|
||||
<text locale="de">Adamantium</text>
|
||||
<text locale="en">adamantium</text>
|
||||
</string>
|
||||
|
||||
<string name="adamantiumaxe">
|
||||
<text locale="de">Adamantiumaxt</text>
|
||||
<text locale="en">adamantium axe</text>
|
||||
</string>
|
||||
<string name="adamantiumaxe_p">
|
||||
<text locale="de">Adamantiumäxte</text>
|
||||
<text locale="en">adamantium axes</text>
|
||||
</string>
|
||||
|
||||
<string name="adamantiumplate">
|
||||
<text locale="de">Adamantiumrüstung</text>
|
||||
<text locale="en">adamantium plate</text>
|
||||
</string>
|
||||
<string name="adamantiumplate_p">
|
||||
<text locale="de">Adamantiumrüstungen</text>
|
||||
<text locale="en">adamantium plates</text>
|
||||
</string>
|
||||
|
||||
<!--Fort-Ausbaustufen -->
|
||||
<string name="calendar::thirdage">
|
||||
<text locale="de">des dritten Zeitalters</text>
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
require "multis"
|
||||
require "e3a.frost"
|
||||
|
||||
function process(orders)
|
||||
local confirmed_multis = { }
|
||||
local suspected_multis = { }
|
||||
|
||||
if open_game(get_turn())~=0 then
|
||||
print("could not read game")
|
||||
return -1
|
||||
end
|
||||
init_summary()
|
||||
|
||||
-- run the turn:
|
||||
if read_orders(orders) ~= 0 then
|
||||
print("could not read " .. orders)
|
||||
return -1
|
||||
end
|
||||
|
||||
-- plan_monsters()
|
||||
local mon = get_faction(666)
|
||||
if mon ~= nil then
|
||||
mon.lastturn = get_turn()
|
||||
end
|
||||
|
||||
if nmr_check(config.maxnmrs or 30)~=0 then
|
||||
return -1
|
||||
end
|
||||
|
||||
process_orders()
|
||||
if xmas2009~=nil then
|
||||
xmas2009()
|
||||
end
|
||||
|
||||
-- create new monsters:
|
||||
spawn_dragons()
|
||||
spawn_undead()
|
||||
|
||||
if get_turn()>=config.kill_after then
|
||||
kill_nonstarters()
|
||||
end
|
||||
-- post-turn updates:
|
||||
update_guards()
|
||||
update_scores()
|
||||
frost.update()
|
||||
|
||||
local localechange = { en = { "L46o" } }
|
||||
change_locales(localechange)
|
||||
|
||||
-- use newfactions file to place out new players
|
||||
-- autoseed(config.basepath .. "/newfactions", false)
|
||||
|
||||
write_files(config.locales)
|
||||
|
||||
file = "" .. get_turn() .. ".dat"
|
||||
if eressea.write_game(file)~=0 then
|
||||
print("could not write game")
|
||||
return -1
|
||||
end
|
||||
return 0
|
||||
end
|
|
@ -0,0 +1,4 @@
|
|||
require "spells"
|
||||
require "e3a.rules"
|
||||
require "e3a.markets"
|
||||
require "e3a.frost"
|
|
@ -164,36 +164,4 @@
|
|||
</resource>
|
||||
<!-- christmas items: end -->
|
||||
|
||||
<resource name="adamantium" limited="yes" material="rm_adamantium">
|
||||
<item weight="200" score="200">
|
||||
<construction skill="mining" minskill="8" reqsize="1"/>
|
||||
</item>
|
||||
<resourcelimit>
|
||||
<modifier type="require" building="mine"/>
|
||||
<guard flag="mining"/>
|
||||
</resourcelimit>
|
||||
</resource>
|
||||
|
||||
<resource name="adamantiumaxe">
|
||||
<item weight="100" score="500">
|
||||
<construction skill="weaponsmithing" minskill="8" reqsize="1">
|
||||
<requirement type="adamantium" quantity="1"/>
|
||||
<requirement type="log" quantity="1"/>
|
||||
</construction>
|
||||
<weapon cut="true" skill="melee" offmod="2" defmod="-2" magres="0.30">
|
||||
<damage type="rider" value="3d4+15"/>
|
||||
<damage type="footman" value="3d4+15"/>
|
||||
</weapon>
|
||||
</item>
|
||||
</resource>
|
||||
|
||||
<resource name="adamantiumplate">
|
||||
<item weight="100" score="2000">
|
||||
<construction skill="armorer" minskill="10" reqsize="1">
|
||||
<requirement type="adamantium" quantity="3"/>
|
||||
</construction>
|
||||
<armor ac="7" penalty="0.1"/>
|
||||
</item>
|
||||
</resource>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -18,7 +18,7 @@ fi
|
|||
echo $ROOT
|
||||
$ROOT/$BIN_DIR/eressea/test_eressea
|
||||
pushd $ROOT/game-e2
|
||||
$ROOT/$BIN_DIR/eressea/eressea -e run_tests
|
||||
$ROOT/$BIN_DIR/eressea/eressea runtests.lua
|
||||
cd $ROOT/game-e3
|
||||
$ROOT/$BIN_DIR/eressea/eressea -e run_tests
|
||||
$ROOT/$BIN_DIR/eressea/eressea runtests.lua
|
||||
popd
|
||||
|
|
|
@ -8,7 +8,7 @@ function item_canuse(u, iname)
|
|||
end
|
||||
end
|
||||
if iname=="rep_crossbow" then
|
||||
-- only dwarves and halflings allowed to use towershield
|
||||
-- only dwarves and halflings allowed to use repeating crossbow
|
||||
return race=="dwarf" or race=="halfling"
|
||||
end
|
||||
if iname=="scale" then
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
local srcpath = config.source_dir
|
||||
local respath = srcpath .. '/res'
|
||||
local paths = {
|
||||
'scripts/?.lua',
|
||||
'core/scripts/?.lua',
|
||||
'lunit/?.lua'
|
||||
}
|
||||
|
||||
for idx, path in pairs(paths) do
|
||||
package.path = srcpath .. '/' .. path .. ';' .. package.path
|
||||
end
|
||||
|
||||
read_xml()
|
||||
|
||||
require "init"
|
|
@ -0,0 +1,100 @@
|
|||
function new_faction(email, race, lang, r)
|
||||
f = faction.create(email, race, lang)
|
||||
u = unit.create(f, r, 10)
|
||||
u:add_item("log", 5);
|
||||
u:add_item("horse", 2);
|
||||
u:add_item("silver", 1000);
|
||||
u:add_item("adamantium", 1);
|
||||
end
|
||||
|
||||
function get_homes(f)
|
||||
homes={}
|
||||
for u in f.units do
|
||||
table.insert(homes, u.region)
|
||||
end
|
||||
return homes
|
||||
end
|
||||
|
||||
if eressea~=nil then
|
||||
eressea.free_game()
|
||||
eressea.read_game("game4.dat")
|
||||
homes = get_homes(get_faction("xin8"))
|
||||
else
|
||||
-- running in the lua interpreter, not eressea. fake it.
|
||||
new_faction = print
|
||||
eressea = { ['write_game'] = function(s) print("writing " .. s) end }
|
||||
homes = { "Andune", "Bedap", "Curtis", "Dovre" }
|
||||
end
|
||||
|
||||
local f=assert(io.open("factions", "r"))
|
||||
line=f:read("*line")
|
||||
players = {}
|
||||
emails = {}
|
||||
patrons = {}
|
||||
nplayers = 0
|
||||
while line~=nil do
|
||||
fields = {}
|
||||
line:gsub("([^\t]*)\t*", function(c) table.insert(fields, c) end)
|
||||
line=f:read("*line")
|
||||
email = fields[1]
|
||||
if fields[2]=='yes' then
|
||||
table.insert(patrons, email)
|
||||
else
|
||||
table.insert(emails, email)
|
||||
end
|
||||
if fields[3]=='German' then lang='de' else lang='en' end
|
||||
race=string.gsub(fields[4], "/.*", ''):lower()
|
||||
players[email] = { ['lang'] = lang, ['race'] = race }
|
||||
nplayers = nplayers + 1
|
||||
end
|
||||
|
||||
for k, r in ipairs(homes) do
|
||||
print(k, r)
|
||||
end
|
||||
npatrons = #patrons
|
||||
print(#homes .. " regions.")
|
||||
print(nplayers .. " players.")
|
||||
print(npatrons .. " patrons.")
|
||||
|
||||
maxfactions = 20
|
||||
selected = {}
|
||||
if maxfactions > nplayers then maxfactions = nplayers end
|
||||
while maxfactions > 0 do
|
||||
if npatrons > 0 then
|
||||
email = patrons[npatrons]
|
||||
patrons[npatrons] = nil
|
||||
npatrons = npatrons - 1
|
||||
else
|
||||
local np = #emails
|
||||
local i = math.random(np)
|
||||
email = emails[i]
|
||||
emails[i] = emails[np]
|
||||
emails[np] = nil
|
||||
end
|
||||
local player = players[email]
|
||||
player.email = email
|
||||
table.insert(selected, player)
|
||||
maxfactions = maxfactions - 1
|
||||
end
|
||||
|
||||
-- random shuffle
|
||||
for j=1,#selected do
|
||||
k = math.random(j)
|
||||
if k ~= j then
|
||||
local temp = selected[j]
|
||||
selected[j] = selected[k]
|
||||
selected[k] = temp
|
||||
end
|
||||
end
|
||||
|
||||
print('## players')
|
||||
for k, player in ipairs(selected) do
|
||||
local r = homes[1 + k % #homes]
|
||||
new_faction(player.email, player.race, player.lang, r)
|
||||
print(player.email)
|
||||
end
|
||||
eressea.write_game("game4.dat")
|
||||
print("## no faction")
|
||||
for i, email in ipairs(emails) do
|
||||
print(email)
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
p = plane.get(0)
|
||||
w, h = p:size()
|
||||
print(p, w, h)
|
||||
for x=0,w-1 do
|
||||
for y=0,h-1 do
|
||||
r = get_region(x,y)
|
||||
if r==nil then
|
||||
r = region.create(x, y, "ocean")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,37 @@
|
|||
function main()
|
||||
for f in factions() do
|
||||
if f.race=="demon" then
|
||||
f.flags = 2147484672
|
||||
for u in f.units do
|
||||
u.building.size = 2
|
||||
u.building.name = u.region.name .. " Keep"
|
||||
u.name = "Lord " .. u.region.name
|
||||
u:add_item("money", 1000-u:get_item("money"))
|
||||
end
|
||||
else
|
||||
u = f.units()
|
||||
u:add_item("money", 1000-u:get_item("money"))
|
||||
u:add_item("adamantium", 1-u:get_item("adamantium"))
|
||||
end
|
||||
end
|
||||
for r in regions() do for u in r.units do
|
||||
print(u)
|
||||
things = ""
|
||||
comma = ""
|
||||
for i in u.items do
|
||||
things = things .. comma .. u:get_item(i) .. " " .. i
|
||||
comma = ", "
|
||||
end
|
||||
print(' - ' .. things)
|
||||
end end
|
||||
end
|
||||
|
||||
if eressea==nil then
|
||||
print("this script is part of eressea")
|
||||
else
|
||||
read_xml()
|
||||
eressea.read_game('0.dat')
|
||||
main()
|
||||
eressea.write_game('0.dat')
|
||||
print('done')
|
||||
end
|
|
@ -0,0 +1,4 @@
|
|||
read_xml()
|
||||
eressea.read_game('0.dat')
|
||||
init_reports()
|
||||
write_reports()
|
|
@ -0,0 +1,2 @@
|
|||
require "setup"
|
||||
run_turn()
|
|
@ -152,7 +152,15 @@ target_link_libraries(test_eressea
|
|||
)
|
||||
|
||||
add_test(server test_eressea)
|
||||
add_test(NAME E3 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/game-e3 COMMAND $<TARGET_FILE:eressea> -e run_tests)
|
||||
add_test(NAME E2 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/game-e2 COMMAND $<TARGET_FILE:eressea> -e run_tests)
|
||||
add_test(
|
||||
NAME E3
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/game-e3
|
||||
COMMAND $<TARGET_FILE:eressea> runtests.lua
|
||||
)
|
||||
add_test(
|
||||
NAME E2
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/game-e2
|
||||
COMMAND $<TARGET_FILE:eressea> runtests.lua
|
||||
)
|
||||
|
||||
install(TARGETS eressea DESTINATION bin)
|
||||
|
|
|
@ -375,7 +375,14 @@ static int tolua_faction_set_locale(lua_State * L)
|
|||
{
|
||||
faction *self = (faction *) tolua_tousertype(L, 1, 0);
|
||||
const char *name = tolua_tostring(L, 2, 0);
|
||||
self->locale = find_locale(name);
|
||||
const struct locale *loc = find_locale(name);
|
||||
if (loc) {
|
||||
self->locale = loc;
|
||||
}
|
||||
else {
|
||||
tolua_pushstring(L, "invalid locale");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,16 +15,17 @@ without prior permission by the authors of Eressea.
|
|||
#include "bind_unit.h"
|
||||
#include "bindings.h"
|
||||
|
||||
#include <kernel/config.h>
|
||||
#include <sqlite3.h>
|
||||
#include <tolua.h>
|
||||
|
||||
#define LTYPE_DB TOLUA_CAST "db"
|
||||
|
||||
extern int db_update_factions(sqlite3 * db, bool force);
|
||||
extern int db_update_factions(sqlite3 * db, bool force, int game);
|
||||
static int tolua_db_update_factions(lua_State * L)
|
||||
{
|
||||
sqlite3 *db = (sqlite3 *) tolua_tousertype(L, 1, 0);
|
||||
db_update_factions(db, tolua_toboolean(L, 2, 0));
|
||||
db_update_factions(db, tolua_toboolean(L, 2, 0), global.game_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -462,9 +462,14 @@ static int tolua_init_reports(lua_State * L)
|
|||
static int tolua_write_report(lua_State * L)
|
||||
{
|
||||
faction *f = (faction *) tolua_tousertype(L, 1, 0);
|
||||
time_t ltime = time(0);
|
||||
int result = write_reports(f, ltime);
|
||||
tolua_pushnumber(L, (lua_Number) result);
|
||||
if (f) {
|
||||
time_t ltime = time(0);
|
||||
int result = write_reports(f, ltime);
|
||||
tolua_pushnumber(L, (lua_Number)result);
|
||||
}
|
||||
else {
|
||||
tolua_pushstring(L, "function expects a faction, got nil");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -995,10 +1000,10 @@ static int tolua_get_spells(lua_State * L)
|
|||
|
||||
int tolua_read_xml(lua_State * L)
|
||||
{
|
||||
const char *filename = tolua_tostring(L, 1, 0);
|
||||
const char *catalog = tolua_tostring(L, 2, 0);
|
||||
init_data(filename, catalog);
|
||||
return 0;
|
||||
const char *filename = tolua_tostring(L, 1, "config.xml");
|
||||
const char *catalog = tolua_tostring(L, 2, "catalog.xml");
|
||||
lua_pushinteger(L, init_data(filename, catalog));
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef struct event_args {
|
||||
|
@ -1196,7 +1201,7 @@ lua_State *lua_init(void) {
|
|||
return L;
|
||||
}
|
||||
|
||||
int eressea_run(lua_State *L, const char *luafile, const char *entry_point)
|
||||
int eressea_run(lua_State *L, const char *luafile)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
|
@ -1204,30 +1209,22 @@ int eressea_run(lua_State *L, const char *luafile, const char *entry_point)
|
|||
/* run the main script */
|
||||
if (luafile) {
|
||||
log_debug("executing script %s\n", luafile);
|
||||
|
||||
lua_getglobal(L, "debug");
|
||||
lua_getfield(L, -1, "traceback");
|
||||
lua_remove(L, -2);
|
||||
lua_getglobal(L, "dofile");
|
||||
lua_pushstring(L, luafile);
|
||||
err = lua_pcall(L, 1, 0, 0);
|
||||
err = lua_pcall(L, 1, 1, -3);
|
||||
if (err != 0) {
|
||||
log_lua_error(L);
|
||||
abort();
|
||||
return err;
|
||||
}
|
||||
}
|
||||
if (entry_point) {
|
||||
if (strcmp("console", entry_point)==0) {
|
||||
return lua_console(L);
|
||||
}
|
||||
lua_getglobal(L, entry_point);
|
||||
if (lua_isfunction(L, -1)) {
|
||||
log_debug("calling entry-point: %s\n", entry_point);
|
||||
err = lua_pcall(L, 0, 1, 0);
|
||||
if (err != 0) {
|
||||
log_lua_error(L);
|
||||
} else {
|
||||
if (lua_isnumber(L, -1)) {
|
||||
err = (int)lua_tonumber(L, -1);
|
||||
}
|
||||
return err;
|
||||
} else {
|
||||
log_error("unknown entry-point: %s\n", entry_point);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
return lua_console(L);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ extern "C" {
|
|||
|
||||
void lua_done(struct lua_State *L);
|
||||
struct lua_State *lua_init(void);
|
||||
int eressea_run(struct lua_State *L, const char *luafile, const char *entry_point);
|
||||
int eressea_run(struct lua_State *L, const char *luafile);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -93,12 +93,13 @@ struct settings global = {
|
|||
"Eressea", /* gamename */
|
||||
};
|
||||
|
||||
bool lomem = false;
|
||||
FILE *logfile;
|
||||
FILE *updatelog;
|
||||
const struct race *new_race[MAXRACES];
|
||||
bool sqlpatch = false;
|
||||
bool battledebug = false;
|
||||
int turn = 0;
|
||||
int turn = -1;
|
||||
|
||||
int NewbieImmunity(void)
|
||||
{
|
||||
|
@ -1196,19 +1197,40 @@ void update_lighthouse(building * lh)
|
|||
int count_all(const faction * f)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
int n = 0;
|
||||
unit *u;
|
||||
for (u = f->units; u; u = u->nextF) {
|
||||
if (playerrace(u_race(u))) {
|
||||
n += u->number;
|
||||
assert(f == u->faction);
|
||||
unit *u;
|
||||
int np = 0, n = 0;
|
||||
for (u = f->units; u; u = u->nextF) {
|
||||
assert(f == u->faction);
|
||||
n += u->number;
|
||||
if (playerrace(u_race(u))) {
|
||||
np += u->number;
|
||||
}
|
||||
}
|
||||
if (f->num_people != np) {
|
||||
log_error("# of people in %s is != num_people: %d should be %d.\n", factionid(f), f->num_people, np);
|
||||
}
|
||||
if (f->num_total != n) {
|
||||
log_error("# of men in %s is != num_total: %d should be %d.\n", factionid(f), f->num_total, n);
|
||||
}
|
||||
}
|
||||
if (f->num_people != n) {
|
||||
log_error("# of people in %s is != num_people: %d should be %d.\n", factionid(f), f->num_people, n);
|
||||
}
|
||||
#endif
|
||||
return f->num_people;
|
||||
return (f->flags & FFL_NPC) ? f->num_total : f->num_people;
|
||||
}
|
||||
|
||||
int count_units(const faction * f)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
unit *u;
|
||||
int n = 0, np = 0;
|
||||
for (u = f->units; u; u = u->nextF) {
|
||||
++n;
|
||||
if (playerrace(u_race(u))) ++np;
|
||||
}
|
||||
n = (f->flags & FFL_NPC) ? n : np;
|
||||
if (f->no_units && n != f->no_units) {
|
||||
log_warning("# of units in %s is != no_units: %d should be %d.\n", factionid(f), f->no_units, n);
|
||||
}
|
||||
#endif
|
||||
return n;
|
||||
}
|
||||
|
||||
int count_migrants(const faction * f)
|
||||
|
@ -1557,10 +1579,6 @@ void freestrlist(strlist * s)
|
|||
}
|
||||
}
|
||||
|
||||
/* - Meldungen und Fehler ------------------------------------------------- */
|
||||
|
||||
bool lomem = false;
|
||||
|
||||
/* - Namen der Strukturen -------------------------------------- */
|
||||
typedef char name[OBJECTIDSIZE + 1];
|
||||
static name idbuf[8];
|
||||
|
@ -3147,7 +3165,6 @@ void load_inifile(dictionary * d)
|
|||
make_locales(str);
|
||||
|
||||
/* excerpt from [config] (the rest is used in bindings.c) */
|
||||
game_name = iniparser_getstring(d, "config:game", game_name);
|
||||
|
||||
global.game_id = iniparser_getint(d, "config:game_id", 0);
|
||||
global.inifile = d;
|
||||
}
|
||||
|
|
|
@ -256,9 +256,10 @@ extern "C" {
|
|||
extern int rule_alliance_limit(void);
|
||||
extern int rule_faction_limit(void);
|
||||
|
||||
extern int count_all(const struct faction *f);
|
||||
extern int count_migrants(const struct faction *f);
|
||||
extern int count_maxmigrants(const struct faction *f);
|
||||
int count_units(const struct faction * f);
|
||||
int count_all(const struct faction *f);
|
||||
int count_migrants(const struct faction *f);
|
||||
int count_maxmigrants(const struct faction *f);
|
||||
|
||||
extern bool has_limited_skills(const struct unit *u);
|
||||
extern const struct race *findrace(const char *, const struct locale *);
|
||||
|
@ -392,6 +393,7 @@ extern "C" {
|
|||
void *vm_state;
|
||||
float producexpchance;
|
||||
int cookie;
|
||||
int game_id;
|
||||
int data_version; /* TODO: eliminate in favor of gamedata.version */
|
||||
struct _dictionary_ *inifile;
|
||||
|
||||
|
@ -449,7 +451,7 @@ extern "C" {
|
|||
extern struct attrib_type at_guard;
|
||||
extern void free_gamedata(void);
|
||||
#if 1 /* disable to count all units */
|
||||
# define count_unit(u) playerrace(u_race(u))
|
||||
# define count_unit(u) (u->number>0 && playerrace(u_race(u)))
|
||||
#else
|
||||
# define count_unit(u) 1
|
||||
#endif
|
||||
|
|
|
@ -112,7 +112,7 @@ faction *get_monsters(void)
|
|||
if (!monsters) {
|
||||
faction *f;
|
||||
for (f = factions; f; f = f->next) {
|
||||
if (f->flags & FFL_NPC) {
|
||||
if ((f->flags & FFL_NPC) && !(f->flags & FFL_DEFENDER)) {
|
||||
return monsters = f;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,117 +129,133 @@ db_update_email(sqlite3 * db, const faction * f, const db_faction * dbstate,
|
|||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
int db_update_factions(sqlite3 * db, bool force)
|
||||
{
|
||||
int game_id = 6;
|
||||
const char sql_select[] =
|
||||
"SELECT faction.id, faction.email_id, faction.code, email.email, faction.password_md5, faction.name, faction.lastturn FROM email, faction"
|
||||
" WHERE email.id=faction.email_id AND faction.game_id=? AND (lastturn IS NULL OR lastturn>?)";
|
||||
sqlite3_stmt *stmt_select = stmt_cache_get(db, sql_select);
|
||||
faction *f;
|
||||
int res;
|
||||
|
||||
res = sqlite3_bind_int(stmt_select, 1, game_id);
|
||||
SQL_EXPECT(res, SQLITE_OK);
|
||||
res = sqlite3_bind_int(stmt_select, 2, turn - 2);
|
||||
SQL_EXPECT(res, SQLITE_OK);
|
||||
for (;;) {
|
||||
sqlite3_uint64 id_faction;
|
||||
int lastturn;
|
||||
|
||||
/*
|
||||
int db_get_game(sqlite3 *db) {
|
||||
int game_id = 0;
|
||||
const char sql_game[] =
|
||||
"SELECT id FROM game WHERE name=?";
|
||||
sqlite3_stmt *stmt_game = stmt_cache(db, sql_game);
|
||||
res = sqlite3_bind_text(stmt_game, 1, gamename, -1, SQLITE_TRANSIENT);
|
||||
SQL_EXPECT(res, SQLITE_OK);
|
||||
res = sqlite3_step(stmt_select);
|
||||
if (res != SQLITE_ROW)
|
||||
break;
|
||||
|
||||
id_faction = sqlite3_column_int64(stmt_select, 0);
|
||||
lastturn = sqlite3_column_int(stmt_select, 6);
|
||||
f = get_faction_by_id((int)id_faction);
|
||||
|
||||
if (f == NULL || !f->alive) {
|
||||
if (lastturn == 0) {
|
||||
const char sql_update[] = "UPDATE faction SET lastturn=? WHERE id=?";
|
||||
sqlite3_stmt *stmt = stmt_cache_get(db, sql_update);
|
||||
|
||||
lastturn = f ? f->lastorders : turn - 1;
|
||||
sqlite3_bind_int(stmt, 1, lastturn);
|
||||
sqlite3_bind_int64(stmt, 2, id_faction);
|
||||
res = sqlite3_step(stmt);
|
||||
SQL_EXPECT(res, SQLITE_DONE);
|
||||
}
|
||||
} else {
|
||||
md5_state_t ms;
|
||||
md5_byte_t digest[16];
|
||||
int i;
|
||||
char passwd_md5[MD5_LENGTH_0];
|
||||
sqlite3_uint64 id_email;
|
||||
bool update = force;
|
||||
db_faction dbstate;
|
||||
const char *no_b36;
|
||||
|
||||
fset(f, FFL_MARK);
|
||||
dbstate.id_faction = id_faction;
|
||||
dbstate.id_email = sqlite3_column_int64(stmt_select, 1);
|
||||
no_b36 = (const char *)sqlite3_column_text(stmt_select, 2);
|
||||
dbstate.no = no_b36 ? atoi36(no_b36) : -1;
|
||||
dbstate.email = (const char *)sqlite3_column_text(stmt_select, 3);
|
||||
dbstate.passwd_md5 = (const char *)sqlite3_column_text(stmt_select, 4);
|
||||
dbstate.name = (const char *)sqlite3_column_text(stmt_select, 5);
|
||||
|
||||
id_email = dbstate.id_email;
|
||||
res = db_update_email(db, f, &dbstate, force, &id_email);
|
||||
SQL_EXPECT(res, SQLITE_OK);
|
||||
|
||||
md5_init(&ms);
|
||||
md5_append(&ms, (md5_byte_t *) f->passw, (int)strlen(f->passw));
|
||||
md5_finish(&ms, digest);
|
||||
for (i = 0; i != 16; ++i)
|
||||
sprintf(passwd_md5 + 2 * i, "%.02x", digest[i]);
|
||||
|
||||
if (!update) {
|
||||
update = ((id_email != 0 && dbstate.id_email != id_email)
|
||||
|| dbstate.no != f->no || dbstate.passwd_md5 == NULL
|
||||
|| strcmp(passwd_md5, dbstate.passwd_md5) != 0 || dbstate.name == NULL
|
||||
|| strncmp(f->name, dbstate.name, MAX_FACTION_NAME) != 0);
|
||||
}
|
||||
if (update) {
|
||||
const char sql_update_faction[] =
|
||||
"UPDATE faction SET email_id=?, password_md5=?, code=?, name=?, firstturn=? WHERE id=?";
|
||||
sqlite3_stmt *stmt_update_faction =
|
||||
stmt_cache_get(db, sql_update_faction);
|
||||
|
||||
res = sqlite3_bind_int64(stmt_update_faction, 1, id_email);
|
||||
SQL_EXPECT(res, SQLITE_OK);
|
||||
res =
|
||||
sqlite3_bind_text(stmt_update_faction, 2, passwd_md5, MD5_LENGTH,
|
||||
SQLITE_TRANSIENT);
|
||||
SQL_EXPECT(res, SQLITE_OK);
|
||||
res =
|
||||
sqlite3_bind_text(stmt_update_faction, 3, no_b36, -1,
|
||||
SQLITE_TRANSIENT);
|
||||
SQL_EXPECT(res, SQLITE_OK);
|
||||
res =
|
||||
sqlite3_bind_text(stmt_update_faction, 4, f->name, -1,
|
||||
SQLITE_TRANSIENT);
|
||||
SQL_EXPECT(res, SQLITE_OK);
|
||||
res = sqlite3_bind_int(stmt_update_faction, 5, turn - f->age);
|
||||
SQL_EXPECT(res, SQLITE_OK);
|
||||
res = sqlite3_bind_int64(stmt_update_faction, 6, f->subscription);
|
||||
SQL_EXPECT(res, SQLITE_OK);
|
||||
res = sqlite3_step(stmt_update_faction);
|
||||
SQL_EXPECT(res, SQLITE_DONE);
|
||||
}
|
||||
return game_id;
|
||||
}
|
||||
*/
|
||||
int db_update_factions(sqlite3 * db, bool force, int game_id)
|
||||
{
|
||||
const char sql_select[] =
|
||||
"SELECT faction.id, faction.email_id, faction.code, email.email, faction.password_md5, faction.name, faction.lastturn FROM email, faction"
|
||||
" WHERE email.id=faction.email_id AND faction.game_id=? AND (lastturn IS NULL OR lastturn>?)";
|
||||
sqlite3_stmt *stmt_select = stmt_cache_get(db, sql_select);
|
||||
faction *f;
|
||||
int res;
|
||||
|
||||
res = sqlite3_bind_int(stmt_select, 1, game_id);
|
||||
SQL_EXPECT(res, SQLITE_OK);
|
||||
res = sqlite3_bind_int(stmt_select, 2, turn - 2);
|
||||
SQL_EXPECT(res, SQLITE_OK);
|
||||
for (;;) {
|
||||
sqlite3_uint64 id_faction;
|
||||
int lastturn;
|
||||
const char * no_b36;
|
||||
|
||||
res = sqlite3_step(stmt_select);
|
||||
if (res != SQLITE_ROW)
|
||||
break;
|
||||
|
||||
id_faction = sqlite3_column_int64(stmt_select, 0);
|
||||
lastturn = sqlite3_column_int(stmt_select, 6);
|
||||
no_b36 = (const char *)sqlite3_column_text(stmt_select, 2);
|
||||
f = get_faction_by_id((int)id_faction);
|
||||
if (!f) {
|
||||
int no = atoi36(no_b36);
|
||||
f = findfaction(no);
|
||||
if (f) {
|
||||
f->subscription = (int)id_faction;
|
||||
}
|
||||
}
|
||||
if (!f || !f->alive) {
|
||||
if (lastturn == 0) {
|
||||
const char sql_update[] = "UPDATE faction SET lastturn=? WHERE id=?";
|
||||
sqlite3_stmt *stmt = stmt_cache_get(db, sql_update);
|
||||
|
||||
lastturn = f ? f->lastorders : turn - 1;
|
||||
sqlite3_bind_int(stmt, 1, lastturn);
|
||||
sqlite3_bind_int64(stmt, 2, id_faction);
|
||||
res = sqlite3_step(stmt);
|
||||
SQL_EXPECT(res, SQLITE_DONE);
|
||||
}
|
||||
} else {
|
||||
md5_state_t ms;
|
||||
md5_byte_t digest[16];
|
||||
int i;
|
||||
char passwd_md5[MD5_LENGTH_0];
|
||||
sqlite3_uint64 id_email;
|
||||
bool update = force;
|
||||
db_faction dbstate;
|
||||
|
||||
fset(f, FFL_MARK);
|
||||
dbstate.id_faction = id_faction;
|
||||
dbstate.id_email = sqlite3_column_int64(stmt_select, 1);
|
||||
dbstate.no = no_b36 ? atoi36(no_b36) : -1;
|
||||
dbstate.email = (const char *)sqlite3_column_text(stmt_select, 3);
|
||||
dbstate.passwd_md5 = (const char *)sqlite3_column_text(stmt_select, 4);
|
||||
dbstate.name = (const char *)sqlite3_column_text(stmt_select, 5);
|
||||
|
||||
id_email = dbstate.id_email;
|
||||
res = db_update_email(db, f, &dbstate, force, &id_email);
|
||||
SQL_EXPECT(res, SQLITE_OK);
|
||||
|
||||
md5_init(&ms);
|
||||
md5_append(&ms, (md5_byte_t *) f->passw, (int)strlen(f->passw));
|
||||
md5_finish(&ms, digest);
|
||||
for (i = 0; i != 16; ++i)
|
||||
sprintf(passwd_md5 + 2 * i, "%.02x", digest[i]);
|
||||
|
||||
if (!update) {
|
||||
update = ((id_email != 0 && dbstate.id_email != id_email)
|
||||
|| dbstate.no != f->no || dbstate.passwd_md5 == NULL
|
||||
|| strcmp(passwd_md5, dbstate.passwd_md5) != 0 || dbstate.name == NULL
|
||||
|| strncmp(f->name, dbstate.name, MAX_FACTION_NAME) != 0);
|
||||
}
|
||||
if (update) {
|
||||
const char sql_update_faction[] =
|
||||
"UPDATE faction SET email_id=?, password_md5=?, code=?, name=?, firstturn=? WHERE id=?";
|
||||
sqlite3_stmt *stmt_update_faction =
|
||||
stmt_cache_get(db, sql_update_faction);
|
||||
|
||||
res = sqlite3_bind_int64(stmt_update_faction, 1, id_email);
|
||||
SQL_EXPECT(res, SQLITE_OK);
|
||||
res =
|
||||
sqlite3_bind_text(stmt_update_faction, 2, passwd_md5, MD5_LENGTH,
|
||||
SQLITE_TRANSIENT);
|
||||
SQL_EXPECT(res, SQLITE_OK);
|
||||
res =
|
||||
sqlite3_bind_text(stmt_update_faction, 3, no_b36, -1,
|
||||
SQLITE_TRANSIENT);
|
||||
SQL_EXPECT(res, SQLITE_OK);
|
||||
res =
|
||||
sqlite3_bind_text(stmt_update_faction, 4, f->name, -1,
|
||||
SQLITE_TRANSIENT);
|
||||
SQL_EXPECT(res, SQLITE_OK);
|
||||
res = sqlite3_bind_int(stmt_update_faction, 5, turn - f->age);
|
||||
SQL_EXPECT(res, SQLITE_OK);
|
||||
res = sqlite3_bind_int64(stmt_update_faction, 6, f->subscription);
|
||||
SQL_EXPECT(res, SQLITE_OK);
|
||||
res = sqlite3_step(stmt_update_faction);
|
||||
SQL_EXPECT(res, SQLITE_DONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (f = factions; f; f = f->next) {
|
||||
if (!fval(f, FFL_MARK)) {
|
||||
log_error("%s (sub=%d, email=%s) has no entry in the database\n", factionname(f), f->subscription, f->email);
|
||||
} else {
|
||||
freset(f, FFL_MARK);
|
||||
|
||||
for (f = factions; f; f = f->next) {
|
||||
if (!fval(f, FFL_MARK)) {
|
||||
log_error("%s (sub=%d, email=%s) has no entry in the database\n", factionname(f), f->subscription, f->email);
|
||||
} else {
|
||||
freset(f, FFL_MARK);
|
||||
}
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
int db_update_scores(sqlite3 * db, bool force)
|
||||
|
|
|
@ -1070,43 +1070,51 @@ struct building *inside_building(const struct unit *u)
|
|||
|
||||
void u_setfaction(unit * u, faction * f)
|
||||
{
|
||||
int cnt = u->number;
|
||||
int cnt = u->number;
|
||||
if (u->faction == f)
|
||||
return;
|
||||
if (u->faction) {
|
||||
if (count_unit(u)) {
|
||||
--u->faction->no_units;
|
||||
}
|
||||
set_number(u, 0);
|
||||
join_group(u, NULL);
|
||||
free_orders(&u->orders);
|
||||
set_order(&u->thisorder, NULL);
|
||||
|
||||
if (u->faction == f)
|
||||
return;
|
||||
if (u->faction) {
|
||||
set_number(u, 0);
|
||||
if (count_unit(u))
|
||||
--u->faction->no_units;
|
||||
join_group(u, NULL);
|
||||
free_orders(&u->orders);
|
||||
set_order(&u->thisorder, NULL);
|
||||
if (u->nextF) {
|
||||
u->nextF->prevF = u->prevF;
|
||||
}
|
||||
if (u->prevF) {
|
||||
u->prevF->nextF = u->nextF;
|
||||
}
|
||||
else {
|
||||
u->faction->units = u->nextF;
|
||||
}
|
||||
}
|
||||
|
||||
if (u->nextF)
|
||||
u->nextF->prevF = u->prevF;
|
||||
if (u->prevF)
|
||||
u->prevF->nextF = u->nextF;
|
||||
else
|
||||
u->faction->units = u->nextF;
|
||||
}
|
||||
if (f != NULL) {
|
||||
if (f->units) {
|
||||
f->units->prevF = u;
|
||||
}
|
||||
u->prevF = NULL;
|
||||
u->nextF = f->units;
|
||||
f->units = u;
|
||||
}
|
||||
else {
|
||||
u->nextF = NULL;
|
||||
}
|
||||
|
||||
if (f != NULL) {
|
||||
if (f->units)
|
||||
f->units->prevF = u;
|
||||
u->prevF = NULL;
|
||||
u->nextF = f->units;
|
||||
f->units = u;
|
||||
} else
|
||||
u->nextF = NULL;
|
||||
|
||||
u->faction = f;
|
||||
if (u->region)
|
||||
update_interval(f, u->region);
|
||||
if (cnt && f) {
|
||||
set_number(u, cnt);
|
||||
if (count_unit(u))
|
||||
++f->no_units;
|
||||
}
|
||||
u->faction = f;
|
||||
if (u->region) {
|
||||
update_interval(f, u->region);
|
||||
}
|
||||
if (cnt) {
|
||||
set_number(u, cnt);
|
||||
}
|
||||
if (f && count_unit(u)) {
|
||||
++f->no_units;
|
||||
}
|
||||
}
|
||||
|
||||
/* vorsicht Sprüche können u->number == RS_FARVISION haben! */
|
||||
|
|
|
@ -4517,10 +4517,6 @@ void init_processor(void)
|
|||
add_proc_region(p, &enter_1, "Betreten (1. Versuch)");
|
||||
add_proc_order(p, K_USE, &use_cmd, 0, "Benutzen");
|
||||
|
||||
if (!global.disabled[K_GM]) {
|
||||
add_proc_global(p, &gmcommands, "GM Kommandos");
|
||||
}
|
||||
|
||||
p += 10; /* in case it has any effects on alliance victories */
|
||||
add_proc_order(p, K_GIVE, &give_control_cmd, 0, "GIB KOMMANDO");
|
||||
|
||||
|
|
14
src/main.c
14
src/main.c
|
@ -40,7 +40,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
|
||||
static const char *logfile= "eressea.log";
|
||||
static const char *luafile = 0;
|
||||
static const char *entry_point = NULL;
|
||||
static const char *inifile = "eressea.ini";
|
||||
static int memdebug = 0;
|
||||
|
||||
|
@ -52,8 +51,6 @@ static void parse_config(const char *filename)
|
|||
log_debug("reading from configuration file %s\n", filename);
|
||||
|
||||
memdebug = iniparser_getint(d, "eressea:memcheck", memdebug);
|
||||
entry_point = iniparser_getstring(d, "eressea:run", entry_point);
|
||||
luafile = iniparser_getstring(d, "eressea:load", luafile);
|
||||
|
||||
/* only one value in the [editor] section */
|
||||
force_color = iniparser_getint(d, "editor:color", force_color);
|
||||
|
@ -100,7 +97,7 @@ static int parse_args(int argc, char **argv, int *exitcode)
|
|||
|
||||
for (i = 1; i != argc; ++i) {
|
||||
if (argv[i][0] != '-') {
|
||||
return usage(argv[0], argv[i]);
|
||||
luafile = argv[i];
|
||||
} else if (argv[i][1] == '-') { /* long format */
|
||||
if (strcmp(argv[i] + 2, "version") == 0) {
|
||||
printf("\n%s PBEM host\n"
|
||||
|
@ -118,18 +115,12 @@ static int parse_args(int argc, char **argv, int *exitcode)
|
|||
} else {
|
||||
const char *arg;
|
||||
switch (argv[i][1]) {
|
||||
case 'C':
|
||||
entry_point = "console";
|
||||
break;
|
||||
case 'f':
|
||||
i = get_arg(argc, argv, 2, i, &luafile, 0);
|
||||
break;
|
||||
case 'l':
|
||||
i = get_arg(argc, argv, 2, i, &logfile, 0);
|
||||
break;
|
||||
case 'e':
|
||||
i = get_arg(argc, argv, 2, i, &entry_point, 0);
|
||||
break;
|
||||
case 't':
|
||||
i = get_arg(argc, argv, 2, i, &arg, 0);
|
||||
turn = atoi(arg);
|
||||
|
@ -138,7 +129,6 @@ static int parse_args(int argc, char **argv, int *exitcode)
|
|||
verbosity = 0;
|
||||
break;
|
||||
case 'r':
|
||||
entry_point = "run_turn";
|
||||
i = get_arg(argc, argv, 2, i, &arg, 0);
|
||||
turn = atoi(arg);
|
||||
break;
|
||||
|
@ -271,7 +261,7 @@ int main(int argc, char **argv)
|
|||
register_spells();
|
||||
bind_monsters(L);
|
||||
|
||||
err = eressea_run(L, luafile, entry_point);
|
||||
err = eressea_run(L, luafile);
|
||||
if (err) {
|
||||
log_error("server execution failed with code %d\n", err);
|
||||
return err;
|
||||
|
|
|
@ -54,65 +54,25 @@
|
|||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
|
||||
/**
|
||||
** at_permissions
|
||||
**/
|
||||
|
||||
static void mistake(const unit * u, struct order *ord, const char *comment)
|
||||
{
|
||||
if (!is_monsters(u->faction)) {
|
||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "mistake",
|
||||
"error", comment));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
write_permissions(const attrib * a, const void *owner, struct storage *store)
|
||||
{
|
||||
a_write(store, (attrib *) a->data.v, owner);
|
||||
}
|
||||
|
||||
static int read_permissions(attrib * a, void *owner, struct storage *store)
|
||||
{
|
||||
attrib *attr = NULL;
|
||||
a_read(store, &attr, NULL);
|
||||
a->data.v = attr;
|
||||
a_free(attr);
|
||||
return AT_READ_OK;
|
||||
}
|
||||
|
||||
struct attrib_type at_permissions = {
|
||||
"GM:permissions",
|
||||
NULL, NULL, NULL,
|
||||
write_permissions, read_permissions,
|
||||
NULL, read_permissions,
|
||||
ATF_UNIQUE
|
||||
};
|
||||
|
||||
attrib *make_atpermissions(void)
|
||||
{
|
||||
return a_new(&at_permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
** GM: CREATE <number> <itemtype>
|
||||
**/
|
||||
|
||||
static void
|
||||
write_gmcreate(const attrib * a, const void *owner, struct storage *store)
|
||||
{
|
||||
const item_type *itype = (const item_type *)a->data.v;
|
||||
assert(itype);
|
||||
WRITE_TOK(store, resourcename(itype->rtype, 0));
|
||||
}
|
||||
|
||||
static int read_gmcreate(attrib * a, void *owner, struct storage *store)
|
||||
{
|
||||
char zText[32];
|
||||
READ_TOK(store, zText, sizeof(zText));
|
||||
a->data.v = it_find(zText);
|
||||
if (a->data.v == NULL) {
|
||||
log_error("unknown itemtype %s in gmcreate attribute\n", zText);
|
||||
return AT_READ_FAIL;
|
||||
}
|
||||
return AT_READ_OK;
|
||||
}
|
||||
|
||||
|
@ -120,640 +80,11 @@ static int read_gmcreate(attrib * a, void *owner, struct storage *store)
|
|||
attrib_type at_gmcreate = {
|
||||
"GM:create",
|
||||
NULL, NULL, NULL,
|
||||
write_gmcreate, read_gmcreate
|
||||
NULL, read_gmcreate
|
||||
};
|
||||
|
||||
attrib *make_atgmcreate(const struct item_type * itype)
|
||||
{
|
||||
attrib *a = a_new(&at_gmcreate);
|
||||
a->data.v = (void *)itype;
|
||||
return a;
|
||||
}
|
||||
|
||||
static void gm_create(const void *tnext, struct unit *u, struct order *ord)
|
||||
{
|
||||
int i;
|
||||
attrib *permissions = a_find(u->faction->attribs, &at_permissions);
|
||||
if (permissions)
|
||||
permissions = (attrib *) permissions->data.v;
|
||||
if (!permissions)
|
||||
return;
|
||||
i = getint();
|
||||
|
||||
if (i > 0) {
|
||||
const char *iname = getstrtoken();
|
||||
const item_type *itype = finditemtype(iname, u->faction->locale);
|
||||
if (itype == NULL) {
|
||||
mistake(u, ord, "unknown item.");
|
||||
} else {
|
||||
attrib *a = a_find(permissions, &at_gmcreate);
|
||||
|
||||
while (a && a->type == &at_gmcreate && a->data.v != (void *)itype)
|
||||
a = a->next;
|
||||
if (a)
|
||||
i_change(&u->items, itype, i);
|
||||
else
|
||||
mistake(u, ord, "your faction cannot create this item.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool has_permission(const attrib * permissions, unsigned int key)
|
||||
{
|
||||
return (find_key((attrib *) permissions->data.v, key) ||
|
||||
find_key((attrib *) permissions->data.v, atoi36("master")));
|
||||
}
|
||||
|
||||
/**
|
||||
** GM: GATE <id> <x> <y>
|
||||
** requires: permission-key "gmgate"
|
||||
**/
|
||||
static void gm_gate(const void *tnext, struct unit * u, struct order *ord)
|
||||
{
|
||||
const struct plane *pl = rplane(u->region);
|
||||
int id = getid();
|
||||
int x = rel_to_abs(pl, u->faction, getint(), 0);
|
||||
int y = rel_to_abs(pl, u->faction, getint(), 1);
|
||||
building *b = findbuilding(id);
|
||||
region *r;
|
||||
|
||||
pnormalize(&x, &y, pl);
|
||||
r = findregion(x, y);
|
||||
if (b == NULL || r == NULL || pl != rplane(b->region) || pl != rplane(r)) {
|
||||
mistake(u, ord, "the unit cannot transform this building.");
|
||||
return;
|
||||
} else {
|
||||
/* checking permissions */
|
||||
attrib *permissions = a_find(u->faction->attribs, &at_permissions);
|
||||
if (permissions && has_permission(permissions, atoi36("gmgate"))) {
|
||||
remove_triggers(&b->attribs, "timer", &tt_gate);
|
||||
remove_triggers(&b->attribs, "create", &tt_unguard);
|
||||
if (r != b->region) {
|
||||
add_trigger(&b->attribs, "timer", trigger_gate(b, r));
|
||||
add_trigger(&b->attribs, "create", trigger_unguard(b));
|
||||
fset(b, BLD_UNGUARDED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** GM: TERRAFORM <x> <y> <terrain>
|
||||
** requires: permission-key "gmterf"
|
||||
**/
|
||||
static void gm_terraform(const void *tnext, struct unit *u, struct order *ord)
|
||||
{
|
||||
const struct plane *p = rplane(u->region);
|
||||
int x = rel_to_abs(p, u->faction, getint(), 0);
|
||||
int y = rel_to_abs(p, u->faction, getint(), 1);
|
||||
const char *c = getstrtoken();
|
||||
variant token;
|
||||
void **tokens = get_translations(u->faction->locale, UT_TERRAINS);
|
||||
region *r;
|
||||
pnormalize(&x, &y, p);
|
||||
r = findregion(x, y);
|
||||
|
||||
if (r == NULL || p != rplane(r)) {
|
||||
mistake(u, ord, "region is in another plane.");
|
||||
return;
|
||||
} else {
|
||||
/* checking permissions */
|
||||
attrib *permissions = a_find(u->faction->attribs, &at_permissions);
|
||||
if (!permissions || !has_permission(permissions, atoi36("gmterf")))
|
||||
return;
|
||||
}
|
||||
|
||||
if (findtoken(*tokens, c, &token) != E_TOK_NOMATCH) {
|
||||
const terrain_type *terrain = (const terrain_type *)token.v;
|
||||
terraform_region(r, terrain);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** GM: TELEPORT <unit> <x> <y>
|
||||
** requires: permission-key "gmtele"
|
||||
**/
|
||||
static void gm_teleport(const void *tnext, struct unit *u, struct order *ord)
|
||||
{
|
||||
const struct plane *p = rplane(u->region);
|
||||
unit *to = findunit(getid());
|
||||
int x = rel_to_abs(p, u->faction, getint(), 0);
|
||||
int y = rel_to_abs(p, u->faction, getint(), 1);
|
||||
region *r = findregion(x, y);
|
||||
|
||||
if (r == NULL || p != rplane(r)) {
|
||||
mistake(u, ord, "region is in another plane.");
|
||||
} else if (to == NULL) {
|
||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found",
|
||||
""));
|
||||
} else if (rplane(to->region) != rplane(r) && !ucontact(to, u)) {
|
||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact",
|
||||
"target", to));
|
||||
} else {
|
||||
/* checking permissions */
|
||||
attrib *permissions = a_find(u->faction->attribs, &at_permissions);
|
||||
if (!permissions || !has_permission(permissions, atoi36("gmtele"))) {
|
||||
mistake(u, ord, "permission denied.");
|
||||
} else
|
||||
move_unit(to, r, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** GM: TELL PLANE <string>
|
||||
** requires: permission-key "gmmsgr"
|
||||
**/
|
||||
static void gm_messageplane(const void *tnext, struct unit *gm, struct order *ord)
|
||||
{
|
||||
const struct plane *p = rplane(gm->region);
|
||||
const char *zmsg = getstrtoken();
|
||||
if (p == NULL) {
|
||||
mistake(gm, ord, "In diese Ebene kann keine Nachricht gesandt werden.");
|
||||
} else {
|
||||
/* checking permissions */
|
||||
attrib *permissions = a_find(gm->faction->attribs, &at_permissions);
|
||||
if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) {
|
||||
mistake(gm, ord, "permission denied.");
|
||||
} else {
|
||||
message *msg = msg_message("msg_event", "string", zmsg);
|
||||
faction *f;
|
||||
region *r;
|
||||
for (f = factions; f; f = f->next) {
|
||||
freset(f, FFL_SELECT);
|
||||
}
|
||||
for (r = regions; r; r = r->next) {
|
||||
unit *u;
|
||||
if (rplane(r) != p)
|
||||
continue;
|
||||
for (u = r->units; u; u = u->next)
|
||||
if (!fval(u->faction, FFL_SELECT)) {
|
||||
f = u->faction;
|
||||
fset(f, FFL_SELECT);
|
||||
add_message(&f->msgs, msg);
|
||||
}
|
||||
}
|
||||
msg_release(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gm_messagefaction(const void *tnext, struct unit *gm, struct order *ord)
|
||||
{
|
||||
int n = getid();
|
||||
faction *f = findfaction(n);
|
||||
const char *msg = getstrtoken();
|
||||
plane *p = rplane(gm->region);
|
||||
attrib *permissions = a_find(gm->faction->attribs, &at_permissions);
|
||||
if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) {
|
||||
mistake(gm, ord, "permission denied.");
|
||||
return;
|
||||
}
|
||||
if (f != NULL) {
|
||||
region *r;
|
||||
for (r = regions; r; r = r->next)
|
||||
if (rplane(r) == p) {
|
||||
unit *u;
|
||||
for (u = r->units; u; u = u->next)
|
||||
if (u->faction == f) {
|
||||
add_message(&f->msgs, msg_message("msg_event", "string", msg));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
mistake(gm, ord, "cannot send messages to this faction.");
|
||||
}
|
||||
|
||||
/**
|
||||
** GM: TELL REGION <x> <y> <string>
|
||||
** requires: permission-key "gmmsgr"
|
||||
**/
|
||||
static void gm_messageregion(const void *tnext, struct unit *u, struct order *ord)
|
||||
{
|
||||
const struct plane *p = rplane(u->region);
|
||||
int x = rel_to_abs(p, u->faction, getint(), 0);
|
||||
int y = rel_to_abs(p, u->faction, getint(), 1);
|
||||
const char *msg = getstrtoken();
|
||||
region *r = findregion(x, y);
|
||||
|
||||
if (r == NULL || p != rplane(r)) {
|
||||
mistake(u, ord, "region is in another plane.");
|
||||
} else {
|
||||
/* checking permissions */
|
||||
attrib *permissions = a_find(u->faction->attribs, &at_permissions);
|
||||
if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) {
|
||||
mistake(u, ord, "permission denied.");
|
||||
} else {
|
||||
add_message(&r->msgs, msg_message("msg_event", "string", msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** GM: KILL UNIT <id> <string>
|
||||
** requires: permission-key "gmkill"
|
||||
**/
|
||||
static void gm_killunit(const void *tnext, struct unit *u, struct order *ord)
|
||||
{
|
||||
const struct plane *p = rplane(u->region);
|
||||
unit *target = findunit(getid());
|
||||
const char *msg = getstrtoken();
|
||||
region *r = target->region;
|
||||
|
||||
if (r == NULL || p != rplane(r)) {
|
||||
mistake(u, ord, "region is in another plane.");
|
||||
} else {
|
||||
/* checking permissions */
|
||||
attrib *permissions = a_find(u->faction->attribs, &at_permissions);
|
||||
if (!permissions || !has_permission(permissions, atoi36("gmkill"))) {
|
||||
mistake(u, ord, "permission denied.");
|
||||
} else {
|
||||
scale_number(target, 0);
|
||||
ADDMSG(&target->faction->msgs, msg_message("killedbygm",
|
||||
"region unit string", r, target, msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** GM: KILL FACTION <id> <string>
|
||||
** requires: permission-key "gmmsgr"
|
||||
**/
|
||||
static void gm_killfaction(const void *tnext, struct unit *u, struct order *ord)
|
||||
{
|
||||
int n = getid();
|
||||
faction *f = findfaction(n);
|
||||
const char *msg = getstrtoken();
|
||||
plane *p = rplane(u->region);
|
||||
attrib *permissions = a_find(u->faction->attribs, &at_permissions);
|
||||
if (!permissions || !has_permission(permissions, atoi36("gmkill"))) {
|
||||
mistake(u, ord, "permission denied.");
|
||||
return;
|
||||
}
|
||||
if (f != NULL) {
|
||||
region *r;
|
||||
for (r = regions; r; r = r->next)
|
||||
if (rplane(r) == p) {
|
||||
unit *target;
|
||||
for (target = r->units; target; target = target->next) {
|
||||
if (target->faction == f) {
|
||||
scale_number(target, 0);
|
||||
ADDMSG(&target->faction->msgs, msg_message("killedbygm",
|
||||
"region unit string", r, target, msg));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mistake(u, ord, "cannot remove a unit from this faction.");
|
||||
}
|
||||
|
||||
/**
|
||||
** GM: TELL <unit> <string>
|
||||
** requires: permission-key "gmmsgr"
|
||||
**/
|
||||
static void gm_messageunit(const void *tnext, struct unit *u, struct order *ord)
|
||||
{
|
||||
const struct plane *p = rplane(u->region);
|
||||
unit *target = findunit(getid());
|
||||
const char *msg = getstrtoken();
|
||||
region *r;
|
||||
|
||||
if (target == NULL) {
|
||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found",
|
||||
""));
|
||||
return;
|
||||
}
|
||||
|
||||
r = target->region;
|
||||
|
||||
if (r == NULL || p != rplane(r)) {
|
||||
mistake(u, ord, "region is in another plane.");
|
||||
} else {
|
||||
/* checking permissions */
|
||||
attrib *permissions = a_find(u->faction->attribs, &at_permissions);
|
||||
if (!permissions || !has_permission(permissions, atoi36("gmmsgu"))) {
|
||||
mistake(u, ord, "permission denied.");
|
||||
} else {
|
||||
add_message(&target->faction->msgs,
|
||||
msg_message("regionmessage", "region sender string", r, u, msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** GM: GIVE <unit> <int> <itemtype>
|
||||
** requires: permission-key "gmgive"
|
||||
**/
|
||||
static void gm_give(const void *tnext, struct unit *u, struct order *ord)
|
||||
{
|
||||
unit *to = findunit(getid());
|
||||
int num = getint();
|
||||
const item_type *itype = finditemtype(getstrtoken(), u->faction->locale);
|
||||
|
||||
if (to == NULL || rplane(to->region) != rplane(u->region)) {
|
||||
/* unknown or in another plane */
|
||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found",
|
||||
""));
|
||||
} else if (itype == NULL || i_get(u->items, itype) == 0) {
|
||||
/* unknown or not enough */
|
||||
mistake(u, ord, "invalid item or item not found.");
|
||||
} else {
|
||||
/* checking permissions */
|
||||
attrib *permissions = a_find(u->faction->attribs, &at_permissions);
|
||||
if (!permissions || !has_permission(permissions, atoi36("gmgive"))) {
|
||||
mistake(u, ord, "permission denied.");
|
||||
} else {
|
||||
int i = i_get(u->items, itype);
|
||||
if (i < num)
|
||||
num = i;
|
||||
if (num) {
|
||||
i_change(&u->items, itype, -num);
|
||||
i_change(&to->items, itype, num);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** GM: TAKE <unit> <int> <itemtype>
|
||||
** requires: permission-key "gmtake"
|
||||
**/
|
||||
static void gm_take(const void *tnext, struct unit *u, struct order *ord)
|
||||
{
|
||||
unit *to = findunit(getid());
|
||||
int num = getint();
|
||||
const item_type *itype = finditemtype(getstrtoken(), u->faction->locale);
|
||||
|
||||
if (to == NULL || rplane(to->region) != rplane(u->region)) {
|
||||
/* unknown or in another plane */
|
||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found",
|
||||
""));
|
||||
} else if (itype == NULL || i_get(to->items, itype) == 0) {
|
||||
/* unknown or not enough */
|
||||
mistake(u, ord, "invalid item or item not found.");
|
||||
} else {
|
||||
/* checking permissions */
|
||||
attrib *permissions = a_find(u->faction->attribs, &at_permissions);
|
||||
if (!permissions || !has_permission(permissions, atoi36("gmtake"))) {
|
||||
mistake(u, ord, "permission denied.");
|
||||
} else {
|
||||
int i = i_get(to->items, itype);
|
||||
if (i < num)
|
||||
num = i;
|
||||
if (num) {
|
||||
i_change(&to->items, itype, -num);
|
||||
i_change(&u->items, itype, num);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** GM: SKILL <unit> <skill> <tage>
|
||||
** requires: permission-key "gmskil"
|
||||
**/
|
||||
static void gm_skill(const void *tnext, struct unit *u, struct order *ord)
|
||||
{
|
||||
unit *to = findunit(getid());
|
||||
skill_t skill = findskill(getstrtoken(), u->faction->locale);
|
||||
int num = getint();
|
||||
|
||||
if (to == NULL || rplane(to->region) != rplane(u->region)) {
|
||||
/* unknown or in another plane */
|
||||
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found",
|
||||
""));
|
||||
} else if (skill == NOSKILL || skill == SK_MAGIC || skill == SK_ALCHEMY) {
|
||||
/* unknown or not enough */
|
||||
mistake(u, ord, "unknown skill, or skill cannot be raised.");
|
||||
} else if (num < 0 || num > 30) {
|
||||
/* sanity check failed */
|
||||
mistake(u, ord, "invalid value.");
|
||||
} else {
|
||||
/* checking permissions */
|
||||
attrib *permissions = a_find(u->faction->attribs, &at_permissions);
|
||||
if (!permissions || !has_permission(permissions, atoi36("gmskil"))) {
|
||||
mistake(u, ord, "permission denied.");
|
||||
} else {
|
||||
set_level(to, skill, num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void * g_keys;
|
||||
static void * g_root;
|
||||
static void * g_tell;
|
||||
static void * g_kill;
|
||||
|
||||
void register_gmcmd(void)
|
||||
{
|
||||
at_register(&at_gmcreate);
|
||||
at_register(&at_permissions);
|
||||
add_command(&g_root, &g_keys, "gm", NULL);
|
||||
add_command(&g_keys, NULL, "terraform", &gm_terraform);
|
||||
add_command(&g_keys, NULL, "create", &gm_create);
|
||||
add_command(&g_keys, NULL, "gate", &gm_gate);
|
||||
add_command(&g_keys, NULL, "give", &gm_give);
|
||||
add_command(&g_keys, NULL, "take", &gm_take);
|
||||
add_command(&g_keys, NULL, "teleport", &gm_teleport);
|
||||
add_command(&g_keys, NULL, "skill", &gm_skill);
|
||||
add_command(&g_keys, &g_tell, "tell", NULL);
|
||||
add_command(&g_tell, NULL, "region", &gm_messageregion);
|
||||
add_command(&g_tell, NULL, "unit", &gm_messageunit);
|
||||
add_command(&g_tell, NULL, "plane", &gm_messageplane);
|
||||
add_command(&g_tell, NULL, "faction", &gm_messagefaction);
|
||||
add_command(&g_keys, &g_kill, "kill", NULL);
|
||||
add_command(&g_kill, NULL, "unit", &gm_killunit);
|
||||
add_command(&g_kill, NULL, "faction", &gm_killfaction);
|
||||
}
|
||||
|
||||
/*
|
||||
* execute gm-commands for all units in the game
|
||||
*/
|
||||
|
||||
void gmcommands(void)
|
||||
{
|
||||
region **rp = ®ions;
|
||||
while (*rp) {
|
||||
region *r = *rp;
|
||||
unit **up = &r->units;
|
||||
while (*up) {
|
||||
unit *u = *up;
|
||||
struct order *ord;
|
||||
for (ord = u->orders; ord; ord = ord->next) {
|
||||
if (get_keyword(ord) == K_GM) {
|
||||
do_command(&g_root, u, ord);
|
||||
}
|
||||
}
|
||||
if (u == *up)
|
||||
up = &u->next;
|
||||
}
|
||||
if (*rp == r)
|
||||
rp = &r->next;
|
||||
}
|
||||
}
|
||||
|
||||
#define EXTENSION 10000
|
||||
|
||||
faction *gm_addquest(const char *email, const char *name, int radius,
|
||||
unsigned int flags)
|
||||
{
|
||||
plane *pl;
|
||||
watcher *w = calloc(sizeof(watcher), 1);
|
||||
region *center;
|
||||
bool invalid = false;
|
||||
int minx, miny, maxx, maxy, cx, cy;
|
||||
int x;
|
||||
faction *f;
|
||||
|
||||
/* GM playfield */
|
||||
do {
|
||||
minx = ((rng_int() % (2 * EXTENSION)) - EXTENSION);
|
||||
miny = ((rng_int() % (2 * EXTENSION)) - EXTENSION);
|
||||
for (x = 0; !invalid && x <= radius * 2; ++x) {
|
||||
int y;
|
||||
for (y = 0; !invalid && y <= radius * 2; ++y) {
|
||||
region *r = findregion(minx + x, miny + y);
|
||||
if (r)
|
||||
invalid = true;
|
||||
}
|
||||
}
|
||||
} while (invalid);
|
||||
maxx = minx + 2 * radius;
|
||||
cx = minx + radius;
|
||||
maxy = miny + 2 * radius;
|
||||
cy = miny + radius;
|
||||
pl = create_new_plane(rng_int(), name, minx, maxx, miny, maxy, flags);
|
||||
center = new_region(cx, cy, pl, 0);
|
||||
for (x = 0; x <= 2 * radius; ++x) {
|
||||
int y;
|
||||
for (y = 0; y <= 2 * radius; ++y) {
|
||||
region *r = findregion(minx + x, miny + y);
|
||||
if (!r) {
|
||||
r = new_region(minx + x, miny + y, pl, 0);
|
||||
}
|
||||
freset(r, RF_ENCOUNTER);
|
||||
if (distance(r, center) == radius) {
|
||||
terraform_region(r, newterrain(T_FIREWALL));
|
||||
} else if (r == center) {
|
||||
terraform_region(r, newterrain(T_PLAIN));
|
||||
} else {
|
||||
terraform_region(r, newterrain(T_OCEAN));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* watcher: */
|
||||
f = gm_addfaction(email, pl, center);
|
||||
w->faction = f;
|
||||
w->mode = see_unit;
|
||||
w->next = pl->watchers;
|
||||
pl->watchers = w;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
faction *gm_addfaction(const char *email, plane * p, region * r)
|
||||
{
|
||||
attrib *a;
|
||||
unit *u;
|
||||
faction *f = calloc(1, sizeof(faction));
|
||||
|
||||
assert(p != NULL);
|
||||
|
||||
/* GM faction */
|
||||
a_add(&f->attribs, make_key(atoi36("quest")));
|
||||
f->banner = _strdup("quest faction");
|
||||
f->name = _strdup("quest faction");
|
||||
f->passw = _strdup(itoa36(rng_int()));
|
||||
if (set_email(&f->email, email) != 0) {
|
||||
log_error("Invalid email address for faction %s: %s\n", itoa36(f->no), email);
|
||||
}
|
||||
f->race = new_race[RC_TEMPLATE];
|
||||
f->age = 0;
|
||||
f->lastorders = turn;
|
||||
f->alive = true;
|
||||
f->locale = default_locale;
|
||||
f->options =
|
||||
want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN);
|
||||
{
|
||||
faction *xist;
|
||||
int id = atoi36("gm00") - 1;
|
||||
do {
|
||||
xist = findfaction(++id);
|
||||
} while (xist);
|
||||
|
||||
f->no = id;
|
||||
addlist(&factions, f);
|
||||
fhash(f);
|
||||
}
|
||||
|
||||
/* generic permissions */
|
||||
a = a_add(&f->attribs, a_new(&at_permissions));
|
||||
if (a) {
|
||||
attrib *ap = (attrib *) a->data.v;
|
||||
const char *keys[] =
|
||||
{ "gmterf", "gmtele", "gmgive", "gmskil", "gmtake", "gmmsgr", "gmmsgu",
|
||||
"gmgate", 0 };
|
||||
const char **key_p = keys;
|
||||
while (*key_p) {
|
||||
add_key(&ap, atoi36(*key_p));
|
||||
++key_p;
|
||||
}
|
||||
a_add(&ap, make_atgmcreate(resource2item(r_silver)));
|
||||
|
||||
a->data.v = ap;
|
||||
}
|
||||
|
||||
/* one initial unit */
|
||||
u = create_unit(r, f, 1, new_race[RC_TEMPLATE], 1, "quest master", NULL);
|
||||
u->irace = new_race[RC_GNOME];
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
plane *gm_addplane(int radius, unsigned int flags, const char *name)
|
||||
{
|
||||
region *center;
|
||||
plane *pl;
|
||||
bool invalid = false;
|
||||
int minx, miny, maxx, maxy, cx, cy;
|
||||
int x;
|
||||
|
||||
/* GM playfield */
|
||||
do {
|
||||
minx = (rng_int() % (2 * EXTENSION)) - EXTENSION;
|
||||
miny = (rng_int() % (2 * EXTENSION)) - EXTENSION;
|
||||
for (x = 0; !invalid && x <= radius * 2; ++x) {
|
||||
int y;
|
||||
for (y = 0; !invalid && y <= radius * 2; ++y) {
|
||||
region *r = findregion(minx + x, miny + y);
|
||||
if (r)
|
||||
invalid = true;
|
||||
}
|
||||
}
|
||||
} while (invalid);
|
||||
maxx = minx + 2 * radius;
|
||||
cx = minx + radius;
|
||||
maxy = miny + 2 * radius;
|
||||
cy = miny + radius;
|
||||
pl = create_new_plane(rng_int(), name, minx, maxx, miny, maxy, flags);
|
||||
center = new_region(cx, cy, pl, 0);
|
||||
for (x = 0; x <= 2 * radius; ++x) {
|
||||
int y;
|
||||
for (y = 0; y <= 2 * radius; ++y) {
|
||||
region *r = findregion(minx + x, miny + y);
|
||||
if (!r)
|
||||
r = new_region(minx + x, miny + y, pl, 0);
|
||||
freset(r, RF_ENCOUNTER);
|
||||
if (distance(r, center) == radius) {
|
||||
terraform_region(r, newterrain(T_FIREWALL));
|
||||
} else if (r == center) {
|
||||
terraform_region(r, newterrain(T_PLAIN));
|
||||
} else {
|
||||
terraform_region(r, newterrain(T_OCEAN));
|
||||
}
|
||||
}
|
||||
}
|
||||
return pl;
|
||||
}
|
||||
|
|
10
src/report.c
10
src/report.c
|
@ -2199,8 +2199,14 @@ report_plaintext(const char *filename, report_context * ctx,
|
|||
f->num_people = no_people;
|
||||
}
|
||||
#else
|
||||
no_units = f->no_units;
|
||||
no_people = f->num_people;
|
||||
no_units = count_units(f);
|
||||
no_people = count_all(f);
|
||||
if (f->flags & FFL_NPC) {
|
||||
no_people = f->num_total;
|
||||
}
|
||||
else {
|
||||
no_people = f->num_people;
|
||||
}
|
||||
#endif
|
||||
m = msg_message("nr_population", "population units", no_people, no_units);
|
||||
nr_render(m, f->locale, buf, sizeof(buf), f);
|
||||
|
|
|
@ -321,7 +321,7 @@ int a_read(struct storage *store, attrib ** attribs, void *owner)
|
|||
}
|
||||
}
|
||||
} else {
|
||||
assert(!"fehler: keine laderoutine für attribut");
|
||||
assert(!"error: no registered callback can read attribute");
|
||||
}
|
||||
|
||||
READ_TOK(store, zText, sizeof(zText));
|
||||
|
|
|
@ -108,29 +108,28 @@ int read_xml(const char *filename, const char *catalog)
|
|||
{
|
||||
xml_reader *reader = xmlReaders;
|
||||
xmlDocPtr doc;
|
||||
int result;
|
||||
|
||||
if (catalog) {
|
||||
xmlLoadCatalog(catalog);
|
||||
}
|
||||
#ifdef XML_PARSE_XINCLUDE
|
||||
doc = xmlReadFile(filename, NULL, XML_PARSE_XINCLUDE);
|
||||
#else
|
||||
doc = xmlParseFile(filename);
|
||||
#endif
|
||||
doc = xmlReadFile(filename, NULL, XML_PARSE_XINCLUDE | XML_PARSE_NONET | XML_PARSE_PEDANTIC | XML_PARSE_COMPACT);
|
||||
if (doc == NULL) {
|
||||
log_error("could not open '%s'\n", filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
xmlXIncludeProcess(doc);
|
||||
|
||||
while (reader != NULL) {
|
||||
int i = reader->callback(doc);
|
||||
if (i != 0) {
|
||||
return i;
|
||||
}
|
||||
reader = reader->next;
|
||||
result = xmlXIncludeProcessFlags(doc, XML_PARSE_XINCLUDE | XML_PARSE_NONET | XML_PARSE_PEDANTIC | XML_PARSE_COMPACT);
|
||||
if (result >= 0) {
|
||||
while (reader != NULL) {
|
||||
int i = reader->callback(doc);
|
||||
if (i != 0) {
|
||||
return i;
|
||||
}
|
||||
reader = reader->next;
|
||||
}
|
||||
result = 0;
|
||||
}
|
||||
xmlFreeDoc(doc);
|
||||
return 0;
|
||||
return result;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue