Skip to content

Commit

Permalink
fix(gameplay): improve roll display (#154)
Browse files Browse the repository at this point in the history
  • Loading branch information
natelandau authored Jun 15, 2024
1 parent 3778274 commit 8971071
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 75 deletions.
28 changes: 26 additions & 2 deletions src/valentina/cogs/developer.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,24 @@
from loguru import logger

from valentina.characters import RNGCharGen
from valentina.constants import PREF_MAX_EMBED_CHARACTERS, CharClass, EmbedColor, LogLevel
from valentina.constants import (
PREF_MAX_EMBED_CHARACTERS,
CharClass,
EmbedColor,
InventoryItemType,
LogLevel,
)
from valentina.models import (
AWSService,
Campaign,
CampaignBook,
CampaignBookChapter,
ChangelogPoster,
Character,
CharacterSheetSection,
GlobalProperty,
Guild,
InventoryItem,
RollProbability,
User,
)
Expand Down Expand Up @@ -188,8 +196,24 @@ async def create_dummy_data(self, ctx: ValentinaContext) -> None: # noqa: C901
)
created_characters.append(character)

# Associated characters with campaigns
# Add inventory & custom sections to characters and associate characters with campaigns
for character in created_characters:
for _ in range(3):
i = InventoryItem(
name=Faker().sentence(nb_words=2).rstrip("."),
description=Faker().sentence(),
character=str(character.id),
type=random.choice([x.name for x in InventoryItemType]),
)
item = await i.insert()
character.inventory.append(item)

section = CharacterSheetSection(
title=Faker().sentence(nb_words=3).rstrip("."),
content=Faker().paragraph(nb_sentences=3),
)
character.sheet_sections.append(section)

campaign = random.choice(created_campaigns)
character.campaign = str(campaign.id)
await character.save()
Expand Down
44 changes: 44 additions & 0 deletions src/valentina/utils/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,50 @@
_rng = default_rng()


def convert_int_to_emoji(num: int, markdown: bool = False) -> str:
"""Convert an integer to an emoji or a string.
Args:
num (int): The integer to convert.
markdown (bool, optional): Whether to wrap numbers larger than emojis in markdown code. Defaults to False.
Returns:
str: The emoji corresponding to the integer.
Examples:
>>> convert_int_to_emoji(1)
':one:'
>>> convert_int_to_emoji(10)
':keycap_ten:'
>>> convert_int_to_emoji(11)
'11'
>>> convert_int_to_emoji(11, markdown=True)
'`11`'
"""
if -1 <= num <= 10: # noqa: PLR2004
return (
str(num)
.replace("10", ":keycap_ten:")
.replace("0", ":zero:")
.replace("1", ":one:")
.replace("2", ":two:")
.replace("3", ":three:")
.replace("4", ":four:")
.replace("5", ":five:")
.replace("6", ":six:")
.replace("7", ":seven:")
.replace("8", ":eight:")
.replace("9", ":nine:")
)
if markdown:
return f"`{num}`"

return str(num)


def random_num(ceiling: int = 100) -> int:
"""Get a random number between 1 and ceiling."""
return _rng.integers(1, ceiling + 1)
Expand Down
59 changes: 19 additions & 40 deletions src/valentina/views/character_sheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
InventoryItemType,
TraitCategory,
)
from valentina.models import AWSService, Character, CharacterTrait, InventoryItem, Statistics
from valentina.models import AWSService, Character, CharacterTrait, Statistics
from valentina.models.bot import ValentinaContext


Expand Down Expand Up @@ -142,6 +142,7 @@ async def __embed2(
) -> discord.Embed:
"""Builds the second embed of a character sheet. This embed contains the character's bio and custom sections."""
custom_sections = character.sheet_sections
items = character.inventory

if title is None:
title = f"{character.full_name} - Page 2"
Expand All @@ -157,6 +158,23 @@ async def __embed2(
if character.bio:
embed.add_field(name="**BIOGRAPHY**", value=character.bio, inline=False)

if items:
embed.add_field(name="\u200b", value="**INVENTORY**", inline=False)
for member in InventoryItemType:
sub_items = [i for i in items if i.type == member.name] # type: ignore [attr-defined]
content = ""
for i in sub_items:
line_begin = "- "
name = f"**{i.name}**" # type: ignore [attr-defined]
desc = f": {i.description}" if i.description else "" # type: ignore [attr-defined]
line_end = "\n"
content += f"{line_begin}{name}{desc}{line_end}"

if sub_items:
embed.add_field(name=f"__**{member.value}**__", value=content, inline=False)
else:
embed.add_field(name="**EMPTY INVENTORY**", value="No items in inventory", inline=False)

if len(custom_sections) > 0:
embed.add_field(name="\u200b", value="**CUSTOM SECTIONS**", inline=False)
for section in custom_sections:
Expand All @@ -175,44 +193,6 @@ async def __embed2(
return embed


async def __embed3(
character: Character,
owned_by_user: discord.User | None = None,
title: str | None = None,
show_footer: bool = True,
) -> discord.Embed | None:
"""Builds the third embed of a character sheet. This embed contains the character's inventory."""
items = await InventoryItem.find(InventoryItem.character == str(character.id)).to_list()
if title is None:
title = f"{character.full_name} - INVENTORY - Page 3"

embed = discord.Embed(title=title, description="", color=EmbedColor.INFO.value)

if show_footer:
modified = arrow.get(character.date_modified).humanize()
footer = f"Owned by: {owned_by_user.display_name} • " if owned_by_user else ""
footer += f"Last updated: {modified}"
embed.set_footer(text=footer)

if items:
for member in InventoryItemType:
sub_items = [i for i in items if i.type == member.name]
content = ""
for i in sub_items:
line_begin = "- "
name = f"**{i.name}**"
desc = f": {i.description}" if i.description else ""
line_end = "\n"
content += f"{line_begin}{name}{desc}{line_end}"

if sub_items:
embed.add_field(name=f"__**{member.value}**__", value=content, inline=False)
else:
embed.add_field(name="**EMPTY INVENTORY**", value="No items in inventory", inline=False)

return embed


def __image_embed(
character: Character,
image_key: str,
Expand Down Expand Up @@ -253,7 +233,6 @@ async def show_sheet(
[
__embed1(character, owned_by_user, show_footer=show_footer),
await __embed2(ctx, character, owned_by_user, show_footer=show_footer),
await __embed3(character, owned_by_user, show_footer=show_footer),
]
)

Expand Down
83 changes: 50 additions & 33 deletions src/valentina/views/roll_display.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from valentina.constants import Emoji
from valentina.models import CharacterTrait, DiceRoll
from valentina.models.bot import ValentinaContext
from valentina.utils.helpers import convert_int_to_emoji

p = inflect.engine()

Expand Down Expand Up @@ -41,59 +42,75 @@ def _add_comment_field(self, embed: discord.Embed) -> discord.Embed:

async def get_embed(self) -> discord.Embed:
"""The graphical representation of the roll."""
roll_string = " ".join(f"{die}" for die in self.roll.roll)
roll_string = " ".join(
f"{convert_int_to_emoji(die, markdown=True)}" for die in self.roll.roll
)

if self.desperation_pool > 0:
desperation_roll_string = " ".join(f"{die}" for die in self.roll.desperation_roll)
desperation_roll_string = " ".join(
f"{convert_int_to_emoji(die, markdown=True)}" for die in self.roll.desperation_roll
)

description = f"""\
### {self.ctx.author.mention} rolled `{self.desperation_pool + self.roll.pool}{self.roll.dice_type.name.lower()}`
## {self.roll.embed_title}
{self.roll.embed_description}
"""

description += f"""\
### Rolled Dice:
```scala
Roll : {roll_string}
{"Desperation : " + desperation_roll_string if self.desperation_pool > 0 else ""}
```
"""
embed = discord.Embed(
title=None,
description=description,
color=self.roll.embed_color,
)

# Rolled dice
value = f"{roll_string}"
if self.desperation_pool > 0:
value += f" + {desperation_roll_string}"

embed.add_field(name="Rolled Dice", value=f"{value}", inline=False)

if self.desperation_pool > 0 and self.roll.desperation_botches > 0:
description += f"""\
### {Emoji.FACEPALM.value} `{self.roll.desperation_botches}` Desperation {p.plural_noun('botch', self.roll.desperation_botches)}
embed.add_field(name="\u200b", value="\u200b", inline=False) # spacer
value = f"""\
> You must pick either:
> - {Emoji.DESPAIR.value} **Despair** (Fail your roll)
> - {Emoji.OVERREACH.value} **Overreach** (Succeed but raise the danger level by 1)
"""

description += f"""\
### Roll Details:
```scala
Difficulty : {self.roll.difficulty}
Pool : {self.roll.pool}{self.roll.dice_type.name.lower()}
"""
embed.add_field(
name=f"**{Emoji.FACEPALM.value} {self.roll.desperation_botches} Desperation {p.plural_noun('botch', self.roll.desperation_botches)}**",
value=f"{value}",
inline=False,
)

embed.add_field(name="Difficulty", value=f"`{self.roll.difficulty}`", inline=True)
embed.add_field(
name="Dice Pool",
value=f"`{self.roll.pool}{self.roll.dice_type.name.lower()}`",
inline=True,
)

if self.desperation_pool > 0:
description += f"""\
Desperation Pool : {self.desperation_pool}{self.roll.dice_type.name.lower()}
Total Dice Rolled: {self.desperation_pool + self.roll.pool}{self.roll.dice_type.name.lower()}
"""
embed.add_field(
name="Desperation Pool",
value=f"`{self.desperation_pool}{self.roll.dice_type.name.lower()}`",
inline=True,
)

if self.trait_one:
description += f"{self.trait_one.name:<17}: {self.trait_one.value} {p.plural_noun('die', self.trait_one.value)}\n"
embed.add_field(name="\u200b", value="**TRAITS**", inline=False)
embed.add_field(
name=f"{self.trait_one.name}",
value=f"`{self.trait_one.value} {p.plural_noun('die', self.trait_one.value)}`",
inline=True,
)
if self.trait_two:
description += f"{self.trait_two.name:<17}: {self.trait_two.value} {p.plural_noun('die', self.trait_two.value)}\n"

description += "```"

embed = discord.Embed(
title=None,
description=description,
color=self.roll.embed_color,
)
embed.add_field(
name=f"{self.trait_two.name}",
value=f"`{self.trait_two.value} {p.plural_noun('die', self.trait_two.value)}`",
inline=True,
)

# Thumbnail
embed.set_thumbnail(url=await self.roll.thumbnail_url())

return self._add_comment_field(embed)
Expand Down

0 comments on commit 8971071

Please sign in to comment.