-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
133 lines (115 loc) · 5.37 KB
/
main.py
File metadata and controls
133 lines (115 loc) · 5.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# main.py
"""
Life-Sim Entry Point.
Wires together Config, Logging, Simulation, and Rendering.
"""
import json
import logging
import sys
import pygame
import random
import numpy as np
# Import local modules
# Note: Assumes 'life_sim' package structure.
# If running from root, ensure __init__.py exists in life_sim/
from life_sim import constants, logging_setup
from life_sim.simulation.state import SimState
from life_sim.simulation import logic
from life_sim.simulation.events import EventManager
from life_sim.rendering.renderer import Renderer
def load_config():
try:
with open(constants.CONFIG_FILE, 'r') as f:
return json.load(f)
except FileNotFoundError:
print(f"CRITICAL: {constants.CONFIG_FILE} not found.")
sys.exit(1)
def main():
# 1. Load Config
config = load_config()
# 2. Setup Logging (Rule 2)
logging_setup.setup_logging(config)
logger = logging.getLogger("main")
# 3. Initialize RNG (Rule 12)
seed = config.get("seed", 0)
random.seed(seed)
np.random.seed(seed)
logger.info(f"Life-Sim started. Seed: {seed}")
# 4. Initialize Systems
renderer = None
try:
sim_state = SimState(config)
event_manager = EventManager(config)
renderer = Renderer()
clock = pygame.time.Clock()
running = True
# 5. Main Loop
while running:
# Event Handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Pass event to UI
action_id = renderer.handle_event(event, sim_state)
if action_id:
logger.info(f"Action triggered: {action_id}")
# Handle tuple actions (like event resolution)
if isinstance(action_id, tuple) and action_id[0] == "RESOLVE_EVENT":
# Extract event and selected choices
selected_choice_indices = action_id[1]
event = sim_state.pending_event
event_manager.apply_resolution(sim_state, event, selected_choice_indices)
logger.info(f"Event resolved, player must click Age Up again to proceed")
elif action_id == "AGE_UP":
# First: Advance time
logic.process_turn(sim_state)
# Update background immediately after turn processing
renderer.background_manager.update(sim_state)
# Phase 6: Auto-resolve NPC events using brain policy.
npc_brain_config = config.get("npc_brain", {})
if npc_brain_config.get("events_enabled", False):
npc_events = event_manager.auto_resolve_npc_events(sim_state)
if npc_events > 0:
logger.info(f"Auto-resolved {npc_events} NPC events")
# Second: Check if player is alive
if sim_state.player.is_alive:
# Third: Check for events after time advancement (unless disabled for development)
if not config.get("development", {}).get("disable_events", False):
event = event_manager.evaluate_month(sim_state)
if event:
sim_state.pending_event = event
logger.info(f"Event '{event.id}' pending - turn processing paused")
else:
logger.debug("Events disabled via development config")
elif action_id == "FIND_JOB":
logic.find_job(sim_state)
elif action_id == "WORK":
logic.work(sim_state)
elif action_id == "DOCTOR":
logic.visit_doctor(sim_state)
elif action_id == "TOGGLE_ATTR":
# Default to player when clicking the main menu button
renderer.toggle_attributes(target=sim_state.player)
elif isinstance(action_id, tuple) and action_id[0] == "UPDATE_SCHEDULE":
# Handle schedule updates from UI
schedule_data = action_id[1]
sleep = schedule_data.get("sleep")
attendance = schedule_data.get("attendance")
sim_state.player.set_schedule(sleep=sleep, attendance=attendance)
logger.info(f"Schedule updated: sleep={sleep}, attendance={attendance}")
else:
# Handle placeholders
sim_state.add_log(f"Feature {action_id} coming soon!", constants.COLOR_TEXT_DIM)
# Render
renderer.render(sim_state)
# Cap FPS
clock.tick(constants.FPS)
except Exception as e:
logger.critical(f"Unhandled exception: {e}", exc_info=True)
raise
finally:
if renderer:
renderer.quit()
logger.info("Simulation ended cleanly.")
if __name__ == "__main__":
main()