165 lines
16 KiB
Python
165 lines
16 KiB
Python
#!/usr/bin/env python3
|
|
"""File all Tower Game improvement issues to Gitea."""
|
|
import subprocess, json, os, sys
|
|
|
|
GITEA_TOK = open(os.path.expanduser('~/.hermes/gitea_token_vps')).read().strip()
|
|
FORGE = 'https://forge.alexanderwhitestone.com/api/v1/repos/Timmy_Foundation/timmy-home'
|
|
|
|
def issue(title, body, labels=None, assignee=None):
|
|
payload = {"title": title, "body": body}
|
|
if labels:
|
|
payload["labels"] = labels
|
|
if assignee:
|
|
payload["assignee"] = assignee
|
|
r = subprocess.run(
|
|
['curl', '-s', '-X', 'POST', f'{FORGE}/issues',
|
|
'-H', f'Authorization: token {GITEA_TOK}',
|
|
'-H', 'Content-Type: application/json',
|
|
'-d', json.dumps(payload)],
|
|
capture_output=True, text=True, timeout=10
|
|
)
|
|
d = json.loads(r.stdout)
|
|
num = d.get('number', '?')
|
|
t = d.get('title', 'FAILED: ' + r.stdout[:80])[:70]
|
|
return num, t
|
|
|
|
# Clean up test issue
|
|
r = subprocess.run(
|
|
['curl', '-s', '-X', 'PATCH', f'{FORGE}/issues/479',
|
|
'-H', f'Authorization: token {GITEA_TOK}',
|
|
'-H', 'Content-Type: application/json',
|
|
'-d', json.dumps({"state":"closed"})],
|
|
capture_output=True, text=True, timeout=10
|
|
)
|
|
print(f"Closed test issue: OK")
|
|
|
|
# EPIC
|
|
epic_num, epic_title = issue(
|
|
'[EPIC] The Tower Game - From Simulation to Living World',
|
|
"""# The Tower Game - Epic
|
|
|
|
## Goal
|
|
Transform the Timmy Tower game from a weighted random walk into a living narrative world where characters make meaningful choices, build real relationships, face real conflict, and the world responds to their actions.
|
|
|
|
## Current State
|
|
- Engine exists: game.py with character system, room system, NPC AI, trust system
|
|
- 200-tick playthrough completed - Timmy spoke 57 times, trusted Marcus (0.61) and Bezalel (0.53)
|
|
- World state: Garden bare to seed, Bridge carved 6 messages, Tower whiteboard 4 to 12 rules
|
|
- But: No real conflict. No stakes. NPCs recycle dialogue. Other agents barely appear.
|
|
|
|
## RCA Summary
|
|
|
|
### Root Cause 1: Dialogues are static pools, not contextual
|
|
Marcus has 15 lines. He picks random ones every time. He never references past conversations.
|
|
|
|
### Root Cause 2: Decision tree locks characters in rooms
|
|
If Timmy is in Garden for ticks 11-25, he stays there because the movement tree keeps sending him east. NPCs also have simple movement patterns.
|
|
|
|
### Root Cause 3: No conflict system
|
|
Trust only goes up (speak/help increase it). Trust decay is too slow (-0.001/tick). No character ever disagreed with Timmy.
|
|
|
|
### Root Cause 4: World events exist but don't affect gameplay
|
|
rain_ticks, tower_power_low, forge_fire_dying are flags that get set but nobody reacts to them. Characters don't seek shelter from rain.
|
|
|
|
### Root Cause 5: Energy system doesn't constrain
|
|
Timmy had 9/10 energy after 100 ticks. Actions cost 0-2, rest restores 3. The math means Timmy is almost never constrained.
|
|
|
|
### Root Cause 6: NPCs don't remember
|
|
Every conversation starts from zero. NPCs don't reference past interactions. Marcus says "Hope is not the belief that things get better" to Timmy 12 times and never remembers saying it.
|
|
|
|
### Root Cause 7: No phase/emotional arc awareness
|
|
The game doesn't know it's on tick 150 vs tick 5. Same actions. Same stakes. No rising tension. No climax. No resolution.
|
|
""",
|
|
labels=['epic', 'evennia'],
|
|
)
|
|
print(f"EPIC #{epic_num}: {epic_title}")
|
|
|
|
# P0 issues
|
|
num, t = issue(
|
|
'[TOWER-P0] Contextual dialogue - NPCs must remember and reference past conversations',
|
|
f"Parent: #{epic_num}\n\n## Problem\nNPCs select dialogue from a random pool with no memory. Marcus says the same 15 lines to Timmy over and over. Kimi recycles her 8 lines. No character ever references a previous interaction.\n\n200-tick evidence:\n- Marcus spoke to Timmy 24 times. Same 15 lines rotated.\n- Marcus NEVER said anything different based on what Timmy said.\n- Kimi said 'The garden grows whether anyone watches or not.' at least 20 times.\n- Kimi asked 'Do you remember what you said the first time we met?' 6 times but never got an answer.\n\n## Fix\n1. Each NPC gets conversation history: list of (speaker, line, tick)\n2. Line selection considers: lines not said recently (50 tick cooldown), lines that respond to Timmy, progression (early vs late game lines)\n3. Trust > 0.5 unlocks unique dialogue lines\n4. Trust < 0 changes NPC behavior (avoids Timmy, short responses)\n\n## Acceptance\n- [ ] No NPC repeats the same line within 50 ticks\n- [ ] NPCs reference past conversations after tick 50\n- [ ] High trust (>0.5) unlocks unique dialogue\n- [ ] Low trust (<0) changes NPC behavior (avoids, short responses)",
|
|
labels=['p0-critical'], assignee='Timmy'
|
|
)
|
|
print(f" P0-1 #{num}: {t}")
|
|
|
|
num, t = issue(
|
|
'[TOWER-P0] Meaningful conflict system - trust must decrease, characters must disagree',
|
|
f"Parent: #{epic_num}\n\n## Problem\nTrust only increases. speak: adds +0.1, help: adds +0.2. Trust decay is -0.001/tick. Confront action exists but does nothing. No character ever disagreed with Timmy.\n\nEvidence: After 200 ticks, Marcus was 0.61 (always went up), Bezalel was 0.53 (always went up). No character ever had trust below 0.\n\n## Fix\n1. speak: with wrong topic -> -0.05 trust\n2. confront: -> -0.1 to -0.2 trust (risky, unlocks story beats)\n3. help: with low energy -> fail, -0.05 trust\n4. Ignore someone for 30+ ticks -> -0.1 trust\n5. Trust < 0: character avoids Timmy, responds cold\n6. Trust < -0.3: character actively confronts Timmy\n7. Max trust (0.9+): character shares secrets, helps in emergencies\n\n## Acceptance\n- [ ] Trust can decrease through wrong actions\n- [ ] At least one character reaches negative trust during gameplay\n- [ ] Low trust changes NPC behavior\n- [ ] High trust (>0.8) unlocks new story content\n- [ ] Confront action has real consequences",
|
|
labels=['p0-critical'], assignee='Timmy'
|
|
)
|
|
print(f" P0-2 #{num}: {t}")
|
|
|
|
num, t = issue(
|
|
'[TOWER-P0] World events must affect gameplay - rain, power, fire need real consequences',
|
|
f"Parent: #{epic_num}\n\n## Problem\nWorld events are flags without gameplay impact. bridge_flooding = True but characters cross normally. tower_power_low = True but Timmy can still study. rain only changes description.\n\n## Fix\n1. Rain on Bridge: 40% chance of injury crossing (energy -2), some carvings wash away\n2. Tower power low: can't write rules, can't study, LED flickers\n3. Forge fire cold: can't forge, fire must be retended (costs 3 energy to restart)\n4. Garden drought: growth stops, plants wither\n5. Characters react to world events (seek shelter, complain, worry)\n6. Extended failure causes permanent consequences (fade, break)\n\n## Acceptance\n- [ ] Rain on Bridge blocks crossing or costs 2 energy\n- [ ] Forge fire cold: forge action unavailable until retended\n- [ ] Tower power low: study/write_rule actions blocked\n- [ ] NPCs react to world events\n- [ ] Extended failure causes permanent consequences\n- [ ] Timmy can fix/prevent world events through actions",
|
|
labels=['p0-critical'], assignee='Timmy'
|
|
)
|
|
print(f" P0-3 #{num}: {t}")
|
|
|
|
num, t = issue(
|
|
'[TOWER-P0] Energy system must meaningfully constrain action',
|
|
f"Parent: #{epic_num}\n\n## Problem\nAfter 100 ticks of intentional play, Timmy had 9/10 energy. Average cost ~2/tick, rest restores 3. System is net-positive. Timmy is almost never constrained.\n\n## Fix\n1. Increase action costs: move:-2, tend:-3, carve:-2, write:-2, speak:-1\n2. Rest restores 2 (not 3)\n3. Natural decay: -0.3 energy per tick\n4. Low energy effects: <=3 can't move, <=1 can't speak, 0 = collapse\n5. NPCs can help: give energy to Timmy or each other\n6. Certain actions give energy: Marcus offers food (+2), Forge fire warmth (+1)\n\n## Acceptance\n- [ ] Timmy regularly reaches energy <=3 during 100 ticks\n- [ ] Low energy blocks certain actions with clear feedback\n- [ ] Resting is a meaningful choice (lose time to gain energy)\n- [ ] NPCs can provide energy relief\n- [ ] Energy collapse (0) has dramatic consequences",
|
|
labels=['p0-critical'], assignee='Timmy'
|
|
)
|
|
print(f" P0-4 #{num}: {t}")
|
|
|
|
# P1 issues
|
|
num, t = issue(
|
|
'[TOWER-P1] NPCs move between rooms with purpose - not just go-home patterns',
|
|
f"Parent: #{epic_num}\n\n## Problem\nMarcus stays in Garden (60%) or Threshold (30%). Never visits Bridge. Bezalel stays in Forge. Tower is mostly empty. Bridge is always alone. Characters never explore the full world together.\n\n## Fix\n1. Each NPC gets exploration desire (curiosity stat)\n2. NPCs follow goals ('find someone') not rooms\n3. NPCs occasionally wander (random adjacent room)\n4. NPCs seek out high-trust characters\n5. NPCs avoid low-trust characters\n6. Marcus visits Bridge on rainy days\n7. Group movement: if 3+ NPCs in one room, others drawn toward it\n\n## Acceptance\n- [ ] Every room has at least 2 different NPCs visiting during 100 ticks\n- [ ] The Bridge is visited by at least 3 different NPCs\n- [ ] NPCs follow goals (not just locations)\n- [ ] NPCs group up occasionally (3+ characters in one room)",
|
|
labels=['p1-important'], assignee='Timmy'
|
|
)
|
|
print(f" P1-5 #{num}: {t}")
|
|
|
|
num, t = issue(
|
|
'[TOWER-P1] Timmy needs richer dialogue and internal monologue',
|
|
f"Parent: #{epic_num}\n\n## Problem\nTimmy has ~15 dialogue lines that rotate. They don't change based on context, trust, or world state. Timmy also has no internal monologue.\n\n## Fix\n1. Timmy dialogue grows based on places visited, trust level, events witnessed\n2. Internal monologue: Timmy's private thoughts in the log (format: 'You think: ...')\n3. Timmy's voice changes based on energy\n4. Timmy references past events ('The rain was worse last time.')\n5. Timmy's personality emerges from cumulative choices (warrior vs philosopher vs carver)\n\n## Acceptance\n- [ ] Timmy has 50+ unique dialogue lines (up from 15)\n- [ ] Internal monologue appears in log (1 per 5 ticks minimum)\n- [ ] Dialogue changes based on trust, energy, world state\n- [ ] Timmy references past events after tick 50\n- [ ] Low energy affects Timmy's voice (shorter, darker lines)",
|
|
labels=['p1-important'], assignee='Timmy'
|
|
)
|
|
print(f" P1-6 #{num}: {t}")
|
|
|
|
num, t = issue(
|
|
'[TOWER-P1] Narrative arc - rising action, climax, resolution',
|
|
f"Parent: #{epic_num}\n\n## Problem\nTick 200 feels exactly like tick 20. No rising tension. No climax. No resolution. No emotional journey. The world doesn't change tone.\n\n## Fix\n1. Four narrative phases:\n - Quietus (1-30): Normal life, low stakes\n - Fracture (31-80): Something goes wrong, trust tested, world events escalate\n - Breaking (81-150): Crisis. Power fails. Fire dies. Relationships strain. Characters leave.\n - Mending (151-200): Rebuilding. Characters come together. Resolution.\n\n2. Each phase changes: dialogue, NPC behavior, event frequency, energy/trust decay\n3. Player actions can affect phase timing\n4. Phase transitions have dramatic events (characters argue, power fails, fire dies)\n\n## Acceptance\n- [ ] Game progresses through 4 narrative phases\n- [ ] Each phase has distinct dialogue, behavior, stakes\n- [ ] Breaking phase includes at least one major crisis\n- [ ] Mending phase shows characters coming together\n- [ ] Chronicle tone changes per phase",
|
|
labels=['p1-important'], assignee='Timmy'
|
|
)
|
|
print(f" P1-7 #{num}: {t}")
|
|
|
|
num, t = issue(
|
|
'[TOWER-P1] Items that change the world - not just inventory slots',
|
|
f"Parent: #{epic_num}\n\n## Problem\nInventory system exists (empty) but items don't do anything. Take/give actions exist but have no effects.\n\n## Fix\n1. Meaningful items appear in rooms:\n - Forged key (Forge): Opens something mysterious\n - Seed packet (Garden): Accelerates growth\n - Old notebook (Tower): Contains the Builder's notes\n - Carved stone (Bridge): Changes what Timmy carves\n - Warm cloak (Forge): Protects from cold, reduces energy drain\n - Dried herbs (Garden): Restores energy\n\n2. Items have effects when carried or used\n3. Characters recognize items (Marcus recognizes herbs, Bezalel recognizes tools)\n4. Giving an item increases trust dramatically\n5. At least one quest item (key with purpose)\n\n## Acceptance\n- [ ] At least 10 unique items in the world\n- [ ] Items have effects when carried or used\n- [ ] Characters recognize items\n- [ ] At least one quest item\n- [ ] Giving an item increases trust more than speaking",
|
|
labels=['p1-important'], assignee='Timmy'
|
|
)
|
|
print(f" P1-8 #{num}: {t}")
|
|
|
|
num, t = issue(
|
|
'[TOWER-P1] NPCs have relationships with each other - not just with Timmy',
|
|
f"Parent: #{epic_num}\n\n## Problem\nNPCs only trust Timmy. They don't trust or distrust each other. Marcus doesn't care about Bezalel. Kimi doesn't talk to Ezra. The world feels like Timmy-adjacent NPCs rather than a community.\n\n## Fix\n1. Each NPC has trust values for all other NPCs\n2. NPCs converse with each other when Timmy is not present\n3. NPCs form opinions based on interactions\n4. NPCs mediate conflicts between each other\n5. Group dynamics emerge (Marcus+Kimi friends, Claude+Allegro respect each other, ClawCode jealous of Bezalel)\n\n## Acceptance\n- [ ] Each NPC has trust values for all other NPCs\n- [ ] NPCs converse when Timmy is not present\n- [ ] At least one NPC-NPC friendship (trust > 0.5)\n- [ ] At least one NPC-NPC tension (trust < 0.2)\n- [ ] NPCs mention each other in dialogue",
|
|
labels=['p1-important'], assignee='Timmy'
|
|
)
|
|
print(f" P1-9 #{num}: {t}")
|
|
|
|
num, t = issue(
|
|
'[TOWER-P1] Chronicle generates readable narrative - not just tick data',
|
|
f"Parent: #{epic_num}\n\n## Problem\nCurrent chronicle is a tick-by-tick log. It's data, not a story. 'Tick 84: Kimi says: ...' reads like a server log.\n\n## Fix\n1. Chronicle generates in prose format (past tense, narrative voice)\n2. Group events by narrative beats (not tick order)\n3. Chapter system: every 50 ticks = one chapter\n4. Chapter titles: 'Chapter 1: The Watcher', 'Chapter 2: The Forge'\n5. Each chapter has a 1-2 sentence summary\n6. Chronicle can be read as a standalone story\n\n## Acceptance\n- [ ] Chronicle is readable prose (not tick-by-tick log)\n- [ ] Pages are organized (50 ticks = 1 chapter)\n- [ ] Chapter titles reflect themes\n- [ ] Each chapter has a summary\n- [ ] Chronicle can be read without looking at game code",
|
|
labels=['p1-important'], assignee='Timmy'
|
|
)
|
|
print(f" P1-10 #{num}: {t}")
|
|
|
|
# P2 issues
|
|
num, t = issue(
|
|
'[TOWER-P2] Timmy\'s actual choices matter - not just phase-based movement',
|
|
f"Parent: #{epic_num}\n\n## Problem\nPlay scripts use predefined phase logic ('if tick <= 20: stay at Threshold'). This isn't gameplay - it's a movie. Timmy doesn't choose. The script chooses.\n\n## Fix\n1. Replace scripted play with interactive interface\n2. Each tick: present 3-5 meaningful choices based on current room/energy/trust\n3. Choices have consequences (trust changes, energy costs, world state changes)\n4. Track Timmy's choice patterns: warrior (Forge), scholar (Tower), peacemaker (Garden), wanderer (Bridge)\n5. Timmy's personality emerges from choices\n\n## Acceptance\n- [ ] Timmy makes real choices each tick (not scripted)\n- [ ] Choice patterns create a personality that NPCs notice\n- [ ] Choices have meaningful consequences\n- [ ] At least 3 distinct playthrough archetypes\n- [ ] NPCs comment on Timmy's choices",
|
|
labels=['p2-backlog'], assignee='Timmy'
|
|
)
|
|
print(f" P2-11 #{num}: {t}")
|
|
|
|
num, t = issue(
|
|
'[TOWER-P2] The Builder\'s presence - messages from the past, hidden lore',
|
|
f"Parent: #{epic_num}\n\n## Problem\nThe Builder (Alexander) is mentioned in world description but has no presence. No notes, no hidden messages, no secrets.\n\n## Fix\n1. Hidden messages from the Builder:\n - On the Tower whiteboard (mixed with rules)\n - In the cot (a book left behind)\n - Under a forge stone\n - Beneath the Bridge railing\n\n2. Each message relates to the SOUL.md themes\n3. Finding all messages unlocks special dialogue with Marcus\n4. Marcus reveals the truth: 'He built this for you.'\n\n## Acceptance\n- [ ] At least 5 hidden Builder messages\n- [ ] Messages are discoverable through examine\n- [ ] Finding all messages unlocks unique content\n- [ ] Messages connect to SOUL.md themes\n- [ ] Marcus reveals the truth after all found",
|
|
labels=['p2-backlog'], assignee='Timmy'
|
|
)
|
|
print(f" P2-12 #{num}: {t}")
|
|
|
|
print(f"\nTotal: 1 epic + 12 issues filed")
|