Add initial reputation support
As reputation support is experimental and still under development, the database is being kept in memory and is lost after every server restart. git-svn-id: svn://svn.code.sf.net/p/crossfire/code/maps/trunk@20493 282e977c-c81d-0410-88c4-b93c2d0d6712master
parent
cd6ceec80e
commit
d77739aad0
|
@ -0,0 +1,66 @@
|
|||
import os.path
|
||||
import sqlite3
|
||||
|
||||
import Crossfire
|
||||
|
||||
_dict_name = 'CFReputationConnection'
|
||||
|
||||
def _init_schema(con, version, *init_files):
|
||||
con.execute("PRAGMA journal_mode=WAL;");
|
||||
con.execute("PRAGMA synchronous=NORMAL;");
|
||||
con.execute("CREATE TABLE IF NOT EXISTS schema(version INT);");
|
||||
result = con.execute("SELECT version FROM schema").fetchall();
|
||||
curr = len(result)
|
||||
if curr < version:
|
||||
Crossfire.Log(Crossfire.LogInfo,
|
||||
"Initializing factions schema %d->%d" % (curr, version))
|
||||
for f in init_files:
|
||||
with open(f) as initfile:
|
||||
con.executescript(initfile.read())
|
||||
con.commit()
|
||||
|
||||
def _get_sql_path(f):
|
||||
return os.path.join(Crossfire.DataDirectory(), Crossfire.MapDirectory(),
|
||||
"python/CFReputation/sql", f)
|
||||
|
||||
def _init_db():
|
||||
init_files = map(_get_sql_path, ["init.sql", "gods.sql"])
|
||||
db_path = os.path.join(Crossfire.LocalDirectory(), "factions.db")
|
||||
con = sqlite3.connect(':memory:')
|
||||
_init_schema(con, 1, *init_files)
|
||||
Crossfire.GetSharedDictionary()[_dict_name] = con
|
||||
|
||||
def _get_db():
|
||||
d = Crossfire.GetSharedDictionary()
|
||||
if _dict_name not in d:
|
||||
_init_db()
|
||||
return d[_dict_name]
|
||||
|
||||
def reputation(player):
|
||||
con = _get_db()
|
||||
query="""
|
||||
SELECT faction, CAST(ROUND(reputation*100) as integer) as rep
|
||||
FROM reputations
|
||||
WHERE name=? AND ABS(rep) > 0;
|
||||
"""
|
||||
result = con.execute(query, (player,)).fetchall()
|
||||
return result
|
||||
|
||||
def record_kill(race, region, player, fraction=0.0005, limit=0.4):
|
||||
con = _get_db()
|
||||
query = """
|
||||
WITH updates AS (
|
||||
SELECT faction, -attitude*? AS change
|
||||
FROM regions
|
||||
NATURAL JOIN relations
|
||||
WHERE race=? AND (region=? OR region='ALL'))
|
||||
REPLACE INTO reputations
|
||||
SELECT ? AS player, updates.faction,
|
||||
COALESCE(reputation, 0) + change AS new_rep
|
||||
FROM updates
|
||||
LEFT JOIN reputations
|
||||
ON updates.faction=reputations.faction AND player=reputations.name
|
||||
WHERE ABS(new_rep) <= ?;
|
||||
"""
|
||||
con.execute(query, (fraction, race, region, player, limit))
|
||||
con.commit()
|
|
@ -0,0 +1,51 @@
|
|||
insert into regions values ('Valriel', 'ALL', 0.25);
|
||||
insert into relations values ('Valriel', 'angel', 1);
|
||||
insert into relations values ('Valriel', 'demon', -1);
|
||||
insert into regions values ('Gorokh', 'ALL', 0.25);
|
||||
insert into relations values ('Gorokh', 'demon', 1);
|
||||
insert into relations values ('Gorokh', 'angel', -1);
|
||||
insert into regions values ('Devourers', 'ALL', 0.25);
|
||||
insert into relations values ('Devourers', 'undead', 1);
|
||||
insert into relations values ('Devourers', 'none', -1);
|
||||
insert into regions values ('Sorig', 'ALL', 0.25);
|
||||
insert into relations values ('Sorig', 'air_elemental', 1);
|
||||
insert into relations values ('Sorig', 'none', -1);
|
||||
insert into regions values ('Ruggilli', 'ALL', 0.25);
|
||||
insert into relations values ('Ruggilli', 'consuming_fire_creatures', 1);
|
||||
insert into relations values ('Ruggilli', 'chaotic_water_creatures', -1);
|
||||
insert into regions values ('Ixalovh', 'ALL', 0.25);
|
||||
insert into relations values ('Ixalovh', 'chaotic_water_creatures', 1);
|
||||
insert into relations values ('Ixalovh', 'consuming_fire_creatures', -1);
|
||||
insert into regions values ('Gaea', 'ALL', 0.25);
|
||||
insert into relations values ('Gaea', 'animal', 1);
|
||||
insert into relations values ('Gaea', 'bird', 1);
|
||||
insert into relations values ('Gaea', 'slime', 1);
|
||||
insert into relations values ('Gaea', 'insect', 1);
|
||||
insert into relations values ('Gaea', 'reptile', 1);
|
||||
insert into relations values ('Gaea', 'water_elemental', 1);
|
||||
insert into relations values ('Gaea', 'earth_elemental', 1);
|
||||
insert into relations values ('Gaea', 'air_elemental', 1);
|
||||
insert into relations values ('Gaea', 'fire_elemental', 1);
|
||||
insert into relations values ('Gaea', 'undead', -1);
|
||||
insert into relations values ('Gaea', 'unnatural', -1);
|
||||
insert into regions values ('Valkyrie', 'ALL', 0.25);
|
||||
insert into relations values ('Valkyrie', 'human', 1);
|
||||
insert into relations values ('Valkyrie', 'troll', 1);
|
||||
insert into relations values ('Valkyrie', 'unnatural', -1);
|
||||
insert into relations values ('Valkyrie', 'angel', -1);
|
||||
insert into relations values ('Valkyrie', 'demon', -1);
|
||||
insert into relations values ('Valkyrie', 'undead', -1);
|
||||
insert into regions values ('Mostrai', 'ALL', 0.25);
|
||||
insert into relations values ('Mostrai', 'dwarf', 1);
|
||||
insert into relations values ('Mostrai', 'goblin', -1);
|
||||
insert into relations values ('Mostrai', 'giant', -1);
|
||||
insert into regions values ('Lythander', 'ALL', 0.25);
|
||||
insert into relations values ('Lythander', 'faerie', 1);
|
||||
insert into relations values ('Lythander', 'goblin', -1);
|
||||
insert into relations values ('Lythander', 'troll', -1);
|
||||
insert into regions values ('Gnarg', 'ALL', 0.25);
|
||||
insert into relations values ('Gnarg', 'goblin', 1);
|
||||
insert into relations values ('Gnarg', 'giant', 1);
|
||||
insert into relations values ('Gnarg', 'troll', 1);
|
||||
insert into relations values ('Gnarg', 'faerie', -1);
|
||||
insert into relations values ('Gnarg', 'dwarf', -1);
|
|
@ -0,0 +1,47 @@
|
|||
CREATE TABLE IF NOT EXISTS schema(version INT);
|
||||
|
||||
CREATE TABLE regions(
|
||||
faction TEXT,
|
||||
region TEXT, -- region name (or 'ALL') this faction controls
|
||||
influence NUMERIC,
|
||||
CONSTRAINT influence_range CHECK(influence BETWEEN 0 AND 1)
|
||||
);
|
||||
|
||||
CREATE TABLE relations(
|
||||
faction TEXT,
|
||||
race TEXT,
|
||||
attitude NUMERIC,
|
||||
PRIMARY KEY (faction, race),
|
||||
CONSTRAINT attitude_range CHECK(attitude BETWEEN -1 AND 1)
|
||||
);
|
||||
|
||||
CREATE TABLE reputations(
|
||||
name TEXT, -- player name
|
||||
faction TEXT,
|
||||
reputation NUMERIC,
|
||||
PRIMARY KEY (name, faction),
|
||||
CONSTRAINT reputation_range CHECK(reputation BETWEEN -1 AND 1)
|
||||
);
|
||||
|
||||
INSERT INTO regions VALUES
|
||||
('Dragons', 'ALL', 0.4),
|
||||
('Scorn', 'scorn', 0.5),
|
||||
('Scorn', 'scornarena', 0.5),
|
||||
('Scorn', 'scorncounty', 0.5),
|
||||
('Scorn', 'scornoldcity', 0.5);
|
||||
|
||||
INSERT INTO relations VALUES
|
||||
('Dragons', 'dragon', 1),
|
||||
('Dragons', 'faerie', -1),
|
||||
('Dragons', 'human', -1),
|
||||
('Scorn', 'demon', -1),
|
||||
('Scorn', 'dragon', -1),
|
||||
('Scorn', 'giant', -1),
|
||||
('Scorn', 'goblin', -1),
|
||||
('Scorn', 'human', 1),
|
||||
('Scorn', 'reptile', -1),
|
||||
('Scorn', 'troll', -1),
|
||||
('Scorn', 'undead', -1),
|
||||
('Scorn', 'unnatural', -1);
|
||||
|
||||
INSERT INTO schema VALUES(1);
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env python
|
||||
# gods2factions -- convert `crossfire-server -m6` output to factions SQL
|
||||
import sys
|
||||
|
||||
def print_rels(faction, rel_str, rel):
|
||||
rels = rel_str.split(',')
|
||||
for r in rels:
|
||||
print("insert into relations values ('%s', '%s', %d);"
|
||||
% (faction, r, rel))
|
||||
|
||||
for l in sys.stdin.read().splitlines():
|
||||
xs = map(str.strip, l.split(':'))
|
||||
if len(xs) < 1:
|
||||
continue
|
||||
if xs[0] == 'GOD':
|
||||
curr_god = xs[1]
|
||||
print("insert into regions values ('%s', 'ALL', 0.25);" % curr_god)
|
||||
elif xs[0] == 'aligned_race(s)':
|
||||
print_rels(curr_god, xs[1], 1)
|
||||
elif xs[0] == 'enemy_race(s)':
|
||||
print_rels(curr_god, xs[1], -1)
|
|
@ -0,0 +1,15 @@
|
|||
import CFReputation
|
||||
import Crossfire
|
||||
|
||||
def show_reputation(who):
|
||||
reputations = CFReputation.reputation(who.Name)
|
||||
lines = []
|
||||
if len(reputations) == 0:
|
||||
lines.append("You don't have a reputation with anyone.")
|
||||
else:
|
||||
lines.append("You are known by the following factions:")
|
||||
for p in reputations:
|
||||
lines.append("\t%s....................%d" % (p[0], p[1]))
|
||||
who.Message("\n".join(lines))
|
||||
|
||||
show_reputation(Crossfire.WhoAmI())
|
|
@ -0,0 +1,17 @@
|
|||
import Crossfire
|
||||
import CFReputation
|
||||
|
||||
def get_killer(hitter):
|
||||
owner = hitter.Owner
|
||||
if owner is not None:
|
||||
return owner
|
||||
return hitter
|
||||
|
||||
def is_player(op):
|
||||
return op.Type == Crossfire.Type.PLAYER
|
||||
|
||||
killer = get_killer(Crossfire.WhoIsActivator())
|
||||
victim = Crossfire.WhoAmI()
|
||||
|
||||
if is_player(killer):
|
||||
CFReputation.record_kill(victim.Race, victim.Map.Region.Name, killer.Name)
|
|
@ -0,0 +1,2 @@
|
|||
import Crossfire
|
||||
Crossfire.RegisterCommand("reputation", "/python/commands/reputation", 0)
|
Loading…
Reference in New Issue