Fixed:
-> !wants -> !orgs info -> special cmd's -> !assist -> "afk" for players without active account -> !loot add <item_ref> <count> => nolonger breaks !account Changes: -> grouped !tara, !gaunt, .. into !wb -> Display the most recent news entry on logon (default: enabled) -> improved grouping of !items -> Added the option to authentificate WS connections (Datanet module). This is used in special cases, where the Websocket Server requires the clien tto authentificate itself. (Server sends "#auth", client responds with the auth string) -> Add main name to relaying (priv <-> org) [default: disabled] -> Added logon/logoff messages back -> restricted default access to "dangerous" commands to moderator -> Added optional logging (Private Channel, Org Channel, Tells, ... disabled by default) Rewrite of the Tower Module. -> More verbosity, if enabled in config. by default, GAS and Hot timer only. -> !hot displays currently hot (and in penalty) sites, and these which go hot in < 60 minutes -> !attacks filterable by PF and Site -> display current contract QL's grouped by org: !contracts (requires managed cache)
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
import time
|
||||
|
||||
from core.decorators import instance, event
|
||||
from core.igncore import IgnCore
|
||||
from core.logger import Logger
|
||||
from core.text import Text
|
||||
from modules.standard.helpbot.playfield_controller import PlayfieldController
|
||||
from modules.standard.tower.tower_events import TowerEventController
|
||||
|
||||
|
||||
@instance()
|
||||
class TowerAttackController:
|
||||
def __init__(self):
|
||||
self.logger = Logger(__name__)
|
||||
|
||||
def inject(self, registry):
|
||||
self.bot: IgnCore = registry.get_instance("bot")
|
||||
self.db = registry.get_instance("db")
|
||||
self.text: Text = registry.get_instance("text")
|
||||
self.tower: TowerEventController = registry.get_instance("tower_controller")
|
||||
self.playfield_controller: PlayfieldController = registry.get_instance("playfield_controller")
|
||||
|
||||
def start(self):
|
||||
self.db.shared.exec(
|
||||
"CREATE TABLE IF NOT EXISTS tower_attacker ("
|
||||
"id INT PRIMARY KEY AUTO_INCREMENT, "
|
||||
"att_org_name VARCHAR(50) NOT NULL, "
|
||||
"att_faction VARCHAR(10) NOT NULL, "
|
||||
"att_char_id INT, att_char_name VARCHAR(20) NOT NULL, "
|
||||
"att_level INT NOT NULL, "
|
||||
"att_ai_level INT NOT NULL, "
|
||||
"att_profession VARCHAR(15) NOT NULL, "
|
||||
"x_coord INT NOT NULL, "
|
||||
"y_coord INT NOT NULL, "
|
||||
"is_victory SMALLINT NOT NULL, "
|
||||
"tower_battle_id INT NOT NULL, "
|
||||
"created_at INT NOT NULL)")
|
||||
self.db.shared.exec(
|
||||
"CREATE TABLE IF NOT EXISTS tower_battle ("
|
||||
"id INT PRIMARY KEY AUTO_INCREMENT, "
|
||||
"playfield_id INT NOT NULL, "
|
||||
"site_number INT NOT NULL, "
|
||||
"def_org_name VARCHAR(50) NOT NULL, "
|
||||
"def_faction VARCHAR(10) NOT NULL, "
|
||||
"is_finished INT NOT NULL, "
|
||||
"battle_type VARCHAR(20) NOT NULL, "
|
||||
"last_updated INT NOT NULL)"
|
||||
"")
|
||||
self.db.create_view("tower_battle")
|
||||
self.db.create_view("tower_attacker")
|
||||
|
||||
@event(event_type=TowerEventController.TOWER_ATTACK_EVENT, description="Create logentries for tower attacks",
|
||||
is_enabled=False)
|
||||
def tower_attack_event(self, _, event_data):
|
||||
t = int(time.time())
|
||||
site_number = self.find_closest_site_number(event_data.location.playfield.id, event_data.location.x_coord,
|
||||
event_data.location.y_coord)
|
||||
|
||||
attacker = event_data.attacker or {}
|
||||
defender = event_data.defender
|
||||
|
||||
battle = self.find_or_create_battle(event_data.location.playfield.id, site_number, defender.org_name,
|
||||
defender.faction, "attack", t)
|
||||
self.db.exec(
|
||||
"INSERT INTO tower_attacker (att_org_name, att_faction, att_char_id, att_char_name, "
|
||||
"att_level, att_ai_level, att_profession, "
|
||||
"x_coord, y_coord, is_victory, tower_battle_id, created_at) "
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
[attacker.get("org_name", ""), attacker.get("faction", ""), attacker.get("char_id", 0),
|
||||
attacker.get("name", ""), attacker.get("level", 0),
|
||||
attacker.get("ai_level", 0), attacker.get("profession", ""), event_data.location.x_coord,
|
||||
event_data.location.y_coord, 0, battle.id, t])
|
||||
|
||||
@event(event_type=TowerEventController.TOWER_VICTORY_EVENT, description="Record tower victories", is_enabled=False)
|
||||
def tower_victory_event(self, _, event_data):
|
||||
t = int(time.time())
|
||||
if event_data.type == "attack":
|
||||
row = self.get_last_attack(event_data.winner.faction, event_data.winner.org_name, event_data.loser.faction,
|
||||
event_data.loser.org_name, event_data.location.playfield.id, t, is_finished=0)
|
||||
|
||||
if not row:
|
||||
site_number = 0
|
||||
is_finished = 1
|
||||
self.db.exec(
|
||||
"INSERT INTO tower_battle (playfield_id, site_number, def_org_name, def_faction, "
|
||||
"is_finished, battle_type, last_updated) "
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
[event_data.location.playfield.id, site_number, event_data.loser.org_name, event_data.loser.faction,
|
||||
is_finished, event_data.type, t])
|
||||
battle_id = self.db.last_insert_id()
|
||||
|
||||
attacker = event_data.winner or {}
|
||||
self.db.exec(
|
||||
"INSERT INTO tower_attacker (att_org_name, att_faction, att_char_id, "
|
||||
"att_char_name, att_level, att_ai_level, att_profession, "
|
||||
"x_coord, y_coord, is_victory, tower_battle_id, created_at) "
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
[attacker.get("org_name", ""), attacker.get("faction", ""), attacker.get("char_id", 0),
|
||||
attacker.get("name", ""), attacker.get("level", 0),
|
||||
attacker.get("ai_level", 0), attacker.get("profession", ""), 0, 0, 0, battle_id, t])
|
||||
else:
|
||||
is_victory = 1
|
||||
self.db.exec("UPDATE tower_attacker SET is_victory = ? WHERE id = ?", [is_victory, row.attack_id])
|
||||
|
||||
is_finished = 1
|
||||
self.db.exec("UPDATE tower_battle SET is_finished = ?, last_updated = ? WHERE id = ?",
|
||||
[is_finished, t, row.battle_id])
|
||||
|
||||
elif event_data.type == "terminated":
|
||||
site_number = 0
|
||||
is_finished = 1
|
||||
|
||||
row = self.find_similar_attacks(event_data.loser.faction, event_data.loser.org_name,
|
||||
event_data.location.playfield.id, t, finished=0)
|
||||
if row:
|
||||
self.db.exec("UPDATE tower_battle SET is_finished = ?, last_updated = ? WHERE id = ?",
|
||||
[is_finished, t, row.battle_id])
|
||||
else:
|
||||
self.db.exec(
|
||||
"INSERT INTO tower_battle (playfield_id, site_number, def_org_name, def_faction, "
|
||||
"is_finished, battle_type, last_updated) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
[event_data.location.playfield.id, site_number, event_data.loser.org_name, event_data.loser.faction,
|
||||
is_finished, event_data.type, t])
|
||||
else:
|
||||
raise Exception("Unknown victory event type: '%s'" % event_data.type)
|
||||
|
||||
def find_closest_site_number(self, playfield_id, x_coord, y_coord):
|
||||
# noinspection SqlUnused
|
||||
sql = """
|
||||
SELECT
|
||||
site_number,
|
||||
((x_distance * x_distance) + (y_distance * y_distance)) radius
|
||||
FROM
|
||||
(SELECT
|
||||
playfield_id,
|
||||
site_number,
|
||||
min_ql,
|
||||
max_ql,
|
||||
x_coord,
|
||||
y_coord,
|
||||
site_name,
|
||||
(x_coord - ?) as x_distance,
|
||||
(y_coord - ?) as y_distance
|
||||
FROM
|
||||
tower_sites
|
||||
WHERE
|
||||
playfield_id = ?) t
|
||||
ORDER BY
|
||||
radius
|
||||
LIMIT 1"""
|
||||
|
||||
row = self.db.query_single(sql, [x_coord, y_coord, playfield_id])
|
||||
if row:
|
||||
return row.site_number
|
||||
else:
|
||||
return 0
|
||||
|
||||
def find_or_create_battle(self, playfield_id, site_number, org_name, faction, battle_type, t):
|
||||
last_updated = t - (8 * 3600)
|
||||
is_finished = 0
|
||||
|
||||
sql = """
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
tower_battle
|
||||
WHERE
|
||||
playfield_id = ?
|
||||
AND site_number = ?
|
||||
AND is_finished = ?
|
||||
AND def_org_name = ?
|
||||
AND def_faction = ?
|
||||
AND last_updated >= ?
|
||||
"""
|
||||
|
||||
battle = self.db.query_single(sql, [playfield_id, site_number, is_finished, org_name, faction, last_updated])
|
||||
|
||||
if battle:
|
||||
self.db.exec("UPDATE tower_battle SET last_updated = ? WHERE id = ?", [t, battle.id])
|
||||
return battle
|
||||
else:
|
||||
self.db.exec(
|
||||
"INSERT INTO tower_battle (playfield_id, site_number, def_org_name, def_faction, "
|
||||
"is_finished, battle_type, last_updated) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
[playfield_id, site_number, org_name, faction, is_finished, battle_type, t])
|
||||
return self.db.query_single(sql, [playfield_id, site_number, is_finished, org_name, faction, last_updated])
|
||||
|
||||
def get_last_attack(self, att_faction, att_org_name, def_faction, def_org_name, playfield_id, t, is_finished=None):
|
||||
last_updated = t - (8 * 3600)
|
||||
|
||||
sql = f"""
|
||||
SELECT
|
||||
b.id AS battle_id,
|
||||
a.id AS attack_id,
|
||||
b.playfield_id as pf_id,
|
||||
b.site_number as site
|
||||
FROM
|
||||
tower_battle b
|
||||
JOIN tower_attacker a ON
|
||||
a.tower_battle_id = b.id
|
||||
WHERE
|
||||
a.att_faction = ?
|
||||
AND a.att_org_name = ?
|
||||
AND b.def_faction = ?
|
||||
AND b.def_org_name = ?
|
||||
AND b.playfield_id = ?
|
||||
{'AND b.is_finished = ?' if is_finished is not None else ''}
|
||||
AND b.last_updated >= ?
|
||||
ORDER BY
|
||||
last_updated DESC
|
||||
LIMIT 1"""
|
||||
|
||||
return self.db.query_single(sql,
|
||||
[att_faction, att_org_name, def_faction, def_org_name, playfield_id, is_finished,
|
||||
last_updated]
|
||||
if is_finished is not None else
|
||||
[att_faction, att_org_name, def_faction, def_org_name, playfield_id, last_updated])
|
||||
|
||||
def find_similar_attacks(self, def_faction, def_org_name, playfield_id, t, finished=None):
|
||||
last_updated = t - (8 * 3600)
|
||||
|
||||
sql = f"""
|
||||
SELECT
|
||||
b.id AS battle_id,
|
||||
a.id AS attack_id,
|
||||
b.playfield_id as pf_id,
|
||||
b.site_number as site
|
||||
|
||||
FROM
|
||||
tower_battle b
|
||||
JOIN tower_attacker a ON
|
||||
a.tower_battle_id = b.id
|
||||
WHERE
|
||||
b.def_faction = ?
|
||||
AND b.def_org_name = ?
|
||||
AND b.playfield_id = ?
|
||||
{'AND b.is_finished = ?' if finished else ''}
|
||||
AND b.last_updated >= ?
|
||||
ORDER BY
|
||||
last_updated DESC
|
||||
"""
|
||||
|
||||
return self.db.query_single(sql,
|
||||
[def_faction, def_org_name, playfield_id, finished,
|
||||
last_updated] if finished else
|
||||
[def_faction, def_org_name, playfield_id,
|
||||
last_updated])
|
||||
Reference in New Issue
Block a user