6 g_textures
, g_basic
, g_weapons
, e_graphics
, wadreader
;
43 TModelSoundArray
= Array of TModelSound
;
44 TGibsArray
= Array of TGibSprite
;
45 TWeaponPoints
= Array [WEAPON_SAW
..WEAPON_SUPERPULEMET
] of
46 Array [A_STAND
..A_PAIN
] of
47 Array [D_LEFT
..D_RIGHT
] of Array of TPoint
;
49 TPlayerModel
= class (TObject
)
52 FDirection
: TDirection
;
54 FCurrentAnimation
: Byte;
55 FAnim
: Array [D_LEFT
..D_RIGHT
] of Array [A_STAND
..A_PAIN
] of TAnimation
;
56 FMaskAnim
: Array [D_LEFT
..D_RIGHT
] of Array [A_STAND
..A_PAIN
] of TAnimation
;
57 FWeaponPoints
: TWeaponPoints
;
58 FPainSounds
: TModelSoundArray
;
59 FDieSounds
: TModelSoundArray
;
66 FFlagAnim
: TAnimation
;
71 destructor Destroy(); override;
72 procedure ChangeAnimation(Animation
: Byte; Force
: Boolean = False);
73 function GetCurrentAnimation
: TAnimation
;
74 function GetCurrentAnimationMask
: TAnimation
;
75 procedure SetColor(Red
, Green
, Blue
: Byte);
76 procedure SetWeapon(Weapon
: Byte);
77 procedure SetFlag(Flag
: Byte);
78 procedure SetFire(Fire
: Boolean);
79 function PlaySound(SoundType
, Level
: Byte; X
, Y
: Integer): Boolean;
81 procedure Draw(X
, Y
: Integer; Alpha
: Byte = 0);
83 property Fire
: Boolean read FFire
;
84 property Direction
: TDirection read FDirection write FDirection
;
85 property Animation
: Byte read FCurrentAnimation
;
86 property Weapon
: Byte read FCurrentWeapon
;
87 property Name
: String read FName
;
88 property Color
: TRGB read FColor write FColor
;
91 procedure g_PlayerModel_LoadData();
92 procedure g_PlayerModel_FreeData();
93 function g_PlayerModel_Load(FileName
: String): Boolean;
94 function g_PlayerModel_GetNames(): SArray
;
95 function g_PlayerModel_GetInfo(ModelName
: String): TModelInfo
;
96 function g_PlayerModel_Get(ModelName
: String): TPlayerModel
;
97 function g_PlayerModel_GetAnim(ModelName
: String; Anim
: Byte; var _Anim
, _Mask
: TAnimation
): Boolean;
98 function g_PlayerModel_GetGibs(ModelName
: String; var Gibs
: TGibsArray
): Boolean;
103 g_main
, g_sound
, g_console
, SysUtils
, g_player
, CONFIG
,
104 GL
, GLExt
, e_sound
, g_options
, g_map
, Math
, e_log
;
107 TPlayerModelInfo
= record
109 ModelSpeed
: Array [A_STAND
..A_PAIN
] of Byte;
112 WeaponPoints
: TWeaponPoints
;
114 PainSounds
: TModelSoundArray
;
115 DieSounds
: TModelSoundArray
;
127 FLAG_BASEPOINT
: TPoint
= (X
:16; Y
:43);
128 FLAG_DEFPOINT
: TPoint
= (X
:32; Y
:16);
130 WEAPONBASE
: Array [WEAPON_SAW
..WEAPON_SUPERPULEMET
] of TPoint
=
131 ((X
:8; Y
:4), (X
:8; Y
:8), (X
:16; Y
:16), (X
:16; Y
:24),
132 (X
:16; Y
:16), (X
:24; Y
:24), (X
:16; Y
:16), (X
:24; Y
:24), (X
:16; Y
:16));
134 AnimNames
: Array [A_STAND
..A_PAIN
] of String =
135 ('StandAnim','WalkAnim','Die1Anim','Die2Anim','AttackAnim',
136 'SeeUpAnim','SeeDownAnim','AttackUpAnim','AttackDownAnim','PainAnim');
137 WeapNames
: Array [WEAPON_SAW
..WEAPON_SUPERPULEMET
] of String =
138 ('csaw', 'hgun', 'sg', 'ssg', 'mgun', 'rkt', 'plz', 'bfg', 'spl');
141 WeaponID
: Array [WEAPON_SAW
..WEAPON_SUPERPULEMET
] of
142 Array [W_POS_NORMAL
..W_POS_DOWN
] of
143 Array [W_ACT_NORMAL
..W_ACT_FIRE
] of DWORD
;
144 PlayerModelsArray
: Array of TPlayerModelInfo
;
146 procedure g_PlayerModel_LoadData();
150 for a
:= WEAPON_SAW
to WEAPON_SUPERPULEMET
do
152 g_Texture_CreateWAD(WeaponID
[a
][W_POS_NORMAL
][W_ACT_NORMAL
], GameWAD
+':WEAPONS\'+UpperCase(WeapNames
[a
]));
153 g_Texture_CreateWAD(WeaponID
[a
][W_POS_NORMAL
][W_ACT_FIRE
], GameWAD
+':WEAPONS\'+UpperCase(WeapNames
[a
])+'_FIRE');
154 g_Texture_CreateWAD(WeaponID
[a
][W_POS_UP
][W_ACT_NORMAL
], GameWAD
+':WEAPONS\'+UpperCase(WeapNames
[a
])+'_UP');
155 g_Texture_CreateWAD(WeaponID
[a
][W_POS_UP
][W_ACT_FIRE
], GameWAD
+':WEAPONS\'+UpperCase(WeapNames
[a
])+'_UP_FIRE');
156 g_Texture_CreateWAD(WeaponID
[a
][W_POS_DOWN
][W_ACT_NORMAL
], GameWAD
+':WEAPONS\'+UpperCase(WeapNames
[a
])+'_DN');
157 g_Texture_CreateWAD(WeaponID
[a
][W_POS_DOWN
][W_ACT_FIRE
], GameWAD
+':WEAPONS\'+UpperCase(WeapNames
[a
])+'_DN_FIRE');
161 function GetPoint(var str
: String; var point
: TPoint
): Boolean;
171 if Length(str
) < 3 then
174 for a
:= 1 to Length(str
) do
175 if (str
[a
] = ',') or (a
= Length(str
)) then
177 s
:= Copy(str
, 1, a
);
178 if s
[Length(s
)] = ',' then
179 SetLength(s
, Length(s
)-1);
182 if (Sscanf(s
, '%d:%d', [@x
, @y
]) < 2) or
183 (x
< -64) or (x
> 128) or
184 (y
< -64) or (y
> 128) then
196 function GetWeapPoints(str
: String; weapon
: Byte; anim
: Byte; dir
: TDirection
;
197 frames
: Word; backanim
: Boolean; var wpoints
: TWeaponPoints
): Boolean;
206 backanim
:= backanim
and (frames
> 2);
208 for a
:= 1 to frames
do
210 if not GetPoint(str
, wpoints
[weapon
, anim
, dir
, a
-1]) then
213 with wpoints
[weapon
, anim
, dir
, a
-1] do
215 X
:= X
- WEAPONBASE
[weapon
].X
;
216 Y
:= Y
- WEAPONBASE
[weapon
].Y
;
222 h
:= High(wpoints
[weapon
, anim
, dir
]);
224 for b
:= h
downto frames
do
225 wpoints
[weapon
, anim
, dir
, b
] := wpoints
[weapon
, anim
, dir
, h
-b
+1];
230 function g_PlayerModel_Load(FileName
: string): Boolean;
233 a
, b
, len
, aa
, bb
, f
: Integer;
236 pData
, pData2
: Pointer;
242 e_WriteLog(Format('Loading player model: %s', [ExtractFileName(FileName
)]), MSG_NOTIFY
);
246 WAD
:= TWADFile
.Create
;
247 WAD
.ReadFile(FileName
);
249 if {WAD.GetLastError <> DFWAD_NOERROR} not WAD
.isOpen
then
255 if not WAD
.GetResource('TEXT', 'MODEL', pData
, len
) then
261 config
:= TConfig
.CreateMem(pData
, len
);
264 s
:= config
.ReadStr('Model', 'name', '');
272 SetLength(PlayerModelsArray
, Length(PlayerModelsArray
)+1);
273 ID
:= High(PlayerModelsArray
);
275 prefix
:= FileName
+':TEXTURES\';
277 with PlayerModelsArray
[ID
].Info
do
280 Author
:= config
.ReadStr('Model', 'author', '');
281 Description
:= config
.ReadStr('Model', 'description', '');
284 for b
:= A_STAND
to A_PAIN
do
286 if not (g_Frames_CreateWAD(nil, s
+'_RIGHTANIM'+IntToStr(b
),
287 prefix
+config
.ReadStr(AnimNames
[b
], 'resource', ''),
288 64, 64, config
.ReadInt(AnimNames
[b
], 'frames', 1),
289 config
.ReadBool(AnimNames
[b
], 'backanim', False)) and
290 g_Frames_CreateWAD(nil, s
+'_RIGHTANIM'+IntToStr(b
)+'_MASK',
291 prefix
+config
.ReadStr(AnimNames
[b
], 'mask', ''),
292 64, 64, config
.ReadInt(AnimNames
[b
], 'frames', 1),
293 config
.ReadBool(AnimNames
[b
], 'backanim', False))) then
300 for aa
:= WEAPON_SAW
to WEAPON_SUPERPULEMET
do
301 for bb
:= A_STAND
to A_PAIN
do
302 for cc
:= D_LEFT
to D_RIGHT
do
304 f
:= config
.ReadInt(AnimNames
[bb
], 'frames', 1);
305 if config
.ReadBool(AnimNames
[bb
], 'backanim', False) then
306 if f
> 2 then f
:= 2*f
-2;
307 SetLength(PlayerModelsArray
[ID
].WeaponPoints
[aa
, bb
, cc
], f
);
310 if (config
.ReadStr(AnimNames
[b
], 'resource2', '') <> '') and
311 (config
.ReadStr(AnimNames
[b
], 'mask2', '') <> '') then
313 g_Frames_CreateWAD(nil, s
+'_LEFTANIM'+IntToStr(b
),
314 prefix
+config
.ReadStr(AnimNames
[b
], 'resource2', ''),
315 64, 64, config
.ReadInt(AnimNames
[b
], 'frames', 1),
316 config
.ReadBool(AnimNames
[b
], 'backanim', False));
318 g_Frames_CreateWAD(nil, s
+'_LEFTANIM'+IntToStr(b
)+'_MASK',
319 prefix
+config
.ReadStr(AnimNames
[b
], 'mask2', ''),
320 64, 64, config
.ReadInt(AnimNames
[b
], 'frames', 1),
321 config
.ReadBool(AnimNames
[b
], 'backanim', False));
324 PlayerModelsArray
[ID
].ModelSpeed
[b
] := Max(1, config
.ReadInt(AnimNames
[b
], 'waitcount', 1) div 3);
327 with PlayerModelsArray
[ID
], config
do
329 prefix
:= FileName
+':SOUNDS\';
333 s
:= config
.ReadStr('Sound', 'pain'+IntToStr(a
), '');
336 SetLength(PainSounds
, Length(PainSounds
)+1);
337 g_Sound_CreateWAD(PainSounds
[High(PainSounds
)].ID
, prefix
+s
);
338 PainSounds
[High(PainSounds
)].Level
:= config
.ReadInt('Sound', 'painlevel'+IntToStr(a
), 1);
345 s
:= config
.ReadStr('Sound', 'die'+IntToStr(a
), '');
348 SetLength(DieSounds
, Length(DieSounds
)+1);
349 g_Sound_CreateWAD(DieSounds
[High(DieSounds
)].ID
, prefix
+s
);
350 DieSounds
[High(DieSounds
)].Level
:= config
.ReadInt('Sound', 'dielevel'+IntToStr(a
), 1);
355 SlopSound
:= Min(Max(config
.ReadInt('Sound', 'slop', 0), 0), 2);
357 SetLength(Gibs
, ReadInt('Gibs', 'count', 0));
360 (WAD
.GetResource('TEXTURES', config
.ReadStr('Gibs', 'resource', 'GIBS'), pData
, len
)) and
361 (WAD
.GetResource('TEXTURES', config
.ReadStr('Gibs', 'mask', 'GIBSMASK'), pData2
, len
)) then
363 for a
:= 0 to High(Gibs
) do
364 if e_CreateTextureMemEx(pData
, Gibs
[a
].ID
, a
*32, 0, 32, 32) and
365 e_CreateTextureMemEx(pData2
, Gibs
[a
].MaskID
, a
*32, 0, 32, 32) then
367 Gibs
[a
].Rect
:= e_GetTextureSize2(Gibs
[a
].ID
);
369 if Height
> 3 then Height
:= Height
-1-Random(2);
370 Gibs
[a
].OnlyOne
:= config
.ReadInt('Gibs', 'once', -1) = a
+1;
378 for aa
:= WEAPON_SAW
to WEAPON_SUPERPULEMET
do
379 for bb
:= A_STAND
to A_PAIN
do
380 if not (bb
in [A_DIE1
, A_DIE2
, A_PAIN
]) then
382 ok
:= ok
and GetWeapPoints(config
.ReadStr(AnimNames
[bb
], WeapNames
[aa
]+'_points', ''), aa
, bb
, D_RIGHT
,
383 config
.ReadInt(AnimNames
[bb
], 'frames', 0),
384 config
.ReadBool(AnimNames
[bb
], 'backanim', False),
387 if not GetWeapPoints(config
.ReadStr(AnimNames
[bb
], WeapNames
[aa
]+'2_points', ''), aa
, bb
, D_LEFT
,
388 config
.ReadInt(AnimNames
[bb
], 'frames', 0),
389 config
.ReadBool(AnimNames
[bb
], 'backanim', False),
391 for f
:= 0 to High(WeaponPoints
[aa
, bb
, D_RIGHT
]) do
393 WeaponPoints
[aa
, bb
, D_LEFT
, f
].X
:= -WeaponPoints
[aa
, bb
, D_RIGHT
, f
].X
;
394 WeaponPoints
[aa
, bb
, D_LEFT
, f
].Y
:= WeaponPoints
[aa
, bb
, D_RIGHT
, f
].Y
;
397 if not ok
then Break
;
399 {if ok then g_Console_Add(Info.Name+' weapon points ok')
400 else g_Console_Add(Info.Name+' weapon points fail');}
401 Info
.HaveWeapon
:= ok
;
403 s
:= config
.ReadStr('Model', 'flag_point', '');
404 if not GetPoint(s
, FlagPoint
) then FlagPoint
:= FLAG_DEFPOINT
;
406 FlagAngle
:= config
.ReadInt('Model', 'flag_angle', FLAG_DEFANGLE
);
415 function g_PlayerModel_Get(ModelName
: String): TPlayerModel
;
423 if PlayerModelsArray
= nil then Exit
;
425 for a
:= 0 to High(PlayerModelsArray
) do
426 if AnsiLowerCase(PlayerModelsArray
[a
].Info
.Name
) = AnsiLowerCase(ModelName
) then
428 Result
:= TPlayerModel
.Create
;
430 with PlayerModelsArray
[a
] do
432 Result
.FName
:= Info
.Name
;
434 for b
:= A_STAND
to A_PAIN
do
436 if not (g_Frames_Get(ID
, Info
.Name
+'_RIGHTANIM'+IntToStr(b
)) and
437 g_Frames_Get(ID2
, Info
.Name
+'_RIGHTANIM'+IntToStr(b
)+'_MASK')) then
444 Result
.FAnim
[D_RIGHT
][b
] := TAnimation
.Create(ID
, b
in [A_STAND
, A_WALK
], ModelSpeed
[b
]);
446 Result
.FMaskAnim
[D_RIGHT
][b
] := TAnimation
.Create(ID2
, b
in [A_STAND
, A_WALK
], ModelSpeed
[b
]);
448 if g_Frames_Exists(Info
.Name
+'_LEFTANIM'+IntToStr(b
)) and
449 g_Frames_Exists(Info
.Name
+'_LEFTANIM'+IntToStr(b
)+'_MASK') then
450 if g_Frames_Get(ID
, Info
.Name
+'_LEFTANIM'+IntToStr(b
)) and
451 g_Frames_Get(ID2
, Info
.Name
+'_LEFTANIM'+IntToStr(b
)+'_MASK') then
453 Result
.FAnim
[D_LEFT
][b
] := TAnimation
.Create(ID
, b
in [A_STAND
, A_WALK
], ModelSpeed
[b
]);
455 Result
.FMaskAnim
[D_LEFT
][b
] := TAnimation
.Create(ID2
, b
in [A_STAND
, A_WALK
], ModelSpeed
[b
]);
458 Result
.FPainSounds
:= PainSounds
;
459 Result
.FDieSounds
:= DieSounds
;
460 Result
.FSlopSound
:= SlopSound
;
463 Result
.FDrawWeapon
:= Info
.HaveWeapon
;
464 Result
.FWeaponPoints
:= WeaponPoints
;
466 Result
.FFlagPoint
:= FlagPoint
;
467 Result
.FFlagAngle
:= FlagAngle
;
474 function g_PlayerModel_GetAnim(ModelName
: string; Anim
: Byte; var _Anim
, _Mask
: TAnimation
): Boolean;
482 if PlayerModelsArray
= nil then Exit
;
483 for a
:= 0 to High(PlayerModelsArray
) do
484 if PlayerModelsArray
[a
].Info
.Name
= ModelName
then
485 with PlayerModelsArray
[a
] do
487 if Anim
in [A_STAND
, A_WALK
] then c
:= True else c
:= False;
489 if not g_Frames_Get(ID
, Info
.Name
+'_RIGHTANIM'+IntToStr(Anim
)) then
490 if not g_Frames_Get(ID
, Info
.Name
+'_LEFTANIM'+IntToStr(Anim
)) then Exit
;
492 _Anim
:= TAnimation
.Create(ID
, c
, ModelSpeed
[Anim
]);
493 _Anim
.Speed
:= ModelSpeed
[Anim
];
495 if not g_Frames_Get(ID
, Info
.Name
+'_RIGHTANIM'+IntToStr(Anim
)+'_MASK') then
496 if not g_Frames_Get(ID
, Info
.Name
+'_LEFTANIM'+IntToStr(Anim
)+'_MASK') then Exit
;
498 _Mask
:= TAnimation
.Create(ID
, c
, ModelSpeed
[Anim
]);
499 _Mask
.Speed
:= ModelSpeed
[Anim
];
507 function g_PlayerModel_GetGibs(ModelName
: string; var Gibs
: TGibsArray
): Boolean;
514 if PlayerModelsArray
= nil then Exit
;
515 if gGibsCount
= 0 then Exit
;
519 SetLength(Gibs
, gGibsCount
);
521 for a
:= 0 to High(PlayerModelsArray
) do
522 if PlayerModelsArray
[a
].Info
.Name
= ModelName
then
524 for i
:= 0 to High(Gibs
) do
526 if c
and (Length(PlayerModelsArray
[a
].Gibs
) = 1) then
533 b
:= Random(Length(PlayerModelsArray
[a
].Gibs
));
534 until not (PlayerModelsArray
[a
].Gibs
[b
].OnlyOne
and c
);
536 Gibs
[i
] := PlayerModelsArray
[a
].Gibs
[b
];
538 if Gibs
[i
].OnlyOne
then c
:= True;
546 function g_PlayerModel_GetNames(): SArray
;
552 if PlayerModelsArray
= nil then Exit
;
554 for i
:= 0 to High(PlayerModelsArray
) do
556 SetLength(Result
, Length(Result
)+1);
557 Result
[High(Result
)] := PlayerModelsArray
[i
].Info
.Name
;
561 function g_PlayerModel_GetInfo(ModelName
: string): TModelInfo
;
565 FillChar(Result
, SizeOf(Result
), 0);
566 if PlayerModelsArray
= nil then Exit
;
568 for a
:= 0 to High(PlayerModelsArray
) do
569 if PlayerModelsArray
[a
].Info
.Name
= ModelName
then
571 Result
:= PlayerModelsArray
[a
].Info
;
576 procedure g_PlayerModel_FreeData();
581 for a
:= WEAPON_SAW
to WEAPON_SUPERPULEMET
do
582 for b
:= W_POS_NORMAL
to W_POS_DOWN
do
583 for c
:= W_ACT_NORMAL
to W_ACT_FIRE
do
584 e_DeleteTexture(WeaponID
[a
][b
][c
]);
586 e_WriteLog('Releasing models...', MSG_NOTIFY
);
588 if PlayerModelsArray
= nil then Exit
;
590 for i
:= 0 to High(PlayerModelsArray
) do
591 with PlayerModelsArray
[i
] do
593 for a
:= A_STAND
to A_PAIN
do
595 g_Frames_DeleteByName(Info
.Name
+'_LEFTANIM'+IntToStr(a
));
596 g_Frames_DeleteByName(Info
.Name
+'_LEFTANIM'+IntToStr(a
)+'_MASK');
597 g_Frames_DeleteByName(Info
.Name
+'_RIGHTANIM'+IntToStr(a
));
598 g_Frames_DeleteByName(Info
.Name
+'_RIGHTANIM'+IntToStr(a
)+'_MASK');
601 if PainSounds
<> nil then
602 for b
:= 0 to High(PainSounds
) do
603 e_DeleteSound(PainSounds
[b
].ID
);
605 if DieSounds
<> nil then
606 for b
:= 0 to High(DieSounds
) do
607 e_DeleteSound(DieSounds
[b
].ID
);
610 for b
:= 0 to High(Gibs
) do
612 e_DeleteTexture(Gibs
[b
].ID
);
613 e_DeleteTexture(Gibs
[b
].MaskID
);
617 PlayerModelsArray
:= nil;
622 procedure TPlayerModel
.ChangeAnimation(Animation
: Byte; Force
: Boolean = False);
624 if not Force
then if FCurrentAnimation
= Animation
then Exit
;
626 FCurrentAnimation
:= Animation
;
628 if (FDirection
= D_LEFT
) and
629 (FAnim
[D_LEFT
][FCurrentAnimation
] <> nil) and
630 (FMaskAnim
[D_LEFT
][FCurrentAnimation
] <> nil) then
632 FAnim
[D_LEFT
][FCurrentAnimation
].Reset
;
633 FMaskAnim
[D_LEFT
][FCurrentAnimation
].Reset
;
637 FAnim
[D_RIGHT
][FCurrentAnimation
].Reset
;
638 FMaskAnim
[D_RIGHT
][FCurrentAnimation
].Reset
;
642 destructor TPlayerModel
.Destroy();
646 for a
:= A_STAND
to A_PAIN
do
648 FAnim
[D_LEFT
][a
].Free();
649 FMaskAnim
[D_LEFT
][a
].Free();
650 FAnim
[D_RIGHT
][a
].Free();
651 FMaskAnim
[D_RIGHT
][a
].Free();
657 procedure TPlayerModel
.Draw(X
, Y
: Integer; Alpha
: Byte = 0);
664 if Direction
= D_LEFT
then
667 Mirror
:= M_HORIZONTAL
;
669 if (FFlag
<> FLAG_NONE
) and (FFlagAnim
<> nil) and
670 (not (FCurrentAnimation
in [A_DIE1
, A_DIE2
])) then
672 p
.X
:= IfThen(Direction
= D_LEFT
,
674 64-FLAG_BASEPOINT
.X
);
675 p
.Y
:= FLAG_BASEPOINT
.Y
;
677 FFlagAnim
.DrawEx(X
+IfThen(Direction
= D_LEFT
, FFlagPoint
.X
-1, 2*FLAG_BASEPOINT
.X
-FFlagPoint
.X
+1)-FLAG_BASEPOINT
.X
,
678 Y
+FFlagPoint
.Y
-FLAG_BASEPOINT
.Y
+1, Mirror
, p
,
679 IfThen(FDirection
= D_RIGHT
, FFlagAngle
, -FFlagAngle
));
683 if Direction
= D_RIGHT
then
686 Mirror
:= M_HORIZONTAL
;
689 (not (FCurrentAnimation
in [A_DIE1
, A_DIE2
, A_PAIN
])) and
690 (FCurrentWeapon
in [WEAPON_SAW
..WEAPON_SUPERPULEMET
]) then
692 if FCurrentAnimation
in [A_SEEUP
, A_ATTACKUP
] then
695 if FCurrentAnimation
in [A_SEEDOWN
, A_ATTACKDOWN
] then
700 if (FCurrentAnimation
in [A_ATTACK
, A_ATTACKUP
, A_ATTACKDOWN
]) or
707 e_Draw(WeaponID
[FCurrentWeapon
][pos
][act
],
708 X
+FWeaponPoints
[FCurrentWeapon
, FCurrentAnimation
, FDirection
,
709 FAnim
[D_RIGHT
][FCurrentAnimation
].CurrentFrame
].X
,
710 Y
+FWeaponPoints
[FCurrentWeapon
, FCurrentAnimation
, FDirection
,
711 FAnim
[D_RIGHT
][FCurrentAnimation
].CurrentFrame
].Y
,
712 0, True, False, Mirror
);
716 if (FDirection
= D_LEFT
) and
717 (FAnim
[D_LEFT
][FCurrentAnimation
] <> nil) then
719 FAnim
[D_LEFT
][FCurrentAnimation
].Alpha
:= Alpha
;
720 FAnim
[D_LEFT
][FCurrentAnimation
].Draw(X
, Y
, M_NONE
);
724 FAnim
[D_RIGHT
][FCurrentAnimation
].Alpha
:= Alpha
;
725 FAnim
[D_RIGHT
][FCurrentAnimation
].Draw(X
, Y
, Mirror
);
731 if (FDirection
= D_LEFT
) and
732 (FMaskAnim
[D_LEFT
][FCurrentAnimation
] <> nil) then
734 FMaskAnim
[D_LEFT
][FCurrentAnimation
].Alpha
:= Alpha
;
735 FMaskAnim
[D_LEFT
][FCurrentAnimation
].Draw(X
, Y
, M_NONE
);
739 FMaskAnim
[D_RIGHT
][FCurrentAnimation
].Alpha
:= Alpha
;
740 FMaskAnim
[D_RIGHT
][FCurrentAnimation
].Draw(X
, Y
, Mirror
);
748 function TPlayerModel
.GetCurrentAnimation
: TAnimation
;
750 if (FDirection
= D_LEFT
) and (FAnim
[D_LEFT
][FCurrentAnimation
] <> nil) then
751 Result
:= FAnim
[D_LEFT
][FCurrentAnimation
]
753 Result
:= FAnim
[D_RIGHT
][FCurrentAnimation
];
756 function TPlayerModel
.GetCurrentAnimationMask
: TAnimation
;
758 if (FDirection
= D_LEFT
) and (FMaskAnim
[D_LEFT
][FCurrentAnimation
] <> nil) then
759 Result
:= FMaskAnim
[D_LEFT
][FCurrentAnimation
]
761 Result
:= FMaskAnim
[D_RIGHT
][FCurrentAnimation
];
764 function TPlayerModel
.PlaySound(SoundType
, Level
: Byte; X
, Y
: Integer): Boolean;
766 TempArray
: array of DWORD
;
770 SetLength(TempArray
, 0);
772 if SoundType
= MODELSOUND_PAIN
then
774 if FPainSounds
= nil then Exit
;
776 for a
:= 0 to High(FPainSounds
) do
777 if FPainSounds
[a
].Level
= Level
then
779 SetLength(TempArray
, Length(TempArray
)+1);
780 TempArray
[High(TempArray
)] := FPainSounds
[a
].ID
;
785 if (Level
in [2, 3]) and (FSlopSound
> 0) then
787 g_Sound_PlayExAt('SOUND_MONSTER_SLOP', X
, Y
);
788 if FSlopSound
= 1 then
794 if FDieSounds
= nil then Exit
;
796 for a
:= 0 to High(FDieSounds
) do
797 if FDieSounds
[a
].Level
= Level
then
799 SetLength(TempArray
, Length(TempArray
)+1);
800 TempArray
[High(TempArray
)] := FDieSounds
[a
].ID
;
804 if TempArray
= nil then Exit
;
806 g_Sound_PlayAt(TempArray
[Random(Length(TempArray
))], X
, Y
);
811 procedure TPlayerModel
.SetColor(Red
, Green
, Blue
: Byte);
818 procedure TPlayerModel
.SetFire(Fire
: Boolean);
822 if FFire
then FFireCounter
:= FAnim
[D_RIGHT
, A_ATTACK
].Speed
*FAnim
[D_RIGHT
, A_ATTACK
].TotalFrames
823 else FFireCounter
:= 0;
826 procedure TPlayerModel
.SetFlag(Flag
: Byte);
836 FLAG_RED
: g_Frames_Get(id
, 'FRAMES_FLAG_RED');
837 FLAG_BLUE
: g_Frames_Get(id
, 'FRAMES_FLAG_BLUE');
841 FFlagAnim
:= TAnimation
.Create(id
, True, 8);
844 procedure TPlayerModel
.SetWeapon(Weapon
: Byte);
846 FCurrentWeapon
:= Weapon
;
849 procedure TPlayerModel
.Update();
851 if (FDirection
= D_LEFT
) and (FAnim
[D_LEFT
][FCurrentAnimation
] <> nil) then
852 FAnim
[D_LEFT
][FCurrentAnimation
].Update
else FAnim
[D_RIGHT
][FCurrentAnimation
].Update
;
854 if (FDirection
= D_LEFT
) and (FMaskAnim
[D_LEFT
][FCurrentAnimation
] <> nil) then
855 FMaskAnim
[D_LEFT
][FCurrentAnimation
].Update
else FMaskAnim
[D_RIGHT
][FCurrentAnimation
].Update
;
857 if FFlagAnim
<> nil then FFlagAnim
.Update
;
859 if FFireCounter
> 0 then Dec(FFireCounter
) else FFire
:= False;