d-day-game / app.py
Bc-AI's picture
Update app.py
72833b0 verified
import random
import json
import os
import gradio as gr
class SavingPrivateRyanGame:
def __init__(self):
self.current_mission = 1
self.total_missions = 4
self.mission_names = [
"Omaha Beach Landing",
"Neuville Village: The Sniper",
"The Radar Station: The Field",
"Ramelle: The Bridge"
]
self.player_name = "Captain Miller"
self.inventory = ["Thompson SMG", "Colt 1911", "Sticky Bombs"]
# Real Movie Squad
self.squad = {
"Sergeant Horvath": {"status": "Alive", "death_trigger": 550, "mission": 4},
"Private Reiben": {"status": "Alive", "death_trigger": 999, "mission": 4}, # Survivor
"Private Jackson": {"status": "Alive", "death_trigger": 450, "mission": 4},
"Private Mellish": {"status": "Alive", "death_trigger": 500, "mission": 4},
"Private Caparzo": {"status": "Alive", "death_trigger": 200, "mission": 2},
"Medic Wade": {"status": "Alive", "death_trigger": 250, "mission": 3},
"Corporal Upham": {"status": "Alive", "death_trigger": 999, "mission": 4} # Survivor
}
self.miller_alive = True
self.ryan_found = False
self.game_over = False
self.output_text = ""
self.reset_mission_stats()
def get_chatter(self):
living = [n for n, i in self.squad.items() if i["status"] == "Alive"]
if not living: return "Miller: 'Move up!'"
speaker = random.choice(living)
quotes = [
"'FUBAR, Captain. Absolute FUBAR.'",
"'Why are we risking eight guys for one?'",
"'I've got a bad feeling about that corner.'",
"'Just tell us where we're going, Cap.'",
"'Keep your head down, Upham!'"
]
return f"{speaker}: {random.choice(quotes)}"
def reset_mission_stats(self):
self.distance = 0
self.bunkers_destroyed = 0
self.tiger_tank_approaching = False
configs = {
1: {"map": "BEACH", "obj": 300},
2: {"map": "VILLAGE", "obj": 400},
3: {"map": "FOREST", "obj": 500},
4: {"map": "CITY (RAMELLE)", "obj": 600},
}
cfg = configs.get(self.current_mission)
self.map_type = cfg["map"]
self.mission_objective = cfg["obj"]
def process_plot_points(self):
"""Triggers scripted deaths and events exactly as they happen in the movie."""
event_log = ""
# Mission 2: Caparzo
if self.current_mission == 2 and self.distance >= 200 and self.squad["Private Caparzo"]["status"] == "Alive":
self.squad["Private Caparzo"]["status"] = "Dead"
event_log = "⚠️ PLOT EVENT: Rain starts falling. Caparzo tries to help a childβ€”A SNIPER SHOT! Caparzo is down. Jackson counter-snipes the German in the tower."
# Mission 3: Wade
elif self.current_mission == 3 and self.distance >= 250 and self.squad["Medic Wade"]["status"] == "Alive":
self.squad["Medic Wade"]["status"] = "Dead"
event_log = "⚠️ PLOT EVENT: Assaulting the MG42 nest. 'MEDIC!' Wade is hit in the liver. The squad tries to save him, but he's gone. Miller releases the German prisoner (Steamship Willie)."
# Mission 4: The Final Stand
elif self.current_mission == 4:
if not self.ryan_found:
self.ryan_found = True
event_log = "✨ PLOT EVENT: You found Private James Ryan. He refuses to leave his post. The squad stays to defend the bridge."
# Scripted deaths during the bridge defense
if self.distance >= 450 and self.squad["Private Jackson"]["status"] == "Alive":
self.squad["Private Jackson"]["status"] = "Dead"
event_log = "⚠️ Jackson is in the bell tower... A Tiger tank levels the tower. Jackson has fallen."
if self.distance >= 500 and self.squad["Private Mellish"]["status"] == "Alive":
self.squad["Private Mellish"]["status"] = "Dead"
event_log = "⚠️ Hand-to-hand combat in the ruins. Mellish is overwhelmed. Upham is frozen in the stairwell..."
if self.distance >= 550 and self.squad["Sergeant Horvath"]["status"] == "Alive":
self.squad["Sergeant Horvath"]["status"] = "Dead"
event_log = "⚠️ Horvath is hit multiple times. He fires one last round at the tank. 'I moved the rock...'"
return event_log
def miller_sacrifice(self):
"""The final scene on the bridge."""
self.miller_alive = False
self.game_over = True
sacrifice_text = """
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
πŸ’₯ THE FINAL SACRIFICE πŸ’₯
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Miller is wounded on the bridge, leaning against a pillar.
A Tiger tank rolls toward him. He pulls his Colt 1911 and fires uselessly at the steel.
Suddenlyβ€”BOOM! A P-51 Mustang 'Tank Buster' screams overhead and vaporizes the Tiger.
Reiben finds you. You pull James Ryan close.
Miller: 'James... earn this. Earn it.'
Captain John H. Miller has died.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
"""
return sacrifice_text
def make_move(self, action):
self.output_text = ""
if self.game_over: return self.output_text, "Campaign Finished", gr.update(visible=False)
# Movement
adv = random.randint(40, 80) if action == "rush" else random.randint(20, 40)
self.distance += adv
# Check Plot
plot_event = self.process_plot_points()
if plot_event: self.print_to_output(f"\n{plot_event}\n")
self.print_to_output(f"πŸ“’ {self.get_chatter()}")
# The End Trigger
if self.current_mission == 4 and self.distance >= 590:
self.print_to_output(self.miller_sacrifice())
return self.output_text, "Earn This.", gr.update(visible=False)
# Standard Check
show_action = False
if self.distance >= (self.bunkers_destroyed + 1) * (self.mission_objective / 3):
show_action = True
self.print_to_output("\n⚠️ CONTACT: Enemy forces blocking progress!")
if action == "assault":
self.bunkers_destroyed += 1
self.print_to_output("πŸ’₯ Clear! Advancing...")
self.check_transition()
self.print_status()
return self.output_text, "Awaiting Command", gr.update(visible=show_action)
def print_status(self):
living = [n for n, i in self.squad.items() if i["status"] == "Alive"]
self.print_to_output(f"\nπŸ“ LOCATION: {self.map_type} | DISTANCE: {self.distance}/{self.mission_objective}m")
self.print_to_output(f"πŸ‘₯ SQUAD: Miller, {', '.join(living)}")
def check_transition(self):
if self.distance >= self.mission_objective and self.current_mission < 4:
self.current_mission += 1
self.reset_mission_stats()
self.print_to_output(f"\nβœ… MISSION COMPLETE. Transitioning to {self.mission_names[self.current_mission-1]}...")
def print_to_output(self, text):
self.output_text += text + "\n"
def start_game(self, _):
self.output_text = "June 6, 1944. Dog One Sector. Omaha Beach.\n'CLEAR THE RAMP!'"
self.current_mission = 1
self.reset_mission_stats()
self.print_status()
return self.output_text, "Rangers Lead The Way", gr.update(visible=False)
def create_ui():
game = SavingPrivateRyanGame()
with gr.Blocks(theme=gr.themes.Monochrome()) as demo:
gr.Markdown("# πŸŽ–οΈ SAVING PRIVATE RYAN: THE COMPLETE JOURNEY")
with gr.Row():
with gr.Column(scale=1):
start_btn = gr.Button("πŸš€ Start Campaign", variant="primary")
rush_btn = gr.Button("⚑ Advance")
with gr.Column(visible=False) as action_row:
gr.Markdown("### ⚠️ ENGAGEMENT")
assault_btn = gr.Button("πŸ’₯ Tactical Assault", variant="stop")
with gr.Column(scale=2):
output = gr.TextArea(label="Radio Log", lines=25)
status = gr.Textbox(label="Mission Status")
controls = [output, status, action_row]
start_btn.click(game.start_game, None, controls)
rush_btn.click(lambda: game.make_move("rush"), None, controls)
assault_btn.click(lambda: game.make_move("assault"), None, controls)
return demo
if __name__ == "__main__":
create_ui().launch()