def _get_custom_counters(self): out = [] for cons in self.character_data['consumables']: live_id = f"{cons['id']}-{cons['typeId']}" display_type = 'bubble' if cons['max'] < 7 else None reset = RESET_MAP.get(cons['reset'], 'long') name = cons['name'].replace('\u2019', "'").strip() desc = cons['desc'].replace('\u2019', "'") if cons['desc'] is not None else None source_feature_type = cons['sourceFeatureType'] source_feature_id = cons['sourceFeatureId'] source_feature = compendium.lookup_entity(source_feature_type, source_feature_id) log.debug(f"Processed counter named {name!r} for feature {source_feature}") if source_feature is None: log.warning(f"Could not find source feature ({source_feature_type}, {source_feature_id}) for counter " f"named {name!r}") if cons['max'] and name: # don't make counters with a range of 0 - 0, or blank named counters out.append( CustomCounter(None, name, cons['value'], minv='0', maxv=str(cons['max']), reset=reset, display_type=display_type, live_id=live_id, desc=desc, ddb_source_feature_type=source_feature_type, ddb_source_feature_id=source_feature_id) ) return [cc.to_dict() for cc in out]
async def get_monster(self): """ Gets the Monster associated with the event. Returns None if the event is not associated with a monster. :rtype: gamedata.monster.Monster or None """ if not self.event.entity_id: return None return compendium.lookup_entity('monster', int(self.event.entity_id))
async def admin_debug_entity(self, ctx, tid, eid: int = None): if eid is not None: e = compendium.lookup_entity(int(tid), eid) else: # noinspection PyProtectedMember options = list(compendium._entity_lookup.values()) e = await search_and_select( ctx, options, tid, lambda en: en.name, selectkey=lambda en: f"{en.name} ({en.entity_type})") entitlement_entity = compendium.lookup_entity( e.entitlement_entity_type, e.entitlement_entity_id) entitlement_entity_name = entitlement_entity.name if entitlement_entity is not None else 'unknown entity!' await ctx.send( f"```py\n" f"# {e.entity_id=}, {e.type_id=}\n" f"# {e.entitlement_entity_id=}, {e.entitlement_entity_type=} ({entitlement_entity_name})\n" f"{e!r}\n```")
async def workshop_entitlements_check(ctx, ws_obj): """ :type ws_obj: aliasing.workshop.WorkshopCollectableObject """ entitlements = ws_obj.get_entitlements() # this may take a while, so type await ctx.trigger_typing() # get licensed objects, mapped by entity type available_ids = { k: await ctx.bot.ddb.get_accessible_entities(ctx, ctx.author.id, k) for k in entitlements } # get a list of all missing entities for the license error missing = [] has_connected_ddb = True # run the checks for entity_type, required_ids in entitlements.items(): available_set = available_ids[entity_type] if available_set is None: # user has not connected DDB account has_connected_ddb = False # add all ids of this type to missing for missing_id in required_ids: entity = compendium.lookup_entity(entity_type, missing_id) if entity is not None: missing.append(entity) elif not available_set.issuperset(required_ids): # add the missing ids to missing for missing_id in set(required_ids).difference(available_set): entity = compendium.lookup_entity(entity_type, missing_id) if entity is not None: missing.append(entity) if missing: raise CollectableRequiresLicenses(missing, ws_obj, has_connected_ddb)
async def add_orkira(ctx, combat): priest = compendium.lookup_entity(Monster.entity_type, 16985) orkira = MonsterCombatant.from_monster(monster=priest, ctx=ctx, combat=combat, name="Orkira Illdrex", controller_id=str(ctx.author.id), init=1, private=False, hp=50) combat.add_combatant(orkira) await combat.final() return orkira
async def add_tarrasque(ctx, combat): tarrasque = compendium.lookup_entity(Monster.entity_type, 17034) terry = MonsterCombatant.from_monster( monster=tarrasque, ctx=ctx, combat=combat, name="TA1", controller_id=str(ctx.bot.user.id), init=12, private=True, ) combat.add_combatant(terry) await combat.final() return terry
async def test_usecounter_deserialize(): data = { 'type': 'counter', 'counter': 'Bardic Inspiration', 'amount': '5', 'allowOverflow': True, 'errorBehaviour': None } result = automation.UseCounter.from_data(data) assert result assert result.counter == 'Bardic Inspiration' assert result.amount == '5' assert result.allow_overflow is True assert result.error_behaviour is None data = { 'type': 'counter', 'counter': 'Bardic Inspiration', 'amount': '5' } result = automation.UseCounter.from_data(data) assert result assert result.allow_overflow is False assert result.error_behaviour == 'warn' data = { 'type': 'counter', 'counter': {'slot': 3}, 'amount': '1' } result = automation.UseCounter.from_data(data) assert result assert isinstance(result.counter, automation.effects.usecounter.SpellSlotReference) assert result.counter.slot == 3 data = { 'type': 'counter', 'counter': {'id': 75, 'typeId': 12168134}, 'amount': '5' } result = automation.UseCounter.from_data(data) assert result assert isinstance(result.counter, automation.effects.usecounter.AbilityReference) assert result.counter.entity is compendium.lookup_entity(12168134, 75)
def _get_spellbook(self): spellbook = self.character_data['spellbook'] max_slots = { '1': 0, '2': 0, '3': 0, '4': 0, '5': 0, '6': 0, '7': 0, '8': 0, '9': 0 } slots = { '1': 0, '2': 0, '3': 0, '4': 0, '5': 0, '6': 0, '7': 0, '8': 0, '9': 0 } for slot in spellbook['slots']: slots[str(slot['level'])] = slot['remaining'] max_slots[str(slot['level'])] = slot['available'] dcs = [] sabs = [] mods = [] spells = [] for spell in spellbook['spells']: spell_ab = spell['sab'] spell_dc = spell['dc'] spell_mod = spell['mod'] spell_prepared = spell['prepared'] or 'noprep' in self.args if spell_ab is not None: sabs.append(spell_ab) if spell_dc is not None: dcs.append(spell_dc) if spell_mod is not None: mods.append(spell_mod) result = compendium.lookup_entity(gamedata.Spell.entity_type, spell['id']) if result: spells.append( SpellbookSpell.from_spell(result, sab=spell_ab, dc=spell_dc, mod=spell_mod, prepared=spell_prepared)) else: spells.append( SpellbookSpell(spell['name'].strip(), sab=spell_ab, dc=spell_dc, mod=spell_mod, prepared=spell_prepared)) dc = max(dcs, key=dcs.count, default=None) sab = max(sabs, key=sabs.count, default=None) smod = max(mods, key=mods.count, default=None) # assumption: a character will only ever have one pact slot level, with a given number of slots of that level pact_slot_level = None num_pact_slots = None max_pact_slots = None if spellbook['pactSlots']: pact_info = spellbook['pactSlots'][0] pact_slot_level = pact_info['level'] max_pact_slots = pact_info['available'] num_pact_slots = max_pact_slots - pact_info['used'] return Spellbook(slots, max_slots, spells, dc, sab, self._get_levels().total_level, smod, pact_slot_level=pact_slot_level, num_pact_slots=num_pact_slots, max_pact_slots=max_pact_slots)
def lookup(cls, entity_id: int): """Utility method to look up an instance of this class from the compendium.""" from gamedata.compendium import compendium return compendium.lookup_entity(cls.entity_type, entity_id)