Skip to content

Animation System

shartte edited this page Mar 25, 2015 · 16 revisions

Overview

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.

AAS

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.

Initialization

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

Frame Events

Frames in animations can be associated with events. An event has a type and a string parameter.

There are three types of events.

script

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.

action

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.

end

Seems to be triggered explicitly when the animation ends. Sets a flag outside of AAS (on an optional parameter to the frame advance function).

Animation System (anim)

Animation Goals

List of Goals

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

Animation Goal States

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