### Configure Settings and Timer Intervals Source: https://context7.com/s4l7/claudestoryteller/llms.txt Manage API keys and event frequency bounds. Timer adjustments are automatically clamped to safe operational limits. ```csharp // Access mod settings ClaudeStorytellerSettings settings = ClaudeStorytellerMod.settings; // API key management (stored with XOR obfuscation) settings.ApiKey = "sk-ant-api03-..."; bool hasKey = settings.HasApiKey; string masked = settings.GetMaskedApiKey(); // "sk-ant-•••••••••••••-abcd" // Enable/disable the mod settings.enabled = true; // Event interval configuration (player-adjustable) settings.minorMinHours = 36f; // Minor events: 36-72 game hours settings.minorMaxHours = 72f; settings.majorMinDays = 3f; // Major events: 3-7 game days settings.majorMaxDays = 7f; settings.narrativeMinDays = 4f; // Narrative arcs: 4-8 game days settings.narrativeMaxDays = 8f; // Get randomized intervals within bounds float minorHours = settings.GetMinorInterval(); // Random 36-72 float majorHours = settings.GetMajorInterval(); // Random 3-7 days in hours float narrativeHours = settings.GetNarrativeInterval(); // Claude can suggest timer adjustments (clamped to safe bounds) var adjustment = new TimerAdjustment { MinorMinHours = 24f, MinorMaxHours = 48f, MajorMinDays = 2f, MajorMaxDays = 5f }; settings.ApplyTimerAdjustment(adjustment); // Adjustments clamped to: Minor 6-72h, Major 1-14d, Narrative 2-15d ``` -------------------------------- ### Test API Connection and Key Validity Source: https://context7.com/s4l7/claudestoryteller/llms.txt Use these static methods to verify your Anthropic API key before gameplay. `TestConnection` checks for valid authentication, while `ValidateApiKey` ensures the key format is correct. `CanMakeCall` helps prevent rate limiting. ```csharp // Static method for testing API key validity // Returns: "Success! API key is valid." or error message string result = await ClaudeApiClient.TestConnection("sk-ant-api03-..."); ``` ```csharp // Validate key format before making API calls bool isValid = ClaudeApiClient.ValidateApiKey(apiKey); // Returns true if key starts with "sk-ant-" ``` ```csharp // Check rate limiting before calls (30 second minimum between calls) if (ClaudeApiClient.CanMakeCall()) { // Safe to proceed with API call } ``` -------------------------------- ### Unified Decision Request to Claude API Source: https://context7.com/s4l7/claudestoryteller/llms.txt This snippet demonstrates how to initialize the API client, collect the current colony state, and send a unified request to Claude for narrative decisions. The response includes arc progression, scattered events, storytelling posture, and timing for the next API call. ```csharp // Create API client with your key var client = new ClaudeApiClient(apiKey); ``` ```csharp // Collect colony state for the unified call ColonyState state = ColonyStateCollector.CollectState(map, "unified"); ``` ```csharp // Make the unified decision request UnifiedResponse response = await client.GetUnifiedDecision(state); ``` ```json { "arc": { "decision": "start_arc", "arc_name": "The Silent Siege", "events": [ {"delay_hours": 12, "type": "Eclipse", "intensity": 1.0, "note": "ominous beginning"}, {"delay_hours": 36, "type": "RaidEnemy", "subtype": "siege", "faction": "Pirate", "intensity": 1.3} ], "reasoning": "Colony defenses are strong but rely on turrets. An eclipse siege tests adaptation." }, "scattered_events": [ {"delay_hours": 8, "type": "TraderCaravanArrival", "intensity": 1.0, "note": "false calm"}, {"delay_hours": 72, "type": "WandererJoin", "intensity": 1.0, "note": "hope after crisis"} ], "posture": { "current_blend": "Cassandra-heavy with Phoebe recovery", "reasoning": "Colony is stable and thriving; structured escalation appropriate", "next_posture_hint": "If wealth continues climbing, shift to Randy disruption" }, "next_call_days": 5, "reasoning": "Testing defenses with a siege while wealth is high..." } ``` -------------------------------- ### Resolve Event Names Source: https://context7.com/s4l7/claudestoryteller/llms.txt Map shorthand event names and subtypes to internal RimWorld defNames and strategies. ```csharp // Event name mappings (case-insensitive) // Input -> Resolved defName "Raid" -> "RaidEnemy" "Plague" -> "Disease_Plague" "Disease" -> "Disease_Plague" "Trader" -> "TraderCaravanArrival" "Wanderer" -> "WandererJoin" "Infestation" -> "Infestation" "MechCluster" -> "MechCluster" "Defoliator" -> "DefoliatorShipPartCrash" "Manhunter" -> "ManhunterPack" // Raid subtypes for RaidEnemy events "assault" -> RaidStrategyDef "ImmediateAttack" "sapper" -> RaidStrategyDef "ImmediateAttackSappers" "siege" -> RaidStrategyDef "Siege" "drop_pods" -> RaidStrategyDef "ImmediateAttackSmart" // Faction resolution "Tribal" -> Any faction with TechLevel <= Neolithic "Pirate" -> FactionDefOf.Pirate "Mechanoid" -> FactionDefOf.Mechanoid // Fallback events when primary event can't fire // Minor fallbacks: ShipChunkDrop, ResourcePodCrash, WandererJoin, TraderCaravanArrival... // Major fallbacks: RaidEnemy, TraderCaravanArrival, ResourcePodCrash, RefugeePodCrash... ``` -------------------------------- ### Track Event History and Cooldowns Source: https://context7.com/s4l7/claudestoryteller/llms.txt Record colony events and query history to enforce cooldowns and calculate density metrics. ```csharp StorytellerGameComponent comp = StorytellerGameComponent.Get(); // Record events as they fire ColonyStateCollector.RecordEvent("RaidEnemy", "fired"); ColonyStateCollector.RecordEvent("Disease_Plague", "fired"); // Also triggers disease cooldown // Track colonist casualties ColonyStateCollector.RecordColonistDeath(); ColonyStateCollector.RecordColonistDowned(); // Query recent history List recent = comp.GetRecentEvents(5); // Each: {Type: "RaidEnemy", DaysAgo: 2, Outcome: "fired"} List recentTypes = comp.GetRecentEventTypes(3); // Returns: ["RaidEnemy", "TraderCaravanArrival", "Eclipse"] // Timing queries int daysSinceThreat = (Find.TickManager.TicksGame - comp.LastThreatTick) / GenDate.TicksPerDay; int daysSinceDeath = (Find.TickManager.TicksGame - comp.LastDeathTick) / GenDate.TicksPerDay; // Disease cooldown (hard 25-day minimum) bool canFireDisease = ColonyStateCollector.CanFireDisease(); int daysSinceDisease = comp.DaysSinceLastDisease; // Diseases blocked if daysSinceDisease < 25 // Event density metrics for Claude EventDensity density = ColonyStateCollector.CollectDensity(comp); // density.EventsLast7Days, density.ThreatsLast7Days, density.DiseasesLast30Days ``` -------------------------------- ### Manage Event Queues Source: https://context7.com/s4l7/claudestoryteller/llms.txt Handles delayed event firing with conflict resolution and deduplication. ```csharp // Queue an event for delayed firing var queued = new QueuedEvent { EventType = "RaidEnemy", Subtype = "siege", Faction = "Pirate", Intensity = 1.3f, SourceCycle = "narrative", // "narrative", "scattered", "major", "minor" ArcName = "The Silent Siege", Note = "main arc event" }; // Queue with delay in hours EventQueue.EnqueueDelayed(queued, 36.0f); // Fires in 36 game hours // Pop ready events each tick int currentTick = Find.TickManager.TicksGame; List ready = EventQueue.PopReady(currentTick); foreach (var evt in ready) { // Convert to RimWorld FiringIncident and fire } // Queue inspection int count = EventQueue.Count; List types = EventQueue.GetQueuedTypes(); string summary = EventQueue.GetQueueSummary(); // summary: "RaidEnemy@tick45000(narrative), TraderCaravanArrival@tick42000(scattered)" // Clear events by source (when starting a new arc) EventQueue.ClearBySource("narrative"); ``` -------------------------------- ### Track Narrative Arc Lifecycle Source: https://context7.com/s4l7/claudestoryteller/llms.txt Manages persistent story sequences and storytelling posture across save/load cycles. ```csharp // Get the persistent game component StorytellerGameComponent comp = StorytellerGameComponent.Get(); // Start a new narrative arc comp.StartArc("The Mechanoid Awakening", eventCount: 4); // Record arc events as they fire comp.RecordArcEvent("MechCluster", "fired"); comp.RecordArcEvent("SolarFlare", "fired"); comp.RecordArcEvent("PsychicDrone", "blocked_by_difficulty"); // Event couldn't fire // Arc auto-finalizes when all events fire, or manually: comp.FinalizeArc("completed"); // or "interrupted" // Access arc history for Claude List arcLog = comp.GetArcLog(); // Each entry contains: ArcName, Events, EventOutcomes, Outcome, StartDay, EndDay // Arc timing information int daysSinceArc = comp.DaysSinceArcCompleted; string activeArc = comp.ActiveArcName; // null if no arc running int remaining = comp.ActiveArcEventsRemaining; // Storytelling posture (Claude's current approach) comp.LastPosture = "Randy chaos with brief Phoebe recovery"; string posture = comp.LastPosture; ``` -------------------------------- ### Register Storyteller Definition Source: https://context7.com/s4l7/claudestoryteller/llms.txt Define the storyteller in XML for RimWorld's def system. Place this file in the Defs/StorytellerDefs/ directory. ```xml ClaudeAI Claude watches your colony and adapts. Using AI, events are chosen based on your colony's actual situation—not just wealth curves. Configure your API key in Mod Settings > Claude Storyteller. 10 Storytellers/ClaudeLarge Storytellers/ClaudeTiny
  • ``` -------------------------------- ### Collect Colony State for Claude Source: https://context7.com/s4l7/claudestoryteller/llms.txt Gathers comprehensive colony data including resources, combat readiness, and difficulty settings for API integration. ```csharp // Collect full colony state for API calls ColonyState state = ColonyStateCollector.CollectState(map, "unified"); // State includes: // - Colony info (days survived, phase, wealth, colonist count) // - Combat readiness (defenses, vulnerabilities, skill levels) // - Resources (food days, medicine, components, silver) // - Recent history (last threat, last death, recent events) // - Available events by category (weather, threats, positive, disease) // - Difficulty settings with intensity bounds // - Arc history for narrative continuity // Get available events categorized for Claude Dictionary> available = ColonyStateCollector.GetAvailableEventsByCategory(map); // Returns: {"weather": [...], "threats": [...], "positive": [...], "disease": [...], "other": [...]} // Check difficulty restrictions DifficultyInfo diff = ColonyStateCollector.CollectDifficulty(); // diff.Label: "Strive to Survive" // diff.ThreatScale: 1.0 // diff.AllowThreats: true // diff.AllowMajorThreats: true // diff.MinIntensity: 0.4 // diff.MaxIntensity: 1.3 // Variance systems to prevent repetitive event selection List highlighted = ColonyStateCollector.GenerateHighlightedEvents(available); List excluded = ColonyStateCollector.GenerateExclusionList(available); string mood = ColonyStateCollector.GenerateStorytellingMood(); // mood: "calm before the storm" or "the fragility of civilization" etc. ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.