Once you have programmed your Herman Entertainment System you will want to start making and adding your own games. If you use our HES Space on Perplexity it should make the prompting easy if you want to use AI to create more games, it already has the system specifications and coding information setup. For an example of this, see our discussion for an Oregon Trail clone, it worked well and is an interesting take on the game given the system limitations. Instructions after the video.
TLDR: To add games to the HES use the following steps.
1. To connect to the HES:ssh [email protected]
2. To create the game file, then paste and save code:
nano /home/herman/games/oregon_trail.py
3. To make the game executable:
chmod +x /home/herman/games/oregon_trail.py
4. To restart the system and load new games:
sudo reboot
* To remove broken games:rm /home/herman/games/oregon_trail.py
Once you have the python code you would like to use you will need to SSH into the HES to add the game. This essentially makes it so you are running the command line on the device, the HES in this case, and not the computer you are operating. This allows you to run code, install apps, and run all sorts of function on the HES (raspi). We will use this Oregon trail game as an example. You start by connecting to the HES, you will need to look at your wifi backend to determine the ip address, for example ours is at 192.168.1.95 and was listed on the router as “raspberrypi”. Once you have this you can open a terminal or command line and type (but use your address):
ssh [email protected]
You will be prompted for the password you created when you first setup the HES. Next we need to create the game file.
nano /home/herman/games/oregon_trail.py
This will create the file and open a text editor where we will paste our game code. Please note, there is a conflict with something in the naming conventions and the way the code runs, it is highly recommended to include an underscore in the game name to prevent these conflicts, so “oregon_trail.py” instead of “oregontrail.py” or “tetris_game.py” instead of “tetris.py”.
Now we copy and paste the following into the game file.
#!/usr/bin/env python3
import time
import random
import RPi.GPIO as GPIO
from PIL import Image, ImageDraw, ImageFont
class OregonTrail:
def __init__(self, display_obj, gpio_obj, backlight_obj):
if None in (display_obj, gpio_obj, backlight_obj):
raise ValueError("Missing hardware components")
self.display = display_obj
self.GPIO = gpio_obj
self.backlight = backlight_obj
self.last_input_time = 0
self.debounce_delay = 0.15
# Optimized fonts for 240x240 display
try:
self.font_small = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 14)
self.font_medium = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 16)
self.font_large = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 18)
except:
self.font_small = ImageFont.load_default()
self.font_medium = ImageFont.load_default()
self.font_large = ImageFont.load_default()
self.reset_game()
def reset_game(self):
# Simplified game state
self.money = 400
self.food = 0
self.bullets = 0
self.oxen = 0
self.clothes = 0
# Simplified party (3 people instead of 5)
self.party = [
{"name": "You", "sick": False},
{"name": "Wife", "sick": False},
{"name": "Child", "sick": False}
]
# Journey
self.miles = 0
self.month = 3 # March
self.day = 1
# Simplified landmarks
self.landmarks = [
{"name": "Independence", "miles": 0},
{"name": "Kansas River", "miles": 185},
{"name": "Big Blue River", "miles": 304},
{"name": "Fort Kearney", "miles": 554},
{"name": "Chimney Rock", "miles": 640},
{"name": "Fort Laramie", "miles": 932},
{"name": "Independence Rock", "miles": 1288},
{"name": "Snake River", "miles": 1828},
{"name": "Oregon City", "miles": 2040}
]
self.current_landmark = 0
def read_controls_debounced(self):
current_time = time.time()
if current_time - self.last_input_time < self.debounce_delay:
return {}
controls = {
'up': not self.GPIO.input(17),
'down': not self.GPIO.input(22),
'left': not self.GPIO.input(27),
'right': not self.GPIO.input(23),
'button_a': not self.GPIO.input(5),
'button_b': not self.GPIO.input(6)
}
if any(controls.values()):
self.last_input_time = current_time
return controls
def draw_large_wagon(self, draw, x, y, color=(0, 255, 0)):
"""Draw a detailed wagon sprite"""
# Wagon body
draw.rectangle([x+10, y+5, x+50, y+25], fill=color)
draw.rectangle([x+12, y+7, x+48, y+23], outline=(0, 0, 0), width=2)
# Wagon cover
draw.ellipse([x+8, y-5, x+52, y+15], fill=(255, 255, 255))
draw.ellipse([x+10, y-3, x+50, y+13], outline=(0, 0, 0), width=2)
# Wheels
draw.ellipse([x+5, y+20, x+20, y+35], fill=color)
draw.ellipse([x+7, y+22, x+18, y+33], outline=(0, 0, 0), width=2)
draw.ellipse([x+40, y+20, x+55, y+35], fill=color)
draw.ellipse([x+42, y+22, x+53, y+33], outline=(0, 0, 0), width=2)
# Spokes
draw.line([x+12, y+27, x+13, y+28], fill=(0, 0, 0), width=2)
draw.line([x+47, y+27, x+48, y+28], fill=(0, 0, 0), width=2)
def draw_broken_wagon(self, draw, x, y):
"""Draw a broken wagon with missing wheel"""
# Tilted wagon body
draw.polygon([x+10, y+15, x+50, y+10, x+48, y+30, x+12, y+35], fill=(139, 69, 19))
# Torn wagon cover
draw.polygon([x+8, y+5, x+30, y-5, x+52, y+8, x+35, y+20], fill=(200, 200, 200))
# One good wheel
draw.ellipse([x+5, y+30, x+20, y+45], fill=(139, 69, 19))
draw.ellipse([x+7, y+32, x+18, y+43], outline=(0, 0, 0), width=2)
# Broken wheel pieces
draw.arc([x+40, y+25, x+55, y+40], 0, 180, fill=(139, 69, 19), width=3)
draw.line([x+45, y+35, x+50, y+45], fill=(139, 69, 19), width=2)
def draw_oxen(self, draw, x, y, color=(139, 69, 19)):
"""Draw oxen pulling the wagon"""
# Ox body
draw.ellipse([x, y+10, x+25, y+25], fill=color)
# Ox head
draw.ellipse([x-8, y+12, x+5, y+23], fill=color)
# Horns
draw.line([x-6, y+12, x-4, y+8], fill=(255, 255, 255), width=2)
draw.line([x+1, y+12, x+3, y+8], fill=(255, 255, 255), width=2)
# Legs
draw.line([x+5, y+25, x+5, y+32], fill=color, width=3)
draw.line([x+15, y+25, x+15, y+32], fill=color, width=3)
draw.line([x+20, y+25, x+20, y+32], fill=color, width=3)
def draw_sick_oxen(self, draw, x, y):
"""Draw sick/injured oxen"""
# Lying down ox
draw.ellipse([x, y+20, x+25, y+30], fill=(100, 50, 0))
draw.ellipse([x-8, y+22, x+5, y+28], fill=(100, 50, 0))
# X eyes (dead/sick)
draw.line([x-5, y+23, x-2, y+26], fill=(255, 0, 0), width=2)
draw.line([x-2, y+23, x-5, y+26], fill=(255, 0, 0), width=2)
def draw_river_scene(self, draw, x, y):
"""Draw river crossing scene"""
# River waves
for i in range(4):
draw.arc([x+i*20, y+15, x+i*20+25, y+30], 0, 180, fill=(0, 150, 255), width=3)
draw.arc([x+i*20+12, y+20, x+i*20+37, y+35], 180, 360, fill=(0, 150, 255), width=3)
# Small wagon crossing
self.draw_large_wagon(draw, x+30, y-5, (139, 69, 19))
def draw_fort(self, draw, x, y):
"""Draw fort with flag"""
# Fort walls
draw.rectangle([x, y, x+60, y+40], fill=(139, 69, 19))
draw.rectangle([x+5, y+5, x+55, y+35], outline=(0, 0, 0), width=2)
# Towers
draw.rectangle([x-5, y-10, x+10, y+20], fill=(139, 69, 19))
draw.rectangle([x+50, y-10, x+65, y+20], fill=(139, 69, 19))
# Flag
draw.line([x+30, y-15, x+30, y+5], fill=(139, 69, 19), width=3)
draw.polygon([x+30, y-15, x+45, y-10, x+30, y-5], fill=(255, 0, 0))
def draw_chimney_rock(self, draw, x, y):
"""Draw Chimney Rock landmark"""
# Base rock
draw.ellipse([x, y+20, x+50, y+50], fill=(128, 128, 128))
# Chimney spire
draw.rectangle([x+20, y-10, x+30, y+30], fill=(160, 160, 160))
draw.rectangle([x+18, y-12, x+32, y-8], fill=(128, 128, 128))
def draw_mountains(self, draw, x, y):
"""Draw mountain range"""
# Multiple mountain peaks
draw.polygon([x, y+40, x+20, y, x+40, y+25, x+60, y-5, x+80, y+40], fill=(100, 100, 100))
draw.polygon([x+10, y+40, x+30, y+10, x+50, y+40], fill=(120, 120, 120))
# Snow caps
draw.polygon([x+15, y+5, x+25, y, x+35, y+5, x+25, y+15], fill=(255, 255, 255))
draw.polygon([x+50, y, x+60, y-5, x+70, y, x+60, y+10], fill=(255, 255, 255))
def draw_grave(self, draw, x, y):
"""Draw gravestone"""
# Gravestone
draw.rectangle([x+20, y+10, x+40, y+40], fill=(128, 128, 128))
draw.ellipse([x+20, y+10, x+40, y+25], fill=(128, 128, 128))
# Cross
draw.line([x+30, y+15, x+30, y+30], fill=(255, 255, 255), width=3)
draw.line([x+25, y+20, x+35, y+20], fill=(255, 255, 255), width=3)
# RIP text
draw.text((x+22, y+25), "RIP", font=self.font_small, fill=(0, 0, 0))
def draw_storm_clouds(self, draw, x, y):
"""Draw storm clouds with lightning"""
# Dark clouds
draw.ellipse([x, y, x+30, y+20], fill=(64, 64, 64))
draw.ellipse([x+20, y-5, x+50, y+15], fill=(64, 64, 64))
draw.ellipse([x+40, y, x+70, y+20], fill=(64, 64, 64))
# Lightning bolt
draw.polygon([x+35, y+20, x+30, y+35, x+35, y+35, x+25, y+50, x+30, y+50, x+40, y+30],
fill=(255, 255, 0))
def draw_thief(self, draw, x, y):
"""Draw thief stealing supplies"""
# Thief figure (stick figure with hat)
draw.ellipse([x+15, y, x+25, y+10], fill=(255, 200, 150)) # Head
draw.rectangle([x+12, y-5, x+28, y+2], fill=(0, 0, 0)) # Hat
draw.line([x+20, y+10, x+20, y+30], fill=(0, 0, 0), width=3) # Body
draw.line([x+20, y+15, x+15, y+25], fill=(0, 0, 0), width=2) # Arm
draw.line([x+20, y+15, x+25, y+25], fill=(0, 0, 0), width=2) # Arm
draw.line([x+20, y+30, x+15, y+40], fill=(0, 0, 0), width=2) # Leg
draw.line([x+20, y+30, x+25, y+40], fill=(0, 0, 0), width=2) # Leg
# Stolen supplies bag
draw.ellipse([x+30, y+20, x+45, y+35], fill=(139, 69, 19))
draw.text((x+32, y+25), "$", font=self.font_small, fill=(255, 255, 0))
def draw_snake(self, draw, x, y):
"""Draw snake for snake bite event"""
# Snake body (S-curve)
points = []
for i in range(0, 60, 2):
snake_y = y + 20 + int(10 * (i % 20 - 10) / 10)
points.append((x + i, snake_y))
for i in range(len(points)-1):
draw.line([points[i], points[i+1]], fill=(0, 128, 0), width=4)
# Snake head
draw.ellipse([x+55, y+15, x+65, y+25], fill=(0, 100, 0))
# Eyes
draw.ellipse([x+57, y+17, x+59, y+19], fill=(255, 0, 0))
draw.ellipse([x+61, y+17, x+63, y+19], fill=(255, 0, 0))
def draw_deer(self, draw, x, y):
"""Draw deer for hunting"""
# Deer body
draw.ellipse([x+10, y+15, x+35, y+25], fill=(139, 69, 19))
# Deer head
draw.ellipse([x+30, y+10, x+45, y+20], fill=(139, 69, 19))
# Antlers
draw.line([x+35, y+5, x+32, y], fill=(160, 160, 160), width=2)
draw.line([x+35, y+5, x+38, y], fill=(160, 160, 160), width=2)
draw.line([x+40, y+5, x+37, y], fill=(160, 160, 160), width=2)
draw.line([x+40, y+5, x+43, y], fill=(160, 160, 160), width=2)
# Legs
draw.line([x+15, y+25, x+15, y+35], fill=(139, 69, 19), width=2)
draw.line([x+20, y+25, x+20, y+35], fill=(139, 69, 19), width=2)
draw.line([x+25, y+25, x+25, y+35], fill=(139, 69, 19), width=2)
draw.line([x+30, y+25, x+30, y+35], fill=(139, 69, 19), width=2)
def draw_event_graphic(self, draw, event_type, x, y):
"""Draw graphics for different event types"""
if event_type == "wagon_break":
self.draw_broken_wagon(draw, x, y)
elif event_type == "ox_injury":
self.draw_sick_oxen(draw, x, y)
elif event_type == "storm":
self.draw_storm_clouds(draw, x, y)
elif event_type == "theft":
self.draw_thief(draw, x, y)
elif event_type == "snake_bite":
self.draw_snake(draw, x, y)
elif event_type == "sickness":
self.draw_grave(draw, x, y)
elif event_type == "river_crossing":
self.draw_river_scene(draw, x, y)
elif event_type == "hunting":
self.draw_deer(draw, x, y)
elif event_type == "good_weather":
# Sun
draw.ellipse([x+20, y+10, x+40, y+30], fill=(255, 255, 0))
# Sun rays
for angle in range(0, 360, 45):
import math
rad = math.radians(angle)
x1 = x + 30 + int(25 * math.cos(rad))
y1 = y + 20 + int(25 * math.sin(rad))
x2 = x + 30 + int(35 * math.cos(rad))
y2 = y + 20 + int(35 * math.sin(rad))
draw.line([x1, y1, x2, y2], fill=(255, 255, 0), width=2)
def draw_landmark_graphic(self, draw, landmark_name, x, y):
"""Draw landmark-specific graphics"""
if "River" in landmark_name:
self.draw_river_scene(draw, x, y)
elif "Fort" in landmark_name:
self.draw_fort(draw, x, y)
elif "Chimney Rock" in landmark_name:
self.draw_chimney_rock(draw, x, y)
elif "Rock" in landmark_name:
# Independence Rock
draw.ellipse([x, y+15, x+60, y+45], fill=(128, 128, 128))
draw.ellipse([x+20, y, x+80, y+35], fill=(128, 128, 128))
draw.text((x+25, y+20), "1847", font=self.font_small, fill=(0, 0, 0))
elif "Pass" in landmark_name or "Mountain" in landmark_name:
self.draw_mountains(draw, x, y)
else:
# Default town graphic
draw.rectangle([x+10, y+20, x+30, y+40], fill=(139, 69, 19))
draw.polygon([x+5, y+20, x+20, y+10, x+35, y+20], fill=(255, 0, 0))
draw.rectangle([x+40, y+25, x+55, y+40], fill=(139, 69, 19))
draw.polygon([x+37, y+25, x+47, y+15, x+58, y+25], fill=(255, 0, 0))
def draw_simple_menu(self, title, options, selected):
"""Simplified menu with larger fonts"""
image = Image.new('RGB', (240, 240), (0, 0, 0))
draw = ImageDraw.Draw(image)
# Title
draw.text((10, 10), title, font=self.font_large, fill=(0, 255, 0))
# Options with larger spacing
y = 50
for i, option in enumerate(options):
color = (255, 255, 0) if i == selected else (255, 255, 255)
prefix = ">" if i == selected else " "
draw.text((15, y), f"{prefix} {option}", font=self.font_medium, fill=color)
y += 25
# Instructions
draw.text((10, 210), "A=OK B=Back", font=self.font_small, fill=(255, 255, 0))
self.display.image(image)
def draw_story_screen(self, title, text_lines, graphic_type=None, event_type=None):
"""Story screen with graphics and larger text"""
image = Image.new('RGB', (240, 240), (0, 0, 0))
draw = ImageDraw.Draw(image)
# Title
draw.text((10, 5), title, font=self.font_large, fill=(0, 255, 0))
# Graphics
if graphic_type == "wagon_scene":
self.draw_oxen(draw, 20, 30)
self.draw_large_wagon(draw, 50, 25)
elif event_type:
self.draw_event_graphic(draw, event_type, 120, 30)
elif graphic_type:
if graphic_type == "grave":
self.draw_grave(draw, 100, 30)
else:
self.draw_landmark_graphic(draw, graphic_type, 90, 30)
# Text with proper spacing
y = 90 if (graphic_type or event_type) else 40
for line in text_lines:
if y > 190:
break
draw.text((10, y), line, font=self.font_small, fill=(255, 255, 255))
y += 18
draw.text((10, 215), "Press A to continue", font=self.font_small, fill=(255, 255, 0))
self.display.image(image)
# Wait for input
while True:
controls = self.read_controls_debounced()
if controls.get('button_a') or controls.get('button_b'):
break
time.sleep(0.1)
def shopping_screen(self):
"""Simplified shopping with visual feedback"""
items = [
{"name": "Oxen", "price": 40, "have": self.oxen},
{"name": "Food", "price": 20, "have": self.food},
{"name": "Bullets", "price": 10, "have": self.bullets},
{"name": "Clothes", "price": 15, "have": self.clothes}
]
selected = 0
while True:
image = Image.new('RGB', (240, 240), (0, 0, 0))
draw = ImageDraw.Draw(image)
draw.text((10, 5), "General Store", font=self.font_large, fill=(0, 255, 0))
draw.text((10, 30), f"Money: ${self.money}", font=self.font_medium, fill=(255, 255, 0))
y = 60
for i, item in enumerate(items):
color = (255, 255, 0) if i == selected else (255, 255, 255)
prefix = ">" if i == selected else " "
draw.text((15, y), f"{prefix} {item['name']}: ${item['price']}",
font=self.font_medium, fill=color)
draw.text((15, y+15), f" Have: {item['have']}",
font=self.font_small, fill=(200, 200, 200))
y += 35
draw.text((10, 195), "A=Buy B=Done", font=self.font_small, fill=(255, 255, 0))
draw.text((10, 210), "Need: 2 Oxen, 100 Food", font=self.font_small, fill=(255, 100, 100))
self.display.image(image)
controls = self.read_controls_debounced()
if controls.get('up'):
selected = max(0, selected - 1)
elif controls.get('down'):
selected = min(len(items) - 1, selected + 1)
elif controls.get('button_a'):
item = items[selected]
if self.money >= item["price"]:
self.money -= item["price"]
if selected == 0:
self.oxen += 1
items[0]["have"] = self.oxen
elif selected == 1:
self.food += 50
items[1]["have"] = self.food
elif selected == 2:
self.bullets += 20
items[2]["have"] = self.bullets
elif selected == 3:
self.clothes += 1
items[3]["have"] = self.clothes
elif controls.get('button_b'):
if self.oxen >= 2 and self.food >= 100:
break
else:
self.draw_story_screen("Not Ready!", [
"You need at least:",
"2 Oxen and 100 Food",
"to start your journey"
])
time.sleep(0.1)
def travel_screen(self):
"""Main travel interface with large, clear display"""
image = Image.new('RGB', (240, 240), (0, 0, 0))
draw = ImageDraw.Draw(image)
# Date
months = ["", "", "", "March", "April", "May", "June", "July", "August", "Sept"]
draw.text((10, 5), f"{months[self.month]} {self.day}", font=self.font_medium, fill=(255, 255, 255))
# Progress bar
progress = min(100, int((self.miles / 2040) * 100))
draw.rectangle([10, 25, 230, 35], outline=(255, 255, 255))
draw.rectangle([10, 25, 10 + int(220 * progress / 100), 35], fill=(0, 255, 0))
draw.text((10, 40), f"{self.miles}/2040 miles ({progress}%)", font=self.font_small, fill=(255, 255, 255))
# Current location
current_location = self.landmarks[self.current_landmark]["name"]
draw.text((10, 60), f"At: {current_location}", font=self.font_medium, fill=(0, 255, 0))
# Supplies - larger, clearer display
draw.text((10, 85), f"Food: {self.food} lbs", font=self.font_medium, fill=(255, 255, 255))
draw.text((10, 105), f"Bullets: {self.bullets}", font=self.font_medium, fill=(255, 255, 255))
draw.text((10, 125), f"Oxen: {self.oxen}", font=self.font_medium, fill=(255, 255, 255))
# Party health
draw.text((10, 150), "Party:", font=self.font_medium, fill=(255, 255, 0))
y = 170
for member in self.party:
color = (255, 0, 0) if member["sick"] else (0, 255, 0)
status = "Sick" if member["sick"] else "Good"
draw.text((15, y), f"{member['name']}: {status}", font=self.font_small, fill=color)
y += 15
draw.text((10, 215), "A=Continue B=Menu", font=self.font_small, fill=(255, 255, 0))
self.display.image(image)
def trail_menu(self):
"""Simplified trail menu"""
options = ["Continue", "Rest", "Hunt"]
selected = 0
while True:
self.draw_simple_menu("What now?", options, selected)
controls = self.read_controls_debounced()
if controls.get('up'):
selected = max(0, selected - 1)
elif controls.get('down'):
selected = min(len(options) - 1, selected + 1)
elif controls.get('button_a'):
return selected
elif controls.get('button_b'):
return -1
time.sleep(0.1)
def hunt_game(self):
"""Simplified hunting game with deer graphic"""
if self.bullets < 5:
return "Not enough bullets!", "hunting"
self.draw_story_screen("Hunting", [
"You see a deer!",
"",
"Press A quickly when",
"you see 'SHOOT!'"
], event_type="hunting")
# Wait random time
time.sleep(random.uniform(1, 3))
# Show shoot prompt
image = Image.new('RGB', (240, 240), (0, 0, 0))
draw = ImageDraw.Draw(image)
draw.text((70, 100), "SHOOT!", font=self.font_large, fill=(255, 0, 0))
self.display.image(image)
# Check reaction time
start_time = time.time()
hit = False
while time.time() - start_time < 1.5:
controls = self.read_controls_debounced()
if controls.get('button_a'):
reaction_time = time.time() - start_time
hit = reaction_time < 1.0
break
time.sleep(0.05)
self.bullets -= 5
if hit:
meat = random.randint(20, 60)
self.food += meat
return f"Good shot! Got {meat} lbs meat", "good_weather"
else:
return "Missed! No food gained", "hunting"
def travel_day(self):
"""Simplified daily travel with event graphics"""
# Travel 15-25 miles per day
daily_miles = random.randint(15, 25)
if self.oxen < 2:
daily_miles = int(daily_miles * 0.7) # Slower with fewer oxen
self.miles += daily_miles
# Consume food
self.food = max(0, self.food - 3) # 3 people eat 1 lb each
# Advance date
self.day += 1
if self.day > 30:
self.day = 1
self.month += 1
# Random events with graphics
if random.random() < 0.25:
events = [
{"text": "Wagon wheel broke!", "type": "wagon_break", "effect": "time"},
{"text": "Ox injured and limping", "type": "ox_injury", "effect": "ox"},
{"text": "Severe thunderstorm", "type": "storm", "effect": "time"},
{"text": "Thief stole supplies", "type": "theft", "effect": "food"},
{"text": "Snake bite - someone sick", "type": "snake_bite", "effect": "sick"},
{"text": "Beautiful weather", "type": "good_weather", "effect": "bonus"},
{"text": "River crossing ahead", "type": "river_crossing", "effect": "choice"}
]
event = random.choice(events)
# Apply event effects
if event["effect"] == "food":
self.food = max(0, self.food - random.randint(10, 20))
elif event["effect"] == "ox" and self.oxen > 1:
self.oxen -= 1
elif event["effect"] == "sick":
healthy = [p for p in self.party if not p["sick"]]
if healthy:
random.choice(healthy)["sick"] = True
elif event["effect"] == "bonus":
self.miles += 10
elif event["effect"] == "time":
self.miles = max(0, self.miles - 10)
return event["text"], event["type"]
return None, None
def check_landmarks(self):
"""Check for landmark arrivals with graphics"""
for i, landmark in enumerate(self.landmarks):
if (self.miles >= landmark["miles"] and
i > self.current_landmark and
landmark["miles"] > 0):
self.current_landmark = i
self.draw_story_screen(
"Landmark!",
[f"You have reached", landmark["name"], "",
f"Miles traveled: {self.miles}"],
graphic_type=landmark["name"]
)
return True
return False
def run(self):
game_state = "intro"
while True:
controls = self.read_controls_debounced()
if controls.get('button_b') and game_state == "intro":
return
if game_state == "intro":
self.draw_story_screen("The Oregon Trail", [
"It is 1847. You are a pioneer",
"heading west to Oregon City.",
"",
"You must travel 2040 miles",
"across dangerous frontier.",
"",
"Buy supplies, manage resources,",
"and survive the journey!",
"",
"Good luck, pioneer!"
], graphic_type="wagon_scene")
game_state = "shopping"
elif game_state == "shopping":
self.shopping_screen()
game_state = "traveling"
elif game_state == "traveling":
# Check win condition
if self.miles >= 2040:
game_state = "win"
continue
# Check lose conditions
alive_count = sum(1 for p in self.party if not p["sick"])
if alive_count == 0:
game_state = "lose_sickness"
continue
elif self.food <= 0:
game_state = "lose_starvation"
continue
# Show travel screen
self.travel_screen()
# Wait for input
while True:
controls = self.read_controls_debounced()
if controls.get('button_a'):
break
elif controls.get('button_b'):
choice = self.trail_menu()
if choice == 0: # Continue
break
elif choice == 1: # Rest
self.draw_story_screen("Resting", ["Your party rests for 2 days"],
event_type="good_weather")
self.day += 2
# Chance to recover
for member in self.party:
if member["sick"] and random.random() < 0.5:
member["sick"] = False
elif choice == 2: # Hunt
result, graphic = self.hunt_game()
self.draw_story_screen("Hunt Result", [result], event_type=graphic)
elif choice == -1: # Back
break
time.sleep(0.1)
# Travel for the day
event, event_type = self.travel_day()
if event:
self.draw_story_screen("Trail Event", [event], event_type=event_type)
# Check landmarks
self.check_landmarks()
elif game_state == "win":
alive_count = sum(1 for p in self.party if not p["sick"])
score = alive_count * 200 + self.food + self.bullets
self.draw_story_screen("Success!", [
"You made it to Oregon City!",
"",
f"Final score: {score}",
f"Food left: {self.food} lbs",
f"Bullets left: {self.bullets}",
"",
"A=Play Again B=Menu"
], graphic_type="wagon_scene")
while True:
controls = self.read_controls_debounced()
if controls.get('button_a'):
self.reset_game()
game_state = "shopping"
break
elif controls.get('button_b'):
return
time.sleep(0.1)
elif game_state.startswith("lose"):
if game_state == "lose_sickness":
message = [
"Your entire party has died",
"of dysentery and disease.",
"",
f"You traveled {self.miles} miles",
"out of 2040 total.",
"",
"A=Try Again B=Menu"
]
else: # lose_starvation
message = [
"Your party has starved",
"on the Oregon Trail.",
"",
f"You traveled {self.miles} miles",
"out of 2040 total.",
"",
"A=Try Again B=Menu"
]
self.draw_story_screen("You Have Died", message, graphic_type="grave")
while True:
controls = self.read_controls_debounced()
if controls.get('button_a'):
self.reset_game()
game_state = "shopping"
break
elif controls.get('button_b'):
return
time.sleep(0.1)
time.sleep(0.1)
Now to save this do “Control x”, then “y”, then “enter” to save. There should be instructions for this at the bottom of the window. Now you should be back at the command prompt and we need to modify our file to tell the system it is executable (that it is a program to run) so enter:
chmod +x /home/herman/games/oregon_trail.py
Then to restart your system and load the new game:
sudo reboot
Now you should be all set, it is pretty straightforward, on reboot the device will disconnect from the network so you will lose your connection. Once rebooted the new game should be in your list and ready to play, just try not to die of dysentery.
**A final note on broken games.
If your game is broken, does not load, or gives an error just provide this information to your AI (if that is what you’re using to code) and it will give you new code to try. We have found it easiest to simply remove the original file and then start over. To do that you would use the following code to remove the file, and then just start from the file creation step above (nano…) to recreate it with the new code.
rm /home/herman/games/oregon_trail.py