/
WS: Language Guide

WS: Language Guide

 

 

 

 

Divider.png

 

 

 

 

 

Basics


Comments

During the development of new scripts it is possible to add comments to make it easier to follow your code.

Single line comments can be added like so:

// This is a single line comment

Multi-line comments can be used for bigger blocks of text as well:

/* This text is multiple lines long. ... */

Together they can be used to make your code more easily readable, for example:

/* Example mod by Bob Version 1.0 Created on 2024.05.01. */ exec function scripts_tutorial_test() { // Show the hello text so we can verify easily that the mod works. GetWitcherPlayer().DisplayHudMessage('Hello'); }

Types

WitcherScript has a list of basic types that can be used inside the scripts to store data:

  • int- Standard 32bit integer (value range from -2,147,483,648 to 2,147,483,647)

  • String- Standard string, use quotation marks to pass values, eg.: "This is a string"

  • name- Name type variable, essentially a string used for item names, tags, etc. Use apostrophes to pass values, eg.: 'this is an item name'

  • float- Standard float type, eg.: 1.0f

  • Vector- 4 variable vector (Quaternion) ordered in XYZW order, eg.: Vector(100, 100, 100, 1)

  • EulerAngles- 3 variable rotation ordered in Pitch, Yaw, Roll order, eg.: EulerAngles(0, 180, 0)

  • bool- standard true/false boolean, also accepts 0 and 1 as inputs, however unlike Unreal Script does not accept Yes/No values

  • Matrix- Indicates matrix variable type.

  • array< X > - Indicates an array with X being the type of array, eg. array< int > being an array of integers


Global objects

The game exposes a list of global object that you can use from anywhere. They are always available and expose a lot of very useful functions.

theGame=CR4Game theServer=CServerInterface thePlayer=CR4Player theCamera=CCamera theUI=CGuiWitcher theSound=CScriptSoundSystem theDebug=CDebugAttributesManager theTimer=CTimerScriptKeyword theInput=CInputManager

For example if you want to do something with the player. You can simply write:

thePlayer.DisplayHudMessage('Hello')

Instead of using GetWitcherPlayer() and the game will know that you are referring to the player. These can be changed inside redscripts.ini but it is not recommended to change them since your mod will not be compatible with others who have the default settings.


Variables

It is possible to define variables to store your data and you can use them to pass around your data.

Local variables

Inside a given function to process the data etc. it is possible to define variables that can be used throughout the function. They do have to be defined at the top of your function however.

exec function acquire(skillName : name) { var i : int; var skills : String; // Do something cool with the data }

 

Class variables

Classes can contain member variables as well. They are tied to the given class and can be used to store the data.

class Test { var SomeText : String; }

Function parameters

It is possible to pass parameters to functions which you can use to parameterise them. For example the code snippet bellow can help you change the weather in-game. Try running it in the debug console as RequestWeatherChangeTo('WT_Rain_Storm'); and observer that it has started raining

exec function changeweather(weatherName : name) { RequestWeatherChangeTo( weatherName , 1, false ); }

 

 

 

 

 

 

 

Functions


WitcherScript has different kinds of functions that you can set up. Check the list below.

Exec function

Executable functions are exposed to the game’s debug console and can be used to start functions or utility functions when developing your mods.

exec function stoprain() { RequestWeatherChangeTo('WT_Clear', 1.0, false); }

An example from the Mariska’s Wonderland demo mod, which was used to give the player the key ( item_sqmod1_canyon_hideout_key ) for the back room in the hidden dungeon during debugging:

exec function addKey( key_name : name ) { thePlayer.inv.AddAnItem(key_name, 1); }

Latent function

These are like Coroutines etc. in other engines basically they allow for passing time and slower execution. Bellow you can see the sleep call in the function which allows to wait X amount of seconds.

latent storyscene function ShaveGeralt( player: CStoryScenePlayer ) { var acs : array< CComponent >; acs = thePlayer.GetComponentsByClassName( 'CHeadManagerComponent' ); ( ( CHeadManagerComponent ) acs[0] ).Shave(); Sleep(1.0f); }

Timer function

These functions are real time based timer which can be attached to entities.

states.ws has some utility functions for this:

    // Add named real time based timer to entity; returns unique timer id     import final function AddTimer( timerName : name, period : float, optional repeats : bool /* false */, optional scatter : bool /* false */, optional group : ETickGroup /* Main */, optional saveable : bool /* false */, optional overrideExisting : bool /* true */ ) : int;     // Add named gameplay time based timer to entity; returns unique timer id     import final function AddGameTimeTimer( timerName : name, period : GameTime, optional repeats : bool /* false */, optional scatter : bool /* false */, optional group : ETickGroup /* Main */, optional saveable : bool /* false */, optional overrideExisting : bool /* true */ ) : int;     // Removes all timers with matching name from entity (in given group or all groups if none is specified)     import final function RemoveTimer( timerName : name, optional group : ETickGroup );     // Removes all timers with matching id from entity (in given group or all groups if none is specified)     import final function RemoveTimerById( id : int, optional group : ETickGroup );     // Remove all timers from entity     import final function RemoveTimers();

Setting up a function is really easy like so:

timer function Loop(dt : float, id : int) { LoopFunction(dt); }

The dt parameter defines the “delta time” the amount of time that has passed.

Storyscene function

Special functions that can be used in scenes.

storyscene function EnableFastTravelPin( player: CStoryScenePlayer ,pinTag : name, enable : bool ) { var manager : CCommonMapManager = theGame.GetCommonMapManager(); manager.SetEntityMapPinDisabled( pinTag, !enable ); }

Quest function

Special functions that can be used in Quest nodes.

quest function LaunchCredits() { theGame.GetGuiManager().RequestCreditsMenu(CreditsIndex_Wither3); }

Reward function

These functions can be attached to a given reward inside the editor.

reward function TutorialLevelUp() { var witcher : W3PlayerWitcher; witcher = GetWitcherPlayer(); witcher.AddPoints(EExperiencePoint, 50, false); if(witcher.GetLevel() == FactsQuerySum('tutorial_starting_level')) { witcher.AddPoints(EExperiencePoint, witcher.GetMissingExpForNextLevel(), true); } }

Cleanup function

They cannot return anything and have no parameters. They are used for cleaning up after something has finished.

cleanup function ThrowProjectileCleanup() { if( thrownEntity ) { thrownEntity.StopAiming( false ); if ( !parent.wasBombReleased ) { rider.RaiseEvent( 'actionShootEnd' ); parent.wasBombReleased = true; thrownEntity.Destroy(); thrownEntity = NULL; } } }

Entry function

An entry function is a state entry function for which you can see an example below. These are rarely used in the game.

entry function DrawEvent() { parent.ownerPlayer.SetBehaviorVariable( 'failSafeDraw', 1.0 ); virtual_parent.RaiseOwnerGraphEvents( 'Crossbow_Draw', true ); parent.performedDraw = true; }

Summary

Possible function flags

enum EFunctionFlags { FF_NativeFunction //!< Function is native ( implemented in C++ ) FF_StaticFunction //!< Function is static FF_OperatorFunction //!< Function is data operator FF_ExportedFunction //!< Function is native function that was exported to script FF_FinalFunction //!< Function is final and cannot be overridden in child classes FF_EventFunction //!< Function is special event function FF_LatentFunction //!< Function takes time to execute FF_EntryFunction //!< Function is a state entry function FF_ExecFunction //!< Function can be called from console FF_UndefinedBody //!< Function has no body (just a declaration) FF_TimerFunction //!< Function is a timer FF_SceneFunction //!< Function can be used in Scenes FF_QuestFunction //!< Function can be used in Quests FF_CleanupFunction //!< Function is a cleanup FF_PrivateFunction //!< Function is private FF_ProtectedFunction //!< Function is protected FF_PublicFunction //!< Function is public FF_RewardFunction //!< Function can be attached to reward FF_AccessModifiers = FF_PrivateFunction | FF_ProtectedFunction | FF_PublicFunction, };

Generic flags

enum EScriptStubFlags {     SSF_Import           SSF_Editable         SSF_Const           SSF_Timer           SSF_Abstract         SSF_Entry           SSF_Auto             SSF_Inlined         SSF_Out             SSF_Optional         SSF_Final           SSF_Private         SSF_Protected       SSF_Public           SSF_Event           SSF_Latent           SSF_Exec             SSF_Unused           SSF_Scene           SSF_Saved           SSF_Quest           SSF_Cleanup         SSF_Reward           SSF_StateMachine };

 

 

 

 

 

 

 

Classes


A class in object-oriented programming (OOP) is a blueprint for creating objects. It encapsulates data for the object and methods to manipulate that data. Classes allow for the organization of code into reusable and modular components.

Regular class

Normal classes allow you to hold values and methods inside a common container which you can reuse.

class InterpCurve {     var something: float;   function doSomething( inVal : float, outVal : float ) : int { return 10; } }

Native class

These are classes defined in C++ and need to be imported to WitcherScript

import class C2dArray extends CResource {       // Get value by column, row     import final function GetValueAt( column : int, row : int ) : string;         // Get value using column header and row     import final function GetValue( header : string, row : int ) : string;         // Get name value by column, row     import final function GetValueAtAsName( column : int, row : int ) : name;         // Get name value using column header and row     import final function GetValueAsName( header : string, row : int ) : name;         // Get number of rows     import final function GetNumRows() : int;         // Get index of row with given value in given colum     import final function GetRowIndexAt( column : int, value : string ) : int;         // Get index of row with given value in given colum     import final function GetRowIndex( header : string, value : string ) : int; }

Statemachine

These classes define a default state and then you can define states that it can transition to, think about it like a text like graph with transitions. Below you can see the statemachine for the Witches cage which has two state of being turned on and off.

statemachine class W3WitchesCage extends CEntity {     default autoState = 'TurnedOff'; } state TurnedOff in W3WitchesCage {     event OnEnterState( prevStateName : name )     {         super.OnEnterState( prevStateName );         parent.ApplyAppearance("roots_off");     } } state TurnedOn in W3WitchesCage {     event OnEnterState( prevStateName : name )     {         super.OnEnterState( prevStateName );         parent.ApplyAppearance("roots_on");     } }

You can check states.ws for reference on how to use these functions.

import class CScriptableState extends IScriptable {     // Is this state the active one in the state machine     import function IsActive() : bool;     // Get the name of this state     import function GetStateName() : name;     // Called when we are entering this state     event OnEnterState( prevStateName : name ) {}         // Called when we are leaving this state     event OnLeaveState( nextStateName : name ) {}         // Called to check if this state can be entered     import function CanEnterState( prevStateName : name ) : bool;     // Called to check if this tate can be leaved     import function CanLeaveState( nextStateName : name ) : bool;     // ---- State change callbacks ---     // Invoked before state begins     import function BeginState( prevStateName : name );     // Invoked before state ends     import function EndState( nextStateName : name );     // Invoked on return to state (after other state was popped from the stack)     import function ContinuedState();     // Invoked when other state gets pushed on the stack (thus current state gets paused)     import function PausedState(); }

Summary

enum EClassFlags {     CF_Abstract                         //!< Class is abstract, no instance of it can be created     CF_Native                           //!< Class is defined in C++     CF_Scripted                         //!< Class has definition in script     CF_Exported                         //!< Class definition has been exported to C++ code     CF_State                            //!< Class is a state class     CF_NoDefaultObjectSerialization     //!< Don't compare properties to default object on serialize     CF_AlwaysTransient                  //!< NEVER save or load objects of this class to ANY storage     CF_EditorOnly                       //!< Class and all derived classes should be used in editor only     CF_UndefinedFunctions               //!< This class has one or more undefined functions     CF_StateMachine                     //!< Class is allowed to have states (set by scripts checked by script compiler only) };

 

______________________________________
The Witcher 3: Wild Hunt Complete Edition © 2024 CD PROJEKT S.A. Published by CD PROJEKT S.A. Developed by CD PROJEKT RED. CD PROJEKT®, The Witcher®, REDengine® are registered trademarks of CD PROJEKT Capital Group. All rights reserved. The Witcher game is set in the universe created by Andrzej Sapkowski in his series of books. All rights reserved.