Skip to content

Commit 972380d

Browse files
committed
feat: support custom timeout seconds and embed color for game settings
1 parent 1bd710f commit 972380d

File tree

2 files changed

+52
-22
lines changed

2 files changed

+52
-22
lines changed

bot/exts/fun/adventure.py

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ class GameInfo(TypedDict):
3131
id: str
3232
name: str
3333
description: str
34+
color: str
35+
time: int
3436

3537

3638
BASE_PATH = "bot/resources/fun/adventures"
@@ -72,7 +74,7 @@ class EndRoomData(TypedDict):
7274
emoji: str
7375

7476

75-
class AdventureData(TypedDict):
77+
class GameData(TypedDict):
7678
"""
7779
A dictionary containing the game data, serialized from a JSON file in `resources/fun/adventures`.
7880
@@ -102,17 +104,20 @@ class GameSession:
102104
def __init__(
103105
self,
104106
ctx: Context,
105-
game_code: str | None = None,
107+
game_code_or_index: str | None = None,
106108
):
107109
"""Creates an instance of the GameSession class."""
108110
self._ctx = ctx
109111
self._bot = ctx.bot
110112

111113
# set the game details/ game codes required for the session
112-
self.game_code = game_code
114+
self.game_code = game_code_or_index
113115
self.game_data = None
114-
if game_code:
115-
self.game_data = self._get_game_data(game_code)
116+
self.game_info = None
117+
if game_code_or_index:
118+
self.game_code = self._parse_game_code(game_code_or_index)
119+
self.game_data = self._get_game_data()
120+
self.game_info = self._get_game_info()
116121

117122
# store relevant discord info
118123
self.author = ctx.author
@@ -125,25 +130,31 @@ def __init__(
125130
self._effects: list[str] = []
126131

127132
# session settings
133+
self._timeout_seconds = 30 if self.game_info is None else self.game_info["time"]
128134
self.timeout_message = (
129-
"⏳ Hint: time is running out! You must make a choice within 60 seconds."
135+
f"⏳ Hint: time is running out! You must make a choice within {self._timeout_seconds} seconds."
130136
)
131137
self._timeout_task = None
132138
self.reset_timeout()
133139

134-
def _get_game_data(self, game_code: str) -> AdventureData | None:
135-
"""Returns the game data for the given game code."""
140+
def _parse_game_code(self, game_code_or_index: str) -> str:
141+
"""Returns the actual game code for the given index/ game code."""
136142
# sanitize the game code to prevent directory traversal attacks.
137-
game_code = Path(game_code).name
143+
game_code = Path(game_code_or_index).name
138144

139-
# Convert index to game code if it's a number
145+
# convert index to game code if it's a number
140146
try:
141-
index = int(game_code)
147+
index = int(game_code_or_index)
142148
game_code = AVAILABLE_GAMES[index - 1]["id"]
143-
self.game_code = game_code
144149
except (ValueError, IndexError):
145150
pass
146151

152+
return game_code
153+
154+
def _get_game_data(self) -> GameData | None:
155+
"""Returns the game data for the given game code."""
156+
game_code = self.game_code
157+
147158
# load the game data from the JSON file
148159
try:
149160
game_data = json.loads(
@@ -153,14 +164,27 @@ def _get_game_data(self, game_code: str) -> AdventureData | None:
153164
except FileNotFoundError:
154165
raise GameCodeNotFoundError(f'Game code "{game_code}" not found.')
155166

167+
def _get_game_info(self) -> GameInfo:
168+
"""Returns the game info for the given game code."""
169+
game_code = self.game_code
170+
171+
try:
172+
return AVAILABLE_GAMES_DICT[game_code]
173+
except KeyError:
174+
log.error(
175+
"Game data retrieved, but game info not found. Did you forget to add it to `available_games.json`?"
176+
)
177+
raise GameCodeNotFoundError(f'Game code "{game_code}" not found.')
178+
156179
async def notify_timeout(self) -> None:
157180
"""Notifies the user that the session has timed out."""
158181
await self.message.edit(content="⏰ You took too long to make a choice! The game has ended. :(")
159182

160-
async def timeout(self, seconds: int = 60) -> None:
183+
async def timeout(self) -> None:
161184
"""Waits for a set number of seconds, then stops the game session."""
162-
await asyncio.sleep(seconds)
185+
await asyncio.sleep(self._timeout_seconds)
163186
await self.notify_timeout()
187+
await self.message.clear_reactions()
164188
await self.stop()
165189

166190
def cancel_timeout(self) -> None:
@@ -259,7 +283,7 @@ def _format_room_data(self, room_data: RoomData) -> str:
259283
def embed_message(self, room_data: RoomData | EndRoomData) -> Embed:
260284
"""Returns an Embed with the requested room data formatted within."""
261285
embed = Embed()
262-
embed.color = constants.Colours.soft_orange
286+
embed.color = int(self.game_info["color"], base=16)
263287

264288
current_game_name = AVAILABLE_GAMES_DICT[self.game_code]["name"]
265289

@@ -291,9 +315,9 @@ async def update_message(self, room_id: str) -> None:
291315
self.add_reactions()
292316

293317
@classmethod
294-
async def start(cls, ctx: Context, game_code: str | None = None) -> "GameSession":
318+
async def start(cls, ctx: Context, game_code_or_index: str | None = None) -> "GameSession":
295319
"""Create and begin a game session based on the given game code."""
296-
session = cls(ctx, game_code)
320+
session = cls(ctx, game_code_or_index)
297321
await session.prepare()
298322

299323
return session
@@ -355,10 +379,10 @@ class Adventure(DiscordCog):
355379
"""Custom Embed for Adventure RPG games."""
356380

357381
@commands.command(name="adventure")
358-
async def new_adventure(self, ctx: Context, game_code: str | None = None) -> None:
382+
async def new_adventure(self, ctx: Context, game_code_or_index: str | None = None) -> None:
359383
"""Wanted to slay a dragon? Embark on an exciting journey through text-based RPG adventure."""
360384
try:
361-
await GameSession.start(ctx, game_code)
385+
await GameSession.start(ctx, game_code_or_index)
362386
except GameCodeNotFoundError as error:
363387
await ctx.send(str(error))
364388

bot/resources/fun/adventures/available_games.json

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,22 @@
22
{
33
"id": "three_little_pigs",
44
"name": "Three Little Pigs",
5-
"description": "A wolf is on the prowl! You are one of the three little pigs. Try to survive by building a house."
5+
"description": "A wolf is on the prowl! You are one of the three little pigs. Try to survive by building a house.",
6+
"color": "0x1DA1F2",
7+
"time": 30
68
},
79
{
810
"id": "dragon_slayer",
911
"name": "Dragon Slayer",
10-
"description": "A dragon is terrorizing the kingdom! You are a brave knight, tasked with rescuing the princess and defeating the dragon."
12+
"description": "A dragon is terrorizing the kingdom! You are a brave knight, tasked with rescuing the princess and defeating the dragon.",
13+
"color": "0x1F8B4C",
14+
"time": 60
1115
},
1216
{
1317
"id": "Gurfelts_haunted_mansion",
1418
"name": "Gurfelt's Haunted Mansion",
15-
"description": "Explore a haunted mansion and uncover its secrets!"
19+
"description": "Explore a haunted mansion and uncover its secrets!",
20+
"color": "0xB734EB",
21+
"time": 60
1622
}
1723
]

0 commit comments

Comments
 (0)