The "Challenge" Action


One of the actions available to units in Rootless is a "Challenge".  This is where units engage each other in dialog to try to throw one another off their game in the heat of combat, and also one of the key innovations of Rootless.

The Challenge Action

There's a few different situations where units may be able to execute a challenge action:

  • A player-controlled unit talking to an enemy unit
  • An enemy unit talking to a player controlled unit
  • An ally talking to another ally

In addition, in an effort to make the challenge action "special" (and also to keep generative AI costs down ;) ), there will be key times where a unit can be challenged.  When a unit experiences a "key event", they will become a valid target for a challenge.  Key events may include:

  • Battle start
  • Critical Hit (either given or received)
  • A Miss (either given or received)
  • Defeated Enemy
  • Killed Enemy
  • Ally Defeated
  • Ally Killed
  • Mission Part Succeeded
  • Mission Part Failed

These key events will become part of the context used to generate our dialog options, leading to conversations that feel alive and responsive to the battle.

Generative AI Dialog

The challenge action will be using generative AI (currently the Claude Sonnet 4.5 language model) to generate dialog options for players to choose from.  To do this, we craft a system prompt that guides the language model to do what we want, give it the current context, and also force it to produce its output in a format that is easily read by computer code (JSON in this case).

One of the key aspects of this approach is using game-generated effects.  With past projects I've found that while language models are generally pretty good at following directions, you still have to account for unexpected variations, which can make the code complicated.  By reversing the approach - generating the game effects in-engine and sending those to the language model - you can avoid situations where your game logic breaks or you have to write overly-defensive code and just use the content produced.

Context is King

Here are a few examples of how the game context helps improve the quality of the generated content.  If we send the input into our prompt as the following:

Input
Actor: Fox
Target: Badger
Modifiers: ["-1 strength", "-1 defense"]
Output
"opening_dialog": "You think your clever words will save you, Fox? I've crushed smarter beasts than you!"

"choices[0]": "player_dialog": "Your claws are dull, Badger. Just like your wit.",
"npc_response": "Dull?! I'll show you dull when I—wait, what are you...?",
"modifier": "-1 defense"

"choices[1]": "player_dialog": "I've seen you fight. You're slower than you used to be.",
"npc_response": "Slow? I'm not—my arms feel... heavy. What trickery is this?",
"modifier": "-1 strength"

You can see the generated response is pretty serviceable... it's certainly nothing extraordinary, but it'd work.  I reckon we can do better though...  If we include the key event that the Actor is referencing, we should be able to get a better response.

Input
Actor: Fox
Target: Badger, who just missed their target
Modifiers: ["-1 strength", "-1 defense"]
Output
"opening_dialog": "Damn it! My claws found only air where your throat should be!",

 "choices[0]":  "player_dialog": "Your rage makes you sloppy, Badger. Each wild swing leaves you more exposed.",
 "npc_response": "No... you're in my head now. I can't focus!",
 "modifier": "-1 defense"

"choices[1]": "player_dialog": "That miss took more out of you than you'd like to admit, didn't it?",
 "npc_response": "My arms... they feel like lead. What have you done?",
 "modifier": "-1 strength"

See, even with that small tweak you can see how the contextual response has improved!  Let's add in our Tag system and see what else we can get out of the prompt!

Input
Actor: a Fox who is sly, hungry, wearing armor
Target: a Badger, who is weak, almost out of health, standing in a puddle, and just missed their target
Modifiers: ["-1 strength", "-1 defense"]
Output
"opening_dialog": "Damn it... missed again. I'm... I'm not done yet!",

"choices[0]"
: "player_dialog": "You're trembling, badger. One more swing and you'll collapse on your own.",
"npc_response": "Stay back! I... I can still fight!",
"modifier": "-1 defense"

"choices[1]": "player_dialog"
: "That puddle's making you slow. Let me help you... out of your misery.",
"npc_response": "I won't go down easily, fox!",
"modifier": "-1 strength"

Better still!  The response is aware of the unit's surroundings and state, and can reference them when generating dialog options.  For the final touch, let's throw our "named units" concept in there; this fox and badger know each other and have a history

Input
Actor: a Fox named Freddie, who is sly, hungry, wearing armor
Target: a Badger named O'Brian, who is weak, almost out of health, standing in a puddle, and just missed their target
Modifiers: ["-1 strength", "-1 defense"]
Freddie and O'Brian have fought before; Freddie had left O'Brian injured on a past battlefield
Output
"opening_dialog": "You... you again! Haven't you taken enough from me already?",

 "choices[0]": "player_dialog": "Still can't hit what you're aiming at, I see. Some things never change.",
"npc_response": "Damn you, Freddie... my grip... it's slipping...",
 "modifier": "-1 strength"

"choices[1]": "player_dialog": "That puddle's making you sloppy, O'Brian. One wrong step and you're finished.",
"npc_response": "I... I can't keep my footing. Not like this.",
"modifier": "-1 defense" 

Now you can see how we hope to build emergent narrative that reacts to the player unit's past and present, creating a compelling story using generative AI!

Leave a comment

Log in with itch.io to leave a comment.