Events
Acknowledgment
This tutorial was possible thanks to Kerrax, VAM and their excelent articles (MDS, EventTags) and Avallach from theModders who provided valuable insight.
Animation event block overview
We often need to perform some other actions together with our animation, such as playing a sound effect, inserting item into NPC's hand or changing an item instance into a different one, like turning a raw steel into hot raw steel. These actions often need to be done at very specific moment during the animation playback, therefore they are defined using events(#aniamtion-events) in the event block which follows right after the animation definition. The event block is started and closed by curly brackets.
Example:
Warning
Each animation can define a maximum of 16 events. Should you need more, split the animation into parts and use next_ani
to chain them together.
Animation events
Animation events are commands telling engine to do something. Event *eventSFXGrnd(12 "Run")
will command the engine to play sound Run
at the very moment (12th frame) the character lands food on the ground. So with that in mind here is the general syntax as well as each animation event in the game.
General Syntax:
FRAME
- all events specify on what frame int the animation source file .ASC
should this event happen
KEYWORD
- some events expect very specific keywords.
"INSTANCE"
- this indicates parameter is expected to be inside quotes, usually it;s slot/bone or item/sound instance name from the scrips
[OPTIONAL]
- this is an example of the optional parameter. Optional parameters will be indicated by brackets []
, if you don't specify them, the event will use the default value defined by the engine.
A:VALUE
- some events that have more than one optional parameter use a prefix to know which was specified
NODE_NAME
- will indicate any NODE
should work, be it bones (BIP01
...) or ZS_
slots (ZS_RIGHTHAND
)
SLOT
- this will indicate most likely only ZS_
slots will work.
Warning
Events should follow in ascending order by the frame they appear on. i. e. *eventTag(1 ...)
must come before *eventTag(2 ...)
Event | Description |
---|---|
eventCamTremor | camera shake |
eventMMStartAni | start morph-mesh |
eventPFX | create particle effect |
eventPFXStop | destroy particle effect |
eventSwapMesh | exchange item meshes between two slots |
eventSFX | create sound effect |
eventSFXGRND | create sound effect on the ground |
eventTag | generic event, does action specified in parameters |
Defined in engine but never used ? | |
eventPFXGRND | create particle effect on the ground |
eventSetMesh | ? |
modelTag | same as eventTag, but applies to morphmesh? |
eventCamTremor
Earthquake effect (camera shake)
Example:
Syntax:
eventCamTremor
- is a keyword, for camera shake event
Let's describe all the parameters
FRAME
- animation frame at which this event starts
RANGE
- range from which the effect will be 'felt' defined in in-game centimeters (1000 is 10 meters in-game)
DURATION
- duration of the effect in milliseconds
MIN_AMPLIFIER
- minimum amount of shaking in in-game centimeters
MAX_AMPLIFIER
- the maximum amount of shaking.
eventMMStartAni
Start the animation of the morph-mesh that is attached to the specified node. Mostly used to start NPC facial animations or to animate bows/crossbows shooting.
Example:
Syntax:
FRAME
- animation frame at which animation should start
ANI_NAME
- name of the morph-mesh animation (specified in .MMS) file
NODE_NAME
- node in the hierarchy, to which morph mesh is attached. If not specified, a default value of BIP01 HEAD
will be used.
I:INTENSITY
- float value to specify blending of morph animation with the current one ?
H:HOLD_TIME
- time in seconds, how long will the animation "stay"
Both INTENSITY
and HOLD_TIME
can be specified in the MMS script. All gothic morph meshes specify those values in .MMS, therefore behavior when both specified in eventMMStartAni and .MMS file is unknown/untested
eventPfx
Start particle effect at the specified bone.
Example:
Syntax:
FRAME
- animation frame at which particle effect starts
PFX_NAME
- name of the PFX instance
PFX_HANDLE
- an optional integer value. Specifying this creates a 'handle' and allows stop the PFX later using eventPFXStop
NODE_NAME
- node in the hierarchy. particle effect will be spawned at the node's position. If not specified, a default value of BIP01
will be used.
ATTACH
- keyword, including this keyword, will make particle effect follow the node specified, otherwise, it will stay where it spawned.
Tip
ATTACH
is used to create demons burning hand during the attack, while without this keyword dust particles are made to stay at the position where NPC landed after falling.
eventPFXStop
Stops particle effect previously started by eventPfx
Example:
Syntax:
FRAME
- animation frame at which particle effect should disappear
PFX_HANDLE
- an integer value. Handle of the particle effect, that should be destroyed. Particle effect must be spawned using the same handle by eventPfx first
eventSwapMesh
Move mesh from source NODE
to target node. Item should be present in the node already. Only mesh of the Items is moved, engine internally still keeps a reference to items in the original slot? Never used in game?
Example:
Syntax:
FRAME
- animation frame at which transport of the mesh should happen
SOURCE_NODE_NAME
- source node containing the item.
TARGET_NODE_NAME
- target node that the item should be moved to.
Note
In some rare occasions duplicates item
eventSfx
Play sound effect. It can be either SFX
instance from scripts, or .WAV
file.
Example:
Syntax:
FRAME
- animation frame at which particle effect starts
SFX_NAME
- name of the SFX instance or .WAV
file
R:RANGE
- an optional integer value. The range from which the effect will be 'heard' defined in in-game centimeters (1000 is 10 meters in-game)
[EMPTY_SLOT]
- optional keyword. By default audio effects use a single audio channel (slot) per Model. That means every eventSFX
request will cancel any currently playing effect. If EMPTY_SLOT
is specified, audio will be played on the next available (empty) audio slot and other sounds will not be interrupted.
Note
A lot of original game animations contain EMTPY_SLOT
instead of EMPTY_SLOT
which was probably unintended. Gothic therefore acts as no keyword was provided, which causes a lot of sound interruptions. Therefore be mindful of spelling when copying original MDS scripts
eventSfxGrnd
the same as eventSfx with only one difference, the sound effect name is appended with the current material name.
Example:
Syntax:
Depending on the material of the texture, the character is standing on, the game will add one of the following suffixes:
Spacer Material | Suffix | Gothic 1 | Gothic 2a |
---|---|---|---|
UNDEF | _Undef | ✔️ | ✔️ |
EARTH | _Earth | ✔️ | ✔️ |
SAND | _Sand | ✔️ | ✔️ |
METAL | _Metal | ✔️ | ✔️ |
WATER | _Water | ✔️ | ✔️ |
WOOD | _Wood | ✔️ | ✔️ |
SNOW | _Snow | ❌ | ✔️ |
STONE | _Stone | ✔️ | ✔️ |
default | _Stone | ✔️ | ✔️ |
NPC running on grass texture, with material set to EARTH in world editor, will play sound Run_Earth
by using *eventSFXGrnd (12 "Run")
in run animation. _Earth
suffix is determined and added by the engine.
eventTag
This is a generic type of event that does different actions based on the first parameter after the frame parameter. It was probably later in development to extend MDS functionality without the need to expand parser itself. All parameters except FRAME
are passed inside quotes Further parameters are specific for every EVENT_TAG_TYPE
.
Waning
eventTag contrary to other events is validated only at runtime. If parameters are wrong, it won't work or might crash the game
Syntax:
FRAME
- Frame at which the event will execute. This parameter is always first and the same for all eventTags
EVENT_TAG_TYPE
- a type of event = action that should happen.
Here is a list of event tag types:
EVENT TAG TYPE | Description |
---|---|
DEF_CREATE_ITEM | Creates item into slot |
DEF_INSERT_ITEM | Inserts item to slot from inventory |
DEF_REMOVE_ITEM | Removes item from slot to inventory |
DEF_DESTROY_ITEM | Destroys item in slot |
DEF_PLACE_ITEM | ~~Places item from slot into mob slot~~ Destroys item in slot |
DEF_EXCHANGE_ITEM | Removes item in slot and replaces with new item |
DEF_FIGHTMODE | Sets npc into weapon stance |
DEF_PLACE_MUNITION | Inserts munition into slot |
DEF_REMOVE_MUNITION | Remove munition back to inventory |
DEF_DRAWSOUND | Plays weapon drawing sound based on weapon material |
DEF_UNDRAWSOUND | Plays weapon sheating sound based on weapon material |
DEF_SWAPMESH | Moves items visual to different slot visually |
DEF_DRAWTORCH | Inserts torch |
DEF_INV_TORCH | Moves torch to different slot temporarily |
DEF_DROP_TORCH | Drops torch from slot to world |
DEF_HIT_LIMB | Defines node which deals damage |
DEF_DIR | Defines attack direction |
DEF_DAM_MULTIPLIER | Defines damage mutliplier |
DEF_PAR_FRAME | Defines frame range for blocking |
DEF_OPT_FRAME | Defines damage frames |
DEF_HIT_END | Defines last frame to continue combo |
DEF_WINDOW | Defines frame for combo continuation |
DEF_CREATE_ITEM
Creates a new item instance and inserts it into the specified slot. Item is not inserted permanently but only for the duration of interaction.
Example:
Syntax:
SLOT
- a name of the ZS_
slot, write in UPPERCASE
ITEM_INSTANCE
- item instance from the scripts
Warning
This event tag most likely works only during Mob/Item interaction
DEF_INSERT_ITEM
Insert the interaction item into the specified slot.
- during mob interaction, inserted item instance is of instance taken from UseWithItem mob property.
- during item interaction (i.e. drink potion) item that started the SceneName will be inserted.
In the example below: (1)
inserts ItMiSwordrawhot
that is defined in spacer into ZS_LEFTHAND
, then (2)
spawns ItMw_1H_Mace_L_04
(hammer) into ZS_RIGHTHAND
for anvil interaction.
Example:
Syntax:
SLOT
- a name of the ZS_
slot, use UPPERCASE
ITEM_INSTANCE
- item instance from the scripts
Warning
This event tag most likely works only during Mob/Item interaction
The well-known Gothic bug:
If player gets hit while drinking a potion, the effect of the potion is applied, but the potion remains in the inventory - the reason for the bug is that the potion item is inserted into hand using DEF_INSERT_ITEM
and would be removed from the world at the end of the drinking animation, while the potion's effect (a script function that increases stats) is applied at the very beginning of the animation. When the player is hit, the drinking animation is interrupted, and the engine does not remove the item from the world.
DEF_REMOVE_ITEM
Remove an item inserted into a slot via DEF_INSERT_ITEM
from the slot back into the inventory.
Example:
Syntax:
Warning
This event tag most likely works only during Mob/Item interaction
DEF_DESTROY_ITEM
Destroys an item inserted into a slot via DEF_INSERT_ITEM
. The item is removed from the world.
Example:
Syntax:
Warning
This event tag most likely works only during Mob/Item interaction
DEF_PLACE_ITEM
Remove the item inserted via eventTag DEF_INSERT_ITEM
from the slot and the world. In terms of its action, eventTag DEF_PLACE_ITEM
is a synonym for DEF_DESTROY_ITEM
. Possibly fixed by SystemPack. See intended use.
Example:
Syntax:
Warning
This event tag most likely works only during Mob/Item interaction
Intended use
Presumably, the eventTag DEF_PLACE_ITEM
was intended to have different behavior: If an NPC interacts with a MOB that has a ZS_SLOT
node, then move the item inserted via DEF_INSERT_ITEM
from the NPC node into the ZS_SLOT
node on the MOB. An example would be orc priest hearts in the Temple of the Sleeper, Gothic 1.
During animation on 60th frame,(1)
inserts orc priest sword from the inventory, and (2)
on 90th frame, presumably, should have left the sword inserted into the heart sticking out. There is ZS_SLOT
present to indicate the location of the sword after insertion into the heart.
In reality, (2)
simply removes the sword from the world like DEF_DESTROY_ITEM
. This was most likely an unrealized idea. In G2, eventTag DEF_PLACE_ITEM
is not used.
DEF_EXCHANGE_ITEM
Replace an item in a slot with another item. Item present in the slot is removed from the slot and the world, new item specified in parameters is created and inserted in the same slot.
Example:
Syntax:
SLOT
- a name of the ZS_
slot, use UPPERCASE
ITEM_INSTANCE
- item instance from the scripts
Warning
This event tag most likely works only during Mob/Item interaction
DEF_FIGHTMODE
Set fight mode for the model. Used in transition animations to weapon stances like t_1h_2_1hRun
.
Example:
Syntax:
FIGHT_MODE
- fight modes are defined in the engine and can be one of the following:
""
- remove weapon"FIST"
- fists"1H"
or"1HS"
- one-handed weapon"2H"
or"2HS"
- two-handed weapon"BOW"
- bow"CBOW"
- crossbow"MAG"
- magic
Example: Parameter 1H
sets fight mode for the actor (in the engine), but also exchanges sword from ZS_SWORD
slot to the ZS_RIGHTHAND
DEF_PLACE_MUNITION
Place ammunition, from inventory such as an arrow into the specified slot. Used in reloading animations after a bow/crossbow shot.
Example:
Syntax:
SLOT
- slot where the ammunition is created. There are only two valid slot names: "ZS_LEFTHAND"
and "ZS_RIGHTHAND"
.
Ammunition always corresponds to the equipped ranged weapon instance and its munition
field in the C_ITEM
instance
DEF_REMOVE_MUNITION
Remove ammunition previously placed by DEF_PLACE_MUNITION event
Example:
Syntax:
DEF_DRAWSOUND
Play weapon drawing sound. Determined by drawn weapon material
field in the C_ITEM
instance
“DrawSound_WO.wav”
- for MAT_WOOD;"DrawSound_ME.wav"
- for MAT_METAL.
Example:
Syntax:
DEF_UNDRAWSOUND
Play weapon sheathing sound. Determined by drawn weapon material
field in the C_ITEM
instance
"UndrawSound_WO.wav”
- for MAT_WOOD;"UndrawSound_ME.wav"
- for MAT_METAL.
Example:
Syntax:
DEF_SWAPMESH
Swap items in the specified slots.
Example:
Syntax:
SLOT1
- name of the slot with item to be exchanged.
SLOT2
- name of the slot with item to be exchanged.
Warning
In case SLOT1
or SLOT2
is equal to "ZS_LEFTHAND"
or "ZS_RIGHTHAND"
, the engine will attempt to put the model into fight mode similar to DEF_FIGHTMODE event. This can lead to game freezing.
Tip
This event is similar to the *eventSwapMesh. The main difference is *eventSwapMesh will swap only visuals (meshes) of the items, while eventTag DEF_SWAPMESH will swap items and their slot references. After a game reload, meshes would reset their positions if swapped using *eventSwapMesh. Additionally *eventSwapMesh does not try to set the model into fight mode.
DEF_DRAWTORCH
Does nothing? never used.
Example:
Syntax:
DEF_INV_TORCH
Temporarily return torch into inventory, for the duration of mob/item interaction. Does nothing if a torch is not present in ZS_LEFTHAND
. Used before interacting with mobs like bed, or before performing eating animations that require a left hand.
Example:
Syntax:
DEF_DROP_TORCH
Drop the torch onto the ground if present in ZS_LEFTHAND
.
Example:
Syntax:
DEF_HIT_LIMB
Set which node is dealing damage to others. This node is then used in calculations for collisions. Up to four slots can be specified.
Example:
Syntax:
DEF_DIR
Set the direction of the attack. Enemy block animation is determined by this information. Not used.
Example:
Syntax:
DIRECTIONS
- can be up to 10 characters, each character defines one attack direction during combo attack, default is O
- capital letter O
, not zero 0
. Possible values are
-
O
- (oben) from top/ over -
U
- (unter) from under -
R
- from right -
L
- from left
If the enemy is trying to block an attack with a defined direction it will choose a matching animation adding a direction suffix like t_1hParade_U
for opponent's attack direction U
Note
Sadly this feature was unused in Gothic 1. All attacks use O
direction and only defined animations for blocking are for said t_1hParade_O
But can be easily restored with a few new animations and MDS file edits. In Gothic 2, blocking animation uses zero 0
instead of O
which might indicate the feature no longer works.
DEF_DAM_MULTIPLIER
Set damage multiplier. For the attack animation. The damage will be multiplied by a provided number regardless of whether the attack is a critical attack or not.
Example:
Syntax:
MULTIPLIER
- float value inside quotes
DEF_PAR_FRAME
Set frame range during which damage is blocked. If not provided whole animation is blocking damage.
Example:
Syntax:
START_FRAME_END_FRAME
- Two integer numbers inside quotes. if "0 0"
is provided, the animation will be blocking it's whole duration
DEF_OPT_FRAME
Set frames during which damage collisions should be evaluated. Damage is checked for collision with "hit limb". This event usually comes in pair with eventTags DEF_WINDOW and DEF_HIT_END
Example:
Syntax:
HIT_FRAME1 HIT_FRAME2 ... HIT_FRAME10
- specify 1 and up to 10 integers separated by space inside quotes. Each number represents frame at which damage should be done. Number of provided hit frames determines number of combos (max 10 possible).
DEF_HIT_END
Set frames at which the combo is “cut off” if you do not press the “up” key (G1) or the left mouse button (G2) during the attack. Gothic has bug that in this case we will hear all the sound effects following this frame, and the animation ends with the character’s characteristic twitching. The number of frames specified in this entry must match the number of frames of the eventTag DEF_OPT_FRAME.
Example:
Syntax:
HIT_END1 HIT_END2 ... HIT_END10
- specify 1 and up to 10 integers separated by space inside quotes. After this frame combo cannot be continued and model will continue animation until the current DEF_WINDOW -
1`. Which is usually animation returning to idle stance
DEF_WINDOW
Set a “window” in the animation - an interval of frames during which you need to press the “up” (G1) or the left mouse button (G2) to continue the combo strike.
Example:
Syntax:
HIT_1_WINDOW_START HIT_1_WINDOW_END HIT_2_WINDOW_START HIT_2_WINDOW_END
- specify 1 and up to 20? integers separated by space inside quotes. A window consists of a start and end frame, therefore for each DEF_OPT_FRAME, you must provide 2 numbers.
HIT_WINDOW_START
- First value of the pair defines frame from which attack can continue.HIT_WINDOW_END
- Second value is a little confusing. It defines START of the next attack animation. Ability to continue combo stops at DEF_HIT_END frames. Usually there are few frames of animation, where characters returns to idle position.HIT_WINDOW_END
should be one frame after characters return to idle stance, which should also be first frame of the next attack
Attack eventTags explained
This is original attack combo from Gothic 1
I will edit it slightly to make it more readable. Let's focus on the DEF_OPT_FRAME, DEF_HIT_END,
Let's focus only on the first combo.
Frames | Animation | Description |
---|---|---|
1 | animation start | |
1..4 | swing of the sword | |
4 | sword is in the front of the model | DEF_OPT_FRAME - test damage collisions at this frame |
4..10 | end of the sword swing | |
10 | model stands ready to start next swing | DEF_WINDOW - user can press key to advance combo from this frame. |
10..31 | slight idle 'shake' | if player continues combo, animation playback will jump to the frame 33 (DEF_WINDOW second pair), from the animation perspective, next attack starts from pose similar to frame 10. If perfect inputs would be provided, animation would continue perfectly. |
31 | DEF_HIT_END - ends user input. | |
31..32 | model returns to the idle position | |
32 | idle position, standing with sword in hand | animation will end here, if combo not continued (DEF_WINDOW second pair - 1) |
33 | first frame of the next attack (similar to frame 10) | DEF_WINDOW second pair, start of next attack |
eventPfxGrnd
Not used anywhere in the original game. Could possibly spawn particle effect like eventPfx but with an added suffix similar to how eventSfxGrnd works. Needs to be investigated.
Syntax:
eventSetMesh
Unknown
Syntax:
modelTag
Should work similarly to eventTag, but can be defined inside aniEnum block and applies to all animations of the Model.
Syntax: