|
|
from re import compile as compile_re, escape as escape_re
|
|
|
from enum import Enum
|
|
|
from itertools import chain
|
|
|
from typing import Iterable
|
|
|
|
|
|
CantMoveEmoji = "◼"
|
|
|
DoneMovingEmoji = "☑️"
|
|
|
NotMovedEmoji = "🟦"
|
|
|
TurnsLeftEmoji = [
|
|
|
"0️⃣",
|
|
|
"1️⃣",
|
|
|
"2️⃣",
|
|
|
"3️⃣",
|
|
|
"4️⃣",
|
|
|
"5️⃣",
|
|
|
"6️⃣",
|
|
|
"7️⃣",
|
|
|
"8️⃣",
|
|
|
"9️⃣",
|
|
|
"🔟",
|
|
|
"#️⃣",
|
|
|
]
|
|
|
|
|
|
IndicatorKeys = {
|
|
|
None: "◼",
|
|
|
"0": "0️⃣",
|
|
|
"1": "1️⃣",
|
|
|
"2": "2️⃣",
|
|
|
"3": "3️⃣",
|
|
|
"4": "4️⃣",
|
|
|
"5": "5️⃣",
|
|
|
"6": "6️⃣",
|
|
|
"7": "7️⃣",
|
|
|
"8": "8️⃣",
|
|
|
"9": "9️⃣",
|
|
|
"A": "🇦",
|
|
|
"B": "🇧",
|
|
|
"C": "🇨",
|
|
|
"D": "🇩",
|
|
|
"E": "🇪",
|
|
|
"F": "🇫",
|
|
|
"G": "🇬",
|
|
|
"H": "🇭",
|
|
|
"I": "🇮",
|
|
|
"J": "🇯",
|
|
|
"K": "🇰",
|
|
|
"L": "🇱",
|
|
|
"M": "🇲",
|
|
|
"N": "🇳",
|
|
|
"O": "🇴",
|
|
|
"P": "🇵",
|
|
|
"Q": "🇶",
|
|
|
"R": "🇷",
|
|
|
"S": "🇸",
|
|
|
"T": "🇹",
|
|
|
"U": "🇺",
|
|
|
"V": "🇻",
|
|
|
"W": "🇼",
|
|
|
"X": "🇽",
|
|
|
"Y": "🇾",
|
|
|
"Z": "🇿",
|
|
|
}
|
|
|
|
|
|
|
|
|
def get_indicator_key(key: str) -> str:
|
|
|
return IndicatorKeys.get(key, IndicatorKeys[None])
|
|
|
|
|
|
|
|
|
EmojiDecoder: dict[str, str] = dict(chain(
|
|
|
((v, (f'[{k}]' if k is not None else '[ ]')) for k, v in IndicatorKeys.items()),
|
|
|
{'☑️': '[✓]', '🔟': '[#]', '#️⃣': '[#]', '🟦': '[ ]', '◼': '[✖]'}.items()
|
|
|
))
|
|
|
|
|
|
EmojiDecoderRe = compile_re('|'.join(escape_re(k) for k in EmojiDecoder.keys()))
|
|
|
|
|
|
|
|
|
def decode_emoji(v: str) -> str:
|
|
|
return EmojiDecoderRe.sub(lambda m: EmojiDecoder.get(m, m), v)
|
|
|
|
|
|
|
|
|
DiscordDecoderRe = compile_re(r'\\([\\*|~_`])')
|
|
|
DiscordSplitterRe = compile_re(r'(?<!\\)\*\*')
|
|
|
|
|
|
|
|
|
def decode_discord(v: str, normal_style: str, bold_style: str) -> Iterable[tuple[str, str]]:
|
|
|
return [(normal_style if index % 2 == 0 else bold_style,
|
|
|
DiscordDecoderRe.sub(lambda m: m[1], decode_emoji(text)))
|
|
|
for index, text in enumerate(DiscordSplitterRe.split(v))]
|
|
|
|
|
|
|
|
|
class Affinity(Enum):
|
|
|
Absorb = "absorb"
|
|
|
Immune = "immune"
|
|
|
Resistant = "resistant"
|
|
|
Normal = "normal"
|
|
|
Vulnerable = "vulnerable"
|
|
|
|
|
|
|
|
|
class Element(Enum):
|
|
|
NonElemental = "non-elemental"
|
|
|
Physical = "physical"
|
|
|
Poison = "poison"
|
|
|
Fire = "fire"
|
|
|
Water = "water"
|
|
|
Lightning = "lightning"
|
|
|
Earth = "earth"
|
|
|
Wind = "wind"
|
|
|
Ice = "ice"
|
|
|
Light = "light"
|
|
|
Dark = "dark"
|
|
|
Healing = "healing"
|
|
|
|
|
|
|
|
|
class CharacterType(Enum):
|
|
|
PlayerCharacter = "pc"
|
|
|
NonPlayerCharacter = "npc"
|
|
|
|
|
|
@property
|
|
|
def sp_name_abbr(self):
|
|
|
if self is CharacterType.PlayerCharacter:
|
|
|
return "FP"
|
|
|
elif self is CharacterType.NonPlayerCharacter:
|
|
|
return "UP"
|
|
|
else:
|
|
|
return "SP"
|
|
|
|
|
|
@property
|
|
|
def sp_name(self):
|
|
|
if self is CharacterType.PlayerCharacter:
|
|
|
return "Fabula Points"
|
|
|
elif self is CharacterType.NonPlayerCharacter:
|
|
|
return "Ultima Points"
|
|
|
else:
|
|
|
return "Special Points"
|
|
|
|
|
|
|
|
|
class Visibility(Enum):
|
|
|
ShowEvenIfKO = "show_even_if_ko"
|
|
|
ShowAll = "show"
|
|
|
MaskStats = "mask_stats"
|
|
|
MaskName = "mask_name"
|
|
|
Hide = "hide"
|
|
|
|
|
|
@property
|
|
|
def show_name(self):
|
|
|
return self not in (Visibility.MaskName, Visibility.Hide)
|
|
|
|
|
|
@property
|
|
|
def show_stats(self):
|
|
|
return self not in (Visibility.MaskStats, Visibility.MaskName, Visibility.Hide)
|
|
|
|
|
|
def show_in_party_list(self, down=False):
|
|
|
if down:
|
|
|
return self == Visibility.ShowEvenIfKO
|
|
|
else:
|
|
|
return self != Visibility.Hide
|
|
|
|
|
|
|
|
|
class Counter(Enum):
|
|
|
HP = "HP"
|
|
|
MP = "MP"
|
|
|
IP = "IP"
|
|
|
SP = "SP"
|
|
|
|
|
|
def ctr_name_abbr(self, t: CharacterType) -> str:
|
|
|
if self == Counter.SP:
|
|
|
return t.sp_name_abbr
|
|
|
else:
|
|
|
return self.value
|
|
|
|
|
|
def ctr_name(self, t: CharacterType) -> str:
|
|
|
if self == Counter.HP:
|
|
|
return "Hit Points"
|
|
|
if self == Counter.MP:
|
|
|
return "Mind Points"
|
|
|
if self == Counter.IP:
|
|
|
return "Inventory Points"
|
|
|
if self == Counter.SP:
|
|
|
return t.sp_name
|
|
|
|
|
|
|
|
|
class MissType(Enum):
|
|
|
Dodged = "dodged"
|
|
|
Missed = "missed"
|
|
|
Blocked = "blocked"
|
|
|
Avoided = "avoided"
|
|
|
Repelled = "repelled"
|
|
|
Countered = "countered"
|
|
|
Parried = "parried"
|
|
|
Shielded = "shielded"
|
|
|
Resisted = "resisted"
|
|
|
Immunity = "immune"
|
|
|
Protected = "protected"
|
|
|
|
|
|
|
|
|
class CombatSide(Enum):
|
|
|
Heroes = "heroes"
|
|
|
Villains = "villains"
|
|
|
|
|
|
@property
|
|
|
def opposite(self):
|
|
|
if self == CombatSide.Heroes:
|
|
|
return CombatSide.Villains
|
|
|
else:
|
|
|
return CombatSide.Heroes
|
|
|
|
|
|
|
|
|
class ClockIcon(Enum):
|
|
|
Hourglass = "⏳"
|
|
|
EmptyHourglass = "⌛"
|
|
|
Warning = "⚠"
|
|
|
Lightning = "⚡"
|
|
|
Silhouettes = "👥"
|
|
|
Flame = "🔥"
|
|
|
Sparkles = "✨"
|
|
|
Candle = "🕯"
|
|
|
Star = "⭐"
|
|
|
ShiningStar = "🌟"
|
|
|
ShootingStar = "🌠"
|
|
|
Dragon = "🐲"
|
|
|
Robot = "🤖"
|
|
|
Silhouette = "👤"
|
|
|
Question = "❓"
|
|
|
Skull = "💀"
|
|
|
AlarmClock = "⏰"
|
|
|
Stopwatch = "⏱️"
|
|
|
Watch = "⌚"
|
|
|
Clock = "🕓"
|
|
|
Gem = "💎"
|
|
|
Sleep = "💤"
|
|
|
Sound = "🔊"
|
|
|
Heart = "❤️"
|
|
|
|
|
|
|
|
|
class ClockTicks(Enum):
|
|
|
Good = "🟦/🔸"
|
|
|
Bad = "🟧/🔹"
|
|
|
Tug = "🟦/🟧"
|
|
|
|
|
|
@property
|
|
|
def empty(self):
|
|
|
return self.value.split('/')[1]
|
|
|
|
|
|
@property
|
|
|
def full(self):
|
|
|
return self.value.split('/')[0]
|
|
|
|