Animation System
System | Description |
---|---|
anim | This is the gameplay part of the animation system. It handles animating game objects in terms of animation goals and can sequence multiple subgoals per object. It registers itself as a timed event to process the sequence for an object in regular intervals |
timeevent | Generic system for handling timed events. Is used for multiple animation tasks: animation sequence processing, fidget animations and background animations |
animprivate | Seems to mostly contain utility functionality for the higher level anim system |
aas | Handles the actual skeletal animation mostly on a SKM/SKA file basis. It's pretty decoupled from the other systems and triggers events via callbacks and setting flags. |
This system handles 3D models and how they are animated using skeletal animation. The animation is performed on the CPU in memory and does not offload any computations to the GPU.
As is apparent in some places, the system was written in C++ and uses several classes and vtables.
The system supports up to 5000 loaded models concurrently and stores the data in a global array @ 0x10EFB900.
The system is initialized by gamelib_init directly and does not seem to be part of the game system array. Apparently the system was developed as a reusable part, since some functions are passed in as callbacks.
// Resolves a numeric mesh id (i.e. from protos.tab) to the actual filename
typedef int (__cdecl *AasResolveFileFn)(int meshId, char *filenameOut);
// Runs an arbitrary piece of script code found in the animation frame events
typedef void (__cdecl *AasRunScriptFn)(const char *script);
// Config structure passed to AasInit from within gamelib_init
struct AasConfig {
// These are used for translating 2d world coordinates into 3d world coordinates
float pixelPerWorldTile1; // = 0x41E24630
float pixelPerWorldTile2; // = 0x41E24630
AasResolveFileFn getSkaFilename; // = 0x10004230
AasResolveFileFn getSkmFilename; // = 0x100041E0
... getAnimName; // = 0
... animCallback; // = 0
int unknown; // = 0
AasRunScriptFn runScript; // = 0x100AD990
};
void AasInit(const AasConfig *config); // @ 0x102640B0
Frames in animations can be associated with events. An event has a type and a string parameter.
There are three types of events.
Executes an arbitrary fragment of Python code when the frame is reached. The python code to execute is the event parameter. All globals are available. No special locals are set for this. Instead, there is a global Python object "anim_obj", which points to the object being animated. In the DLL, this is backed by a PyObject*
at address 0x10BCA76C.
This object is initialized in the function @ 0x100B40A0 to be a tuple containing a 64-bit integer, which is initially 0. This value is apparently overwritten with the object handle of the object being animated before the event handler is called. This happens in the function @ 0x100AEDA0.
Some animations have to interact with the actual action system (i.e. attack animations) to trigger an action mid-animation. For example the attack animation for a long two-handed weapon swing should trigger hit sounds and damage calculations when the weapon hits the opponent. This could be in the middle of the animation. To accomplish this, some animations have one of the frames tagged with an event of type "action" (no parameters). This causes aas to set a flag on an optional parameter to the advance frame function. How this is evaluated is still not quite clear, but it seems reasonable that the anim-system advanced frames in AAS and after that checks the flags that have been set by aas to trigger the in-game action if necessary.
Seems to be triggered explicitly when the animation ends. Sets a flag outside of AAS (on an optional parameter to the frame advance function).
IDs of the goals start at 0 for ag_animate
. There's one additional goal at the end, for which the name is unknown.
- ag_animate
- ag_animate_loop,
- ag_anim_idle,
- ag_anim_fidget,
- ag_move_to_tile,
- ag_run_to_tile,
- ag_attempt_move,
- ag_move_to_pause,
- ag_move_near_tile,
- ag_move_near_obj,
- ag_move_straight,
- ag_attempt_move_straight,
- ag_open_door,
- ag_attempt_open_door,
- ag_unlock_door,
- ag_jump_window,
- ag_pickup_item,
- ag_attempt_pickup,
- ag_pickpocket,
- ag_attack,
- ag_attempt_attack,
- ag_talk,
- ag_pick_weapon,
- ag_chase,
- ag_follow,
- ag_follow_to_location,
- ag_flee,
- ag_throw_spell,
- ag_attempt_spell,
- ag_shoot_spell,
- ag_hit_by_spell,
- ag_hit_by_weapon,
- ag_dying,
- ag_destroy_obj,
- ag_use_skill_on,
- ag_attempt_use_skill_on,
- ag_skill_conceal,
- ag_projectile,
- ag_throw_item,
- ag_use_object,
- ag_use_item_on_object,
- ag_use_item_on_object_with_skill,
- ag_use_item_on_tile,
- ag_use_item_on_tile_with_skill,
- ag_knockback,
- ag_floating,
- ag_close_door,
- ag_attempt_close_door,
- ag_animate_reverse,
- ag_move_away_from_obj,
- ag_rotate,
- ag_unconceal,
- ag_run_near_tile,
- ag_run_near_obj,
- ag_animate_stunned,
- ag_animate_kneel_magic_hands,
- ag_attempt_move_near,
- ag_knock_down,
- ag_anim_get_up,
- ag_attempt_move_straight_knockback,
- ag_wander,
- ag_wander_seek_darkness,
- ag_use_picklock_skill_on,
- ag_please_move,
- ag_attempt_spread_out,
- ag_animate_door_open,
- ag_animate_door_closed,
- ag_pend_closing_door,
- ag_throw_spell_friendly,
- ag_attempt_spell_friendly,
- ag_animate_loop_fire_dmg,
- ag_attempt_move_straight_spell,
- ag_move_near_obj_combat,
- ag_attempt_move_near_combat,
- ag_use_container,
- ag_throw_spell_w_cast_anim,
- ag_attempt_spell_w_cast_anim,
- ag_throw_spell_w_cast_anim_2ndary,
- ag_back_off_from,
- ag_attempt_use_pickpocket_skill_on,
- ag_use_disable_device_skill_on_data
The following table contains all functions that are referenced in animation goal states, in how many different animation goals they are used and what those goals are.
Function | Number of Uses | Used by Animation Goals |
---|---|---|
10012c70 | 32 | ag_anim_fidget, ag_anim_get_up, ag_anim_idle, ag_animate, ag_animate_door_closed, ag_animate_kneel_magic_hands, ag_animate_loop, ag_attempt_attack, ag_attempt_move, ag_attempt_move_near, ag_attempt_move_straight, ag_attempt_move_straight_knockback, ag_attempt_move_straight_spell, ag_destroy_obj, ag_dying, ag_hit_by_spell, ag_hit_by_weapon, ag_knock_down, ag_move_away_from_obj, ag_move_near_obj_combat, ag_pend_closing_door, ag_please_move, ag_run_near_tile, ag_skill_conceal, ag_throw_item, ag_throw_spell_w_cast_anim_2ndary, ag_unconceal, ag_unknown, ag_use_container, ag_use_disable_device_skill_on_data, ag_use_object, ag_wander |
10262530 | 22 | ag_anim_get_up, ag_animate_door_open, ag_animate_stunned, ag_attack, ag_attempt_move, ag_attempt_move_near, ag_attempt_move_near_combat, ag_attempt_spread_out, ag_attempt_use_skill_on, ag_follow, ag_hit_by_spell, ag_knock_down, ag_move_away_from_obj, ag_move_near_obj, ag_move_near_tile, ag_move_straight, ag_move_to_pause, ag_move_to_tile, ag_run_near_obj, ag_run_to_tile, ag_shoot_spell, ag_use_container |
10015240 | 20 | ag_anim_fidget, ag_animate, ag_animate_door_open, ag_animate_kneel_magic_hands, ag_attempt_move_near, ag_attempt_move_straight_knockback, ag_attempt_spell, ag_attempt_use_pickpocket_skill_on, ag_chase, ag_destroy_obj, ag_flee, ag_follow, ag_hit_by_spell, ag_knock_down, ag_move_away_from_obj, ag_skill_conceal, ag_throw_spell_w_cast_anim_2ndary, ag_use_container, ag_use_disable_device_skill_on_data, ag_use_object |
1000e250 | 18 | ag_animate, ag_animate_kneel_magic_hands, ag_animate_stunned, ag_attack, ag_attempt_move_near, ag_attempt_move_near_combat, ag_attempt_spell_friendly, ag_attempt_spell_w_cast_anim, ag_attempt_spread_out, ag_destroy_obj, ag_move_near_obj, ag_move_near_tile, ag_move_to_tile, ag_rotate, ag_run_near_obj, ag_run_to_tile, ag_talk, ag_throw_spell |
1000d150 | 17 | ag_animate_stunned, ag_attempt_move, ag_attempt_move_near_combat, ag_attempt_spread_out, ag_attempt_use_skill_on, ag_floating, ag_knock_down, ag_move_near_obj, ag_move_near_tile, ag_move_straight, ag_move_to_tile, ag_rotate, ag_run_near_obj, ag_run_to_tile, ag_shoot_spell, ag_throw_item, ag_use_container |
1000e270 | 17 | ag_animate_kneel_magic_hands, ag_animate_stunned, ag_attack, ag_attempt_move_near, ag_attempt_move_near_combat, ag_attempt_spell_friendly, ag_attempt_spell_w_cast_anim, ag_attempt_spread_out, ag_destroy_obj, ag_move_near_obj, ag_move_near_tile, ag_move_to_tile, ag_rotate, ag_run_near_obj, ag_run_to_tile, ag_talk, ag_throw_spell |
10017460 | 15 | ag_animate_door_open, ag_animate_stunned, ag_attack, ag_attempt_move_near_combat, ag_attempt_use_pickpocket_skill_on, ag_attempt_use_skill_on, ag_chase, ag_flee, ag_follow, ag_move_near_obj, ag_rotate, ag_throw_spell_w_cast_anim, ag_use_item_on_object, ag_use_item_on_object_with_skill, ag_use_item_on_tile |
101f5850 | 15 | ag_anim_idle, ag_animate_loop_fire_dmg, ag_attack, ag_attempt_attack, ag_attempt_move, ag_attempt_move_straight_spell, ag_attempt_spell, ag_attempt_spell_friendly, ag_attempt_spell_w_cast_anim, ag_back_off_from, ag_floating, ag_move_to_pause, ag_throw_item, ag_throw_spell, ag_throw_spell_w_cast_anim_2ndary |
10011d40 | 12 | ag_attack, ag_attempt_spell_friendly, ag_attempt_spell_w_cast_anim, ag_attempt_use_pickpocket_skill_on, ag_attempt_use_skill_on, ag_flee, ag_knockback, ag_talk, ag_throw_spell, ag_use_item_on_object_with_skill, ag_use_item_on_tile, ag_use_item_on_tile_with_skill |
100185e0 | 11 | ag_anim_get_up, ag_animate, ag_attempt_move_straight_knockback, ag_dying, ag_hit_by_weapon, ag_run_near_tile, ag_skill_conceal, ag_throw_spell_w_cast_anim_2ndary, ag_unknown, ag_use_disable_device_skill_on_data, ag_use_object |
1000ce60 | 10 | ag_attempt_spread_out, ag_floating, ag_move_near_tile, ag_move_straight, ag_move_to_pause, ag_move_to_tile, ag_run_near_obj, ag_run_to_tile, ag_shoot_spell, ag_throw_item |
10017b30 | 9 | ag_animate_reverse, ag_attempt_close_door, ag_attempt_move, ag_attempt_open_door, ag_knock_down, ag_open_door, ag_throw_spell_w_cast_anim, ag_use_container, ag_use_item_on_object |
10011be0 | 7 | ag_attempt_attack, ag_attempt_move, ag_please_move, ag_skill_conceal, ag_unknown, ag_use_disable_device_skill_on_data, ag_use_object |
10018400 | 7 | ag_animate, ag_dying, ag_hit_by_weapon, ag_skill_conceal, ag_unknown, ag_use_disable_device_skill_on_data, ag_use_object |
1000c9c0 | 6 | ag_animate_loop_fire_dmg, ag_animate_reverse, ag_attempt_open_door, ag_attempt_spell, ag_open_door, ag_throw_spell_w_cast_anim_2ndary |
1000efb0 | 6 | ag_animate_reverse, ag_attempt_close_door, ag_attempt_open_door, ag_open_door, ag_throw_spell_w_cast_anim, ag_use_item_on_object |
10011600 | 6 | ag_animate_stunned, ag_attempt_use_pickpocket_skill_on, ag_chase, ag_flee, ag_run_near_obj, ag_run_to_tile |
10012a00 | 6 | ag_attempt_attack, ag_please_move, ag_skill_conceal, ag_throw_spell, ag_unknown, ag_use_disable_device_skill_on_data |
10012c80 | 6 | ag_animate_loop_fire_dmg, ag_attempt_attack, ag_attempt_spell, ag_skill_conceal, ag_throw_spell_w_cast_anim_2ndary, ag_use_object |
100125f0 | 5 | ag_attempt_spread_out, ag_move_near_tile, ag_move_to_tile, ag_run_near_obj, ag_run_to_tile |
1000f550 | 4 | ag_attempt_open_door, ag_open_door, ag_throw_spell_w_cast_anim, ag_use_item_on_object |
100102c0 | 4 | ag_animate_loop_fire_dmg, ag_attempt_spell, ag_shoot_spell, ag_throw_spell_w_cast_anim_2ndary |
0 | 3 | ag_attempt_move, ag_run_near_tile, ag_wander |
1000cf10 | 3 | ag_follow_to_location, ag_knockback, ag_use_item_on_tile_with_skill |
1000d560 | 3 | ag_attempt_spread_out, ag_move_to_tile, ag_run_to_tile |
1000e4f0 | 3 | ag_attempt_move, ag_knock_down, ag_use_container |
1000e8b0 | 3 | ag_animate_stunned, ag_attempt_use_skill_on, ag_move_near_obj |
10010250 | 3 | ag_attempt_spell_friendly, ag_attempt_spell_w_cast_anim, ag_throw_spell |
10010290 | 3 | ag_animate_loop_fire_dmg, ag_attempt_spell, ag_throw_spell_w_cast_anim_2ndary |
10011e90 | 3 | ag_animate_door_open, ag_chase, ag_follow |
100127b0 | 3 | ag_attempt_use_skill_on, ag_throw_spell_w_cast_anim, ag_use_item_on_object |
100147d0 | 3 | ag_attempt_move, ag_knock_down, ag_use_container |
10015150 | 3 | ag_animate_loop_fire_dmg, ag_attempt_spell, ag_back_off_from |
10015170 | 3 | ag_animate_loop_fire_dmg, ag_attempt_spell, ag_back_off_from |
10017100 | 3 | ag_animate_loop_fire_dmg, ag_attempt_spell, ag_throw_spell_w_cast_anim_2ndary |
10019630 | 3 | ag_attempt_move, ag_knock_down, ag_use_container |
10019920 | 3 | ag_attempt_move_straight, ag_move_near_obj_combat, ag_wander |
1000ce10 | 2 | ag_shoot_spell, ag_use_skill_on |
1000db30 | 2 | ag_move_straight, ag_shoot_spell |
1000e6f0 | 2 | ag_move_near_tile, ag_run_near_obj |
1000f000 | 2 | ag_attempt_open_door, ag_open_door |
1000f140 | 2 | ag_attempt_open_door, ag_open_door |
1000f2c0 | 2 | ag_attempt_open_door, ag_open_door |
1000f350 | 2 | ag_attempt_open_door, ag_open_door |
1000f400 | 2 | ag_knock_down, ag_use_container |
1000f490 | 2 | ag_throw_spell_w_cast_anim, ag_use_item_on_object |
10010410 | 2 | ag_attempt_spell_w_cast_anim, ag_throw_spell |
10011cf0 | 2 | ag_throw_spell_w_cast_anim, ag_use_item_on_object |
10011f20 | 2 | ag_animate_door_open, ag_follow |
10012b60 | 2 | ag_attempt_spell_w_cast_anim, ag_use_object |
10012d10 | 2 | ag_animate_loop, ag_attempt_move_straight_spell |
10012fa0 | 2 | ag_animate_loop, ag_attempt_move_straight_spell |
10019130 | 2 | ag_animate_loop, ag_attempt_move_straight_spell |
100199b0 | 2 | ag_attempt_move_straight, ag_move_near_obj_combat |
1000ccf0 | 1 | ag_throw_item |
1000cfe0 | 1 | ag_attempt_move |
1000d060 | 1 | ag_knock_down |
1000dca0 | 1 | ag_floating |
1000dd80 | 1 | ag_rotate |
1000e2c0 | 1 | ag_animate_kneel_magic_hands |
1000ec10 | 1 | ag_attempt_move_near_combat |
1000f0d0 | 1 | ag_animate_reverse |
1000f860 | 1 | ag_use_item_on_object_with_skill |
1000f9a0 | 1 | ag_use_item_on_tile |
1000fbc0 | 1 | ag_use_item_on_tile_with_skill |
1000fce0 | 1 | ag_knockback |
1000fec0 | 1 | ag_rotate |
1000ff10 | 1 | ag_attack |
1000ff60 | 1 | ag_attempt_move_near_combat |
1000fff0 | 1 | ag_attempt_attack |
10010160 | 1 | ag_anim_fidget |
100101d0 | 1 | ag_attempt_move_near_combat |
10010500 | 1 | ag_throw_spell_w_cast_anim_2ndary |
10010520 | 1 | ag_throw_spell_w_cast_anim_2ndary |
100105f0 | 1 | ag_throw_spell_w_cast_anim_2ndary |
10010760 | 1 | ag_shoot_spell |
100107e0 | 1 | ag_use_disable_device_skill_on_data |
10010aa0 | 1 | ag_skill_conceal |
10010b50 | 1 | ag_use_disable_device_skill_on_data |
10010b70 | 1 | ag_attempt_use_skill_on |
10010b90 | 1 | ag_please_move |
10010cd0 | 1 | ag_unknown |
10010d60 | 1 | ag_attempt_attack |
10010e00 | 1 | ag_attempt_attack |
10010f70 | 1 | ag_use_object |
100110a0 | 1 | ag_talk |
100111e0 | 1 | ag_talk |
100112d0 | 1 | ag_talk |
100114d0 | 1 | ag_animate_door_closed |
10011530 | 1 | ag_throw_spell_friendly |
10011660 | 1 | ag_attempt_attack |
100117f0 | 1 | ag_destroy_obj |
10011880 | 1 | ag_hit_by_weapon |
10011a30 | 1 | ag_dying |
10011d20 | 1 | ag_pickpocket |
10011dc0 | 1 | ag_shoot_spell |
10011e70 | 1 | ag_follow_to_location |
10012040 | 1 | ag_rotate |
100121b0 | 1 | ag_unconceal |
100122a0 | 1 | ag_unconceal |
100130f0 | 1 | ag_anim_get_up |
10013250 | 1 | ag_throw_item |
10013af0 | 1 | ag_throw_item |
100140c0 | 1 | ag_destroy_obj |
10014f10 | 1 | ag_close_door |
10014f30 | 1 | ag_close_door |
10014ff0 | 1 | ag_close_door |
100150a0 | 1 | ag_close_door |
10017170 | 1 | ag_attempt_spread_out |
10017570 | 1 | ag_wander_seek_darkness |
10017810 | 1 | ag_use_picklock_skill_on |
10017dd0 | 1 | ag_throw_spell_w_cast_anim_2ndary |
10018730 | 1 | ag_anim_idle |
10018810 | 1 | ag_anim_fidget |
100188f0 | 1 | ag_anim_idle |
100189b0 | 1 | ag_anim_fidget |
10018a70 | 1 | ag_animate_door_closed |
10018b90 | 1 | ag_animate_door_closed |
10018c50 | 1 | ag_pend_closing_door |
10018d40 | 1 | ag_pend_closing_door |
10018e00 | 1 | ag_please_move |
10018ee0 | 1 | ag_please_move |
10018fa0 | 1 | ag_destroy_obj |
10019070 | 1 | ag_destroy_obj |
100191f0 | 1 | ag_animate_kneel_magic_hands |
10019330 | 1 | ag_animate_kneel_magic_hands |
10019470 | 1 | ag_attempt_move_straight_knockback |
10019540 | 1 | ag_run_near_tile |
10019c20 | 1 | ag_wander |
10019e10 | 1 | ag_destroy_obj |
10019f00 | 1 | ag_attempt_attack |
1001a080 | 1 | ag_attempt_attack |
1001a170 | 1 | ag_attempt_attack |
1001bf70 | 1 | ag_use_container |
1001c100 | 1 | ag_attack |