py2gui 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- py2gui-0.1.0/LICENSE +21 -0
- py2gui-0.1.0/PKG-INFO +9 -0
- py2gui-0.1.0/py2gui/game_example.py +659 -0
- py2gui-0.1.0/py2gui/py2gui.py +875 -0
- py2gui-0.1.0/py2gui/test.py +110 -0
- py2gui-0.1.0/py2gui.egg-info/PKG-INFO +9 -0
- py2gui-0.1.0/py2gui.egg-info/SOURCES.txt +9 -0
- py2gui-0.1.0/py2gui.egg-info/dependency_links.txt +1 -0
- py2gui-0.1.0/py2gui.egg-info/top_level.txt +1 -0
- py2gui-0.1.0/pyproject.toml +15 -0
- py2gui-0.1.0/setup.cfg +4 -0
py2gui-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 andy64lol
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
py2gui-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,659 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The Lost Artifact - A Text Adventure Game
|
|
3
|
+
A game where you explore ancient ruins, solve puzzles, and find hidden treasure.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from py2gui import display, user_type_in, run, clear, exit_gui, user_write, display_colored, set_theme
|
|
7
|
+
import random
|
|
8
|
+
import time
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AdventureGame:
|
|
12
|
+
def __init__(self):
|
|
13
|
+
self.player_name = ""
|
|
14
|
+
self.current_room = "entrance"
|
|
15
|
+
self.inventory = []
|
|
16
|
+
self.health = 100
|
|
17
|
+
self.score = 0
|
|
18
|
+
self.game_over = False
|
|
19
|
+
self.has_torch = False
|
|
20
|
+
self.has_key = False
|
|
21
|
+
self.has_map = False
|
|
22
|
+
self.solved_riddle = False
|
|
23
|
+
self.visited_rooms = set()
|
|
24
|
+
|
|
25
|
+
# Game map with descriptions and connections
|
|
26
|
+
self.rooms = {
|
|
27
|
+
"entrance": {
|
|
28
|
+
"name": "Ancient Temple Entrance",
|
|
29
|
+
"description": "\033[33mYou stand before the crumbling entrance of an ancient temple. "
|
|
30
|
+
"Vines cover the stone walls, and the heavy wooden door creaks in the wind. "
|
|
31
|
+
"The air smells of damp earth and mystery.\033[0m",
|
|
32
|
+
"exits": {"north": "main_hall", "east": "garden"},
|
|
33
|
+
"items": ["stone tablet"],
|
|
34
|
+
"puzzle": None
|
|
35
|
+
},
|
|
36
|
+
"main_hall": {
|
|
37
|
+
"name": "Grand Hall",
|
|
38
|
+
"description": "\033[33mA vast hall with towering pillars. Faded murals decorate the walls, "
|
|
39
|
+
"depicting ancient rituals. Cobwebs hang from the ceiling like ghostly curtains.\033[0m",
|
|
40
|
+
"exits": {"south": "entrance", "east": "library", "west": "statue_room"},
|
|
41
|
+
"items": ["rusted sword"],
|
|
42
|
+
"puzzle": None
|
|
43
|
+
},
|
|
44
|
+
"garden": {
|
|
45
|
+
"name": "Overgrown Garden",
|
|
46
|
+
"description": "\033[32mA once-beautiful garden now wild with vegetation. Strange glowing mushrooms "
|
|
47
|
+
"illuminate the path. A small fountain gurgles in the center.\033[0m",
|
|
48
|
+
"exits": {"west": "entrance", "north": "library"},
|
|
49
|
+
"items": ["herbs", "strange mushroom"],
|
|
50
|
+
"puzzle": "mushroom"
|
|
51
|
+
},
|
|
52
|
+
"library": {
|
|
53
|
+
"name": "Ancient Library",
|
|
54
|
+
"description": "\033[35mDusty scrolls and crumbling books line the walls. A large stone desk "
|
|
55
|
+
"holds an open tome. Moonlight filters through a cracked ceiling.\033[0m",
|
|
56
|
+
"exits": {"west": "main_hall", "south": "garden", "north": "dark_passage"},
|
|
57
|
+
"items": ["old book", "quill"],
|
|
58
|
+
"puzzle": "riddle"
|
|
59
|
+
},
|
|
60
|
+
"statue_room": {
|
|
61
|
+
"name": "Chamber of Statues",
|
|
62
|
+
"description": "\033[36mFour stone statues stand guard in this circular chamber. Each faces a "
|
|
63
|
+
"cardinal direction. One statue's hand is outstretched, as if offering something.\033[0m",
|
|
64
|
+
"exits": {"east": "main_hall"},
|
|
65
|
+
"items": ["torch"],
|
|
66
|
+
"puzzle": "statues"
|
|
67
|
+
},
|
|
68
|
+
"dark_passage": {
|
|
69
|
+
"name": "Dark Passage",
|
|
70
|
+
"description": "\033[90mPitch darkness. You can't see more than a few inches ahead. "
|
|
71
|
+
"The air is cold and smells of decay. Something scuttles in the shadows.\033[0m",
|
|
72
|
+
"exits": {"south": "library", "north": "treasure_room"},
|
|
73
|
+
"items": [],
|
|
74
|
+
"puzzle": "darkness"
|
|
75
|
+
},
|
|
76
|
+
"treasure_room": {
|
|
77
|
+
"name": "Treasure Chamber",
|
|
78
|
+
"description": "\033[93mA glittering hoard of gold, gems, and artifacts! In the center rests "
|
|
79
|
+
"a pedestal with the legendary Artifact of Aethelred.\033[0m",
|
|
80
|
+
"exits": {"south": "dark_passage"},
|
|
81
|
+
"items": ["gold coins", "ruby", "emerald", "Artifact of Aethelred"],
|
|
82
|
+
"puzzle": "final"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
# Game messages with colors
|
|
87
|
+
self.messages = {
|
|
88
|
+
"welcome": "\033[1;36m========== THE LOST ARTIFACT ==========\033[0m\n"
|
|
89
|
+
"A Text Adventure Game\n\n"
|
|
90
|
+
"\033[3mLong ago, the powerful Artifact of Aethelred was hidden in an ancient temple. "
|
|
91
|
+
"Many have searched, but none have returned. Will you be the one to find it?\033[0m\n",
|
|
92
|
+
|
|
93
|
+
"help": "\033[1;37m===== COMMANDS =====\033[0m\n"
|
|
94
|
+
"\033[32m• look/l: Look around the room\n"
|
|
95
|
+
"• go [direction]: Move (north, south, east, west)\n"
|
|
96
|
+
"• take [item]: Pick up an item\n"
|
|
97
|
+
"• use [item]: Use an item from inventory\n"
|
|
98
|
+
"• inv/i: Check inventory\n"
|
|
99
|
+
"• health/h: Check health\n"
|
|
100
|
+
"• score: Check score\n"
|
|
101
|
+
"• map: Show visited rooms\n"
|
|
102
|
+
"• help: Show this help\n"
|
|
103
|
+
"• quit: End the game\033[0m",
|
|
104
|
+
|
|
105
|
+
"win": "\033[1;33m╔══════════════════════════════════════════╗\n"
|
|
106
|
+
" CONGRATULATIONS, {name}!\n"
|
|
107
|
+
" You have found the Artifact of Aethelred!\n"
|
|
108
|
+
" Score: {score}\n"
|
|
109
|
+
" Health: {health}\n"
|
|
110
|
+
"╚══════════════════════════════════════════╝\033[0m",
|
|
111
|
+
|
|
112
|
+
"game_over": "\033[1;31m╔══════════════════════════════════════╗\n"
|
|
113
|
+
" GAME OVER\n"
|
|
114
|
+
" Your adventure ends here...\n"
|
|
115
|
+
" Final Score: {score}\n"
|
|
116
|
+
"╚══════════════════════════════════════╝\033[0m"
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
# Room descriptions when revisiting
|
|
120
|
+
self.brief_descriptions = {
|
|
121
|
+
"entrance": "The temple entrance. The heavy door still creaks.",
|
|
122
|
+
"main_hall": "The grand hall with its fading murals.",
|
|
123
|
+
"garden": "The overgrown garden with glowing mushrooms.",
|
|
124
|
+
"library": "The ancient library, dusty and silent.",
|
|
125
|
+
"statue_room": "The chamber with four stone statues.",
|
|
126
|
+
"dark_passage": "A terrifyingly dark passage.",
|
|
127
|
+
"treasure_room": "THE TREASURE ROOM! Glittering wealth everywhere!"
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
def show_title(self):
|
|
131
|
+
"""Display the game title screen"""
|
|
132
|
+
clear()
|
|
133
|
+
display_colored("=" * 60, "cyan")
|
|
134
|
+
display_colored("THE LOST ARTIFACT", "bright cyan", bold=True)
|
|
135
|
+
display_colored("A Text Adventure Game", "white", italic=True)
|
|
136
|
+
display_colored("=" * 60, "cyan")
|
|
137
|
+
display("")
|
|
138
|
+
|
|
139
|
+
# Create a simple ASCII art
|
|
140
|
+
temple_art = """
|
|
141
|
+
/\\
|
|
142
|
+
/ \\
|
|
143
|
+
/____\\
|
|
144
|
+
/| |\\
|
|
145
|
+
/_|____|_\\
|
|
146
|
+
/__________\\
|
|
147
|
+
/____________\\
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
display_colored(temple_art, "yellow")
|
|
151
|
+
display("")
|
|
152
|
+
display_colored("Explore the ancient temple, solve puzzles,", "green")
|
|
153
|
+
display_colored("find the legendary Artifact of Aethelred!", "green")
|
|
154
|
+
display("")
|
|
155
|
+
|
|
156
|
+
def get_player_name(self):
|
|
157
|
+
"""Get the player's name"""
|
|
158
|
+
display_colored("What is your name, adventurer?", "bright magenta")
|
|
159
|
+
name = user_type_in("Name: ")
|
|
160
|
+
if name and name.strip():
|
|
161
|
+
self.player_name = name.strip()
|
|
162
|
+
else:
|
|
163
|
+
self.player_name = "Adventurer"
|
|
164
|
+
display(f"\nWelcome, {self.player_name}! Let the adventure begin!\n")
|
|
165
|
+
time.sleep(1)
|
|
166
|
+
|
|
167
|
+
def describe_room(self, room_name, first_visit=True):
|
|
168
|
+
"""Describe the current room"""
|
|
169
|
+
room = self.rooms[room_name]
|
|
170
|
+
self.visited_rooms.add(room_name)
|
|
171
|
+
|
|
172
|
+
display_colored(f"\n[{room['name']}]", "bright yellow", bold=True)
|
|
173
|
+
|
|
174
|
+
if first_visit or room_name not in self.brief_descriptions:
|
|
175
|
+
display(room['description'])
|
|
176
|
+
else:
|
|
177
|
+
display_colored(self.brief_descriptions[room_name], "33")
|
|
178
|
+
|
|
179
|
+
# Show exits
|
|
180
|
+
exits = list(room['exits'].keys())
|
|
181
|
+
if exits:
|
|
182
|
+
display_colored(f"\nExits: {', '.join(exits)}", "bright blue")
|
|
183
|
+
|
|
184
|
+
# Show items
|
|
185
|
+
if room['items']:
|
|
186
|
+
display_colored(f"\nYou see: {', '.join(room['items'])}", "bright green")
|
|
187
|
+
|
|
188
|
+
# Special room descriptions
|
|
189
|
+
if room_name == "dark_passage" and not self.has_torch:
|
|
190
|
+
display_colored("\n\033[1;31mWARNING: It's too dark to proceed! You need a light source.\033[0m", "red", bold=True)
|
|
191
|
+
|
|
192
|
+
display("")
|
|
193
|
+
|
|
194
|
+
def process_command(self, command):
|
|
195
|
+
"""Process player commands"""
|
|
196
|
+
cmd = command.lower().strip()
|
|
197
|
+
parts = cmd.split()
|
|
198
|
+
|
|
199
|
+
if not parts:
|
|
200
|
+
return
|
|
201
|
+
|
|
202
|
+
action = parts[0]
|
|
203
|
+
|
|
204
|
+
# Movement commands
|
|
205
|
+
if action in ["go", "move", "walk", "north", "south", "east", "west"]:
|
|
206
|
+
if action in ["north", "south", "east", "west"]:
|
|
207
|
+
direction = action
|
|
208
|
+
elif len(parts) > 1:
|
|
209
|
+
direction = parts[1]
|
|
210
|
+
else:
|
|
211
|
+
display("Go where?")
|
|
212
|
+
return
|
|
213
|
+
|
|
214
|
+
self.move_player(direction)
|
|
215
|
+
|
|
216
|
+
# Look around
|
|
217
|
+
elif action in ["look", "l"]:
|
|
218
|
+
self.describe_room(self.current_room, first_visit=False)
|
|
219
|
+
|
|
220
|
+
# Take item
|
|
221
|
+
elif action == "take":
|
|
222
|
+
if len(parts) > 1:
|
|
223
|
+
item_name = " ".join(parts[1:])
|
|
224
|
+
self.take_item(item_name)
|
|
225
|
+
else:
|
|
226
|
+
display("Take what?")
|
|
227
|
+
|
|
228
|
+
# Use item
|
|
229
|
+
elif action == "use":
|
|
230
|
+
if len(parts) > 1:
|
|
231
|
+
item_name = " ".join(parts[1:])
|
|
232
|
+
self.use_item(item_name)
|
|
233
|
+
else:
|
|
234
|
+
display("Use what?")
|
|
235
|
+
|
|
236
|
+
# Inventory
|
|
237
|
+
elif action in ["inv", "inventory", "i"]:
|
|
238
|
+
self.show_inventory()
|
|
239
|
+
|
|
240
|
+
# Health
|
|
241
|
+
elif action in ["health", "h", "hp"]:
|
|
242
|
+
self.show_health()
|
|
243
|
+
|
|
244
|
+
# Score
|
|
245
|
+
elif action == "score":
|
|
246
|
+
self.show_score()
|
|
247
|
+
|
|
248
|
+
# Map
|
|
249
|
+
elif action == "map":
|
|
250
|
+
self.show_map()
|
|
251
|
+
|
|
252
|
+
# Help
|
|
253
|
+
elif action in ["help", "?"]:
|
|
254
|
+
display(self.messages["help"])
|
|
255
|
+
|
|
256
|
+
# Quit
|
|
257
|
+
elif action in ["quit", "exit", "q"]:
|
|
258
|
+
confirm = user_type_in("Are you sure you want to quit? (yes/no): ")
|
|
259
|
+
if confirm and confirm.lower() in ["y", "yes"]:
|
|
260
|
+
self.game_over = True
|
|
261
|
+
display("\nThanks for playing!")
|
|
262
|
+
|
|
263
|
+
else:
|
|
264
|
+
display("I don't understand that. Type 'help' for commands.")
|
|
265
|
+
|
|
266
|
+
def move_player(self, direction):
|
|
267
|
+
"""Move the player to a new room"""
|
|
268
|
+
room = self.rooms[self.current_room]
|
|
269
|
+
|
|
270
|
+
if direction in room["exits"]:
|
|
271
|
+
new_room = room["exits"][direction]
|
|
272
|
+
|
|
273
|
+
# Check for special conditions
|
|
274
|
+
if new_room == "dark_passage" and not self.has_torch:
|
|
275
|
+
display_colored("\n\033[1;31mYou stumble in the darkness and hurt yourself!\033[0m", "red")
|
|
276
|
+
self.health -= 20
|
|
277
|
+
display(f"Health: {self.health}")
|
|
278
|
+
|
|
279
|
+
if self.health <= 0:
|
|
280
|
+
self.game_over = True
|
|
281
|
+
display(self.messages["game_over"].format(score=self.score))
|
|
282
|
+
return
|
|
283
|
+
|
|
284
|
+
self.current_room = new_room
|
|
285
|
+
self.score += 5 # Points for exploring
|
|
286
|
+
self.describe_room(new_room, first_visit=new_room not in self.visited_rooms)
|
|
287
|
+
|
|
288
|
+
# Random event chance
|
|
289
|
+
if random.random() < 0.3: # 30% chance
|
|
290
|
+
self.random_event()
|
|
291
|
+
|
|
292
|
+
else:
|
|
293
|
+
display(f"You can't go {direction} from here.")
|
|
294
|
+
|
|
295
|
+
def take_item(self, item_name):
|
|
296
|
+
"""Take an item from the current room"""
|
|
297
|
+
room = self.rooms[self.current_room]
|
|
298
|
+
room_items = room["items"]
|
|
299
|
+
|
|
300
|
+
# Check if item exists in room
|
|
301
|
+
found_item = None
|
|
302
|
+
for item in room_items:
|
|
303
|
+
if item_name.lower() in item.lower():
|
|
304
|
+
found_item = item
|
|
305
|
+
break
|
|
306
|
+
|
|
307
|
+
if found_item:
|
|
308
|
+
room["items"].remove(found_item)
|
|
309
|
+
self.inventory.append(found_item)
|
|
310
|
+
display_colored(f"\nYou take the {found_item}.", "green")
|
|
311
|
+
self.score += 10
|
|
312
|
+
|
|
313
|
+
# Special items
|
|
314
|
+
if found_item == "torch":
|
|
315
|
+
self.has_torch = True
|
|
316
|
+
display_colored("The torch flickers to life!", "yellow")
|
|
317
|
+
elif found_item == "old book":
|
|
318
|
+
self.has_map = True
|
|
319
|
+
display_colored("Inside the book, you find a map of the temple!", "bright cyan")
|
|
320
|
+
elif found_item == "stone tablet":
|
|
321
|
+
display_colored("The tablet has an inscription: 'Seek the four guardians'", "cyan")
|
|
322
|
+
else:
|
|
323
|
+
display(f"There is no {item_name} here.")
|
|
324
|
+
|
|
325
|
+
def use_item(self, item_name):
|
|
326
|
+
"""Use an item from inventory"""
|
|
327
|
+
# Check if player has the item
|
|
328
|
+
has_item = False
|
|
329
|
+
for item in self.inventory:
|
|
330
|
+
if item_name.lower() in item.lower():
|
|
331
|
+
has_item = item
|
|
332
|
+
break
|
|
333
|
+
|
|
334
|
+
if not has_item:
|
|
335
|
+
display(f"You don't have {item_name}.")
|
|
336
|
+
return
|
|
337
|
+
|
|
338
|
+
room = self.rooms[self.current_room]
|
|
339
|
+
|
|
340
|
+
# Special item uses
|
|
341
|
+
if "torch" in item_name.lower() and self.current_room == "dark_passage":
|
|
342
|
+
display_colored("\nThe torch illuminates the dark passage! You can see the way forward.", "yellow")
|
|
343
|
+
display("The passage leads to a treasure room!")
|
|
344
|
+
|
|
345
|
+
elif "herbs" in item_name.lower() and self.health < 100:
|
|
346
|
+
self.health = min(100, self.health + 30)
|
|
347
|
+
self.inventory.remove(has_item)
|
|
348
|
+
display_colored(f"\nYou use the healing herbs. Health: {self.health}", "green")
|
|
349
|
+
|
|
350
|
+
elif "rusted sword" in item_name.lower():
|
|
351
|
+
display_colored("\nYou swing the sword. It's rusty but still sharp!", "cyan")
|
|
352
|
+
|
|
353
|
+
elif "strange mushroom" in item_name.lower():
|
|
354
|
+
display_colored("\nYou eat the glowing mushroom...", "magenta")
|
|
355
|
+
if random.random() < 0.5:
|
|
356
|
+
self.health -= 20
|
|
357
|
+
display_colored("It was poisonous! You feel sick.", "red")
|
|
358
|
+
else:
|
|
359
|
+
self.health += 25
|
|
360
|
+
display_colored("You feel strangely energized!", "green")
|
|
361
|
+
self.inventory.remove(has_item)
|
|
362
|
+
display(f"Health: {self.health}")
|
|
363
|
+
|
|
364
|
+
else:
|
|
365
|
+
display(f"You use the {has_item}, but nothing happens.")
|
|
366
|
+
|
|
367
|
+
def show_inventory(self):
|
|
368
|
+
"""Display player's inventory"""
|
|
369
|
+
if self.inventory:
|
|
370
|
+
display_colored("\n=== INVENTORY ===", "bright cyan")
|
|
371
|
+
for item in self.inventory:
|
|
372
|
+
display(f" • {item}")
|
|
373
|
+
else:
|
|
374
|
+
display("Your inventory is empty.")
|
|
375
|
+
|
|
376
|
+
def show_health(self):
|
|
377
|
+
"""Display player's health"""
|
|
378
|
+
health_bar = "█" * (self.health // 10) + "░" * (10 - (self.health // 10))
|
|
379
|
+
color = "green" if self.health > 50 else "yellow" if self.health > 25 else "red"
|
|
380
|
+
|
|
381
|
+
display_colored(f"\nHealth: {self.health}/100", color)
|
|
382
|
+
display_colored(f"[{health_bar}]", color)
|
|
383
|
+
|
|
384
|
+
if self.health <= 30:
|
|
385
|
+
display_colored("WARNING: Health is low! Find healing items!", "red", bold=True)
|
|
386
|
+
|
|
387
|
+
def show_score(self):
|
|
388
|
+
"""Display player's score"""
|
|
389
|
+
display_colored(f"\nScore: {self.score}", "bright yellow")
|
|
390
|
+
|
|
391
|
+
# Give hints based on score
|
|
392
|
+
if self.score < 50:
|
|
393
|
+
display("Keep exploring to increase your score!")
|
|
394
|
+
elif self.score < 100:
|
|
395
|
+
display("You're making good progress!")
|
|
396
|
+
else:
|
|
397
|
+
display("Excellent! You're close to the treasure!")
|
|
398
|
+
|
|
399
|
+
def show_map(self):
|
|
400
|
+
"""Show a map of visited rooms"""
|
|
401
|
+
if not self.visited_rooms:
|
|
402
|
+
display("You haven't explored anywhere yet!")
|
|
403
|
+
return
|
|
404
|
+
|
|
405
|
+
display_colored("\n=== TEMPLE MAP ===", "bright cyan")
|
|
406
|
+
display_colored("(X = Current location, O = Visited)", "cyan")
|
|
407
|
+
display("")
|
|
408
|
+
|
|
409
|
+
# Simple grid representation
|
|
410
|
+
room_positions = {
|
|
411
|
+
"garden": (0, 0),
|
|
412
|
+
"entrance": (1, 0),
|
|
413
|
+
"main_hall": (2, 0),
|
|
414
|
+
"library": (0, 1),
|
|
415
|
+
"statue_room": (2, 1),
|
|
416
|
+
"dark_passage": (0, 2),
|
|
417
|
+
"treasure_room": (0, 3)
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
# Create a 4x4 grid
|
|
421
|
+
for y in range(4):
|
|
422
|
+
row = ""
|
|
423
|
+
for x in range(3):
|
|
424
|
+
room_here = None
|
|
425
|
+
for room, (rx, ry) in room_positions.items():
|
|
426
|
+
if rx == x and ry == y:
|
|
427
|
+
room_here = room
|
|
428
|
+
break
|
|
429
|
+
|
|
430
|
+
if room_here:
|
|
431
|
+
if room_here == self.current_room:
|
|
432
|
+
row += "[X] "
|
|
433
|
+
elif room_here in self.visited_rooms:
|
|
434
|
+
row += "[O] "
|
|
435
|
+
else:
|
|
436
|
+
row += "[ ] "
|
|
437
|
+
else:
|
|
438
|
+
row += " "
|
|
439
|
+
display(row)
|
|
440
|
+
|
|
441
|
+
display("")
|
|
442
|
+
display_colored(f"Current room: {self.rooms[self.current_room]['name']}", "yellow")
|
|
443
|
+
|
|
444
|
+
def random_event(self):
|
|
445
|
+
"""Random events that can happen when moving"""
|
|
446
|
+
events = [
|
|
447
|
+
("You hear a distant echo...", "white"),
|
|
448
|
+
("A bat flies past your head!", "90"),
|
|
449
|
+
("Dust falls from the ceiling.", "white"),
|
|
450
|
+
("You see a glint in the shadows.", "yellow"),
|
|
451
|
+
("The ground rumbles slightly.", "white"),
|
|
452
|
+
("You hear whispering... or is it the wind?", "90")
|
|
453
|
+
]
|
|
454
|
+
|
|
455
|
+
if random.random() < 0.2: # 20% chance of event
|
|
456
|
+
event, color = random.choice(events)
|
|
457
|
+
display_colored(f"\n{event}", color)
|
|
458
|
+
|
|
459
|
+
# Small chance of finding something
|
|
460
|
+
if random.random() < 0.1:
|
|
461
|
+
found_items = ["gold coin", "silver locket", "ancient coin"]
|
|
462
|
+
item = random.choice(found_items)
|
|
463
|
+
self.inventory.append(item)
|
|
464
|
+
display_colored(f"You found a {item}!", "green")
|
|
465
|
+
self.score += 5
|
|
466
|
+
|
|
467
|
+
def check_puzzles(self):
|
|
468
|
+
"""Check and handle room-specific puzzles"""
|
|
469
|
+
room = self.rooms[self.current_room]
|
|
470
|
+
|
|
471
|
+
# Garden mushroom puzzle
|
|
472
|
+
if self.current_room == "garden" and "strange mushroom" in self.inventory:
|
|
473
|
+
display_colored("\nThe glowing mushrooms pulse with a soft light...", "magenta")
|
|
474
|
+
response = user_type_in("Eat the mushroom? (yes/no): ")
|
|
475
|
+
if response and response.lower() in ["y", "yes"]:
|
|
476
|
+
if random.random() < 0.7:
|
|
477
|
+
self.health += 20
|
|
478
|
+
display_colored("The mushroom gives you a vision! You see a hidden path!", "bright green")
|
|
479
|
+
else:
|
|
480
|
+
self.health -= 15
|
|
481
|
+
display_colored("The mushroom was poisonous!", "red")
|
|
482
|
+
self.inventory.remove("strange mushroom")
|
|
483
|
+
|
|
484
|
+
# Library riddle puzzle
|
|
485
|
+
elif self.current_room == "library" and not self.solved_riddle:
|
|
486
|
+
display_colored("\nThe open tome on the desk contains a riddle:", "cyan")
|
|
487
|
+
display_colored("'I speak without a mouth and hear without ears.'", "bright cyan")
|
|
488
|
+
display_colored("'I have no body, but I come alive with wind.'", "bright cyan")
|
|
489
|
+
display_colored("'What am I?'", "bright cyan")
|
|
490
|
+
|
|
491
|
+
answer = user_type_in("Your answer: ")
|
|
492
|
+
if answer and answer.lower() in ["echo", "an echo"]:
|
|
493
|
+
display_colored("\nCorrect! The bookcase slides open, revealing a passage!", "green")
|
|
494
|
+
self.score += 50
|
|
495
|
+
self.solved_riddle = True
|
|
496
|
+
# Add the dark passage exit
|
|
497
|
+
self.rooms["library"]["exits"]["north"] = "dark_passage"
|
|
498
|
+
else:
|
|
499
|
+
display_colored("\nNothing happens. The riddle remains unsolved.", "yellow")
|
|
500
|
+
|
|
501
|
+
# Statue room puzzle
|
|
502
|
+
elif self.current_room == "statue_room" and "torch" in self.inventory:
|
|
503
|
+
display_colored("\nThe statues seem to be looking at something...", "yellow")
|
|
504
|
+
display("One statue's hand is empty. Another holds a rusted bowl.")
|
|
505
|
+
|
|
506
|
+
response = user_type_in("Place the torch in the statue's hand? (yes/no): ")
|
|
507
|
+
if response and response.lower() in ["y", "yes"]:
|
|
508
|
+
display_colored("\nThe torch fits perfectly! The statues' eyes glow red.", "yellow")
|
|
509
|
+
display("A hidden compartment opens in the wall!")
|
|
510
|
+
if "key" not in self.inventory:
|
|
511
|
+
self.inventory.append("ancient key")
|
|
512
|
+
display_colored("You find an ancient key!", "green")
|
|
513
|
+
self.has_key = True
|
|
514
|
+
|
|
515
|
+
# Treasure room final puzzle
|
|
516
|
+
elif self.current_room == "treasure_room" and "ancient key" in self.inventory:
|
|
517
|
+
display_colored("\nThe Artifact of Aethelred is protected by a magical seal!", "bright yellow")
|
|
518
|
+
response = user_type_in("Use the ancient key? (yes/no): ")
|
|
519
|
+
if response and response.lower() in ["y", "yes"]:
|
|
520
|
+
display_colored("\nThe key turns with a satisfying click!", "green")
|
|
521
|
+
display_colored("The magical seal dissipates!", "bright green")
|
|
522
|
+
display_colored("You have obtained the Artifact of Aethelred!", "bright yellow", bold=True)
|
|
523
|
+
self.score += 1000
|
|
524
|
+
self.game_over = True
|
|
525
|
+
self.show_ending()
|
|
526
|
+
|
|
527
|
+
def show_ending(self):
|
|
528
|
+
"""Show the winning ending"""
|
|
529
|
+
clear()
|
|
530
|
+
display(self.messages["win"].format(
|
|
531
|
+
name=self.player_name,
|
|
532
|
+
score=self.score,
|
|
533
|
+
health=self.health
|
|
534
|
+
))
|
|
535
|
+
display("")
|
|
536
|
+
display_colored("THE END", "bright cyan", bold=True)
|
|
537
|
+
display("")
|
|
538
|
+
|
|
539
|
+
# Show final stats
|
|
540
|
+
display_colored("=== FINAL STATISTICS ===", "bright yellow")
|
|
541
|
+
display(f"Player: {self.player_name}")
|
|
542
|
+
display(f"Final Score: {self.score}")
|
|
543
|
+
display(f"Final Health: {self.health}")
|
|
544
|
+
display(f"Rooms Explored: {len(self.visited_rooms)}/{len(self.rooms)}")
|
|
545
|
+
display(f"Items Collected: {len(self.inventory)}")
|
|
546
|
+
display("")
|
|
547
|
+
|
|
548
|
+
if self.score >= 1000:
|
|
549
|
+
display_colored("PERFECT SCORE! Legendary Adventurer!", "bright magenta", bold=True)
|
|
550
|
+
elif self.score >= 500:
|
|
551
|
+
display_colored("Great Success! Master Explorer!", "green", bold=True)
|
|
552
|
+
else:
|
|
553
|
+
display_colored("Well done! Novice Explorer!", "yellow", bold=True)
|
|
554
|
+
|
|
555
|
+
display("")
|
|
556
|
+
display_colored("Thank you for playing The Lost Artifact!", "cyan")
|
|
557
|
+
|
|
558
|
+
def play(self):
|
|
559
|
+
"""Main game loop"""
|
|
560
|
+
self.show_title()
|
|
561
|
+
self.get_player_name()
|
|
562
|
+
display(self.messages["help"])
|
|
563
|
+
display("\n" + "="*60)
|
|
564
|
+
display_colored("Press Enter to begin your adventure...", "bright white")
|
|
565
|
+
user_type_in("")
|
|
566
|
+
|
|
567
|
+
# Start in the entrance
|
|
568
|
+
self.describe_room(self.current_room)
|
|
569
|
+
|
|
570
|
+
# Main game loop
|
|
571
|
+
while not self.game_over:
|
|
572
|
+
# Check for death
|
|
573
|
+
if self.health <= 0:
|
|
574
|
+
display(self.messages["game_over"].format(score=self.score))
|
|
575
|
+
break
|
|
576
|
+
|
|
577
|
+
# Check for puzzles in current room
|
|
578
|
+
self.check_puzzles()
|
|
579
|
+
|
|
580
|
+
# Get player command
|
|
581
|
+
command = user_type_in("> ")
|
|
582
|
+
|
|
583
|
+
if command:
|
|
584
|
+
self.process_command(command)
|
|
585
|
+
|
|
586
|
+
# Small chance to lose health (danger of temple)
|
|
587
|
+
if random.random() < 0.1: # 10% chance per turn
|
|
588
|
+
self.health -= random.randint(1, 5)
|
|
589
|
+
if self.health <= 0:
|
|
590
|
+
display_colored("\nThe temple's dangers have overcome you...", "red")
|
|
591
|
+
display(self.messages["game_over"].format(score=self.score))
|
|
592
|
+
break
|
|
593
|
+
|
|
594
|
+
# Check for win condition
|
|
595
|
+
if "Artifact of Aethelred" in self.inventory:
|
|
596
|
+
self.game_over = True
|
|
597
|
+
self.show_ending()
|
|
598
|
+
break
|
|
599
|
+
|
|
600
|
+
# Game over
|
|
601
|
+
display("")
|
|
602
|
+
play_again = user_type_in("Play again? (yes/no): ")
|
|
603
|
+
if play_again and play_again.lower() in ["y", "yes"]:
|
|
604
|
+
return True
|
|
605
|
+
return False
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
def main_game():
|
|
609
|
+
"""Main game function to be passed to run()"""
|
|
610
|
+
display_colored("\nInitializing The Lost Artifact...", "cyan")
|
|
611
|
+
time.sleep(1)
|
|
612
|
+
|
|
613
|
+
while True:
|
|
614
|
+
game = AdventureGame()
|
|
615
|
+
play_again = game.play()
|
|
616
|
+
|
|
617
|
+
if not play_again:
|
|
618
|
+
display_colored("\nFarewell, adventurer!", "bright cyan")
|
|
619
|
+
time.sleep(2)
|
|
620
|
+
break
|
|
621
|
+
else:
|
|
622
|
+
display_colored("\nStarting new adventure...", "cyan")
|
|
623
|
+
time.sleep(1)
|
|
624
|
+
clear()
|
|
625
|
+
|
|
626
|
+
def start_game():
|
|
627
|
+
"""Start the adventure game with the Py2GUI framework"""
|
|
628
|
+
# Set a theme for the game
|
|
629
|
+
set_theme("dark")
|
|
630
|
+
|
|
631
|
+
# Welcome message
|
|
632
|
+
clear()
|
|
633
|
+
display_colored("=" * 60, "bright cyan")
|
|
634
|
+
display_colored("THE LOST ARTIFACT - TEXT ADVENTURE", "bright cyan", bold=True)
|
|
635
|
+
display_colored("=" * 60, "bright cyan")
|
|
636
|
+
display("")
|
|
637
|
+
display("A game of exploration, puzzles, and discovery!")
|
|
638
|
+
display("Type 'help' at any time for commands.")
|
|
639
|
+
display("")
|
|
640
|
+
|
|
641
|
+
# Start the game
|
|
642
|
+
main_game()
|
|
643
|
+
|
|
644
|
+
# Ask if user wants to exit
|
|
645
|
+
display("")
|
|
646
|
+
response = user_type_in("Return to main menu? (yes/no): ")
|
|
647
|
+
if response and response.lower() in ["y", "yes"]:
|
|
648
|
+
return
|
|
649
|
+
else:
|
|
650
|
+
exit_gui()
|
|
651
|
+
|
|
652
|
+
# For direct execution
|
|
653
|
+
if __name__ == "__main__":
|
|
654
|
+
# Create a wrapper that uses the Py2GUI framework
|
|
655
|
+
def game_wrapper():
|
|
656
|
+
start_game()
|
|
657
|
+
|
|
658
|
+
# Run the game with the GUI framework
|
|
659
|
+
run(game_wrapper)
|