diff --git a/bot/helpers/qud_decode.py b/bot/helpers/qud_decode.py index cc78d41..a1a1a7c 100644 --- a/bot/helpers/qud_decode.py +++ b/bot/helpers/qud_decode.py @@ -9,8 +9,11 @@ from hagadias.qudtile import QudTile from bot.shared import gameroot + gamecodes = gameroot.get_character_codes() +ATTR_NAMES = ("Strength", "Agility", "Toughness", "Intelligence", "Willpower", "Ego") + class Character: """Represents a Caves of Qud player character. This class is intended for modern build codes @@ -52,7 +55,9 @@ def __init__(self, code: dict): case ['XRL.CharacterBuilds.Qud.QudAttributesModule', *_]: pointspurchased = module['data']['PointsPurchased'] base = 10 if self.genotype == 'Mutated Human' else 12 - self.attributes = [base + attr for name, attr in pointspurchased.items()] + self.attributes = [] + for attribute in ATTR_NAMES: + self.attributes.append(base + pointspurchased[attribute]) case ['XRL.CharacterBuilds.Qud.QudCustomizeCharacterModule', *_]: self.name = module['data']['name'] self.pet = module['data']['pet'] @@ -69,11 +74,10 @@ def __init__(self, code: dict): def make_sheet(self) -> str: """Build a printable character sheet for the Character.""" attr_widths = (11, 11, 11, 14, 14, 14) - attr_names = ('Strength:', 'Agility:', 'Toughness:', 'Intelligence:', 'Willpower:', 'Ego:') attr_strings = [] - for width, attr_text, attr, bonus in zip(attr_widths, - attr_names, + for width, attr_name, attr, bonus in zip(attr_widths, + ATTR_NAMES, self.attributes, self.bonuses): # print a +/- in front of any existing bonus @@ -83,15 +87,15 @@ def make_sheet(self) -> str: bonus_text = f'{bonus}' # already has a minus sign else: bonus_text = '' - attr_strings.append(f'{attr_text:{width}}{attr:2}{bonus_text}') + attr_strings.append(f'{attr_name:{width}}{attr:2}{bonus_text}') if hasattr(self, 'name') and self.name is not None: title = f'{self.name} the {self.genotype} {self.subtype}' else: title = f'{self.genotype} {self.subtype}' charsheet = f"""{title} -{attr_strings[0]:18}{attr_strings[3]} -{attr_strings[1]:18}{attr_strings[4]} -{attr_strings[2]:18}{attr_strings[5]}""" +{attr_strings[0]:20}{attr_strings[3]} +{attr_strings[1]:20}{attr_strings[4]} +{attr_strings[2]:20}{attr_strings[5]}""" charsheet += f"\n{self.selection_noun}s: {', '.join(self.selections)}\n" charsheet += f"Starting location: {self.startinglocation}" return charsheet diff --git a/tests/qud_decode_test.py b/tests/qud_decode_test.py new file mode 100644 index 0000000..a20e3e6 --- /dev/null +++ b/tests/qud_decode_test.py @@ -0,0 +1,61 @@ +"""Tests for the newstyle character code decoder.""" +import base64 +import gzip +import json + +import pytest + +from bot.helpers.qud_decode import Character + +# Test cases are lists in this format: +# [ +# build code, +# [expected attributes in game order], +# [expected bonuses in game order] +# ] + +# game order is Strength, Agility, Toughness, Intelligence, Willpower, Ego + +CASES = [ + [ + "H4sIAAAAAAAAA81WXW/aMBR9r9T/YEV7DIgiNnWVeGDpNra1EmtoO2nqg5PcJV4d2/LHKob477MNhSSsg05qBBIKvud+HO49ufL8+AihIMcl/AKpCGfBGQr63V633xt0X58GoccTQ2hWcTixDr0VVvLMUFDW/N2dEZovH2toOhPggr5dXXSjAkucapDvXEbV/Woy9/0IjGvrdukDQjRSCsqEzjpRbANEiG6WtYcbZiGKDNVGwpCB0RLTEE1MQkn6BWZTfg9syAylS46eTIY1tjTW7KzplX4utXObZIvepojN+ejv0l4ajTVkaGxKzGpeW718xBbLH4vwv3sZm+RAW1ljtruTK3eXNE4LTrFsq4V+bja3OsAmNrjtbmMpbMZe1aKAQupzbF7a5WdePaCVgFdNjgpSgsTV3N4n4oZp63DSBG6wJNhDvSqyCPetOOb8XqEfXKIPALrFwtMH3hkDziBrs6gkgkLnJydMt1r4nFudQqc0KqWtFr5mSmNbGrmdWcKTlfv7Vt4c7lraFCOtJUmMhkNcFU1yu3fFxIlPTYxMC6ysFs7q8wtGOaFEz6z9bW0mwfucW+ObuvGTFTKlJAeWOqqndTTWEliui+24KTd5wUCp7aBbQqngDyBd1Aapai7AIhbg1dEZDOrAFZSYMMLy5kpM7N8duUVZj3hB5URGaV6S37DGD1BBT5HcrSRmb5R+h2OWzVBMTV6DBbj5OJJVq1VK5kfbBITkzC6D+K9RLzmkgnMFscZSW9Fc8NTvrkMc1D+I7nHTasS5Yp+5EPh5Fy73uDs+WvwB4vrnYFQMAAA=", # noqa E501 + [16, 19, 18, 18, 16, 16], # attributes + [2, 2, 0, 2, 0, 0], # bonuses + ], + [ + "H4sIAAAAAAAAA81W22rbQBB9D+QfFtFHxTjBbdOAHxQl9JIE3MikhZKHlTSVl6x2xV5SVON/76zk2JKc1ElLhA1G1pyZM8dzWXa+v0eIl9Ec7kFpJoV3QryjwXBwNBwN3h57foXHlvG04XCIDsMllsvUctBo/uHeCZnXjxU0LQtwQd+vLwfhjCqaGFCnjlEPvtrUfT+CkAbdrqoAnwRaQx7z8iCMMKDwyU2de7xW5pPQcmMVjAVYoyj3ycTGnCUXUE7lHYixsJzXGisxKTUUZazUoemNeam0MyTZkLdOgpwP/o72yhpqICWfbE5Fy2ujlg/Yov6x8P+5lpGNd7SULWXbK7l0d6QTxjPF8r5KWPUNufUOFrGjbXsZ8wIZh02LBg5JxbFe2vozb76Q5QAvi3zughRLKCc446BqwO9EhNIKg+6HXeCGKkYraNhEFv5z859ChoVgIusx51QKlpCAc1BZ2WPeM5kz0XeBQ06ZupclFQn8f9r1y21PWxsYHM/YGtjFte2K2763E8mE0ROrkhnVkLZzIh5kuA2mRPv7Vk+880yi8UPb+FkY4Jxl4Jp7Qt610cgoEJmZbZJNpc1mArQ7Ko7b0DfGeSF/gXJ8a6Q5cB4togKq6TgYjdrANeSUCbfPneMpxr8buEOrHfGKkxNabXDjfsMK38EJekrk9kkSeLtz5Bf05x1tIQW41jh9TSsOSVp1tQsUSgo8B6JHo16zPzMpNUSGKoPzcimT6szaxR79RegzLjydOJfsiywK+rJ7j3vc7u8t/gCu1vr52wsAAA==", # noqa E501 + [17, 17, 18, 16, 16, 19], # attributes + [0, 0, 0, 0, 2, 0], # bonuses + ], +] + + +@pytest.mark.parametrize("test_input,expected_attrs,_", CASES) +def test_decode_attributes(test_input, expected_attrs, _): + """Check the decoded attributes against the expected attributes.""" + decode = base64.b64decode(test_input) + unzip = gzip.decompress(decode).decode(encoding='utf-8') + code = json.loads(unzip) + char = Character(code) + assert char.attributes == expected_attrs + + +@pytest.mark.parametrize("test_input,_,expected_bonuses", CASES) +def test_decode_bonuses(test_input, _, expected_bonuses): + """Check the decoded bonuses against the expected bonuses.""" + decode = base64.b64decode(test_input) + unzip = gzip.decompress(decode).decode(encoding='utf-8') + code = json.loads(unzip) + char = Character(code) + assert char.bonuses == expected_bonuses + + +@pytest.mark.parametrize("test_input,_,__", CASES) +def test_decode_make_sheet(test_input, _, __): + """Check that a text sheet can be rendered from each character code.""" + decode = base64.b64decode(test_input) + unzip = gzip.decompress(decode).decode(encoding='utf-8') + code = json.loads(unzip) + char = Character(code) + sheet = char.make_sheet() + assert len(sheet) > 100