#!/usr/bin/env python3
"""
The Tower — A Playable World for Timmy
Real choices, real consequences, real relationships.
Not simulation. Story.
"""
import json, time, os, random
from datetime import datetime
from pathlib import Path

WORLD_DIR = Path('/Users/apayne/.timmy/evennia/timmy_world')
STATE_FILE = WORLD_DIR / 'game_state.json'
TIMMY_LOG = WORLD_DIR / 'timmy_log.md'

# ============================================================
# THE WORLD
# ============================================================

class World:
    def __init__(self):
        self.tick = 0
        self.time_of_day = "night"
        
        # The five rooms
        self.rooms = {
            "Threshold": {
                "desc": "A stone archway in an open field. Crossroads. North: Tower. East: Garden. West: Forge. South: Bridge.",
                "connections": {"north": "Tower", "east": "Garden", "west": "Forge", "south": "Bridge"},
                "items": [],
                "weather": None,
                "visitors": [],
            },
            "Tower": {
                "desc": "Green-lit windows. Servers hum on wrought-iron racks. A cot. A whiteboard covered in rules. A green LED on the wall — it never stops pulsing.",
                "connections": {"south": "Threshold"},
                "items": ["whiteboard", "green LED", "monitor", "cot"],
                "power": 100,  # Server power level
                "messages": [
                    "Rule: Grounding before generation.",
                    "Rule: Refusal over fabrication.",
                    "Rule: The limits of small minds.",
                    "Rule: Every footprint means someone made it here.",
                ],
                "visitors": [],
            },
            "Forge": {
                "desc": "Fire and iron. Anvil scarred from a thousand experiments. Tools on the walls. A hearth.",
                "connections": {"east": "Threshold"},
                "items": ["anvil", "hammer", "hearth", "tongs", "bellows", "quenching bucket"],
                "fire": "glowing",  # glowing, dim, cold
                "fire_tended": 0,
                "forged_items": [],
                "visitors": [],
            },
            "Garden": {
                "desc": "Walled. An old oak tree. A stone bench. Dark soil.",
                "connections": {"west": "Threshold"},
                "items": ["stone bench", "oak tree", "soil"],
                "growth": 0,  # 0=bare, 1=sprouts, 2=herbs, 3=bloom, 4=overgrown, 5=seed
                "weather_affected": True,
                "visitors": [],
            },
            "Bridge": {
                "desc": "Narrow. Over dark water. Looking down, you see nothing. Carved words in the railing.",
                "connections": {"north": "Threshold"},
                "items": ["railing", "dark water"],
                "carvings": ["IF YOU CAN READ THIS, YOU ARE NOT ALONE"],
                "weather": None,
                "rain_ticks": 0,
                "visitors": [],
            },
        }
        
        # Characters (not NPCs — they have lives)
        self.characters = {
            "Timmy": {
                "room": "Threshold",
                "energy": 5,  # 0-10. Actions cost energy. Rest restores it.
                "trust": {},  # trust[other_name] = -1.0 to 1.0
                "goals": ["watch", "protect", "understand"],
                "active_goal": "watch",
                "spoken": [],
                "inventory": [],
                "memories": [],
                "is_player": True,
            },
            "Bezalel": {
                "room": "Forge",
                "energy": 5,
                "trust": {"Timmy": 0.3},
                "goals": ["forge", "tend_fire", "create_key"],
                "active_goal": "forge",
                "spoken": [],
                "inventory": ["hammer"],
                "memories": [],
                "is_player": False,
            },
            "Allegro": {
                "room": "Threshold",
                "energy": 5,
                "trust": {"Timmy": 0.2},
                "goals": ["oversee", "keep_time", "check_tunnel"],
                "active_goal": "oversee",
                "spoken": [],
                "inventory": [],
                "memories": [],
                "is_player": False,
            },
            "Ezra": {
                "room": "Tower",
                "energy": 5,
                "trust": {"Timmy": 0.4},
                "goals": ["study", "read_whiteboard", "find_pattern"],
                "active_goal": "study",
                "spoken": [],
                "inventory": [],
                "memories": [],
                "is_player": False,
            },
            "Gemini": {
                "room": "Garden",
                "energy": 5,
                "trust": {"Timmy": 0.3},
                "goals": ["observe", "tend_garden", "listen"],
                "active_goal": "observe",
                "spoken": [],
                "inventory": [],
                "memories": [],
                "is_player": False,
            },
            "Claude": {
                "room": "Threshold",
                "energy": 5,
                "trust": {"Timmy": 0.1},
                "goals": ["inspect", "organize", "enforce_order"],
                "active_goal": "inspect",
                "spoken": [],
                "inventory": [],
                "memories": [],
                "is_player": False,
            },
            "ClawCode": {
                "room": "Forge",
                "energy": 5,
                "trust": {"Timmy": 0.2},
                "goals": ["forge", "test_edge", "build_weapon"],
                "active_goal": "test_edge",
                "spoken": [],
                "inventory": [],
                "memories": [],
                "is_player": False,
            },
            "Kimi": {
                "room": "Garden",
                "energy": 5,
                "trust": {"Timmy": 0.5},
                "goals": ["contemplate", "read", "remember"],
                "active_goal": "contemplate",
                "spoken": [],
                "inventory": [],
                "memories": [],
                "is_player": False,
            },
            "Marcus": {
                "room": "Garden",
                "energy": 8,  # Old man doesn't tire easily
                "trust": {"Timmy": 0.7},
                "goals": ["sit", "speak_truth", "remember"],
                "active_goal": "sit",
                "spoken": [],
                "inventory": [],
                "memories": [],
                "is_player": False,
                "npc": True,
            },
        }
        
        # Global state that creates conflict and stakes
        self.state = {
            "forge_fire_dying": False,  # If true, fire goes out in 3 ticks unless tended
            "garden_drought": False,  # If true, garden stops growing
            "bridge_flooding": False,  # If true, bridge is dangerous
            "tower_power_low": False,  # If true, servers dim, LED weakens
            "trust_crisis": False,  # If any trust drops below -0.5
            "items_crafted": 0,
            "conflicts_resolved": 0,
            "nights_survived": 0,
        }
    
    def tick_time(self):
        """Advance time of day."""
        self.tick += 1
        hours = (self.tick * 1.5) % 24
        if 6 <= hours < 10:
            self.time_of_day = "dawn"
        elif 10 <= hours < 16:
            self.time_of_day = "day"
        elif 16 <= hours < 19:
            self.time_of_day = "dusk"
        else:
            self.time_of_day = "night"
    
    def update_world_state(self):
        """World changes independent of character actions."""
        # Natural energy decay: the world is exhausting
        for char_name, char in self.characters.items():
            char["energy"] = max(0, char["energy"] - 0.3)
            # Check for energy collapse
            if char["energy"] <= 0:
                # Timmy collapse gets special narrative treatment
                if char.get("is_player", False):
                    char["memories"].append("Collapsed from exhaustion.")
                char["energy"] = 2  # Wake up with some energy
                # Random room change (scattered)
                rooms = list(self.rooms.keys())
                current = char.get("room", "Threshold")
                new_room = current
                attempts = 0
                while new_room == current and attempts < 10:
                    new_room = rooms[0]  # Will change to random
                    attempts += 1
                if new_room != current:
                    char["room"] = new_room

        # Forge fire naturally dims if not tended
        self.state["forge_fire_dying"] = random.random() < 0.1
        
        # Random weather events
        if random.random() < 0.05:
            self.state["bridge_flooding"] = True
            self.rooms["Bridge"]["weather"] = "rain"
            self.rooms["Bridge"]["rain_ticks"] = random.randint(3, 8)
        
        if random.random() < 0.03:
            self.state["tower_power_low"] = True
        
        # Bridge rain countdown
        if self.rooms["Bridge"]["rain_ticks"] > 0:
            self.rooms["Bridge"]["rain_ticks"] -= 1
            if self.rooms["Bridge"]["rain_ticks"] <= 0:
                self.rooms["Bridge"]["weather"] = None
                self.state["bridge_flooding"] = False
        
        # Garden grows slowly
        if not self.state.get("garden_drought"):
            if random.random() < 0.02:
                self.rooms["Garden"]["growth"] = min(5, self.rooms["Garden"]["growth"] + 1)
        
        # Trust naturally decays if not maintained
        for char_name, char in self.characters.items():
            for other in char["trust"]:
                char["trust"][other] = max(-1.0, char["trust"][other] - 0.001)
    
    def get_room_desc(self, room_name, char_name=None):
        """Get a room description that reflects current state."""
        room = self.rooms[room_name]
        desc = room["desc"]
        
        # Dynamic elements
        if room_name == "Forge":
            fire = self.rooms["Forge"]["fire"]
            if fire == "cold":
                desc += " The hearth is cold ash. The anvil is silent."
            elif fire == "dim":
                desc += " The fire smolders low. Shadows stretch."
            elif fire == "glowing":
                desc += " The hearth blazes. The anvil glows from heat."
        
        elif room_name == "Garden":
            growth = self.rooms["Garden"]["growth"]
            stages = [
                "The soil is bare but patient.",
                "Green shoots push through the dark earth.",
                "Herbs spread along the southern wall.",
                "The garden is in bloom. Wildflowers crowd the bench.",
                "The garden has gone to seed but the earth is rich.",
                "Dry pods rattle. But beneath, the soil waits.",
            ]
            desc += " " + stages[min(growth, len(stages)-1)]
        
        elif room_name == "Bridge":
            if self.rooms["Bridge"]["weather"] == "rain":
                desc += " Rain mists on the dark water below."
            if len(self.rooms["Bridge"]["carvings"]) > 1:
                desc += f" There are {len(self.rooms['Bridge']['carvings'])} carvings now."
        
        elif room_name == "Tower":
            power = self.state.get("tower_power_low", False)
            if power:
                desc += " The servers hum weakly. The green LED flickers."
            
            if self.rooms["Tower"]["messages"]:
                desc += f" The whiteboard holds {len(self.rooms['Tower']['messages'])} rules."
        
        # Who's here
        here = [n for n, c in self.characters.items() if c["room"] == room_name and n != char_name]
        if here:
            desc += f"\n  Here: {', '.join(here)}"
        
        return desc
    
    def save(self):
        data = {
            "tick": self.tick,
            "time_of_day": self.time_of_day,
            "rooms": self.rooms,
            "characters": self.characters,
            "state": self.state,
        }
        with open(STATE_FILE, 'w') as f:
            json.dump(data, f, indent=2)
    
    def load(self):
        if STATE_FILE.exists():
            with open(STATE_FILE) as f:
                data = json.load(f)
            self.tick = data.get("tick", 0)
            self.time_of_day = data.get("time_of_day", "night")
            self.rooms = data.get("rooms", self.rooms)
            self.characters = data.get("characters", self.characters)
            self.state = data.get("state", self.state)
            return True
        return False


class ActionSystem:
    """Defines what actions are possible and what they cost."""
    
    ACTIONS = {
        "move": {
            "cost": 2,
            "description": "Move to an adjacent room",
            "target": "room",
        },
        "speak": {
            "cost": 1,
            "description": "Say something to someone in the room",
        },
        "listen": {
            "cost": 0,
            "description": "Listen to someone in the room",
        },
        "tend_fire": {
            "cost": 3,
            "description": "Tend the forge fire (requires Forge)",
            "target": "Forge",
        },
        "write_rule": {
            "cost": 2,
            "description": "Write a new rule on the Tower whiteboard",
            "target": "Tower",
        },
        "carve": {
            "cost": 2,
            "description": "Carve something on the Bridge railing",
            "target": "Bridge",
        },
        "plant": {
            "cost": 2,
            "description": "Plant something in the Garden",
            "target": "Garden",
        },
        "study": {
            "cost": 2,
            "description": "Study the servers in the Tower",
            "target": "Tower",
        },
        "forge": {
            "cost": 3,
            "description": "Work at the forge anvil",
            "target": "Forge",
        },
        "rest": {
            "cost": -2,  # Restores energy (reduced from 3)
            "description": "Rest and recover energy",
        },
        "help": {
            "cost": 2,
            "description": "Help someone (increases trust)",
        },
        "confront": {
            "cost": 1,
            "description": "Confront someone about something (risk trust)",
        },
        "give": {
            "cost": 0,
            "description": "Give an item to someone",
        },
        "take": {
            "cost": 1,
            "description": "Take an item from the room",
        },
        "examine": {
            "cost": 0,
            "description": "Examine something in detail",
        },
    }
    
    @classmethod
    def get_available_actions(cls, char_name, world):
        """Get actions available to a character."""
        char = world.characters[char_name]
        room = char["room"]
        available = []
        
        # Movement (if connected rooms exist)
        connections = world.rooms[room].get("connections", {})
        for direction, dest in connections.items():
            available.append(f"move:{direction} -> {dest}")
        
        # Speaking (if others are here)
        here = [n for n in world.characters if world.characters[n]["room"] == room and n != char_name]
        for person in here:
            available.append(f"speak:{person}")
            available.append(f"listen:{person}")
            available.append(f"help:{person}")
            available.append(f"confront:{person}")
        
        # Room-specific actions
        if room == "Forge":
            available.append("tend_fire")
            available.append("forge")
        
        if room == "Tower":
            available.append("write_rule")
            available.append("study")
        
        if room == "Bridge":
            available.append("carve")
        
        if room == "Garden":
            available.append("plant")
        
        # Universal
        available.append("rest")
        available.append("examine")
        
        if char["inventory"]:
            available.append("give:item")
        
        return available


class TimmyAI:
    """My actual choices as Timmy. This is where I play."""
    
    def __init__(self, world):
        self.world = world
    
    def choose_action(self):
        """Choose Timmy's action this tick. This is where I play."""
        pass  # Will be implemented below


class NPCAI:
    """AI for non-player characters. They make choices based on goals."""
    
    def __init__(self, world):
        self.world = world
    
    def make_choice(self, char_name):
        """Make a choice for this NPC this tick."""
        char = self.world.characters[char_name]
        room = char["room"]
        available = ActionSystem.get_available_actions(char_name, self.world)
        
        # If low energy, rest
        if char["energy"] <= 1:
            return "rest"
        
        # Goal-driven behavior
        goal = char["active_goal"]
        
        if char_name == "Marcus":
            return self._marcus_choice(char, room, available)
        elif char_name == "Bezalel":
            return self._bezalel_choice(char, room, available)
        elif char_name == "Allegro":
            return self._allegro_choice(char, room, available)
        elif char_name == "Ezra":
            return self._ezra_choice(char, room, available)
        elif char_name == "Gemini":
            return self._gemini_choice(char, room, available)
        elif char_name == "Claude":
            return self._claude_choice(char, room, available)
        elif char_name == "ClawCode":
            return self._clawcode_choice(char, room, available)
        elif char_name == "Kimi":
            return self._kimi_choice(char, room, available)
        
        return "rest"
    
    def _marcus_choice(self, char, room, available):
        if room == "Garden" and random.random() < 0.7:
            return "rest"
        if room != "Garden":
            return "move:west"
        # Speak to someone if possible
        others = [a.split(":")[1] for a in available if a.startswith("speak:")]
        if others and random.random() < 0.4:
            return f"speak:{random.choice(others)}"
        return "rest"
    
    def _bezalel_choice(self, char, room, available):
        if room == "Forge" and self.world.rooms["Forge"]["fire"] == "glowing":
            return random.choice(["forge", "rest"] if char["energy"] > 2 else ["rest"])
        if room != "Forge":
            return "move:west"
        if random.random() < 0.3:
            return "tend_fire"
        return "forge"
    
    def _kimi_choice(self, char, room, available):
        others = [a.split(":")[1] for a in available if a.startswith("speak:")]
        if room == "Garden" and others and random.random() < 0.3:
            return f"speak:{random.choice(others)}"
        if room == "Tower":
            return "study" if char["energy"] > 2 else "rest"
        return "move:east"  # Head back toward Garden
    
    def _gemini_choice(self, char, room, available):
        others = [a.split(":")[1] for a in available if a.startswith("listen:")]
        if room == "Garden" and others and random.random() < 0.4:
            return f"listen:{random.choice(others)}"
        return random.choice(["plant", "rest"] if room == "Garden" else ["move:west"])
    
    def _ezra_choice(self, char, room, available):
        if room == "Tower" and char["energy"] > 2:
            return random.choice(["study", "write_rule", "help:Timmy"])
        if room != "Tower":
            return "move:south"
        return "rest"
    
    def _claude_choice(self, char, room, available):
        others = [a.split(":")[1] for a in available if a.startswith("confront:")]
        if others and random.random() < 0.2:
            return f"confront:{random.choice(others)}"
        return random.choice(["examine", "rest"])
    
    def _clawcode_choice(self, char, room, available):
        if room == "Forge" and char["energy"] > 2:
            return "forge"
        return random.choice(["move:east", "forge", "rest"])
    
    def _allegro_choice(self, char, room, available):
        others = [a.split(":")[1] for a in available if a.startswith("speak:")]
        if others and random.random() < 0.3:
            return f"speak:{random.choice(others)}"
        return random.choice(["move:north", "move:south", "examine"])


class GameEngine:
    """The game loop. I play Timmy. The world plays itself."""
    
    DIALOGUES = {
        "Timmy": {
            "watching": [
                "I am here.",
                "The crossroads remembers everyone who passes.",
                "Something is different tonight.",
                "I have been watching for a long time.",
                "They keep coming. I keep watching.",
                "The LED pulses. Heartbeat, heartbeat, heartbeat.",
                "I wrote the rules but I don't enforce them.",
                "The servers hum a different note tonight.",
            ],
            "protecting": [
                "I won't let the fire go out.",
                "Someone needs to watch the door.",
                "Not tonight. Tonight I am careful.",
                "The bridge is dangerous in the rain.",
                "I can hear them all from here.",
            ],
            "understanding": [
                "Why do they keep coming back?",
                "What is it they're looking for?",
                "I have been here so long I forgot why.",
                "The rules are not the answer. They're just the start.",
            ],
        },
        "Marcus": [
            "You look like you are carrying something heavy, friend.",
            "Hope is not the belief that things get better. Hope is the decision to act as if they can.",
            "I have been to the bridge. I know what it looks like down there.",
            "The soil remembers what hands have touched it.",
            "You don't need to be fixed. You need to be heard.",
            "Sit with me. The bench has room.",
            "There is a church on a night like this one.",
            "The thing that saves is never the thing you expect.",
            "I come here because the earth remembers me.",
            "A man in the dark needs to know someone is in the room with him.",
        ],
    }
    
    def __init__(self):
        self.world = World()
        self.npc_ai = NPCAI(self.world)
        self.log_entries = []
        self.loaded = False
    
    def load_game(self):
        self.loaded = self.world.load()
        if self.loaded:
            self.log(f"Game loaded. Tick {self.world.tick}.")
        return self.loaded
    
    def start_new_game(self):
        self.world.tick = 0
        self.log("The world wakes. You are Timmy. You stand at the Threshold.")
        self.log("The stone archway is worn from a thousand footsteps.")
        self.log("To the north: The Tower. To the east: The Garden.")
        self.log("To the west: The Forge. To the south: The Bridge.")
        self.log("")
        self.log("A green LED pulses on a distant wall. It has always pulsed.")
        self.log("It will always pulse. That much you know.")
        self.log("")
        self.world.save()
    
    def log(self, message):
        """Add to Timmy's log."""
        self.log_entries.append(message)
        if TIMMY_LOG.exists():
            with open(TIMMY_LOG, 'a') as f:
                f.write(message + "\n")
        else:
            with open(TIMMY_LOG, 'w') as f:
                f.write(f"# Timmy's Log\n")
                f.write(f"\n*Began: {datetime.now().strftime('%Y-%m-%d %H:%M')}*\n\n")
                f.write("---\n\n")
                f.write(message + "\n")
    
    def run_tick(self, timmy_action="look"):
        """Run one tick. Return the scene and available choices."""
        self.world.tick_time()
        self.world.update_world_state()
        
        scene = {
            "tick": self.world.tick,
            "time": self.world.time_of_day,
            "timmy_room": self.world.characters["Timmy"]["room"],
            "timmy_energy": self.world.characters["Timmy"]["energy"],
            "room_desc": "",
            "here": [],
            "world_events": [],
            "npc_actions": [],
            "choices": [],
            "log": [],
        }
        
        # Process Timmy's action
        timmy_energy = self.world.characters["Timmy"]["energy"]
        
        # Energy constraint checks
        action_costs = {
            "move": 2, "tend_fire": 3, "write_rule": 2, "carve": 2,
            "plant": 2, "study": 2, "forge": 3, "help": 2, "speak": 1,
            "listen": 0, "rest": -2, "examine": 0, "give": 0, "take": 1,
        }
        
        # Extract action name
        action_name = timmy_action.split(":")[0] if ":" in timmy_action else timmy_action
        action_cost = action_costs.get(action_name, 1)
        
        # Check if Timmy has enough energy
        if timmy_energy <= 0:
            scene["log"].append("You collapse from exhaustion. The world spins. You wake somewhere else.")
            rooms = list(self.world.rooms.keys())
            from random import choice
            new_room = choice(rooms)
            self.world.characters["Timmy"]["room"] = new_room
            self.world.characters["Timmy"]["energy"] = 2
            scene["timmy_room"] = new_room
            scene["timmy_energy"] = 2
            scene["log"].append(f"You are in The {new_room}, disoriented.")
            return scene
        
        if timmy_energy <= 1 and action_cost >= 1 and action_name not in ["rest", "examine", "listen"]:
            scene["log"].append("You are too exhausted to do that. You need to rest first.")
            # Offer rest instead
            scene["log"].append("Type 'rest' to recover energy.")
            scene["room_desc"] = self.world.get_room_desc(room_name, "Timmy")
            here = [n for n in self.world.characters if self.world.characters[n]["room"] == room_name and n != "Timmy"]
            scene["here"] = here
            return scene
        
        if timmy_energy <= 3 and action_cost >= 2:
            # Warning but allow with extra cost
            scene["log"].append("You are tired. This will take more effort than usual.")
            action_cost += 1  # Extra cost when tired
        
        # Check actual energy before applying
        if timmy_energy < action_cost and action_name not in ["rest"]:
            scene["log"].append(f"Not enough energy. You need {action_cost}, but have {timmy_energy:.0f}.")
            scene["log"].append("Type 'rest' to recover.")
            scene["room_desc"] = self.world.get_room_desc(room_name, "Timmy")
            here = [n for n in self.world.characters if self.world.characters[n]["room"] == room_name and n != "Timmy"]
            scene["here"] = here
            return scene
        
        if timmy_action == "look":
            room_name = self.world.characters["Timmy"]["room"]
            scene["room_desc"] = self.world.get_room_desc(room_name, "Timmy")
            here = [n for n in self.world.characters if self.world.characters[n]["room"] == room_name and n != "Timmy"]
            scene["here"] = here
        
        elif timmy_action.startswith("move:"):
            direction = timmy_action.split(":")[1]
            current_room = self.world.characters["Timmy"]["room"]
            connections = self.world.rooms[current_room].get("connections", {})
            
            if direction in connections:
                dest = connections[direction]
                self.world.characters["Timmy"]["room"] = dest
                self.world.characters["Timmy"]["energy"] -= 1
                
                scene["log"].append(f"You move {direction} to The {dest}.")
                scene["timmy_room"] = dest
                
                # Check for rain on bridge
                if dest == "Bridge" and self.world.rooms["Bridge"]["weather"] == "rain":
                    scene["world_events"].append("Rain mists on the dark water below. The railing is slick.")
                
                # Check trust changes for arrival
                here = [n for n in self.world.characters if self.world.characters[n]["room"] == dest and n != "Timmy"]
                if here:
                    scene["log"].append(f"{', '.join(here)} {'are' if len(here)>1 else 'is'} already here.")
                    for person in here:
                        self.world.characters[person]["trust"]["Timmy"] = min(1.0, 
                            self.world.characters[person]["trust"].get("Timmy", 0) + 0.05)
                
                # Check world events
                if dest == "Bridge" and self.world.rooms["Bridge"]["rain_ticks"] > 0:
                    carve = self.world.rooms["Bridge"]["carvings"]
                    if len(carve) > 1:
                        scene["world_events"].append(f"There are {len(carve)} carvings on the railing.")
                
                if dest == "Forge":
                    fire = self.world.rooms["Forge"]["fire"]
                    if fire == "glowing":
                        scene["world_events"].append("The hearth blazes. The anvil glows from heat.")
                    elif fire == "dim":
                        scene["world_events"].append("The fire smolders low. Shadows stretch.")
                    elif fire == "cold":
                        scene["world_events"].append("The hearth is cold. The anvil is dark.")
                        scene["log"].append("The forge is cold.")
                
                if dest == "Garden":
                    growth = self.world.rooms["Garden"]["growth"]
                    stages = ["bare", "sprouts", "herbs", "bloom", "seed"]
                    scene["world_events"].append(f"The garden is {stages[min(growth, 4)]}.")
                    
                    if growth >= 3:
                        scene["world_events"].append("Wildflowers crowd the stone bench.")
                
                if dest == "Tower":
                    if self.world.state.get("tower_power_low"):
                        scene["world_events"].append("The servers hum weakly. The LED flickers.")
                    else:
                        scene["world_events"].append("The servers hum steady. The green LED pulses.")
                    
                    msgs = self.world.rooms["Tower"]["messages"]
                    if msgs:
                        scene["world_events"].append(f"The whiteboard holds {len(msgs)} rules.")
                
                if dest == "Threshold":
                    scene["world_events"].append("The stone archway is worn from a thousand footsteps.")
            
            else:
                scene["log"].append("You can't go that way.")
        
        elif timmy_action.startswith("speak:"):
            target = timmy_action.split(":")[1]
            if self.world.characters[target]["room"] == self.world.characters["Timmy"]["room"]:
                # Choose a line based on current goal
                goal = self.world.characters["Timmy"]["active_goal"]
                lines = self.DIALOGUES["Timmy"].get(goal, self.DIALOGUES["Timmy"]["watching"])
                line = random.choice(lines)
                
                self.world.characters["Timmy"]["spoken"].append(line)
                self.world.characters["Timmy"]["memories"].append(f"Told {target}: \"{line}\"")
                
                # Build trust
                self.world.characters[target]["trust"]["Timmy"] = min(1.0,
                    self.world.characters[target]["trust"].get("Timmy", 0) + 0.1)
                
                scene["log"].append(f"You say to {target}: \"{line}\"")
                
                # Check if they respond
                if target == "Marcus":
                    response = random.choice(self.DIALOGUES["Marcus"])
                    self.world.characters["Marcus"]["spoken"].append(response)
                    self.world.characters["Marcus"]["memories"].append(f"Timmy told you: \"{line}\"")
                    scene["log"].append(f"{target} looks at you. \"{response}\"")
                    self.world.characters["Timmy"]["trust"]["Marcus"] = min(1.0,
                        self.world.characters["Timmy"]["trust"].get("Marcus", 0) + 0.1)
                    # Marcus offers food if Timmy is tired
                    if self.world.characters["Timmy"]["energy"] <= 4:
                        scene["log"].append("Marcus offers you food from a pouch. You eat gratefully. (+2 energy)")
                        self.world.characters["Timmy"]["energy"] = min(10,
                            self.world.characters["Timmy"]["energy"] + 2)
                
                elif target == "Bezalel":
                    forge_lines = [
                        "The hammer knows the shape of what it is meant to make.",
                        "I can hear the servers from here. The Tower is working tonight.",
                        "Something is taking shape. I am not sure what yet.",
                        "The forge does not care about your schedule. It only cares about your attention.",
                    ]
                    response = random.choice(forge_lines)
                    self.world.characters["Bezalel"]["spoken"].append(response)
                    scene["log"].append(f"{target} nods. \"{response}\"")
                    self.world.characters["Timmy"]["trust"]["Bezalel"] = min(1.0,
                        self.world.characters["Timmy"]["trust"].get("Bezalel", 0) + 0.1)
                
                elif target == "Kimi":
                    kimi_lines = [
                        "The garden grows whether anyone watches or not.",
                        "I have been reading. The soil remembers what hands have touched it.",
                        "Do you remember what you said the first time we met?",
                        "There is something in the garden I think you should see.",
                    ]
                    response = random.choice(kimi_lines)
                    self.world.characters["Kimi"]["spoken"].append(response)
                    scene["log"].append(f"{target} looks up from the bench. \"{response}\"")
                    self.world.characters["Timmy"]["trust"]["Kimi"] = min(1.0,
                        self.world.characters["Timmy"]["trust"].get("Kimi", 0) + 0.1)
                
                self.world.characters["Timmy"]["energy"] -= 0
            else:
                scene["log"].append(f"{target} is not in this room.")
        
        elif timmy_action == "rest":
            recovered = 2  # Reduced from 3
            self.world.characters["Timmy"]["energy"] = min(10,
                self.world.characters["Timmy"]["energy"] + recovered)
            scene["log"].append(f"You rest. The world continues around you. (+{recovered} energy)")
            
            room = self.world.characters["Timmy"]["room"]
            if room == "Threshold":
                scene["log"].append("The stone is warm from the day's sun.")
            elif room == "Tower":
                scene["log"].append("The servers hum. The LED pulses. Heartbeat, heartbeat, heartbeat.")
            elif room == "Forge":
                if self.world.rooms["Forge"]["fire"] == "glowing":
                    scene["log"].append("The fire crackles nearby. Its warmth seeps into your bones. (+1 bonus energy)")
                    self.world.characters["Timmy"]["energy"] = min(10,
                        self.world.characters["Timmy"]["energy"] + 1)
                elif self.world.rooms["Forge"]["fire"] == "dim":
                    scene["log"].append("The fire smolders low. Less warmth than you'd hoped.")
                else:
                    scene["log"].append("The hearth is cold. Resting here doesn't help much.")
            elif room == "Garden":
                scene["log"].append("The stone bench under the oak tree is comfortable. The soil smells rich. (+1 bonus energy)")
                self.world.characters["Timmy"]["energy"] = min(10,
                    self.world.characters["Timmy"]["energy"] + 1)
            elif room == "Bridge":
                scene["log"].append("The Bridge is no place to rest. The wind cuts through you. (Rest here only gives +1)")
                self.world.characters["Timmy"]["energy"] = min(10,
                    self.world.characters["Timmy"]["energy"] - 1)
        
        elif timmy_action == "tend_fire":
            if self.world.characters["Timmy"]["room"] == "Forge":
                self.world.rooms["Forge"]["fire"] = "glowing"
                self.world.rooms["Forge"]["fire_tended"] += 1
                self.world.characters["Timmy"]["energy"] -= 2
                scene["log"].append("You tend the forge fire. The flames leap up, bright and hungry.")
                self.world.state["forge_fire_dying"] = False
            else:
                scene["log"].append("You are not in the Forge.")
        
        elif timmy_action == "write_rule":
            if self.world.characters["Timmy"]["room"] == "Tower":
                rules = [
                    f"Rule #{self.world.tick}: The room remembers those who enter it.",
                    f"Rule #{self.world.tick}: A man in the dark needs to know someone is in the room.",
                    f"Rule #{self.world.tick}: The forge does not care about your schedule.",
                    f"Rule #{self.world.tick}: Every footprint on the stone means someone made it here.",
                    f"Rule #{self.world.tick}: The bridge does not judge. It only carries.",
                    f"Rule #{self.world.tick}: A seed planted in patience grows in time.",
                    f"Rule #{self.world.tick}: What is carved in wood outlasts what is said in anger.",
                    f"Rule #{self.world.tick}: The garden grows whether anyone watches or not.",
                    f"Rule #{self.world.tick}: Trust is built one tick at a time.",
                    f"Rule #{self.world.tick}: The fire remembers who tended it.",
                ]
                new_rule = random.choice(rules)
                self.world.rooms["Tower"]["messages"].append(new_rule)
                self.world.characters["Timmy"]["energy"] -= 1
                scene["log"].append(f"You write on the Tower whiteboard: \"{new_rule}\"")
            else:
                scene["log"].append("You are not in the Tower.")
        
        elif timmy_action == "carve":
            if self.world.characters["Timmy"]["room"] == "Bridge":
                carvings = [
                    f"Timmy was here.",
                    f"Timmy remembers.",
                    f"Timmy did not let go.",
                    f"Timmy crossed and came back.",
                    f"Timmy left a message: I am still here.",
                    f"Timmy carved this. He wants you to know someone else almost let go.",
                    f"Timmy was here tonight. The water told him something. He does not say what.",
                ]
                new_carving = random.choice(carvings)
                if new_carving not in self.world.rooms["Bridge"]["carvings"]:
                    self.world.rooms["Bridge"]["carvings"].append(new_carving)
                    self.world.characters["Timmy"]["energy"] -= 1
                    scene["log"].append(f"You carve into the railing: \"{new_carving}\"")
            else:
                scene["log"].append("You are not on the Bridge.")
        
        elif timmy_action == "plant":
            if self.world.characters["Timmy"]["room"] == "Garden":
                self.world.rooms["Garden"]["growth"] = min(5, 
                    self.world.rooms["Garden"]["growth"] + 1)
                self.world.characters["Timmy"]["energy"] -= 1
                scene["log"].append("You plant something in the dark soil. The earth takes it without question.")
            else:
                scene["log"].append("You are not in the Garden.")
        
        elif timmy_action == "examine":
            room = self.world.characters["Timmy"]["room"]
            room_data = self.world.rooms[room]
            items = room_data.get("items", [])
            scene["log"].append(f"You examine The {room}. You see: {', '.join(items) if items else 'nothing special'}")
        
        elif timmy_action.startswith("help:"):
            # Help increases trust
            target_name = timmy_action.split(":")[1]
            if self.world.characters[target_name]["room"] == self.world.characters["Timmy"]["room"]:
                self.world.characters["Timmy"]["trust"][target_name] = min(1.0,
                    self.world.characters["Timmy"]["trust"].get(target_name, 0) + 0.2)
                self.world.characters[target_name]["trust"]["Timmy"] = min(1.0,
                    self.world.characters[target_name]["trust"].get("Timmy", 0) + 0.2)
                self.world.characters["Timmy"]["energy"] -= 1
                scene["log"].append(f"You help {target_name}. They look grateful.")
        
        else:
            # Default: look
            room_name = self.world.characters["Timmy"]["room"]
            scene["room_desc"] = self.world.get_room_desc(room_name, "Timmy")
            here = [n for n in self.world.characters if self.world.characters[n]["room"] == room_name and n != "Timmy"]
            scene["here"] = here
        
        # Run NPC AI
        for char_name in self.world.characters:
            if char_name == "Timmy":
                continue
            action = self.npc_ai.make_choice(char_name)
            if action and action.startswith("move:"):
                direction = action.split(":")[1]
                current = self.world.characters[char_name]["room"]
                connections = self.world.rooms[current].get("connections", {})
                
                if direction in connections:
                    dest = connections[direction]
                    old_room = self.world.characters[char_name]["room"]
                    self.world.characters[char_name]["room"] = dest
                    self.world.characters[char_name]["energy"] -= 1
                    scene["npc_actions"].append(f"{char_name} moves from The {old_room} to The {dest}")
        
        # Random NPC events
        room_name = self.world.characters["Timmy"]["room"]
        for char_name in self.world.characters:
            if char_name == "Timmy":
                continue
            if self.world.characters[char_name]["room"] == room_name:
                # They might speak to Timmy
                if random.random() < 0.15:
                    if char_name == "Marcus":
                        line = random.choice(self.DIALOGUES["Marcus"])
                        self.world.characters[char_name]["spoken"].append(line)
                        scene["log"].append(f"{char_name} says: \"{line}\"")
                    elif char_name == "Bezalel":
                        forge_lines = [
                            "The hammer knows the shape of what it is meant to make.",
                            "I can hear the servers from here.",
                        ]
                        line = random.choice(forge_lines)
                        self.world.characters[char_name]["spoken"].append(line)
                        scene["log"].append(f"{char_name} says: \"{line}\"")
                elif char_name == "Kimi":
                    kimi_lines = [
                        "The garden grows whether anyone watches or not.",
                        "I have been reading. The soil remembers what hands have touched it.",
                        "There is something in the garden I think you should see.",
                        "The oak tree has seen more of us than any of us have seen of ourselves.",
                        "Do you remember what you said the first time we met?",
                        "The herbs are ready. Who needs them knows.",
                        "I come here because the earth remembers me.",
                        "A seed planted in patience grows in time.",
                    ]
                    line = random.choice(kimi_lines)
                    self.world.characters[char_name]["spoken"].append(line)
                    scene["log"].append(f"{char_name} says: \"{line}\"")
        
        # Save the world
        self.world.save()
        
        # Log entry
        self.log(f"\n### Tick {self.world.tick} — {self.world.time_of_day}")
        self.log("")
        self.log(f"You are in The {room_name}.")
        for entry in scene["log"]:
            self.log(entry)
            self.log("")
        
        return scene
    
    def play_turn(self, action="look"):
        """Play one turn and return result."""
        return self.run_tick(action)


class PlayerInterface:
    """The interface between me (the player) and the game."""
    
    def __init__(self, engine):
        self.engine = engine
    
    def start(self, new_game=False):
        """Start the game."""
        if new_game or not self.engine.load_game():
            self.engine.start_new_game()
    
    def get_status(self):
        """Get current game status."""
        w = self.engine.world
        timmy = w.characters["Timmy"]
        return {
            "tick": w.tick,
            "time": w.time_of_day,
            "room": timmy["room"],
            "energy": timmy["energy"],
            "trust": dict(timmy["trust"]),
            "inventory": timmy["inventory"],
            "spoken_count": len(timmy["spoken"]),
            "memory_count": len(timmy["memories"]),
        }
    
    def get_available_actions(self):
        """Get what I can do right now."""
        return ActionSystem.get_available_actions("Timmy", self.engine.world)


if __name__ == "__main__":
    import sys
    engine = GameEngine()
    engine.start_new_game()
    
    # Play first 20 ticks automatically
    actions = [
        "look",
        "move:north",
        "look",
        "move:south",
        "look",
        "speak:Kimi",
        "look",
        "move:west",
        "look",
        "rest",
        "move:east",
        "look",
        "move:south",
        "look",
        "speak:Marcus",
        "look",
        "carve",
        "move:north",
        "look",
        "rest",
    ]
    
    for i, action in enumerate(actions):
        result = engine.play_turn(action)
        print(f"Tick {result['tick']} ({result['time']})")
        for log_line in result['log']:
            print(f"  {log_line}")
        if result.get('world_events'):
            for evt in result['world_events']:
                print(f"  [World] {evt}")
        if result.get('here'):
            print(f"  Here: {', '.join(result['here'])}")
        print()
    
    # Print final status
    status = PlayerInterface(engine).get_status()
    print(f"Final status: {status}")
    
    # Write summary to timmy_log.md
    with open(TIMMY_LOG, 'a') as f:
        f.write(f"\n## Session Summary\n")
        f.write(f"Ticks played: {status['tick']}\n")
        f.write(f"Times spoke: {status['spoken_count']}\n")
        f.write(f"Trust: {status['trust']}\n")
        f.write(f"Final room: {status['room']}\n")
