d0c8c1744c
Added default alias !list for !loot (bebot like) Changed the layout of !notes, its more compact now. fixed !count in the rare case of an empty private channel
405 lines
19 KiB
Python
405 lines
19 KiB
Python
import re
|
|
import secrets
|
|
import time
|
|
from collections import OrderedDict
|
|
|
|
from core.chat_blob import ChatBlob
|
|
from core.command_alias_service import CommandAliasService
|
|
from core.command_param_types import Const, Int, Any
|
|
from core.db import DB
|
|
from core.decorators import instance, command, timerevent
|
|
from core.setting_service import SettingService
|
|
from core.text import Text
|
|
from core.tyrbot import Tyrbot
|
|
from modules.core.accounting.services.account_service import AccountService
|
|
from modules.raidbot.raid.raidbot_controller import Raider
|
|
from modules.standard.items.items_controller import ItemsController
|
|
from modules.standard.loot.item_types import LootItem
|
|
from modules.standard.raid.leader_controller import LeaderController
|
|
|
|
|
|
@instance()
|
|
class LootController:
|
|
NOT_LEADER_MSG = "Error! You must be raid leader, or have higher access " \
|
|
"level than the raid leader to use this command."
|
|
|
|
def __init__(self):
|
|
self.loot_list = OrderedDict()
|
|
self.last_modify = None
|
|
|
|
def inject(self, registry):
|
|
self.bot: Tyrbot = registry.get_instance("bot")
|
|
self.db: DB = registry.get_instance("db")
|
|
self.text: Text = registry.get_instance("text")
|
|
self.leader_controller: LeaderController = registry.get_instance("leader_controller", is_optional=True)
|
|
self.setting_service: SettingService = registry.get_instance("setting_service")
|
|
self.items_controller: ItemsController = registry.get_instance("items_controller")
|
|
self.raid_controller = None
|
|
self.raid_controller = registry.get_instance("raidbot_controller", is_optional=True)
|
|
self.account_service: AccountService = registry.get_instance("account_service")
|
|
self.alts_service: AccountService = registry.get_instance("account_service")
|
|
self.alias: CommandAliasService = registry.get_instance("command_alias_service")
|
|
|
|
def pre_start(self):
|
|
self.db.load_sql_file(self.module_dir + "/raid_loot.sql", pre_optimized=True)
|
|
self.db.create_view("raid_loot")
|
|
self.alias.add_alias("add", "loot add")
|
|
self.alias.add_alias("rem", "loot rem")
|
|
self.alias.add_alias("remove", "loot remo")
|
|
self.alias.add_alias("flatroll", "loot roll")
|
|
self.alias.add_alias("result", "loot roll")
|
|
self.alias.add_alias("results", "loot roll")
|
|
self.alias.add_alias("list", "loot")
|
|
self.alias.add_alias("win", "loot roll")
|
|
|
|
@command(command="loot", params=[], description="Show the list of added items", access_level="member")
|
|
def loot_cmd(self, _):
|
|
if not self.loot_list:
|
|
return "Loot list is empty."
|
|
|
|
return self.get_loot_list()
|
|
|
|
@command(command="loot", params=[Const("edit")], description="Show the list of added items", access_level="leader",
|
|
sub_command="modify")
|
|
def loot_edit_cmd(self, _, _1):
|
|
if not self.loot_list:
|
|
return "Loot list is empty."
|
|
|
|
return self.get_loot_list(edit=True)
|
|
|
|
@command(command="loot", params=[Const("clear")], description="Clear all loot", access_level="leader",
|
|
sub_command="modify")
|
|
def loot_clear_cmd(self, request, _):
|
|
if not self.leader_controller.can_use_command(request.sender.char_id) if self.leader_controller else False:
|
|
return LeaderController.NOT_LEADER_MSG
|
|
|
|
if self.loot_list:
|
|
self.loot_list.clear()
|
|
self.last_modify = None
|
|
self.bot.send_private_channel_message("Loot list cleared.")
|
|
else:
|
|
return "Loot list is already empty."
|
|
|
|
@command(command="loot", params=[Const("remitem"), Int("item_index")],
|
|
description="Remove an existing loot item", access_level="leader", sub_command="modify")
|
|
def loot_rem_item_cmd(self, request, _, item_index: int):
|
|
if not self.leader_controller.can_use_command(request.sender.char_id) if self.leader_controller else False:
|
|
return LeaderController.NOT_LEADER_MSG
|
|
|
|
if not self.loot_list:
|
|
return "Loot list is empty."
|
|
|
|
try:
|
|
if self.loot_list[item_index]:
|
|
self.last_modify = int(time.time())
|
|
self.bot.send_private_channel_message(
|
|
"Removed %s from loot list." % self.loot_list.pop(item_index).get_item_str())
|
|
else:
|
|
return "Item error."
|
|
except KeyError:
|
|
return "Wrong index given."
|
|
|
|
@command(command="loot", params=[Const("increase"), Int("item_index")], description="Increase item count",
|
|
access_level="leader", sub_command="modify")
|
|
def loot_increase_item_cmd(self, request, _, item_index: int):
|
|
if not self.leader_controller.can_use_command(request.sender.char_id) if self.leader_controller else False:
|
|
return LeaderController.NOT_LEADER_MSG
|
|
|
|
if not self.loot_list:
|
|
return "Loot list is empty."
|
|
|
|
try:
|
|
loot_item = self.loot_list[item_index]
|
|
|
|
if loot_item:
|
|
loot_item.count += 1
|
|
self.last_modify = int(time.time())
|
|
self.bot.send_private_channel_message(
|
|
"Increased item count for %s to %d." % (loot_item.get_item_str(), loot_item.count))
|
|
else:
|
|
return "Item error."
|
|
except KeyError:
|
|
return "Wrong index given."
|
|
|
|
@command(command="loot", params=[Const("decrease"), Int("item_index")], description="Decrease item count",
|
|
access_level="leader", sub_command="modify")
|
|
def loot_decrease_item_cmd(self, request, _, item_index: int):
|
|
if not self.leader_controller.can_use_command(request.sender.char_id) if self.leader_controller else False:
|
|
return LeaderController.NOT_LEADER_MSG
|
|
|
|
if not self.loot_list:
|
|
return "Loot list is empty."
|
|
|
|
try:
|
|
loot_item = self.loot_list[item_index]
|
|
|
|
if loot_item:
|
|
loot_item.count = loot_item.count - 1 if loot_item.count > 1 else 1
|
|
self.last_modify = int(time.time())
|
|
self.bot.send_private_channel_message(
|
|
"Decreased item count for %s to %d." % (loot_item.get_item_str(), loot_item.count))
|
|
else:
|
|
return "Item error."
|
|
except KeyError:
|
|
return "Wrong index given."
|
|
|
|
@command(command="loot", params=[Const("add"), Int("item_index")], description="Add yourself to item",
|
|
access_level="member")
|
|
def loot_add_to_cmd(self, request, _, item_index: int):
|
|
main = self.alts_service.get_account(request.sender.char_id)
|
|
if self.raid_controller:
|
|
raider: Raider = self.raid_controller.is_in_raid(main.char_id)
|
|
if type(raider) == Raider:
|
|
if not raider.is_active:
|
|
self.bot.send_mass_message(request.sender.char_id,
|
|
"You are not participating in the raid, and cannot add to the loot.")
|
|
return
|
|
elif raider is None:
|
|
self.bot.send_mass_message(request.sender.char_id,
|
|
"You are not participating in the raid, and cannot add to the loot.")
|
|
return
|
|
try:
|
|
loot_item = self.loot_list[item_index]
|
|
old_item = self.is_already_added(request.sender.name)
|
|
if old_item:
|
|
if old_item.get_item_str() == loot_item.get_item_str():
|
|
name = "You have" if request.channel == "msg" else request.sender.name
|
|
self.bot.send_mass_message(request.sender.char_id,
|
|
"%s already added to %s." % (name, loot_item.get_item_str()))
|
|
old_item.bidders.remove(request.sender.name)
|
|
|
|
loot_item.bidders.append(request.sender.name)
|
|
|
|
self.last_modify = int(time.time())
|
|
|
|
if old_item is not None:
|
|
text = "moved from %s to %s." % (old_item.get_item_str(), loot_item.get_item_str())
|
|
self.bot.send_mass_message(request.sender.char_id, "You have %s" % text)
|
|
self.bot.send_private_channel_message(request.sender.name + " " + text)
|
|
else:
|
|
text = "added to %s." % loot_item.get_item_str()
|
|
self.bot.send_mass_message(request.sender.char_id, "You have %s" % text)
|
|
self.bot.send_private_channel_message(request.sender.name + " " + text)
|
|
|
|
except KeyError:
|
|
return "Wrong index given."
|
|
|
|
@command(command="loot", params=[Const("rem")], description="Remove yourself from item", access_level="member")
|
|
def loot_rem_from_cmd(self, request, _):
|
|
try:
|
|
loot_item = self.is_already_added(request.sender.name)
|
|
|
|
if loot_item is not None:
|
|
loot_item.bidders.remove(request.sender.name)
|
|
|
|
self.last_modify = int(time.time())
|
|
text = "removed from %s." % loot_item.get_item_str()
|
|
self.bot.send_private_message(request.sender.char_id, "You were %s" % text)
|
|
self.bot.send_private_channel_message(request.sender.name + " was " + text)
|
|
else:
|
|
return "You are not added to any loot."
|
|
except KeyError:
|
|
return "Wrong index given."
|
|
|
|
@command(command="loot", params=[Const("roll")], description="Roll all loot", access_level="leader",
|
|
sub_command="modify")
|
|
def loot_roll_cmd(self, request, _):
|
|
if not self.leader_controller.can_use_command(request.sender.char_id) if self.leader_controller else False:
|
|
return LeaderController.NOT_LEADER_MSG
|
|
|
|
if self.loot_list:
|
|
blob = ""
|
|
remove = []
|
|
for i, loot_item in self.loot_list.items():
|
|
winners = []
|
|
|
|
if loot_item.bidders:
|
|
if len(loot_item.bidders) <= loot_item.count:
|
|
winners = loot_item.bidders.copy()
|
|
loot_item.count -= len(loot_item.bidders)
|
|
loot_item.bidders = []
|
|
else:
|
|
for j in range(0, loot_item.count):
|
|
winner = secrets.choice(loot_item.bidders)
|
|
|
|
winners.append(winner)
|
|
loot_item.bidders.remove(winner)
|
|
loot_item.count = loot_item.count - 1 if loot_item.count > 0 else 0
|
|
for user in winners:
|
|
self.account_service.add_log(self.account_service.character_service.resolve_char_to_id(user),
|
|
"loot",
|
|
f"{loot_item.get_item_str()}",
|
|
request.sender.char_id)
|
|
blob += "%d. %s\n" % (i, loot_item.get_item_str())
|
|
blob += " | Winners: <red>%s<end>\n\n" % '<end>, <red>'.join(winners)
|
|
if loot_item.count == 0:
|
|
remove.append(i)
|
|
for i in remove:
|
|
self.loot_list.pop(i)
|
|
|
|
msg = ChatBlob("Roll results", blob)
|
|
msg.page_prefix = "Time is up! "
|
|
self.bot.send_private_channel_message(msg if len(blob) > 0 else "No one was added to any loot")
|
|
if self.loot_list:
|
|
count = 1
|
|
for key in sorted(list(self.loot_list.keys())):
|
|
if self.loot_list[key].count <= 0:
|
|
del self.loot_list[key]
|
|
else:
|
|
loot_item = self.loot_list[key]
|
|
del self.loot_list[key]
|
|
self.loot_list[count] = loot_item
|
|
count += 1
|
|
else:
|
|
return "No loot to roll."
|
|
|
|
@command(command="loot", params=[Const("addraiditem"), Int("raid_item_id"), Int("item_count")],
|
|
description="Add item from pre-defined raid to loot list", access_level="leader", sub_command="modify")
|
|
def loot_add_raid_item(self, request, _, raid_item_id: int, item_count: int):
|
|
if not self.leader_controller.can_use_command(request.sender.char_id) if self.leader_controller else False:
|
|
return LeaderController.NOT_LEADER_MSG
|
|
|
|
sql = "SELECT r.name, r.comment, r.ql, a.lowid AS low_id, a.highid AS high_id FROM aodb a " \
|
|
"LEFT JOIN raid_loot r ON (a.name = r.name AND a.highql >= r.ql) " \
|
|
"WHERE r.id = ? LIMIT 1"
|
|
item = self.db.query_single(sql, [raid_item_id])
|
|
|
|
if item:
|
|
self.add_item_to_loot(item, item.comment, item_count)
|
|
|
|
self.bot.send_private_channel_message("Added %s to loot list." % item.name)
|
|
else:
|
|
return "Failed to add item with ID %s." % raid_item_id
|
|
|
|
@command(command="loot", params=[Const("addraid"), Any("raid"), Any("category")],
|
|
description="Add all loot from pre-defined raid", access_level="leader", sub_command="modify")
|
|
def loot_add_raid_loot(self, request, _, raid: str, category: str):
|
|
if not self.leader_controller.can_use_command(request.sender.char_id) if self.leader_controller else False:
|
|
return LeaderController.NOT_LEADER_MSG
|
|
|
|
items = self.db.query(
|
|
"SELECT r.raid, r.category, r.id, r.ql, r.name, r.comment, r.multiloot, "
|
|
"a.lowid AS low_id, "
|
|
"a.highid AS high_id, a.icon "
|
|
"FROM raid_loot r "
|
|
"LEFT JOIN aodb a "
|
|
"ON (r.name = a.name AND r.ql <= a.highql) "
|
|
"WHERE r.raid = ? AND r.category = ? "
|
|
"ORDER BY r.name",
|
|
[raid, category]
|
|
)
|
|
|
|
if items:
|
|
for item in items:
|
|
self.add_item_to_loot(item, item.comment, item.multiloot)
|
|
|
|
self.bot.send_private_channel_message(f"{category} table was added to loot.")
|
|
else:
|
|
return f"{category} does not have any items registered in loot table."
|
|
|
|
@command(command="loot",
|
|
params=[Const("additem", is_optional=True), Int("item"), Int("item_count", is_optional=True)],
|
|
description="Add an item to loot list by item id", access_level="leader", sub_command="modify")
|
|
def loot_add_item_id_cmd(self, request, _, item_id, item_count: int):
|
|
if not self.leader_controller.can_use_command(request.sender.char_id) if self.leader_controller else False:
|
|
return LeaderController.NOT_LEADER_MSG
|
|
|
|
if item_count is None:
|
|
item_count = 1
|
|
|
|
item = self.items_controller.get_by_item_id(item_id)
|
|
if not item:
|
|
return f"Could not find item with ID <highlight>{item_id}<end>."
|
|
|
|
self.add_item_to_loot(item, item_count=item_count)
|
|
|
|
self.bot.send_private_channel_message("%s was added to loot list." % item.name)
|
|
|
|
@command(command="loot",
|
|
params=[Const("additem", is_optional=True), Any("item"), Int("item_count", is_optional=True)],
|
|
description="Add an item to loot list", access_level="leader", sub_command="modify")
|
|
def loot_add_item_cmd(self, request, _, item, item_count: int):
|
|
if not self.leader_controller.can_use_command(request.sender.char_id) if self.leader_controller else False:
|
|
return LeaderController.NOT_LEADER_MSG
|
|
loot = ""
|
|
if item_count is None:
|
|
item_count = 1
|
|
item = item.replace("'", "'")
|
|
items = re.findall(r"(([^<]+)?<a href=[\"\']itemref://(\d+)/(\d+)/(\d+)[\"\']>([^<]+)</a>([^<]+)?)", item)
|
|
if items and item_count == 1:
|
|
for item in items:
|
|
item = self.text.make_item(int(item[2]), int(item[3]), int(item[4]), item[5])
|
|
if loot != "":
|
|
loot += ", " + item
|
|
else:
|
|
loot += item
|
|
self.add_item_to_loot(item)
|
|
else:
|
|
loot += item
|
|
self.add_item_to_loot(item, item_count=item_count)
|
|
|
|
self.bot.send_private_channel_message(f"<highlight>{loot}<end> was added to loot list.")
|
|
|
|
@timerevent(budatime="1h",
|
|
description="Periodically check when loot list was last modified, and clear it "
|
|
"if last modification was done 1+ hours ago")
|
|
def loot_clear_event(self, _1, _2):
|
|
if self.loot_list and self.last_modify:
|
|
if int(time.time()) - self.last_modify > 3600 and self.loot_list:
|
|
self.last_modify = None
|
|
self.loot_list = OrderedDict()
|
|
self.bot.send_org_message("Loot was last modified more than 1 hour ago, list has been cleared.")
|
|
self.bot.send_private_channel_message(
|
|
"Loot was last modified more than 1 hour ago, list has been cleared.")
|
|
|
|
def is_already_added(self, name: str):
|
|
for i, loot_item in self.loot_list.items():
|
|
if name in loot_item.bidders:
|
|
return loot_item
|
|
return None
|
|
|
|
def add_item_to_loot(self, item, comment=None, item_count=1):
|
|
existing_item = next((loot_item for x, loot_item in self.loot_list.items() if loot_item.item == item), None)
|
|
if existing_item:
|
|
existing_item.count += 1
|
|
else:
|
|
# this prevents loot items from being re-numbered when items are removed
|
|
end_index = list(self.loot_list.keys())[-1] + 1 if len(self.loot_list) > 0 else 1
|
|
|
|
self.loot_list[end_index] = LootItem(item, comment, item_count)
|
|
|
|
self.last_modify = int(time.time())
|
|
|
|
def get_loot_list(self, edit=False):
|
|
blob = ""
|
|
remove = self.text.make_chatcmd("Remove from rolls", "/tell <myname> loot rem")
|
|
blob += f"[{remove}]\n\n"
|
|
for i, loot_item in self.loot_list.items():
|
|
bidders = loot_item.bidders
|
|
img = ""
|
|
|
|
if loot_item.get_item_str()[:2] == "<a" and loot_item.get_item_str()[-4:] == "</a>":
|
|
item = re.findall(r"(([^<]+)?<a href=[\"\']itemref://(\d+)/(\d+)/(\d+)[\"\']>([^<]+)</a>([^<]+)?)",
|
|
loot_item.get_item_str())
|
|
imgid = self.db.query_single("SELECT icon from aodb where lowid=? or highid=?",
|
|
[item[0][2], item[0][3]])
|
|
if imgid is not None:
|
|
img = self.text.make_image(imgid.get("icon")) + " - "
|
|
blob += f"{i:d}. {img}{item[0][0]} "
|
|
|
|
else:
|
|
blob += f"{i:d}. {loot_item.get_item_str()} "
|
|
blob += f"x{loot_item.count} [{self.text.make_chatcmd('Add', f'/tell <myname> loot add {i}')}]\n"
|
|
blob += " └ "
|
|
if edit:
|
|
blob += f"<yellow>[ {self.text.make_tellcmd('+1', f'loot increase {i}')} | " \
|
|
f"{self.text.make_tellcmd('-1', f'loot decrease {i}')} ]" \
|
|
f"[ {self.text.make_tellcmd('REM', f'loot remitem {i}')} ]</yellow>\n\n"
|
|
else:
|
|
if len(bidders) > 0:
|
|
blob += "<yellow>%s<end>\n\n" % ', '.join(bidders)
|
|
else:
|
|
blob += "<yellow>None added<end>\n\n"
|
|
|
|
return ChatBlob("Loot (%d)" % len(self.loot_list), blob)
|