[Utility] Encoder for creating basic (but extensive) new dialogues between player and one npc

+
[Utility] Encoder for creating basic (but extensive) new dialogues between player and one npc

Hello everybody,

here's a dialogue cli encoder for creating extensive dialogues between the player and one npc to be usable in your mods (as a w2scene). ONLY subtitle dialogues are supported. There is NO integration of any new audio samples. Also NO support for mouth/lipsync animations at this point.

This is not a beginners modding tool. I will provide some tutorials for presenting the features but you should have intermediate or advanced W3 modding knowledge.

I will upload the encoder to nexusmods as soon as I finish the tutorials to prevent questions which will be covered by the tutorials. I reconsidered since it takes too long to write the tutorials and the most important stuff is already covered, see link below.

The tool is compiled for 64bit windows.

Here's an overview:

the good:
  • easy creation of 1 vs 1 dialogues with multiple conversation flows based on player choices
  • supports script calls from specific points in dialogues
  • supports conditional conversation flow based on (quest)fact checking
  • supports most choice icons
  • automatic camera changes during dialogue (optional)
  • supports custom camera changes
  • supports defining custom camera settings
  • supports attaching of animations and mimics (facial animation) from the game to actors
  • supports dumping of camera settings, animation/mimic settings from existing scenes to examine how it was done by CDPR

the bad:
  • the stage is set: positioning of player and npc is hardcoded at this moment (1.6m apart facing each other)
  • no gui, so no visual feedback for camera definitions besides testing in-game. it's ok if you have good spatial imagination but nevertheless time consuming/difficult
  • no support for adding new audio and no lipsync/mouth movement
  • only rudimentary checks for validity of the dialogue definitions. You will have to use your brain (although society would argue that's a good thing)

the ugly:
  • no visual feedback for animation timing and blending. You will strain your imagination skills. It's possible to get some nice results here and there but don't expect top notch results. And no results at all without pain.
  • the generated w2scene file header still contains unknown bytes (e.g. wrong checksum) but the game ignores this anyway

If any of these points is a deal-breaker for you then save your time by skipping the rest.

So here we are. You are willing to invest some time to add some depth to npc interactions in your mod by creating new dialogues. But first some prerequisites. I assume:
  • you are familiar with creating and installing a dlc mod (e.g. with Sarcen's editor)
  • you have the debug console installed (required for testing)
  • you have basic knowledge about using the windows command line
  • you have notepad++ installed (other editors with YAML support are fine, too)
  • you have read and understood the part about idspace in the w3strings encoder info

Since in the tutorials some directories are used as examples for configurations you have to exchange them accordingly with your local counterparts. So for the tutorials I assumed:
  • your Witcher 3 installation is located in: c:\The Witcher 3 Wild Hunt\
  • you have unzipped the encoder package into: c:\w3modding\dialog_encoder\
  • you have a dialogue tutorial project base directory: c:\w3modding\dialog_tutorials\
  • your modeditor project base directory for the tutorials will be: c:\w3modding\modeditor\

What the tutorials will cover
  • Part 1 - some basics + encoding and in-game-testing
  • Part 2 - creating your own dialogue - what's necessary
  • Part 3 - creating a more interesting conversation - about dialogscript
  • Part 4 - dialogue presentation - about cameras (difficulty: moderate/advanced)
  • Part 5 - advanced presentation - actors in motion (difficulty: high tolerance of frustration required)
link to nexusmods

CRC for w2scene.exe

  • size: 5083903 bytes
  • md5: c6cb6b41adfe29480ed6d63bc5e17df5
  • sha256: 66ba81b93b35dcba133856e93b82c93ca523d336c3b39d545c4abb171865f0a7
CRC for w3strings.exe
  • size: 5041071 bytes
  • md5: 10a09e41b1fc732dd6ac5e574de78361
  • sha256: 6f06cd3dab38d515298a7d0ae22545c7038607360941d99891c871464cfb9f28
Have fun.

---------- Updated at 09:22 PM ----------

Part 1 - Basics + Encoding and in-game-testing

In this first part you will get some background (how dialogues are used in game) and step by step instructions how to get one of the provided dialogue examples into the game and how to test it.

First some theory

The W3 dialogue system is very powerful and is an essential part to the story telling of the game. Besides defining multiple flows of a conversation it also incorporates a flexible and configurable system for presenting conversations to the gamer. This includes amongst other things camera changes and defining animation and mimics for all participating actors. All pre configured settings (conversation flow, camera definitions/transitions, animation parameters, etc) are encoded as a w2scene file. All used strings/speech samples are stored as ids and reference the actual strings/speech samples in w3strings and w3speech files.

A w2scene can be played directly from scripts and can be triggered to be played by quest phases, too. In both cases the w2scene must be included as a dlc mod (adding it as a resource in the normal mods directory does NOT work).

Describing how a scene is triggered by quests is out of scope for this tutorial. So we will concentrate on playing it by using a w3 script. Unfortunately scripts cannot be included in dlc mods. This means the installation of a mod with w2scene dialogues requires to install two parts:
  • a dlc mod with the w2scene and w3strings file into the witcher dlc directory
  • a scripting mod with the scene playing script (and all other scripts required for your mod) into the witcher mods directory

How to get a new dialogue into the game

To create new dialogues with this encoder the dialogue must be defined using a special text file format (more about this in the next part). Let's assume you already have all your definitions for a dialogue ready and want to try it out in the game. To demonstrate how this works we will create a new dialogue project and take the mini example from the encoder package named "minimal.example.yml".

First setup the dialog project directories and files

1. Copy the file "minimal.example.yml" from the "docs\minimal.example" directory into a new dialog project directory "c:\w3modding\dialog_tutorials\tutorial_1"


2. Create a new modeditor project named "moddlg_tut_1" in the modeditor project base directory, set the "Install as DLC" option in Mod/Mod Settings and save the project. This will create the subdirectories required for the next steps.


3. Copy the "reencode.bat" and "reencode-with-strings.bat" files from the encoder package into the tutorial_1 directory. These are some convenience batch files which perform multiple necessary steps at once.


4. Edit both batch files in the new directory and adjust the following path settings (don't worry if the dir_output and dir_dlc directories do not exist at this moment as they will be created on first batch usage):
reencode-with-strings.bat:
set dir_encoder=c:\w3modding\dialog_encoder
set dir_output=c:\w3modding\modeditor\moddlg_tut_1\files\dlc\moddlg_tut_1
set dir_dlc=c:\The Witcher 3 Wild Hunt\dlc\moddlg_tut_1

reencode.bat:
set dir_encoder=c:\w3modding\dialog_encoder
set dir_output=c:\w3modding\modeditor\moddlg_tut_1\files\dlc\moddlg_tut_1


Encode the example dialogue to a w2scene file and create a dlc mod


1. Open the windows command prompt, adjust the layout and history buffer of the window in the window properties to double the width and increased height to see the output unmangled. Then navigate to your dialog project folder dialog_tutorials\tutorial_1 using the command prompt, e.g:
cd \w3modding\dialog_tutorials\tutorial_1

2. Start the reencode-with-strings.bat file with the minimal.example as parameter (without the extension!) in the command prompt. This will load the example dialogue definitions, make some sanity checks, create a w2scene file and copy it to the destination path. It will also convert the strings csv created by the w2scene encoder to a w3strings file and copy it to the final dlc directory. Non existing target paths will be automatically created.
reencode-with-strings.bat minimal.example

You should see more or less the following output:
w2scene producer v0.3.2
INFO - ENCODING minimal.example to c:\w3modding\modeditor\moddlg_tut_1\files\dlc\moddlg_tut_1\minimal.example.w2scene (strings csv: c:\w3modding\modeditor\moddlg_tut_1\files\dlc\moddlg_tut_1\minimal.example.w3strings-csv)
INFO - scanning for repository files in c:\w3modding\dialog_encoder\repo
INFO - parsing yaml file: c:\w3modding\dialog_encoder\repo\example.animation.mimics.women.repo.yml
INFO - parsing yaml file: c:\w3modding\dialog_encoder\repo\example.animations.women.repo.yml
INFO - parsing yaml file: c:\w3modding\dialog_encoder\repo\example.repo.yml
INFO - assets in repository: 102
INFO - parsing yaml file: minimal.example.yml
INFO - sections in dialogscript: 6
INFO - special blocks in dialogscript: 0
INFO - production manifest:
INFO - settings:
INFO - > sceneid: 1
INFO - > strings idspace: 9999 start: 0
INFO - assets in scene: 4
INFO - > camera assets: 2
INFO - > actor assets: 2
INFO - > animation assets: 0
INFO - > mimic assets: 0
INFO - > mimic animation assets: 0
INFO - events in storyboard: 0
INFO - > sections with events: 0
INFO - building scene from definitions...
INFO - adding start section: section_start_input
INFO - adding dialog section ( 2 lines, 0 pause elements): section_geralts_choice_1
INFO - adding dialog section ( 2 lines, 0 pause elements): section_geralts_choice_2
INFO - adding dialog section ( 1 lines, 0 pause elements): section_start
INFO - adding choice section ( 3 choice elements): section_choice_start
INFO - adding end section: section_exit
INFO - creating w2scene
INFO - creating c:\w3modding\modeditor\moddlg_tut_1\files\dlc\moddlg_tut_1\minimal.example.w2scene...
INFO - stored raw strings data chunk (offset: 000000a0 size: 2239b crc: df330d2f elements: 2239)
INFO - stored string mappings data chunk (offset: 0000095f size: 1120b crc: ee541880 elements: 140)
INFO - stored import mappings data chunk (offset: 00000dbf size: 16b crc: e5d9cabf elements: 2)
INFO - stored buffer mappings data chunk (offset: 00000dcf size: 16b crc: ecbb4b55 elements: 1)
INFO - stored object mappings data chunk (offset: 00000ddf size: 792b crc: 257db694 elements: 33)
INFO - stored objects data chunk (offset: 000010f7 size: 3779b crc: 17c9e0dd elements: 33)
INFO - finalizing header information
INFO - creating c:\w3modding\modeditor\moddlg_tut_1\files\dlc\moddlg_tut_1\minimal.example.w3strings-csv...
INFO - storing 8 strings
w3strings decoder/encoder v0.3.2
INFO - ENCODING c:\w3modding\modeditor\moddlg_tut_1\files\dlc\moddlg_tut_1\minimal.example.w3strings-csv to c:\w3modding\modeditor\moddlg_tut_1\files\dlc\moddlg_tut_1\minimal.example.w3strings-csv.w3strings (testscript: c:\w3modding\modeditor\moddlg_tut_1\files\dlc\moddlg_tut_1\minimal.example.w3strings-csv.w3strings.ws)
INFO - opening c:\w3modding\modeditor\moddlg_tut_1\files\dlc\moddlg_tut_1\minimal.example.w3strings-csv...
INFO - identified language: en
INFO - verifying string ids are within [2119999000..2119999999]
INFO - creating c:\w3modding\modeditor\moddlg_tut_1\files\dlc\moddlg_tut_1\minimal.example.w3strings-csv.w3strings...
INFO - storing language: en
INFO - storing 8 strings
INFO - creating c:\w3modding\modeditor\moddlg_tut_1\files\dlc\moddlg_tut_1\minimal.example.w3strings-csv.w3strings.ws...

Check your output for any errors! If there are errors you can add a --verbose or a --very-verbose parameter to the above batch command line. It may help to identify the error but be prepared to be flooded with debug messages. But you probably just have a typo somewhere in the batch file paths.

Please note: the batch files are only for development purpose. Normally, if you have multiple scenes and/or other strings you use in your mod you should merge all those strings into one csv, make sure you have no duplicate ids and create all localized w3strings files from this before publishing your mod.

3. Create a dlc mod with the modeditor

3.1 Reopen the dialog project with the modeditor. You should see your newly created w2scene in the dlc\moddlg_tut_1 directory in the mod editor explorer.

3.2 Pack and install the mod as dlc with the modeditor

At this point you should have the following files in the c:\The Witcher 3 Wild Hunt\dlc\moddlg_tut_1\content directory
blob0.bundle
metadata.store
en.w3strings

Test the scene

1. Setup a dummy mod for the sceneplayer script by creating a new mod_dlgtest subdirectory in your Witcher 3 mods directory. The name is not really important as this is only for testing.

2. Create the content\scripts directory in the new mod dir and copy the "dummyScenePlayer.ws" script from the encoder root dir to it.

3. Edit and adjust the w2scene path and name in the dummy player script so the script looks like:

PHP:
exec function playscene() {
    var scene : CStoryScene;
    scene = (CStoryScene)LoadResource( "dlc\moddlg_tut_1\minimal.example.w2scene", true);
    theGame.GetStorySceneSystem().PlayScene(scene, "Input");
}

Note: If you want to create and test multiple scenes later on you have to make sure the names of your dummyplayer functions differ!

4. Start the game, enable subtitles, load a savegame, open the console, start the scene with "playscene()" and close the console.

If everything worked you should see the mini dialog scene at this point.
 
Last edited:
Part 2 - Creating your own dialogue - what's necessary

I assume you already read and understood part 1, successfully encoded an example and chose wisely in-game.

But before you can create new dialogue definitions you still need some more background info: In this part you will get a brief introduction to YAML, the format all definitions for the dialogue encoder are required to be specified in. Also some information about the used analogies for these definitions. And finally we create a tiny dialogue very similar to the example used in part 1 from scratch to see the basic structure of dialogue definitions.

YAML

I tested some different formats but in the end dialogues described in YAML looked most readable (to me). YAML is a pretty simple and human readable text format which is quite useful if you need to specify lists and key value tables which can be nested.

Notepad++ supports YAML out of the box with folding of child elements which is a big plus for bigger files. YAML uses indentation to define nesting of elements. But it only accepts spaces and NOT tabs. So the first thing to do is to adjust the tab setting for YAML files in notepad++ (Settings/Preferences/Tab Settings set "replace by space" for yaml files).

You can read up more about YAML on the internet. Here are the MOST important things you need to know in order the create dialogue definitions. You can skip this if you are familiar with YAML.

Comments are prefixed with the number sign #. Everything following the sign up to the end of the line is a comment.

Lists elements are defined with a hyphen and a space followed by the value, like this:
PHP:
# this is a list
- "element 1"
- "element 2"
- "element 3"
The important thing is: the order of elements matters.

They can also be defined as inline lists like this:
PHP:
# this is the same as an inline list
[ "element 1", "element 2", "element 3" ]

Key value tables are defined like this (value are separated from keys by a colon followed by a space):
PHP:
# these are key value pairs
key1: value1
key2: value2
key2: value1234   # this value overwrites the previous value for key2 !

For key value tables the order does not matter. Also no duplicate keys are allowed: the latter definition overwrites the former!

Key value tables can be defined as inline tables, too. But readability suffers so I would not recommend it.

Some examples of nested kv-tables and lists:
PHP:
# a list as a value for key1
key1:
  - element 1
  - element 2

# kv-tables as list elements
- key: value
- key: value 2
  anotherkey: another value  # this is part of the kv table and thus still part of
                             # the SECOND list element and NOT a third list element!

# list with lists as elements
-
  - subelement 1
  - subelement 2
- [ subelement 1, subelement 2 ]  # the same as above but as inline list

# a kv-table with lists as values. and the lists contain key value elements for which the value is a list :)
line_1:
  - key: [ 1.0, "previous list element is a float" ]
  - key: [ "0.5", "previous list element is a string" ]
line_2:
  - key2: [ 0.25, something ]

This should be enough to understand the encoder definitions and to create new ones.

Analogies for dialogue definitions


As already mentioned in part 1 the dialog system for Witcher 3 is a very flexible system. Although this dialogue encoder covers only a reduced set of all settings it still gets complicated to stay on top of things. To make things easier to explain, I used terms analogous to film production for the encoder definitions. After all, the files are called scenes. You can skip the following if you are familiar with these terms.

Disclaimer: I have no clue how film production works in reality. This is merely how I think it could be :)

So let's start by mapping some aspects to personas from a film/show/theater production.

First we need someone who writes a script, in our case "only" a dialogscript. The scriptwriter transforms the ideas, characters, conflicts, themes, jokes, etc. that he wants to be conveyed by the scene into a meaningfull, interesting and hopefully engaging conversation. Dialoglines are his only tool for this. Additionally he is allowed to annotate the lines with some remarks or clues if they emphasise a key point. But at the end he does not have a say in how and (to a degree) by whom it will be presented to the viewer.

Secondly we need a director who delivers the dialog(script) to the viewer. The content are the dialoglines but it's the directors vision and artistic style that defines the presentation of the conversation. This includes camera-placement, -shots, -cuts, guidance of the actors, etc. His tool in pre production is a storyboard (with some instructions) that helps to visualize all these aspects to some extent.

Finally there is the producer. He is the pragmatic keep-it-all-together-and-make-it-work guy or as someone put it: he tries to get a bunch of crazies to actually get the job done. He makes sure all necessary assets are acquired and available for production and on set when the director needs them. This includes sobered up actors. Since he manages productions all the time he has access to a repository of previously used assets.

I omitted actors intentionally. While they are important on a film set (and totally overpaid in blockbusters) for our scenes they are just willing puppets :)

To sum it up:

  • most important is the scriptwriter who writes the dialogscript: all about content - no presentation.
  • scene director is all about presentation of the final dialogscript to the viewer: no content only presentation.
  • producer provides the assets and ties it all together into a production: all about assets and general set-up - not about content or presentation.

Magically this maps to the input of the dialog encoder:
  • dialogscript
    • contains the dialoglines and names of the speaking actors
    • contains interactive choices for the player
    • contains alternative dialog sections for different player choices
    • contains some conditions for conversation flow
    • contains optional annotations with hints for special treatment in storyboard
  • storyboard
    • contains definitions for camera shots/cuts
    • contains instructions for actor animations/mimics
  • production
    • contains all required settings for the scene
    • contains a list of assets (cameras, actors, animations, mimics with adjusted settings) which are available in this production
  • repository
    • contains ALL reusable templates (cameras, actors, animations, mimics) which can be "acquired" by a scene production
Now, after all this yadayada comes the part where we *finally* create a new dialogue scene.

Dialog from scratch

First, setup dialog project directories for a new project as done in part 1. Name the directories/project files as you like, e.g. tutorial_2 and moddlg_tut_2. But make sure all path settings in the batch files are set accordingly.

We keep it simple. We hired a n00b scriptwriter directly from college, let's call him Joe. A pro producer with access to a vast repository of templates joined the team, let's call him Kermit. And we also hired a trusted director who knows his stuff but doesn't give any directions to actors and is somewhat quiet, let's call him Bob.

Joe had this brilliant idea that since Geralt sails so much he needs to have his own boat. He sells the idea to Kermit and Kermit starts looking into his repository for assets useable for this production. After many days of work Joe returns with a file named "oscar_candidate_1.yml" which contains a "brilliantly written dialog between Geralt and Dan, the boat seller" (Joe's words). The production team examines the file:

PHP:
dialogscript:
    player: geralt
    actors: [ geralt, dan ]

    section_start:
        - dan: "Hello."
        - geralt: "Hello."
        - dan: "I sell boats. Do you need one?"
        - NEXT: section_choice_start

    section_choice_start:
        - CHOICE:
            - [ "yes", section_yes ]
            - [ "no", section_no ]

    section_yes:
        - geralt: "yes."
        - dan: "good, it will cost you 25000 and it will be delivered in 6 months."
        - geralt: "I don't have that much time."
        - dan: "ok. good bye."
        - NEXT: section_exit

    section_no:
        - geralt: "no."
        - dan: "ok. good bye."
        - NEXT: section_exit

    section_exit:
        - EXIT
Well, since marketing already promised the world a scene they have to use something. Bob tunes in by making a nod and creates a minimal storyboard:
PHP:
storyboard:
    defaults:
        camera:
            geralt: geralt_medium
            dan: dan_medium
Kermit adds the production manifest with the general set-up and adds the requested assets from the repository to this production:
PHP:
production:
    settings:
        sceneid: 1
        strings-idspace: 9999
        strings-idstart: 0

    assets:
        actors:
            geralt:
                repo: geralt
                by_voicetag: true
            dan:
                repo: skellige_merchant
                by_voicetag: false

        cameras:
            geralt_medium:
                repo: 1_2_medium

            dan_medium:
                repo: 2_1_medium
The teams makes a copy of all snippets, saves them combined to a file named tutorial_2.yml and ships it to the post production encoder guy (aka you). So this is an example of a low-budget/low-quality production. Try to encode it and test it in-game as you did in part 1.

Step by step breakdown

Now let's examine tutorial_2.yml step by step. We start with the production definition because the dialogscript and storyboard can only use assets defined in it.

Production

The first key is "settings" and it defines the general set-up. As of this moment only the scene id (number between 0 and 9999, though I'm unsure if this is really required for w2scene files) and two strings settings must be defined. The encoder auto generates numeric ids for all dialoglines. These ids are stored in the w2scene file and they reference the actual strings in w3strings files. Hence you have to define which id space (number between 0 and 9999) should be used (see here for more info) and from what number the autogeneration should start. That's important if you want to create multiple scenes within the same idspace.

The second key is "assets". Here you have to define what actual assets are available for the current scene. There are multiple asset categories. The absolute minimum that has to be defined for a simple scene like ours are actors and cameras. In later parts more categories will be added. Every asset has a name that you define (like dan, geralt_medium, etc.) and it's always based on a repository template which is referenced by the "repo" setting. We will look into the repository a little later.

Our actors have a "by_voicetag" setting. This defines if the actor should be searched by tag (meaning he must be present in this map). If this is set to false the actor will be spawned for the duration of the scene. Thus players should always be searched by tag. For our purpose and for easy debugging the npc should be spawned. (Note: someone should confirm this. I didn't test it ALL..)

As for the cameras there are no further settings. They are just an import from the repository with a customized name.

Dialogscript

The first two settings of the dialogscript define the player actor and the complete set of actors for this dialog. These are the names that have to be used in dialoglines and they must match an actor asset in the production definition. Since at the moment only 1 on 1 dialogues with the player are supported this definition will look almost always like this.

The remaining definitions of a dialogscript consist of (dialogue) sections. There are different types of sections and the types are distinguished by their naming (or more precisely by the name prefix). Let's first look at a "normal" section from our example:

PHP:
    section_yes:
        - geralt: "yes."
        - dan: "good, it will cost you 25000 and it will be delivered in 6 months."
        - geralt: "I don't have that much time."
        - dan: "ok. good bye."
        - NEXT: section_exit
A "normal" section is basically an ordered list with dialoglines for a specific actor which will be played by the game in exactly that order and without any interaction (aka choices) from the gamer. Sections can be linked by using the NEXT statement as last list element. The value for this key is the name of another section.

By linking normal sections into a chain you cannot define multiple conversation paths. For this there are "choice" sections. Their names must always start with "section_choice", like in our example:
PHP:
    section_choice_start:
        - CHOICE:
            - [ "yes", section_yes ]
            - [ "no", section_no ]
A "pure" choice section does not contain any dialoglines but only the CHOICE statement. Its value is an ordered (!) list of (up to 7) available choices for the player. Every of these choices is a list (in our example defined as an inline list!) with the displayed choice string as first element and the section to be played next (if this choice is selected by the player) as the second list element.

The combination of these two section types allows for very complex conversations.

But all conversations need to have a start so there are start sections, like in our example:
PHP:
    section_start:
        - dan: "Hello."
        - geralt: "Hello."
        - dan: "I sell boats. Do you need one?"
        - NEXT: section_choice_start
Start sections are like normal sections except their name starts with "section_start". There is more to start sections but that is *very* advanced stuff so I'll skip it here.

No conversation is *that* interesting that it should never end. Exit sections are used for this. Their names start with "section_exit". Exit sections are special as they must not have any dialoglines and no NEXT statement but instead require EXIT as last list element. A couple of more settings for exit sections will be covered in the next part.

Obviously you should create dialogues in which every conversation path starts at a start section and ends in an exit section.

To sum it up:
  • a dialogscript consists of actor and player definitions and of a set of dialog sections
  • a dialog must have at least one start section and one exit section
  • all section names start with "section_" and the names are used to link section among each other
  • start section names start with "section_start"
  • exit section names start with "section_exit"
  • choice section names start with "section_choice"
  • choice section can have at most 7 choices

Storyboard

For this minimal example the storyboard defines just a default actor-facing camera for every actor. The encoder will automatically generate events to change to the appropriate actor camera if the actor is performing his line. Additionally the player-actor facing camera will be activated at the beginning of every choice section. These auto cams are optional: if you do not define a default camera for an actor then the encoder will not generate a camera change.

In the last two tutorial parts more interesting storyboard settings will be covered.

Repository

Finally let's take a quick look at the repository. The basic idea for the repository is to have a central storage of template definitions which can be easily reused for multiple scenes. The basic structure looks like this:
PHP:
repository:
    actors:
        geralt:
            template: "gameplay\\templates\\characters\\player\\player.w2ent"
            #tags: [ ]
        # omitted some settings and other templates

    cameras:
        1_2_medium:
            fov: 20.0
            transform:
                pos: [ -1.12, -1.40, 1.71 ]
                rot: [ 0.0, -5.0, 332.0]
        # omitted some settings and other templates

    mimics:
        # omitted templates

    animations.mimic:
        # omitted templates

    animations:
        # omitted templates
As you can see there are five template categories in the repository:
  • actors
  • cameras
  • mimics
  • animations
  • animations.mimic

I won't go into details for every category as they will be covered in later parts (at least to an extent). Just remember: those repo templates only reference assets/templates from the game and/or tweak some settings. But all those assets already need to be present in the game!

In our example we need only two actor and two camera templates.

Actor templates require a path to the template entity from the game or if you created/modified your own entity the path to its position in your dlc mod. You can also specify an additional list of tags a spawned entity REQUIRES to be having in the game to be identified as YOUR actor for this particular scene. But that's not necessary for our example as we don't search by tags and spawn the entity anyway.

In our example we also requested two cameras. Camera templates are complex and will be covered in part 4.

As the template definitions can be rather long the repository can be splitted into multiple files: when you start the encoder the first thing it does is searching in a repo directory for all "*.repo.yml" files. The important thing is: only templates found in the repository are available for import in your production definition.

The downloaded encoder package contains only a handful of repository templates for the examples. You can use those for your own dialogues, too. The repository is located in the repo directory of the encoder.

However you can and probably will need to define additional templates yourself. Look at the existing example template definitions and what's available in the game and create your own templates as you need them.

Also if you think you have some cool template definitions (e.g. nice camera definitions) publish them with a description so others can benefit from your work.

Some final words


The tutorial_2.yml is a valid dialogue definition. I encourage you to make some invalid changes in this simple definition here and there. This way you can familiarize yourself with various error messages from the encoder which should help you to figure out problems in bigger definitions way faster.

That's it for part 2. The first thing to do in part 3 will be to fire Joe.
 
Last edited:
Part 3 - Creating a more interesting conversation - about dialogscript

So you've read part 1 and part 2 and looking at your set of Nobel Price in Literature gold medals glittering in the last beams of sunset you think: so far this dialogue system sure didn't make an impression on me. Well, here's some more information.

In this part we will concentrate on the dialogscript definition. You will learn how to make conversations more variable by randomizing some sections and by linking sections based on conditions. We will look into calling witcher script functions from certain points in the dialog, a very flexible and powerful tool. Also you will learn about advanced options for choice definitions and about choice actions. And finally some settings for exit sections wil be covered, too.

A memorable character

First setup dialog project directories for a new project as done in the last parts and double check if your directories are set correctly in the batch files. If you wish you can also extend your last tutorial project however I assume you named the dialog definition "tutorial_3.yml".

So, Joe. The team liked his enthusiasm but that ain't enough to cut it. Kermit got some heat for the results and Joe had to... take a long-term vacation. A new writer was needed. George called, but well, the team wanted a good script so they favoured someone else. Let's call him Stanley.

First thing Stanley did was to create a persona for Dan. It helps him to think of Dan as a real character every time he has to come up with a line for him.

Dan loves his job. Dan thinks he is a pro. His whole family has a talent for selling boats and so has he (he thinks). Except he never sold one. He learned from the best and he (thinks he) surpassed them all. But he has a terrible memory so only few lines sticked. And he totally forgot which were supposed to work best. So he has to improvise. But he knows for sure: never accept a no for an answer and always be proactive (aka never let a customer the time to think it through).

Stanley presents his dialogue and the team is... awed and humbled. Everbody loves it. Except for Kermit who realizes that >79k of dialoglines for a minor npc may be a tad too much. So Stanley has to cut. A lot.

He returns with the following ripped dialogscript:
PHP:
dialogscript:
    player: geralt
    actors: [ geralt, dan ]

    section_start:
        - geralt: "Hello"
        - NEXT:
            condition: [ moddlg_facts_havemet, "=", 1 ]
            on_true: section_already_met
            on_false: script_setfact_have_met

    script_setfact_have_met:
        - SCRIPT:
            function: AddFact_S
            parameter:
                - factName: moddlg_facts_havemet
                - value: 1
                - validFor: 0
        - NEXT: section_first_meeting

    section_first_meeting:
        - dan: "Hello Mister.. ?"
        - geralt: "My name is Geralt. I'm a..."
        - dan: "Can I do something for you?"
        - geralt: "..."
        - dan: "Of course I can. What a silly question, Geralt. I may call you Geralt, can't I? Of course I can."
        - dan: "I have some interesting offer for you. You will not regret hearing me out."
        - geralt: "I..."
        - dan: "Because, really, who doesn't want a boat! Boats are for everyone!"
        - geralt: "But..."
        - dan: "You are a boatsman. I see this. Salt in your nose. Wind in your hair."
        - dan: "[You know.. You could use a haircut.]"
        - dan: "Where is that boat of mine, you ask yourself"
        - geralt: "Not really"
        - dan: "Well, I got it. I saved it."
        - dan: "Just."
        - dan: "For."
        - dan: "You, my friend."
        - CHOICE:
            - ["Erm...", "section_storytime"]
            - ["I don't need a boat", "section_no"]
            - ["I could use a boat", "section_yes"]
            - TIME_LIMIT: 3.0

    section_yes:
        - geralt: "Mhmm. Maybe I could use a boat. It gets rather tiresome to "borrow" boats."
        - dan: "Yes! A good choice, Geralt! Your best decision!"
        - dan: "Ever!"
        - dan: "She's a real beauty! If I could I'd marry her in an instant!"
        - geralt: "Yeah, great love story: "From honeymoon cruise to stormy weather", including break up and drowning your sorrow."
        - dan: "You're right! She's a luxury cruise! We're on the same page!"
        - dan: "You said it yourself. LUXURY cruise! And it's only 30000!"
        - geralt: "What!?"
        - dan: "25000."
        - geralt: "No."
        - dan: "20000."
        - PAUSE: 5.0
        - dan: "Alright! But just because I like you! 15000!"
        - geralt: "That's more reasonable. I need.."
        - dan: "Yes! And they said I couldn't sell a fake ship!"
        - geralt: "Wait, what?"
        - dan: "Nothing. I heard nothing. Did you hear anything?"
        - dan: "No? Me neither."
        - PAUSE: 1.0
        - dan: "Well. Let's get started. I need you to deposit the cash beforehand."
        - dan: "After a reasonable time the ship will be constr... delivered to you."
        - NEXT: section_bye

    section_no:
        - geralt: "I don't need a boat"
        - dan: "Are you sure? You could use a boat, you know."
        - dan: "Think of all the times you needed a boat and there was none."
        - dan: "Or the countless times you had to "borrow" that broken pile of wood"
        - NEXT: section_choice_maybe

    section_choice_maybe:
        - CHOICE:
            - ["Maybe it's not a bad idea", section_yes]
            - ["Still don't need a boat", section_no2]
            - ["Gotta go", section_bye, exit]
            - TIME_LIMIT: 10

    section_no2:
        - geralt: "No, I don't need a boat"
        - dan: "I knew it."
        - dan: "My cousin, this old weasel. He already made you an offer."
        - dan: "He is ruining my business since I and his wife.."
        - dan: "Well, it wasn't personal. Just business."
        - PAUSE: 1
        - dan: "Kind of."
        - NEXT: section_bye

    section_already_met:
        - dan: "Geralt! You're back!"
        - geralt: "I..."
        - dan: "No! Wait! Let me guess!"
        - dan: "You are in search for a boat!"
        - geralt: "No."
        - dan: "I knew it! It was the beauty I showed you that never got out of your head!"
        - dan: "But I'm afraid I already have promised it to someone else."
        - dan: "The deal is done."
        - dan: "Sorry."
        - dan: "I can't do anything for you."
        - geralt: "Actually, I..."
        - dan: "Ok. OK! Stop it! I know how much you want it."
        - dan: "And I trust you!"
        - dan: "Because here you are! Torn apart by your desire to call yourself a proud owner of this masterpiece!"
        - NEXT:
            condition: [ moddlg_facts_dan_storytime, "<", 2 ]
            on_true: section_storytime
            on_false: section_choice_maybe

    section_storytime:
        - dan: "I see you still struggle to decide."
        - dan: "Geralt, dear friend, let me tell you a story."
        - NEXT: section_choice_story

    section_choice_story:
        - CHOICE:
            - [ "Erm..", section_storytime_start ]
            - choice: [ "Let's skip the story.", script_storytime_skip ]
              condition: [ moddlg_facts_dan_storytime, "<", 1 ]
            - choice: [ "Let's SKIP the story.", script_storytime_skip_axii, axii ]
              condition: [ moddlg_facts_dan_storytime, ">=", 1 ]
              single_use: true
            - TIME_LIMIT: 3.0

    script_storytime_skip:
        - SCRIPT:
            function: AddFact_S
            parameter:
                - factName: moddlg_facts_dan_storytime
                - value: 1
                - validFor: 0
        - NEXT: section_storytime_start

    script_storytime_skip_axii:
        - SCRIPT:
            function: AddFact_S
            parameter:
                - factName: moddlg_facts_dan_storytime
                - value: 2
                - validFor: 0
        - NEXT: section_no_storytime

    section_storytime_start:
        - RANDOM:
            - section_story_part1_1
            - section_story_part1_2

    section_story_part1_1:
        - dan: "You know how I got to be a boat seller?"
        - dan: "I was young and my older brother gave me a boat. Not just a boat."
        - dan: "But a limited Junior Ultra Skellige Warrior Assault Boat."
        - dan: "And you know what I realized?"
        - NEXT: section_randomizer_story_part2

    section_story_part1_2:
        - dan: "There was this guy standing in the port, looking at all the travelers."
        - dan: "And then he saw one of them flip a coin and board a boat."
        - dan: "He became so obsessed with that idea of..."
        - geralt: "...destiny..."
        - dan: "Exactly. He obsessed with the idea of getting all the coin to acquire a boat, because, you know:"
        - NEXT: section_randomizer_story_part2

    section_randomizer_story_part2:
        - section_story_part2_1
        - section_story_part2_2

    section_story_part2_1:
        - dan: "Wherever you want to go, you go. That's what a boat is."
        - dan: "It's not just a keel and a hull and sails. That's what a boat needs."
        - dan: "No, what a boat is. What it really is, is freedom!"
        - NEXT: section_story_end

    section_story_part2_2:
        - dan: "Boats are the future! They are an investment!"
        - dan: "Soon everybody will have multiple boats."
        - dan: "One to sail to raids. One to sail to the nearest merchant."
        - dan: "And at least one to show off."
        - NEXT: section_story_end

    section_story_end:
        - dan: "See? Isn't that reason enough?"
        - geralt: "Well..."
        - NEXT: section_storytime

    section_no_storytime:
        - geralt: "Let's skip the stories."
        - dan: "I..."
        - PAUSE: 2.0
        - dan: "I... don't know what to say. This never happened to me."
        - dan: "But that's no problem. I know you get me!"
        - NEXT: section_choice_maybe

    section_bye:
        - geralt: "I need to go. But I'll get back to you."
        - PAUSE: 2.0
        - geralt: "Later. [Much later]"
        - dan: "Wait! You're missing out!"
        - NEXT: section_exit

    section_exit:
        - CAMERA_BLEND: 5.0
        - EXIT

With the absence of all the favourite stories the team members liked so much and all the other cuts, well the mood takes a dip. But they're pros and know the reality of a limited budget only too well.

In the meantime Bob left for another promising production and the team is forced to recycle his previous storyboard, which oddly enough works, too. Kermit adds the same production manifest as in the first production and ships the complete tutorial_3.yml file to post production guy. Try to encode it and test some of the conversation flows in-game like you did in the previous parts.

Step by step breakdown

Our example dialogscript is much bigger now. So let's examine the newly introduced features. We start with something simple.

Pause Elements

In the example of part 2 all our normal dialog sections only contained dialog lines for actors and a "NEXT" link as last element. But sometimes more can be said with a well placed silence. For this you can use a key-value PAUSE statement. The duration (in seconds) is defined as a float value, like this:
PHP:
    section_bye:
        - geralt: "I need to go. But I'll get back to you."
        - PAUSE: 2.0
        - geralt: "Later. [Much later]"
        # [...]
PAUSE statements can be used just like dialog lines in every normal dialog section. PAUSE statements will be more interesting in the next tutorial parts.

Randomizer Sections

"Randomizer" sections are a new section type. They enable you to define a set of up to 10 links to other sections and the game will choose one of the links randomly every time the conversation flow touches this section. A randomizer section name always starts with "section_randomizer" and contains only a list of section names, like in our example:
PHP:
    section_randomizer_story_part2:
        - section_story_part2_1
        - section_story_part2_2
The order does not matter as one link will be picked randomly. Sometimes the game sticks to the same selection for a weird long time but if you add more links you'll see it actually is really (somewhat) random.

You may have noticed another randomized definition in our example dialogue. It looks like this:
PHP:
    section_storytime_start:
        - RANDOM:
            - section_story_part1_1
            - section_story_part1_2
This is actually only a shortcut for defining randomizer sections. It will be automatically expanded to:
PHP:
    section_storytime_start:
        - NEXT: section_randomizer_storytime_start

    section_randomizer_storytime_start:
        - section_story_part1_1
        - section_story_part1_2
That's all to randomizer sections. Pretty simple tool for adding variety to dialogues.

Conditional section links

A more controllable option to make dialogues variable and reactive to exterior events (like completed quests or other saved states) is to use conditional section links.

First some background information about the "facts" db:
the game uses a key-value "database" to store various information about the current state of the game. Those state information (like completed quest, visited npc, etc.) are called "facts" and are created/updated/deleted in various places (scripts, scenes and probably many more). The fact db is stored in your savegame when you save and restored when you load a savegame.

As far as I know there is no known complete lists of available fact names for the Witcher 3 BUT you can define and update your *own* facts (more on this in the next section). This is important because for querying the fact db you need to know the facts exact name.

Now let's look at the definition of conditional links, like in the start section of our example:
PHP:
    section_start:
        - geralt: Hello
        - NEXT:
            condition: [ moddlg_facts_havemet, "=", 1 ]
            on_true: section_already_met
            on_false: script_setfact_have_met
Instead of defining the name of the next section you define a key value table with one boolean condition and *two* section names: one to be taken if the condition evaluates to true and the other to be taken if the condition evaluates to false.

The condition is always a three element list (in the above example defined as an inline list):

  1. the *exact* factname (defined as string value)
  2. comparison operator (possible settings: "<", "<=", "=", "!=", ">", ">=")
  3. integer value the fact will be compared to

So in our example this means: query the fact "moddlg_facts_havemet" and if its value is equal to 1 then go to "section_already_met" otherwise to section "script_setfact_have_met". The condition will be reevaluated every time this section is played.

In our example dialogue the conditional links are "only" used to adapt the conversion to a previous conversion with Dan but with appropriate fact checking npcs can react and comment on many things the player has actually done or not done during his play. Much potential there.

Script calls

Script calls are a very powerful tool because the called functions are not limited by the w2scene capabilities but can do (nearly) anything the scripting language allows.

All script calls are defined in a separate segment which name has to start with "script". These segments are embedded in the conversation flow like normal sections and will trigger the script call whenever the segment is visited in the conversation.

Thus they need
  • to be linked to like other sections and
  • to have a successor which must be defined by the "NEXT" statement

For example in the tutorial dialog a script call is used to add a fact to modify the conversion flow of this scene for a second npc encounter. Directly after making the call the dialog section "section_first_meeting" will be played:
PHP:
    script_setfact_have_met:
        - SCRIPT:
            function: AddFact_S
            parameter:
                - factName: moddlg_facts_havemet
                - value: 1
                - validFor: 0
        - NEXT: section_first_meeting
Only two elements are allowed in script segments: the SCRIPT setting and the NEXT setting.

The SCRIPT definition must include a "function" setting and an optional "parameter" setting, which defines a list of parameters AND their values as key-value pairs. Obviously these parameter lists must match the target script function declaration. For example the target function for the above example is already defined in the game/scenes/scene_functions.ws file:
PHP:
storyscene function AddFact_S( player: CStoryScenePlayer, factName: string, value: int, validFor : int )
{
    if (validFor > 0 ) {
        FactsAdd( factName, value, validFor );
    }
    else {
        FactsAdd( factName, value, -1);
    }
    player.DbFactAdded( factName );
}
As you can see both the function name AND the parameter names match the function definition exactly as they are both case sensitive! Double check this because you won't get any errors if they differ!

The parameter types must match, too. But to make the definition more handy the encoder extracts the parameter type from your definition in the script segment. This works for strings, integer values, floats and booleans. The only exception is the CNAME type as it cannot be distinguished from strings automatically. CNAME typed values need to be prefixed with "CNAME_". The prefix is only for type detection and will be removed prior encoding to the w2scene file.

Some examples for type definitions:
  • abc is a string
  • 1 is an integer
  • 1.0 is a float
  • "1" is a string
  • true is a boolean
  • "true" is a string
  • CNAME_abc is a CNAME with value abc
  • "CNAME_abc" is a CNAME with value abc

Currently the encoder supports only primitives and no arrays.

You should take a look at the scene_functions.ws file from the game. There are some interesting scene functions which you can use (like for managing facts). Or you can define your own in your script files and make them do whatever you need at a certain point in your dialogue.

Advanced choice sections

We already looked at the basic definition of choice sections in the previous tutorial part: they provide the gamer with a set of options he has to choose from and link every choice to an appropriate dialog section.

And they allow even more...

But first a hint: like randomizer sections there is a shortcut for choice sections. The following usage:
PHP:
    section_first_meeting:
        # [...]
        - dan: "You, my friend."
        - CHOICE:
            - ["Erm...", "section_storytime"]
            - ["I don't need a boat", "section_no"]
            - TIME_LIMIT: 2.0
will be automatically expanded to:
PHP:
    section_first_meeting:
        # [...]
        - dan: "You, my friend."
        - NEXT: section_choice_first_meeting:

    section_choice_first_meeting:
        - CHOICE:
            - ["Erm...", "section_storytime"]
            - ["I don't need a boat", "section_no"]
            - TIME_LIMIT: 2.0

Choice options - time limit

In the above example the last list element "TIME_LIMIT" defines a 2 seconds time frame. The player has to choose an option within the time frame or the first displayed option will be chosen automatically. Note that the first displayed option is not necessarily the first element of your choice list definition.

This brings us to ordering and conditions for displaying choice options.

Choice options - condition, single use, emphasize

Probably most of the time these extra settings won't be needed. So the "basic" choice option definition is streamlined for the simple usecase. But if you need the extra settings there is a more complex definition for a choice option which enables you to use the full set of options, like in this example section:
PHP:
    section_choice_story:
        - CHOICE:
            - [ "Erm..", section_storytime_start ]
            - choice: [ "Let's skip the story.", script_storytime_skip ]
              condition: [ moddlg_facts_dan_storytime, "<", 1 ]
            - choice: [ "Let's SKIP the story.", script_storytime_skip_axii, axii ]
              condition: [ moddlg_facts_dan_storytime, ">=", 1 ]
              single_use: true
            - TIME_LIMIT: 1.0

The first option is a "basic" definition like you've already used. But the second and third are "advanced" definitions: instead of an (inline) list these are defined as a key value table.

An advanced definition must always contain a "basic" definition as value for the key "choice". All other settings are optional:

  • The "condition" setting is defined exactly like its equivalent for conditional section links: the queried fact is compared to the value and the choice option will be displayed only if the comparison holds
  • The "single_use" setting is a boolean setting (if omitted it's set to false). If set to true it lets this option to be chosen only once by the player. If the player returns to the same choice section in a subsequent conversation it won't be displayed anymore. This is useful, e.g. for options which give the player experience or something else.
  • The "emphasize" setting is a boolean setting (if omitted it's set to false). If set to true it colors this option yellow and pushes it above all other non emphasized choice options.

If you use these settings in time limited choice sections be aware that they *may* change the first displayed choice option dynamically!

There is one more setting for a choice option: the choice action.

Advanced choice sections - choice actions


Choice options with an attached action are displayed in the game with a prepended icon. Most common is probably the shop action (money bag icon). But there are a couple of other predefined actions.

Right now the following are supported by the encoder:
  • shop
  • blacksmith
  • betting
  • gwent
  • axii
  • exit

If you want to attach an action to a specific choice option you just have to add one of the action names as 3rd element of a "basic" choice definition, like this:
PHP:
    section_choice_story:
        - CHOICE:
            - [ "Let's SKIP the story.", script_storytime_skip_axii, axii ]

Please note that the sole adding of an action to the definition does nothing more but show the icon. It's only an indication for the player that choosing this option will (probably) do something "special". You still have to trigger the functionality separately (most often with a script call).

Well, there are exceptions to this rule: just adding the axii action to a choice option definition will give the player some experience points if the option is chosen - and this will happen *every* time. So it is a good idea to use it only with "single_use" setting set to true.

There are also at least three other options (shave, haircut, pay) which trigger a money transfer automatically, but they are not supported by the encoder right now.

So how do you trigger the action functionality. This is just a shortened quick info. You will have to look into other scenes/scripts for more information:
  • shop: call script function "ShowMeGoods" with parameter "merchantTag" set appropriately
  • blacksmith: call script function "ShowCraftingPanel" with parameter "crafterTag" set appropriately
  • betting: call script function "PlaceBet" with parameters "rewardName" and "startingBetPercentage" set appropriately. (Look into rewards.xml for reward names)
  • axii: works just by selecting but if you want the animation you have to specify it yourself (see Part 4)
  • exit: just an icon

A note on gwent: I did not try to get it working but according to w2scenes from the game you have to call a script function "PlaceBet" (like for a betting action) AND add the output "Gwint" AND set blackscreen to true in a subsequent exit section. Also, you will probably need a npc with an associated gwent deck (no idea how this works). If you find out how triggering gwent from a w2scene actually works PM me and I'll update this section.

Choice options - a summary

To sum it up for choice options:
  • "basic" choice options
    • must define a displayed text and a link to a section
    • may define a choice action/icon as last element
  • "advanced" choice options
    • must contain a "basic" choice definition (with or without action)
    • may contain a "condition" for displaying the option
    • may contain a "single_use" flag indicating that the option may only be chosen once
    • may contain an "emphasize" flag indicating that the option should be yellow and above all non emphasized options
  • both versions may be used together in the same choice option list
  • (most) choice actions need to be triggered by specific script calls

Exit Sections

Compared to the complexity of choice sections exit sections are simple. In the example dialogue the only exit section contains a new optional setting:
PHP:
    section_exit:
        - CAMERA_BLEND: 5.0
        - EXIT

"CAMERA_BLEND" defines the time (in seconds) for the last camera used in the dialog to smoothly move and rotate back to the gameplay camera. The longer the time the slower the camera will change. If you omit the setting a one second (I think) blend time will be used.

There is an alternative setting "BLACKSCREEN" for ending a dialogue. Well, it's obvious but here we go: if set to true the screen will be set to black on exit. Handy if you want to simulate "some time has passed", I guess. Though, I don't know how useful this setting really is. In any case it cannot be used in conjunction with "CAMERA_BLEND".

The final setting for exit sections is "OUTPUT", defined like this:
PHP:
    section_exit:
        - BLACKSCREEN: true
        - OUTPUT: Gwint
        - EXIT

It can be used to provide back a string state (in this case "Gwint") to the game if the conversation ends. Since multiple exit section definitions are allowed in the same scene different OUTPUTs can be signaled to the game. Aside from the above (non working) Gwint example this is most useful when used in combination with w2quest and w2phase files to let the game proceed in the quest graph.

That's it for Part 3

We covered all(*) of the supported dialogscript definitions. Next parts will finally look into the storyboard definitions and their usage for presenting the conversation defined in the dialogscript.

(*) one setting irrelevant to convesation flow is still missing :)
 
Last edited:
Hey, bro, thanks for the awesome and extensive guide. And the list of animations and its durations really helped a lot.

If you're still active, do you know if the PlayScene function still work on version 1.22?

I'm trying to load an existing scene and play it, but nothing happens when I call the PlayScene function. Are there certain criteria or state that I have to be in?

Also, it would be great if you can also extract some missing animations if you're still active. Like the ones from the new BAW. And here are some important animations missing in your package:
- ciri related animations (combat, exploration)
- man_work
- woman combat (sword, bow, sorceress)

Ciri exploration animation is in content4, which is really important because it has all animations for traversing the world.
 
Hey, bro, thanks for the awesome and extensive guide. And the list of animations and its durations really helped a lot.

If you're still active, do you know if the PlayScene function still work on version 1.22?
Yup, still here, but only secretly active and avoiding everybody.

So to answer your question (directly from my hide-out): Yes, the function should still work.

I'm trying to load an existing scene and play it, but nothing happens when I call the PlayScene function. Are there certain criteria or state that I have to be in?
Although scenes include conditions they are all embedded to direct only the internal flow (as far as I know). So they should still start playing. I'm guessing here but the actor may not be available in this hub. Try to load the scene in another hub (where the game would have played it). Maybe this helps.

Also, it would be great if you can also extract some missing animations if you're still active. Like the ones from the new BAW. And here are some important animations missing in your package:
- ciri related animations (combat, exploration)
- man_work
- woman combat (sword, bow, sorceress)

Ciri exploration animation is in content4, which is really important because it has all animations for traversing the world.
Well, the animations I included were only a quick dump to have something to play around with the encoder. Unfortunately I don't have HoS and BaW, yet. But there will be an update of the encoder and I plan to include animation meta for all w2anims files.

Also, there are rumors in the secret modder hide-outs that an animation mod with all animation info (including HoS and BaW) will be published soon :)
 
Top Bottom