📄 actor.pas
字号:
unit Actor;
interface
uses SysUtils, Windows, Math, DirectDraw, Globals, MirWil, MirMap, ObjFastBlt;
{------------------------------------------------------------------------------}
// 常量定义
{------------------------------------------------------------------------------}
const
MAX_HUMANFRAME = 600; // 人类动画总帧数 [0..599]
MAX_HAIR = 3; // 头发种类数 [0..2]
MAX_WEAPON = 34; // 武器种类数 [0..34]
WEAPON_BREAKING_BASE = 3750; // 武器破碎效果索引基址,每个方向10帧,共80帧 (magic.wil)
MAGIC_BUBBLE_BASE = 0; // 魔法气泡效果索引基址 (magic.wil)
STATE_BUBBLEDEFENCEUP = $00100000; // 魔法气泡
// Actor 方向常量
DIR_UP = 0;
DIR_UPRIGHT = 1;
DIR_RIGHT = 2;
DIR_DOWNRIGHT = 3;
DIR_DOWN = 4;
DIR_DOWNLEFT = 5;
DIR_LEFT = 6;
DIR_UPLEFT = 7;
{------------------------------------------------------------------------------}
// 数据结构定义
{------------------------------------------------------------------------------}
type
// 动作定义
PActionInfo = ^TActionInfo;
TActionInfo = record
start: word; // 开始帧
frame: word; // 帧数
skip: word; // 跳过的帧数
ftime: word; // 每帧的延迟时间(毫秒)
usetick: byte; // (意义未知)
end;
// 玩家的动作定义
PHumanAction = ^THumanAction;
THumanAction = record
ActStand: TActionInfo; //1
ActWalk: TActionInfo; //8
ActRun: TActionInfo; //8
ActRushLeft: TActionInfo;
ActRushRight: TActionInfo;
ActWarMode: TActionInfo; //1
ActHit: TActionInfo; //6
ActHeavyHit: TActionInfo; //6
ActBigHit: TActionInfo; //6
ActFireHitReady: TActionInfo; //6
ActSpell: TActionInfo; //6
ActSitdown: TActionInfo; //1
ActStruck: TActionInfo; //3
ActDie: TActionInfo; //4
end;
{------------------------------------------------------------------------------}
// TActor class
{------------------------------------------------------------------------------}
TActor = class(TObject)
protected
FrameCount: word; // 当前动作的总帧数
FrameStart: word; // 当前动作的开始帧索引
FrameEnd: word; // 当前动作的结束帧索引
FrameTime: word; // 当前动作每帧等待的时间
FrameIndex: word; // 当前帧索引
FrameTick: Cardinal; // 当前帧显示时的 GetTickCount
public
CurrentMap: TMirMap; // 当前人物所在地图
CurrentAction: byte; // 当前动作
Direction: byte; // 当前方向
Appearance: word; // 外观显示(对 HumanActor 则相当于级别)
// 对其它, 可用 GetOffset 获得
IsInAction: Boolean; // 是否正处在一个 Action 事件中(ActStand 除外)
MapX: word; // 处于地图上的位置(以 MapPoint 为单位)
MapY: word;
ShiftX: Integer; // 当前位移(像素单位, 用于 Walk, Run)
ShiftY: Integer;
MovX: Integer; // 上次 Walk, Run Action 的偏移值
MovY: Integer;
constructor Create(Map: TMirMap); virtual; abstract;
// 重新计算动画帧
procedure ReCalcFrames; virtual; abstract;
// 根据经过的时间处理下一帧
procedure ProcessFrame; virtual; abstract;
end;
{------------------------------------------------------------------------------}
// THumanActor class
{------------------------------------------------------------------------------}
THumanActor = class(TActor)
private
protected
BodyOffset: word; // 身体图片索引的主偏移
HairOffset: word; // 头发图片索引的主偏移
WeaponOffset: word; // 武器图片索引的主偏移
WeaponOrder: byte; // 武器绘制顺序(是否先于身体绘制)
IsWeaponBreaking: Boolean; // 是否显示武器破碎效果
WeaponBreakingFrame: word; // 武器破碎效果当前帧
public
Sex: byte; // 性别
Job: byte; // 职业
Hair: byte; // 发型
Weapon: byte; // 武器
constructor Create(Map: TMirMap); override;
procedure ReCalcFrames; override;
procedure ProcessFrame; override;
procedure Draw(BackDxFastBlt: TDxFastBlt; X, Y, Width, Height: Integer);
function CalcNextDirection: Boolean;
// 移动至 MapPoint, 虽然 MapPoint 坐标定义为 Word, 这里必须用 Integer 代替
// 因为玩家可以点击至 Map 坐标负方向进行转向
procedure Walk(X, Y: Integer);
procedure Run(X, Y: Integer);
procedure Hit(X, Y: Integer);
end;
const
{------------------------------------------------------------------------------}
// 人物动作图片索引
{------------------------------------------------------------------------------}
// 以下二项数据组成 9 * 2 * 600 = 10800 幅图片
// Appearance = [0..8] [没穿衣服/初级/中级/高级(武/法/道)/最高级(武/法/道)]
// Sex = [0..1] [男/女]
// 每个 Appearance 包含 14 种 Action
// 不同 Direction 的 Action = Action 的起始帧 * 8 * Direction
// Action = [0 - 13] (Action 数量与总帧数无关, 并非每个 Action 都 8 帧)
// Direction = [0 - 7]
HUMANACTION_STAND = 0;
HUMANACTION_WALK = 1;
HUMANACTION_RUN = 2;
HUMANACTION_RUSHLEFT = 3;
HUMANACTION_RUSHRIGHT = 4;
HUMANACTION_WARMODE = 5;
HUMANACTION_HIT = 6;
HUMANACTION_HEAVYHIT = 7;
HUMANACTION_BIGHIT = 8;
HUMANACTION_FIREHITREADY = 9;
HUMANACTION_SPELL = 10;
HUMANACTION_SITDOWN = 11;
HUMANACTION_STRUCK = 12;
HUMANACTION_DIE = 13;
HUMANACTIONS: THumanAction =
(
// 开始帧 有效帧 跳过帧 每帧延迟 (意义未知)
ActStand: (start: 0; frame: 4; skip: 4; ftime: 200; usetick: 0);
ActWalk: (start: 64; frame: 6; skip: 2; ftime: 80; usetick: 2);
ActRun: (start: 128; frame: 6; skip: 2; ftime: 90; usetick: 3);
ActRushLeft: (start: 128; frame: 3; skip: 5; ftime: 120; usetick: 3);
ActRushRight: (start: 131; frame: 3; skip: 5; ftime: 120; usetick: 3);
ActWarMode: (start: 192; frame: 1; skip: 0; ftime: 200; usetick: 0);
//ActHit: (start: 200; frame: 5; skip: 3; ftime: 140; usetick: 0);
ActHit: (start: 200; frame: 6; skip: 2; ftime: 85; usetick: 0);
ActHeavyHit: (start: 264; frame: 6; skip: 2; ftime: 90; usetick: 0);
ActBigHit: (start: 328; frame: 8; skip: 0; ftime: 70; usetick: 0);
ActFireHitReady: (start: 192; frame: 6; skip: 4; ftime: 70; usetick: 0);
ActSpell: (start: 392; frame: 6; skip: 2; ftime: 60; usetick: 0);
ActSitdown: (start: 456; frame: 2; skip: 0; ftime: 300; usetick: 0);
ActStruck: (start: 472; frame: 3; skip: 5; ftime: 70; usetick: 0);
ActDie: (start: 536; frame: 4; skip: 4; ftime: 120; usetick: 0);
);
{ HUMANACTIONS: THumanAction =
(
// 开始帧 有效帧 跳过帧 每帧延迟 (意义未知)
ActStand: (start: 0; frame: 4; skip: 4; ftime: 200; usetick: 0);
ActWalk: (start: 64; frame: 6; skip: 2; ftime: 90; usetick: 2);
ActRun: (start: 128; frame: 6; skip: 2; ftime: 120; usetick: 3);
ActRushLeft: (start: 128; frame: 3; skip: 5; ftime: 120; usetick: 3);
ActRushRight: (start: 131; frame: 3; skip: 5; ftime: 120; usetick: 3);
ActWarMode: (start: 192; frame: 1; skip: 0; ftime: 200; usetick: 0);
//ActHit: (start: 200; frame: 5; skip: 3; ftime: 140; usetick: 0);
ActHit: (start: 200; frame: 6; skip: 2; ftime: 85; usetick: 0);
ActHeavyHit: (start: 264; frame: 6; skip: 2; ftime: 90; usetick: 0);
ActBigHit: (start: 328; frame: 8; skip: 0; ftime: 70; usetick: 0);
ActFireHitReady: (start: 192; frame: 6; skip: 4; ftime: 70; usetick: 0);
ActSpell: (start: 392; frame: 6; skip: 2; ftime: 60; usetick: 0);
ActSitdown: (start: 456; frame: 2; skip: 0; ftime: 300; usetick: 0);
ActStruck: (start: 472; frame: 3; skip: 5; ftime: 70; usetick: 0);
ActDie: (start: 536; frame: 4; skip: 4; ftime: 120; usetick: 0);
);
}
{------------------------------------------------------------------------------}
// 武器绘制顺序 (是否先于身体绘制: 0是/1否)
// WEAPONORDERS: array [Sex, FrameIndex] of Byte
{------------------------------------------------------------------------------}
WEAPONORDERS: array[0..1, 0..MAX_HUMANFRAME - 1] of byte =
(
(
//
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1,
//
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
//
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
//
0, 1, 1, 1, 0, 0, 0, 0,
//
1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1,
//
0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1,
//
1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0,
//
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1,
0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1,
//
0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,
//
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1,
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1,
//
0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1,
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1
),
(
//
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1,
//
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
//
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
//
1, 1, 1, 1, 0, 0, 0, 0,
//
1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1,
//
0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1,
//
1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0,
//
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1,
0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1,
//
0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,
//
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1,
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1,
//
0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -