Skip to content

Commit

Permalink
refactor(experience): move xp logic to GuildUser object (#64)
Browse files Browse the repository at this point in the history
* feat: add chargen enums

* refactor(experience): move add/spend/fetch experience to `GuildUser` object
  • Loading branch information
natelandau committed Sep 28, 2023
1 parent 00a3503 commit 5b1df20
Show file tree
Hide file tree
Showing 9 changed files with 449 additions and 102 deletions.
2 changes: 1 addition & 1 deletion src/valentina/cogs/characters.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ async def list_characters(
text += f"**{character.name}**\n"
text += "```\n"
text += f"Class: {character.char_class.name:<20} Created On: {character.created.split(' ')[0]}\n"
text += f"Alive: {alive:<20} Active: {character.is_active}\n"
text += f"Alive: {alive:<20} Active: {bool(character.is_active)}\n"
text += f"Owner: {character.owned_by.data['display_name']:<20}\n"
text += "```\n"

Expand Down
91 changes: 25 additions & 66 deletions src/valentina/cogs/experience.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,32 +64,21 @@ async def xp_add(
)
return

campaign = self.bot.campaign_svc.fetch_active(ctx).id

campaign_xp = user.data.get(f"{campaign}_experience", 0)
campaign_total_xp = user.data.get(f"{campaign}_total_experience", 0)
lifetime_xp = user.data.get("lifetime_experience", 0)

new_xp = campaign_xp + amount
new_total_xp = campaign_total_xp + amount
new_lifetime_xp = lifetime_xp + amount
campaign = self.bot.campaign_svc.fetch_active(ctx)

title = f"Add `{amount}` xp to `{user.data['display_name']}`"
is_confirmed, confirmation_response_msg = await confirm_action(ctx, title, hidden=hidden)

description = "View experience with `/user_info`"
is_confirmed, confirmation_response_msg = await confirm_action(
ctx, title, description=description, hidden=hidden
)
if not is_confirmed:
return

await self.bot.user_svc.update_or_add(
ctx,
user=user,
data={
f"{campaign}_experience": new_xp,
f"{campaign}_total_experience": new_total_xp,
"lifetime_experience": new_lifetime_xp,
},
)
# Make the database updates
user.add_experience(campaign.id, amount)
self.bot.user_svc.purge_cache(ctx)

# Send the confirmation message
await self.bot.guild_svc.send_to_audit_log(ctx, title)
await confirmation_response_msg

Expand All @@ -110,7 +99,7 @@ async def cp_add(
default=False,
),
) -> None:
"""Add experience to a user."""
"""Add cool points to a user."""
if not user:
user = await self.bot.user_svc.fetch_user(ctx)
else:
Expand All @@ -126,40 +115,24 @@ async def cp_add(
)
return

campaign = self.bot.campaign_svc.fetch_active(ctx).id

campaign_xp = user.data.get(f"{campaign}_experience", 0)
campaign_total_xp = user.data.get(f"{campaign}_total_experience", 0)
campaign_total_cp = user.data.get(f"{campaign}_total_cool_points", 0)
lifetime_xp = user.data.get("lifetime_experience", 0)
lifetime_cp = user.data.get("lifetime_cool_points", 0)

xp_amount = amount * COOL_POINT_VALUE
new_xp = campaign_xp + xp_amount
new_total_xp = campaign_total_xp + xp_amount
new_lifetime_xp = lifetime_xp + xp_amount
new_lifetime_cp = lifetime_cp + amount
campaign = self.bot.campaign_svc.fetch_active(ctx)

title = (
f"Add `{amount}` cool {p.plural_noun('point', amount)} to `{user.data['display_name']}`"
)
is_confirmed, confirmation_response_msg = await confirm_action(ctx, title, hidden=hidden)

description = "View cool points with `/user_info`"
is_confirmed, confirmation_response_msg = await confirm_action(
ctx, title, description=description, hidden=hidden
)
if not is_confirmed:
return

await self.bot.user_svc.update_or_add(
ctx,
user=user,
data={
f"{campaign}_experience": new_xp,
f"{campaign}_total_experience": new_total_xp,
f"{campaign}_total_cool_points": campaign_total_cp + amount,
"lifetime_cool_points": new_lifetime_cp,
"lifetime_experience": new_lifetime_xp,
},
)
# Make the database updates
user.add_cool_points(campaign.id, amount)
user.add_experience(campaign.id, amount * COOL_POINT_VALUE)
self.bot.user_svc.purge_cache(ctx)

# Send the confirmation message
await self.bot.guild_svc.send_to_audit_log(ctx, title)
await confirmation_response_msg

Expand All @@ -186,7 +159,7 @@ async def xp_spend(
),
) -> None:
"""Spend experience points."""
campaign = self.bot.campaign_svc.fetch_active(ctx).id
campaign = self.bot.campaign_svc.fetch_active(ctx)
old_trait_value = character.get_trait_value(trait)
category = trait.category.name

Expand Down Expand Up @@ -214,34 +187,20 @@ async def xp_spend(
)
return

current_xp = character.owned_by.data.get(f"{campaign}_experience", 0)
remaining_xp = current_xp - upgrade_cost
new_trait_value = old_trait_value + 1
new_experience = current_xp - upgrade_cost

if remaining_xp < 0:
await present_embed(
ctx,
title="Error: Not enough XP",
description=f"**{trait.name}** upgrade cost is `{upgrade_cost}` xp. You only have `{current_xp}` xp.",
level="error",
ephemeral=True,
)
return

title = f"Upgrade `{trait.name}` from `{old_trait_value}` {p.plural_noun('dot', old_trait_value)} to `{new_trait_value}` {p.plural_noun('dot', new_trait_value)} for `{upgrade_cost}` xp"
is_confirmed, confirmation_response_msg = await confirm_action(ctx, title, hidden=hidden)
if not is_confirmed:
return

# Make the database updates
user = character.owned_by
user.spend_experience(campaign.id, upgrade_cost)
character.set_trait_value(trait, new_trait_value)
await self.bot.user_svc.update_or_add(
ctx,
user=character.owned_by,
data={f"{campaign}_experience": new_experience},
)
self.bot.user_svc.purge_cache(ctx)

# Send the confirmation message
await self.bot.guild_svc.send_to_audit_log(ctx, title)
await confirmation_response_msg

Expand Down
95 changes: 62 additions & 33 deletions src/valentina/cogs/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from discord.commands import Option
from discord.ext import commands

from valentina.constants import SPACER, DiceType, EmbedColor
from valentina.constants import DiceType, EmbedColor
from valentina.models import Probability, Statistics
from valentina.models.bot import Valentina
from valentina.models.db_tables import Character, Macro
Expand Down Expand Up @@ -92,7 +92,7 @@ async def server_info(

embed.add_field(
name="Roll Statistics",
value=roll_stats.get_text(with_title=False),
value=roll_stats.get_text(with_title=False, with_help=True),
inline=False,
)
embed.set_footer(
Expand Down Expand Up @@ -149,7 +149,7 @@ async def user_info(
"""View information about a user."""
target = user or ctx.author
db_user = await self.bot.user_svc.fetch_user(ctx=ctx, user=target)

campaign = self.bot.campaign_svc.fetch_active(ctx)
# Variables for embed
num_characters = (
Character.select()
Expand All @@ -164,49 +164,78 @@ async def user_info(
Macro.select().where(Macro.guild == ctx.guild.id, Macro.user == db_user).count()
)

creation_date = ((target.id >> 22) + 1420070400000) // 1000
roles = ", ".join(r.mention for r in target.roles[::-1][:-1]) or "_Member has no roles_"
roll_stats = Statistics(ctx, user=target)
lifetime_xp = db_user.data.get("lifetime_experience", 0)
lifetime_cp = db_user.data.get("lifetime_cool_points", 0)
campaign = self.bot.campaign_svc.fetch_active(ctx)
campaign_xp = db_user.data.get(f"{campaign.id}_experience", 0)
campaign_total_xp = db_user.data.get(f"{campaign.id}_total_experience", 0)
campaign_cp = db_user.data.get(f"{campaign.id}_total_cool_points", 0)

# Build Embed
description = (
f"# {target.display_name}",
"### __Account Information__",
f"**Account Created :** <t:{creation_date}:R> on <t:{creation_date}:D>",
f"**Joined Server{SPACER * 7}:** <t:{int(target.joined_at.timestamp())}:R> on <t:{int(target.joined_at.timestamp())}:D>",
f"**Roles{SPACER * 24}:** {roles}",
"### __Campaign Information__",
f"Available Experience{SPACER * 2}: `{campaign_xp}`",
f"Total Experience{SPACER * 10}: `{campaign_total_xp}`",
f"Cool Points{SPACER * 20}: `{campaign_cp}`",
"### __Experience Information__",
f"Lifetime Experience{SPACER * 3}: `{lifetime_xp}`",
f"Lifetime Cool Points{SPACER * 2}: `{lifetime_cp}`",
"### __Gameplay Information__",
f"Player Characters{SPACER * 2}: `{num_characters}`",
f"Roll Macros{SPACER * 14}: `{num_macros}`",
"### __Roll Statistics__",
roll_stats.get_text(with_title=False),
roles = (
", ".join(
f"@{r.name}" if not r.name.startswith("@") else r.name
for r in target.roles[::-1][:-1]
if not r.is_integration()
)
or "No roles"
)
roll_stats = Statistics(ctx, user=target)
(
campaign_xp,
campaign_total_xp,
lifetime_xp,
campaign_cp,
lifetime_cp,
) = db_user.fetch_experience(campaign.id)

# Build the Embed
embed = discord.Embed(
title="",
description="\n".join(description),
description=f"# {target.display_name}",
color=EmbedColor.INFO.value,
)
embed.add_field(
name="",
value=f"""\
```scala
Account Created: {arrow.get(target.created_at).humanize()} ({arrow.get(target.created_at).format('YYYY-MM-DD')})
Joined Server : {arrow.get(target.joined_at).humanize()} ({arrow.get(target.joined_at).format('YYYY-MM-DD')})
Roles: {roles}
```
""",
inline=False,
)
embed.add_field(
name="Experience",
value=f"""\
```scala
Lifetime Experience : {lifetime_xp}
Lifetime Cool Points: {lifetime_cp}
"{campaign.name}" (active campaign)
Available Experience: {campaign_xp}
Total Earned : {campaign_total_xp}
Cool Points : {campaign_cp}
```
""",
inline=False,
)
embed.add_field(
name="Gameplay",
value=f"""\
```scala
Player Characters: {num_characters}
Roll Macros : {num_macros}
```
""",
inline=False,
)
embed.add_field(
name="Roll Statistics",
value=roll_stats.get_text(with_title=False, with_help=False),
inline=False,
)
embed.set_thumbnail(url=target.display_avatar.url)
embed.set_footer(
text=f"Requested by {ctx.author}",
icon_url=ctx.author.display_avatar.url,
)
embed.timestamp = discord.utils.utcnow()

# Send the embed
await ctx.respond(embed=embed, ephemeral=hidden)

@commands.slash_command(name="changelog", description="Display the bot's changelog")
Expand Down
44 changes: 44 additions & 0 deletions src/valentina/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,50 @@ class XPMultiplier(Enum):
### DISCORD SETTINGS ###


class CharGenClass(Enum):
"""Enum for RNG character generation classes."""

HUMAN = range(0, 60)
VAMPIRE = range(61, 66)
WEREWOLF = range(67, 72)
MAGE = range(73, 78)
GHOUL = range(79, 84)
CHANGELING = range(85, 90)
CHANGELING_BREED = range(91, 96)
OTHER = range(97, 100)


class CharGenHumans(Enum):
"""Enum for RNG character generation of humans."""

CIVILIAN = range(0, 40)
HUNTER = range(41, 50)
CHANGELING = range(51, 53)
GHOUL = range(54, 60)
WATCHER = range(61, 70)
HUNTER_CLASS = range(71, 80)
SORCERER = range(81, 90)
NUMINOUS = range(91, 100)


class CharGenConcept(Enum):
"""Enum for RNG character generation of concepts."""

BERSERKER = range(0, 8)
PERFORMER = range(9, 16)
HEALER = range(17, 24)
SHAMAN = range(25, 32)
SOLDIER = range(33, 40)
ASCETIC = range(41, 48)
CRUSADER = range(49, 56)
URBAN_TRACKER = range(57, 64)
UNDER_WORLDER = range(65, 72)
SCIENTIST = range(73, 80)
TRADESMAN = range(81, 88)
BUSINESSMAN = range(89, 96)
CHOOSE = range(97, 100)


# CHANNEL_PERMISSIONS: Dictionary containing a mapping of channel permissions.
# Format:
# default role permission,
Expand Down
Loading

0 comments on commit 5b1df20

Please sign in to comment.