Arcane University: World Interactions

The Beyond Skyrim Wiki — Hosted by UESP
Revision as of 21:57, 30 November 2020 by Km816 (talk | contribs) (Implementing the Reaction)
Jump to: navigation, search
< Arcane University:Quest Implementation

This guide covers how to set up World Interactions in the Creation Kit. In Skyrim, these "quests" use the "WI" prefix, and include things like NPCs reacting when you cast a spell on them; when you walk around with a weapon drawn; when you when you swing a weapon near an NPC; or when you craft an item.

Introduction

Prerequisites

Implementing world interactions will require knowledge of dialogue implementation and basic scripting, and more complex reactions will require knowledge of the Story Manager, quest aliases, and scenes. You will also need to know how to generate and SEQ file for the quests you create, and will want Fuz Ro D'oh for testing before you get voiced lines.

Regarding dialogue, you will not have to know how to set up any complex branching conversations. Typically world interactions will only be a single line. However, you should be familiar with making non-Player Dialogue topics (such as Combat topics, Detection topics, and so on).

Types of World Interactions

World Interactions can be grouped into four categories.

  1. Hellos: Hello reactions are essentially standard out-of-dialogue hellos, conditioned to only happen under special conditions. These are some of the easiest to set up, and include things NPCs reacting to you walking around with a fire spell equipped, or commenting on you sneaking past them.
  2. Spell Reactions: These are events where an NPC is directly told to say a line using the Papyrus "Say" command when a spell is cast on them. These are relatively easy to set up, and can mostly be completed with default scripts.
  3. Engine Events: This covers events with a subtype on the Misc Tab of quests, such as NPC reactions to the player bumping into them, watching a fight, or noticing the player about to steal something.
  4. Story Manager Events: The story manager allows you to create world interactions for more complex events. This includes NPC reactions to things like the player crafting an item, dropping something, or having a unique "Hello" if the player previously attacked them.

Each of these types will be covered separately below.

Initial Setup

NPC Preparation

In Skyrim, World Interactions are (broadly speaking) limited to generic NPCs using a default voice type. When you make your own, you will need to condition them in some way so that they are limited to only the NPCs you want. This is best done with one of three methods (or some combination of them):

  • A custom faction, for instance something like "<Mod Prefix>AllowWorldInteractions".
    - (Remember, factions aren't just in-game factions like the Companions or the Mages Guild, they are used for plenty of behind-the-scenes game mechanic things as well.)
  • A formlist of valid NPCs.
  • A formlist of valid voice types.

Or, you could use the reverse: a "DisallowWorldInteractions" faction, a formlist of invalid NPCs, and so on.

Pick which method (or methods) you want to use. Depending on your choice, fill out the formlist(s) or add your faction(s) to NPCs. You will use these factions or formlists for quest dialogue conditions, and possibly also as alias fill conditions or story manager event node conditions.

GetAllowWorldInteractions Condition

You may notice that the Creation Kit has a "GetAllowWorldInteractions()" condition function. This function checks if the NPC's current package has the "World Interactions" flag checked. If it does, then the GetAllowWorldInteractions function will return TRUE. If not, it will return FALSE. In this way, you can dynamically change whether an NPC will have world interactions or not. For instance, if an NPC is fighting with you in a dungeon, you probably don't want them to complain that you have your weapon drawn. So, you should remember to include this condition for quest dialogue and when filling an alias.

Limiting World Interaction Occurrences

Generally, you want to limit how often world interactions play, lest they become stale after a long playthrough. Skyrim uses four methods to limit how frequently World Interactions play.

  1. Comment Chances: These are global variables set to some value between 0 and 100 and are used to give types of comments a percent chance to occur. There usage is typically a GetRandomPercent quest dialogue condition, compared to the Comment chance global variable. For example, vanilla Skyrim has world interaction where NPCs comment if the player has a flame spell equipped (quest WICommentMagicFlames). There is a corresponding global variable WICommentChanceMagicFlames, and a quest dialogue condition GetRandomPercent() <= WICommentChanceMagicFlames.
  2. Comment Timers: In vanilla Skyrim, this is usually global variable WICommentNextAllowed used alongside a default script WICommentScript to limit how frequently world interaction comments occur, however there are a few cases of separate times, such as for spell reactions. For WICommentNextAllowed, when a world interaction comment happens, WICommentScript the current game time and sets WICommentNextAllowed to one hour in the future. Then, a quest dialogue condition requires that the current game time be greater than WICommentNextAllowed (specifically, the condition is GetGlobalValue(GameDaysPassed) >= WICommentNextAllowed). This blocks world interaction comments from happening until one hour has passed since the last comment. This script can be used as-is for new world interactions; you could make your own timer global variables and use those instead; or you could use some combination (for instance, you could make a new timer just for Magic Flames comments, then condition those comments to be one hour since the last world interaction comment of any kind and two hours since the last Magic Flames comment).
  3. Story Manager Timers: This is simply a setting on quest entries in the Story Manager. When quests in the story manager have a value for "Hours until reset", the story manager will not attempt to start that quest again until that much time has passed since the last occurrence.
  4. Event Timers: These are timers used to block whole categories of events in the Story Manager. For instance, Skyrim has seven CastMagic world interaction quests in the story manager—the "Hours until reset" setting would block a single quest for some amount of time, but an event timer would be used to block all seven. Functionally these are similar to comment timers. The code for them exists on WorldInteractionsScript, and are typically used through a custom script that extends WorldInteractionsScript, where the timer functions are called in quest fragments.

WI Quest

Skyrim has a World Interaction parent quest WI, which holds a script WIFunctionScript for some common WI functions and properties. In truth, you probably won't use this much. The functions primarily concern an unused "Mourner" world interaction and dragon attacks. The two functions you might find useful are AllowComplexInteractions/DisallowComplexInteractions, which enables you to enable/disable certain world interactions for whole locations at once (. Also, ShowPlayerRoom is used for some Skyrim tavern scenes. I've personally never needed any of the functions in this script, so I won't cover it in any more depth in this guide.

Hello Reactions

Hello reactions are essentially standard out-of-dialogue hellos, conditioned to only happen under special conditions. These are some of the easiest to set up, and include things NPCs reacting to you walking around with a fire spell equipped, or commenting on you sneaking past them. These are the steps to create "Hello" world interactions:

  1. Create a new quest. Give the quest a readable ID like "<ModPrefix>WIComment<Description>". Click "OK" then reopen the quest.
    - Because quests can only have one "Hello" topic, you will generally need one quest per type of interaction.
  2. Set the quest to Start Game Enabled. At some point before you start testing it, create a new SEQ file for your plugin.
  3. Set the quest data conditions for the world interaction. These are conditions that will apply to all topicinfos.
    - This can include other broad conditions, for example you could exclude NPCs in the Mages Guild from commenting on equipped spells.
    • GetAllowWorldInteractions returns TRUE
    • If desired, a random percent condition
    • If desired, a timer condition
    • If desired, IsInDialogueWithPlayer returns FALSE. This will make it so the line only happens when the player brushes past the NPC, not when the NPC actually greets them to start a conversation.
    • The condition for your specific interaction type. Some examples:
    - IsSneaking: React to the player sneaking
    - SpellHasKeyword: React to an equipped spell
    - HasMagicEffectKeyword: React to a spell active on the player
    - WornHasKeyword: React to some thing the player is (or isn't!) wearing
    - IsWeaponOut: React to the player having a weapon drawn
  4. Set the quest priority to something above totally generic greetings but below actually important quests. Skyrim uses a priority of 40 for world interactions; your mod or project might need something different.
  5. If you are using a timer:
    1. Check the "Allow Repeated Stages" box on the Quest Data Tab.
    2. Go to the Scripts tab and add WICommentScript. If you are using the generic WICommentNextAllowed, you can auto-fill all properties. Otherwise, autofill GameDaysPassed and fill WICommentNextAllowed with your own global variable.
      - If you are using multiple timers, you will need a custom script.
    3. Go to the Quest Stages tab and create a new stage. The stage number is not important. DO NOT enter anything for the log.
    4. Call WICommentScript's Commented() function in the stage's quest fragment.
  6. Go to the Misc tab and create a new topic with subtype "Hello".
  7. Create the individual topicinfos for this world interaction. The exact conditions here will depend on what you've written for the lines or what your writing team has given you. For instance, conditioned on voice type, class, race, faction, and so on.
  8. If you're using a timer, then update the timer by setting the quest stage. In a Begin fragment, call: GetOwningQuest().SetStage(<the stage you made earlier>).

Your world interaction should now work in-game!

Spell Reactions

"Spell Reactions" are where an NPC is directly told to say a when a spell is cast on them. These work by using a script attached to the magic effect to force the NPC to say a line using Papyrus's Say command.

First, we'll cover setting up the quest and dialogue:

  1. Create a new quest. Give the quest a readable ID like "<ModPrefix>WICastMagic<Description>". Click "OK" then reopen the quest.
    • It is possible to have multiple reaction topics in the same quest, so you could make one quest that holds all your spell reaction topics.
  2. Set the quest to Start Game Enabled. At some point before you start testing it, create a new SEQ file for your plugin.
  3. Set the quest data conditions for the world interaction. These are conditions that will apply to all topicinfos.
    Note 1: We can handle the timer in our MagicEffect script (discussed later), so we don't need that here.
    Note 2: GetAllowWorldInteractions is optional here, depending on your specific lines.
  4. Go to the Player Dialogue tab and create a new branch and topic, and set the branch type to "Normal".
    • If you want reactions in combat to be different from reactions outside of combat, create a second topic that is just for in-combat lines. Although it is technically possible to put these all in the same topic, the default script we will be using allows for separate combat and noncombat topics, so it will be easier and more organized to use two topics here.
  5. Create the individual topicinfos for this world interaction. The exact conditions here will depend on what you've written for the lines or what your writing team has given you. For instance, conditioned on voice type, class, race, faction, and so on.

Next, we need to add a script to the magic effects we are interested in.

  1. Open up the magic effect.
  2. In the "Scripts" section, add the script SayOnHitByMagicEffectScript, then open up the Script Properties window.
  3. Auto-fill the GameDaysPassed property.
  4. You can auto-fill WICastNonHostileTimer or use your own timer global variable.
  5. Fill TopicToSay and CombatTopicToSay with your newly-created topics.
  6. Optionally, set AllowForTeammate to 1 to allow your teammates to comment as well when you cast a spell with this magic effect on them.

NPCs should now comment when you cast your spell on them!

Engine Events

The Misc Tab of on quests allows for NPC reactions to a number of events:

  • ActorCollidewithActor: Said when the player bumps into the actor.
  • KnockOverObject: Said when the player collides with a physics object.
  • LockedObject: Said when the player looks at a locked object and it would be a crime to open it.
  • NoticeCorpse: Said when the actor notices a corpse.
  • ObserveCombat: Said when the actor sees combat and is not taking part in it.
  • PickpocketTopic: Said when the player seems to be trying to pickpocket.
  • PlayerIronSights: Said when the player aims at someone with a drawn bow.
  • PlayerShout: Said when the player uses a shout nearby.
  • ShootBow: Said when the player shoots with a bow outside combat.
  • SwingMeleeWeapon: Said when the player swings a melee weapon outside combat.
  • ZKeyObject: Said when the player is holding an object with physics.

Setting these up is relatively straightforward.

  1. Create a new quest. Give the quest a readable ID like "<ModPrefix>WICastMagic<Description>". Click "OK" then reopen the quest.
    - Each event listed above can be it's own topic, so realistically you only need one quest for all of them.
  2. Set the quest to Start Game Enabled. At some point before you start testing it, create a new SEQ file for your plugin.
  3. Set the quest data conditions for the world interaction. These are conditions that will apply to all topicinfos.
    Note: GetAllowWorldInteractions is optional here, depending on your specific lines.
  4. Go to the Misc tab and create a topic for each subtype you want to have a reaction for.
  5. Create the individual topicinfos for this world interaction. The exact conditions here will depend on what you've written for the lines or what your writing team has given you.

Close, save your plugin, and test. NPCs should now be more responsive to the chaos you cause in the world. :)

Story Manager Events

The Story Manager allows us to make some more complex events, regarding what events NPCs react to, picking which NPCs will react to the event, and controlling how NPCs react.

Consider the "Cast Magic" event, for instance. We have already looked at ways make NPCs comment on spells you have equipped, spells that are active on you, and spells that you cast directly on NPCs. What does the Story Manager do differently? First, it can work for spells of any kind—spells cast on you, on an NPC, off into the distance, etc... It does not need to be an effect active on you (like "Hello" interactions) or cast directly on an NPC ("Spell" reactions). Second, the NPC that reactions will be picked randomly from NPCs nearby by filling a quest alias (unlike "Hello" interactions where you must talk to the NPC or at least be close to them, or "Spell" interactions where you must cast the spell on the directly). Third, you have more control over how the NPC reacts. In previous interaction types, we could only make NPCs say a certain line. Now, we could make them do other things, like run away from you, run to start conversation with you, start a fight with another NPC... You can get much more creative with how NPCs respond.

This section will cover the basic setup of a Story Manager based world interaction, followed by some specific examples for different event types.

General Setup

Create The Quest

The first step for a story-manager based world interaction is to create a new quest. Unlike previous quests we've made, this quest will not be start-game enabled and therefore will not require an SEQ file. instead, select the event you want to use from the "Event" dropdown menu.

Once you've created your quest, navigate to the "Aliases" tab. Depending on what exactly you want to happen, you may need several aliases here. Generally, you should create an aliases for:

  1. Every bystander that you want to react to the event. These use a fill type "Find Matching Reference", with "In Loaded Area" checked. You probably also want the "Nearest" box checked, but this depends on your preference and what exactly the world interaction is. Then, you should add conditions so that:
    • The selected NPC is valid, as per Arcane University:World Interactions#NPC Preparation.
    • The selected NPC's package allows world interactions.
    • Any other conditions specific to this world interaction. For instance, if you only want alchemists to react to the player crafting a potion, that would need it's own condition (such as checking class, or another faction, or a list of NPCs or voicetypes, etc...).
  2. Any reference that will be passed in by the event. These also use a fill type "Find Matching Reference", but should come from the event. Make an alias for everything available in "Event Data".
  3. The player. This can be a forced reference. You can attached the script WIPlayerScript for the option to end the interaction early if the player travels too far from where it started.

If you want to use an event timer for this world interaction (as mentioned here Arcane University:World Interactions#Timers): navigate to the "Scripts" tab, then create and attach a new script that extends WorldInteractionsScript. You do not need to add anything else to the script. Then, auto-fill the GameDaysPassed property and fill the remaining two global variable properties with the global variables you are using for your timer. Once the script is attached, go to the "Quest Stages" tab. Create a new quest stage that runs on quest start, and call the timer function SetNextEventGlobals() on the stage's fragment.

Remember to include some way for the quest to end. For world interactions that use a scene, this is a flag you can check there. As mentioned earlier, the WIPlayerScript on the player alias will stop the interaction if the player changes location. Otherwise, create a quest stage that has a fragment to stop the quest. You can then call this stage, for instance through dialogue/a topicinfo fragment, whenever the interaction is over.

Implementing the Reaction

This is a pretty open-ended section, and really depends on what exactly your world interaction is. I'll cover three basic cases, and for anything more complex you'll want to refer to the CK Wiki guides on Packages, Scenes, and Dialogue as appropriate.

  1. Saying a Single Line: To make an NPC idly comment on a player action (think: reactions to smithing an item, mixing a potion, picking something up off the ground), all we need is a simple scene.
    1. Navigate to the "Scenes" tab of your quest, and create a new scene.
    2. Check the flags for "Begin on Quest Start" and "Stop Quest on End".
    3. Add a new actor with the alias that will do the talking. Set the actor behavior so that combat ends the scene (the default will be that it pauses the scene).
    4. Add a new phase, and add a Dialogue action to your actor for that phase. You do not need to check anything for looping, headtracking, etc...
    5. Create TopicInfos for the lines you want your NPC to say.
      • This will work like a normal TopicInfo stack, so the first line that has all of its conditions met will be the line that is spoken.
      • You can use GetEventData conditions and run normal conditions on Event Data to make responses reactive to the player's specific actions. For instance, you can check for keywords on a crafted item, or check the value of an item the player dropped.
    6. (Optional) If your dialogue topic has a very large number of topicinfos and you want to organize it a more nicely, you can split the one phase into multiple, and use phase conditions to make conditioning dialogue lines simpler.
      • Look at WICraftItem01 as an example of this. Rather than have one phase and dialogue action with 72 topicinfos, it uses 8 phases with 9 topicinfos each. Conditions on each phase make it so that only voicetype conditions are needed on the topicinfos.
      • If you go this route, you will want to add a script fragment on phase end to stop the scene, otherwise your NPC may end up saying multiple lines in succession.
      • The Creation Kit will not parse phase conditions when filtering dialogue for an Actor or Voice Type, so you should avoid using condition functions that affect dialogue filtering in phase conditions. These are condition functions like GetIsID, GetIsVoiceType, GetInFaction, and so on (conditions that affect default dialogue).
  2. Start a Conversation: To make an NPC start a conversation with the player when an event happens (think: player drops a weapon and a guard chastises them), we will want to use a ForceGreet package to start ordinary dialogue.
    1. Navigate to the "Player Dialogue" tab of your quest, and create a new blocking branch and a starting topic.
    2. Implement the dialogue like normal (Basic Dialogue Tutorial). There's nothing special that needs to be done.
      • Remember that you can use GetEventData conditions and run normal conditions on Event Data to make dialogue more responsive to the player's specific actions.
    3. Create a quest stage to stop the quest. The stage number is your choice but "10" is common. Include a quest fragment with the command stop(). Set the quest to this stage on any topicinfos that end the world interaction.
    4. Create a new package using the ForceGreet template.
      • Set the package's topic to the starting topic you created earlier.
      • Set the wait location to near package start.
      • Set the Trigger Location and ForceGreet distance to both within some radius of the player. The ForceGreet distance should be smaller than the Trigger Location distance.
      • Uncheck all flags on the package (even the Allow World Interactions flag!).
    5. Add this package to the NPC's quest alias. The NPC will automatically start using this package, unless they are occupying another alias with higher priority.
  3. Delayed Reactions: It's possible to use the story manager to set up NPC world interactions to play later (think: NPCs that have special dialogue when you talk to them some time after assaulting them).
    1. Create a new faction named similar to your quest. It does not need any faction relationships, crime/vendor/etc... information.
    2. On the quest, create a startup stage (typically stage 0).
    3. Create a quest fragment, and add your faction as a script property.
    4. In the fragment, add the faction to the NPC alias(es), then stop the quest. For example:
      (BystanderAlias.GetReference() as Actor).AddToFaction(MyFaction)
      Stop()
    This will record that the NPCs took part in this original event. Then, later, we can check if an NPC is in this faction for future world interactions. For instance:
      • Create a new quest (start-game enabled) with a Hello topic for special greetings for NPCs in the faction you created.
      • Give NPCs a unique reaction to having a spell cast on them after they've seen you cast it once before.
      • Make guards actually respond differently if they catch you dropping a weapon more than once.

Remember, it is absolutely possible to make world interactions that are more complex that what's above. Look at WIRemoveItem03 for instance—two NPCs fight over a dropped object, up to three bystanders arrive to watch, and a guard may intervene. However it's not really possible to write a tutorial for these, as the way to implement them is going to be unique. Still, you should be able to the above steps like building blocks for more complex world interactions.

Updating the Story Manager

Examples

1. Assault Actor Event

2. Cast Magic Event

3. Change Location Event

4. Craft Item Event

5. Dead Body Event

6. Kill Actor Event

7. Player Add Item Event

8. Player Remove Item Event