Last active 1781220113

Revision ee6c47dcb58c4a63c7d9939000fa86aaf69f74d6

Gemma4-Quest-System.md Raw

To implement an AI-Driven NPC Quest System, we need to combine almost every feature of our Universal DSL: AI generation for the quest, Fork-Join for multiple objectives, Event Listeners for player actions, and Saga/Undo logic for quest failure.

In this scenario, the NPC doesn't have a hard-coded quest. Instead, the AI looks at the game world, generates a dynamic quest, and monitors the player's progress in real-time.

The Scenario: "The Dynamic Village Savior"

Goal: An NPC (The Elder) identifies a problem in the world, creates a multi-part quest for the player, and updates the world state upon completion.

# ==============================================================================
# PROJECT: AI-Driven Dynamic Quest System
# NPC: Village Elder
# ==============================================================================

# --- GLOBAL STATE ---
$quest_id = null
$quest_status = "idle"
$world_state = { "forest_danger": "high", "village_food": "low" }
$player_progress = {}

# --- MODULE: QUEST GENERATION (The AI Brain) ---
Module QuestGenerator {
    # AI analyzes world state and generates a unique quest objective
    AI.Generate [model: "gpt-4-game-engine"] {
        context: $world_state,
        prompt: "Generate a quest to fix the village's main problem. 
                Provide two distinct objectives: one 'Fetch' and one 'Slay'."
    } -> Quest.Validate
    
    # Ensure the AI didn't generate something impossible (Constraint Check)
    Quest.Validate /check /verify {objectives} ? [
        is_feasible -> Quest.Finalize,
        impossible -> AI.Generate # Loop back to regenerate
    ]
    
    Quest.Finalize /save {quest_data} -> $quest_id = {qid}
    return {quest_active: true}
}

# --- MODULE: QUEST EXECUTION (The Parallel Game Loop) ---
Module QuestExecution {
    # Fork: The player must complete multiple objectives in any order
    Quest.Start F-> [Obj.FetchItem, Obj.SlayMonster, Obj.DialogueNPC]

    # Objective 1: Fetch Item (Event-Driven)
    # Wait for the player to pick up the specific AI-generated item
    Obj.FetchItem /wait ON (Player.InventoryUpdate) {
        filter: { item == $quest_data.fetch_item }
    } -> Obj.FetchComplete

    # Objective 2: Slay Monster (Event-Driven)
    # Wait for the combat system to report the death of the target
    Obj.SlayMonster /wait ON (Combat.EntityDeath) {
        filter: { target == $quest_data.target_monster }
    } -> Obj.SlayComplete

    # Objective 3: Dialogue (Sequential)
    Obj.DialogueNPC /interact {npc: "ForestSpirit"} /save {info} -> Obj.DialogueComplete

    # Join: Synchronize all objectives
    [Obj.FetchComplete, Obj.SlayComplete, Obj.DialogueComplete] J-> Quest.VerifyCompletion
}

# --- MODULE: VERIFICATION & WORLD UPDATE ---
Module QuestResolution {
    # AI evaluates the "Quality" of completion (e.g., did the player kill too many innocents?)
    AI.Evaluate {
        input: $player_progress,
        criteria: "Evaluate if the quest was completed honorably"
    } -> Eval.Result

    Eval.Result ? [
        honorable -> World.UpdateSuccess,
        dishonorable -> World.UpdateMixed
    ]

    # Server-side Transaction: Update world state and reward player
    World.UpdateSuccess {
        Lock ($village_id) {
            EXT:Server.UpdateWorldState { "forest_danger": "low" }
            EXT:Server.GrantReward { player_id: $player_id, amount: 1000, item: "HeroCape" }
        }
    }
    
    # If something fails during the server update, rollback the quest state
    World.UpdateSuccess /undo { 
        $quest_status = "error"; 
        Notify.Player("World update failed. Please contact support."); 
    }
}

# --- MAIN FLOW ---
# 1. Trigger: Player interacts with the Elder
Welcome.Interaction /start /on (Player.Interact, "Elder") -> QuestGenerator

# 2. Transition to Execution
QuestGenerator.Complete -> QuestExecution

# 3. Transition to Resolution
QuestExecution.Complete -> QuestResolution

# 4. The "Failure" Path (Saga/Recovery)
# If the player dies during the quest, the quest doesn't vanish; it pauses.
ON (Player.Death) -> Quest.Pause {
    $quest_status = "paused"
    Saga.Compensate {
        # Move player back to graveyard, but keep quest items in inventory
        EXT:Server.RelocatePlayer { location: "Graveyard" }
    }
    -> WAIT (Player.Respawn) -> QuestExecution
}

# 5. The "Boredom" Timer (Tick)
# If the player ignores the quest for too long, the NPC gets grumpy
Tick [1hour] {
    condition: $quest_status == "active",
    logic: NPC.Elder.SetMood("Grumpy")
}

Why this is powerful (The "Universal" breakdown):

  1. Non-Deterministic Logic (AI): Instead of if (quest_id == 1), the system uses AI.Generate and AI.Evaluate. The quest changes every time based on $world_state.
  2. Asynchronous Event-Driven Architecture: The Obj.FetchItem and Obj.SlayMonster nodes don't "poll" the database. They use ON (Event) listeners, meaning the workflow sleeps until the game engine pushes a specific event.
  3. Strict Synchronization (Fork-Join): The J-> (Join) ensures the player cannot turn in the quest by just killing the monster; they must also find the item and talk to the spirit.
  4. Infrastructure Safety: The use of Lock ($village_id) prevents a "race condition" where two players completing the same quest at the same time could double-reward themselves or glitch the world state.
  5. Resilience (Saga/Recovery): The ON (Player.Death) handler acts as a recovery mechanism, ensuring the state is preserved across a "fail state" (Death) and resuming the workflow exactly where it left off.
  6. Real-time Ambience (Tick): The Tick [1hour] allows the NPC to react to the passage of time, adding a layer of realism that standard linear workflows cannot handle.