X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_playermodel.pas;h=b2f57e6c95997ff2835acc80f58380b4ec6827ca;hb=d0936017ccb8a078d1b03f55478af284bb015bbc;hp=6174d8780b5d81cfb29375d5166997f8f4380b5c;hpb=1070d03dd32edd73aced8786d3c5a8200a02ed00;p=d2df-sdl.git diff --git a/src/game/g_playermodel.pas b/src/game/g_playermodel.pas index 6174d87..b2f57e6 100644 --- a/src/game/g_playermodel.pas +++ b/src/game/g_playermodel.pas @@ -1,10 +1,26 @@ +(* Copyright (C) Doom 2D: Forever Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License ONLY. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *) +{$INCLUDE ../shared/a_modes.inc} +{$M+} unit g_playermodel; interface uses - g_textures, g_basic, e_graphics, WADEDITOR, - WADSTRUCT, g_weapons; + MAPDEF, g_textures, g_base, g_basic, g_weapons, r_graphics, utils, g_gfx, + ImagingTypes, Imaging, ImagingUtility; const A_STAND = 0; @@ -17,10 +33,37 @@ const A_ATTACKUP = 7; A_ATTACKDOWN = 8; A_PAIN = 9; + // EXTENDED + A_WALKATTACK = 10; + A_WALKSEEUP = 11; + A_WALKSEEDOWN = 12; + A_WALKATTACKUP = 13; + A_WALKATTACKDOWN = 14; + A_FISTSTAND = 15; + A_FISTWALK = 16; + A_FISTATTACK = 17; + A_FISTWALKATTACK = 18; + A_FISTSEEUP = 19; + A_FISTSEEDOWN = 20; + A_FISTATTACKUP = 21; + A_FISTATTACKDOWN = 22; + + A_LASTBASE = A_PAIN; + A_LASTEXT = A_FISTATTACKDOWN; + A_LAST = A_LASTEXT; MODELSOUND_PAIN = 0; MODELSOUND_DIE = 1; + W_POS_NORMAL = 0; + W_POS_UP = 1; + W_POS_DOWN = 2; + + W_ACT_NORMAL = 0; + W_ACT_FIRE = 1; + + FLAG_BASEPOINT: TDFPoint = (X:16; Y:43); + type TModelInfo = record Name: String; @@ -29,6 +72,10 @@ type HaveWeapon: Boolean; end; + TModelBlood = record + R, G, B, Kind: Byte; + end; + TModelSound = record ID: DWORD; Level: Byte; @@ -43,18 +90,20 @@ type TModelSoundArray = Array of TModelSound; TGibsArray = Array of TGibSprite; - TWeaponPoints = Array [WEAPON_SAW..WEAPON_SUPERPULEMET] of - Array [A_STAND..A_PAIN] of - Array [D_LEFT..D_RIGHT] of Array of TPoint; + TWeaponPoints = Array [WP_FIRST + 1..WP_LAST] of + Array [A_STAND..A_LAST] of + Array [TDirection.D_LEFT..TDirection.D_RIGHT] of Array of TDFPoint; + TModelMatrix = Array [TDirection.D_LEFT..TDirection.D_RIGHT] of Array [A_STAND..A_LAST] of TAnimation; - TPlayerModel = class (TObject) + TPlayerModel = class{$IFDEF USE_MEMPOOL}(TPoolObject){$ENDIF} private FName: String; FDirection: TDirection; FColor: TRGB; + FBlood: TModelBlood; FCurrentAnimation: Byte; - FAnim: Array [D_LEFT..D_RIGHT] of Array [A_STAND..A_PAIN] of TAnimation; - FMaskAnim: Array [D_LEFT..D_RIGHT] of Array [A_STAND..A_PAIN] of TAnimation; + FAnim: TModelMatrix; + FMaskAnim: TModelMatrix; FWeaponPoints: TWeaponPoints; FPainSounds: TModelSoundArray; FDieSounds: TModelSoundArray; @@ -62,7 +111,7 @@ type FCurrentWeapon: Byte; FDrawWeapon: Boolean; FFlag: Byte; - FFlagPoint: TPoint; + FFlagPoint: TDFPoint; FFlagAngle: SmallInt; FFlagAnim: TAnimation; FFire: Boolean; @@ -79,87 +128,85 @@ type procedure SetFire(Fire: Boolean); function PlaySound(SoundType, Level: Byte; X, Y: Integer): Boolean; procedure Update(); - procedure Draw(X, Y: Integer; Alpha: Byte = 0); + published property Fire: Boolean read FFire; property Direction: TDirection read FDirection write FDirection; property Animation: Byte read FCurrentAnimation; property Weapon: Byte read FCurrentWeapon; property Name: String read FName; + + public property Color: TRGB read FColor write FColor; + property Blood: TModelBlood read FBlood; + + property Anim: TModelMatrix read FAnim; + property MaskAnim: TModelMatrix read FMaskAnim; + property CurrentAnimation: Byte read FCurrentAnimation; + + property CurrentWeapon: Byte read FCurrentWeapon; + property DrawWeapon: Boolean read FDrawWeapon; + property WeaponPoints: TWeaponPoints read FWeaponPoints; + + property Flag: Byte read FFlag; + property FlagAnim: TAnimation read FFlagAnim; + property FlagAngle: SmallInt read FFlagAngle; + property FlagPoint: TDFPoint read FFlagPoint; end; -procedure g_PlayerModel_LoadData(); procedure g_PlayerModel_FreeData(); function g_PlayerModel_Load(FileName: String): Boolean; -function g_PlayerModel_GetNames(): SArray; +function g_PlayerModel_GetNames(): SSArray; function g_PlayerModel_GetInfo(ModelName: String): TModelInfo; +function g_PlayerModel_GetBlood(ModelName: String): TModelBlood; function g_PlayerModel_Get(ModelName: String): TPlayerModel; function g_PlayerModel_GetAnim(ModelName: String; Anim: Byte; var _Anim, _Mask: TAnimation): Boolean; function g_PlayerModel_GetGibs(ModelName: String; var Gibs: TGibsArray): Boolean; + implementation uses - g_main, g_sound, g_console, SysUtils, g_player, CONFIG, - GL, GLExt, e_sound, g_options, g_map, Math, e_log; + g_sound, g_console, SysUtils, g_player, CONFIG, + e_sound, g_options, g_map, Math, e_log, wadreader; type TPlayerModelInfo = record Info: TModelInfo; ModelSpeed: Array [A_STAND..A_PAIN] of Byte; - FlagPoint: TPoint; + FlagPoint: TDFPoint; FlagAngle: SmallInt; WeaponPoints: TWeaponPoints; Gibs: TGibsArray; PainSounds: TModelSoundArray; DieSounds: TModelSoundArray; SlopSound: Byte; + Blood: TModelBlood; end; const - W_POS_NORMAL = 0; - W_POS_UP = 1; - W_POS_DOWN = 2; - - W_ACT_NORMAL = 0; - W_ACT_FIRE = 1; - - FLAG_BASEPOINT: TPoint = (X:16; Y:43); - FLAG_DEFPOINT: TPoint = (X:32; Y:16); + FLAG_DEFPOINT: TDFPoint = (X:32; Y:16); FLAG_DEFANGLE = -20; - WEAPONBASE: Array [WEAPON_SAW..WEAPON_SUPERPULEMET] of TPoint = + WEAPONBASE: Array [WP_FIRST + 1..WP_LAST] of TDFPoint = ((X:8; Y:4), (X:8; Y:8), (X:16; Y:16), (X:16; Y:24), - (X:16; Y:16), (X:24; Y:24), (X:16; Y:16), (X:24; Y:24), (X:16; Y:16)); + (X:16; Y:16), (X:24; Y:24), (X:16; Y:16), (X:24; Y:24), + (X:16; Y:16), (X:8; Y:8)); - AnimNames: Array [A_STAND..A_PAIN] of String = + AnimNames: Array [A_STAND..A_LASTEXT] of String = ('StandAnim','WalkAnim','Die1Anim','Die2Anim','AttackAnim', - 'SeeUpAnim','SeeDownAnim','AttackUpAnim','AttackDownAnim','PainAnim'); - WeapNames: Array [WEAPON_SAW..WEAPON_SUPERPULEMET] of String = - ('csaw', 'hgun', 'sg', 'ssg', 'mgun', 'rkt', 'plz', 'bfg', 'spl'); + 'SeeUpAnim','SeeDownAnim','AttackUpAnim','AttackDownAnim','PainAnim', + // EXTENDED + 'WalkAttackAnim', 'WalkSeeUpAnim', 'WalkSeeDownAnim', + 'WalkAttackUpAnim', 'WalkAttackDownAnim', 'FistStandAnim', 'FistWalkAnim', + 'FistAttackAnim', 'FistWalkAttackAnim', 'FistSeeUpAnim', 'FistSeeDownAnim', + 'FistAttackUpAnim', 'FistAttackDownAnim'); + WeapNames: Array [WP_FIRST + 1..WP_LAST] of String = + ('csaw', 'hgun', 'sg', 'ssg', 'mgun', 'rkt', 'plz', 'bfg', 'spl', 'flm'); var - WeaponID: Array [WEAPON_SAW..WEAPON_SUPERPULEMET] of - Array [W_POS_NORMAL..W_POS_DOWN] of - Array [W_ACT_NORMAL..W_ACT_FIRE] of DWORD; PlayerModelsArray: Array of TPlayerModelInfo; -procedure g_PlayerModel_LoadData(); -var - a: Integer; -begin - for a := WEAPON_SAW to WEAPON_SUPERPULEMET do - begin - g_Texture_CreateWAD(WeaponID[a][W_POS_NORMAL][W_ACT_NORMAL], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])); - g_Texture_CreateWAD(WeaponID[a][W_POS_NORMAL][W_ACT_FIRE], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_FIRE'); - g_Texture_CreateWAD(WeaponID[a][W_POS_UP][W_ACT_NORMAL], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_UP'); - g_Texture_CreateWAD(WeaponID[a][W_POS_UP][W_ACT_FIRE], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_UP_FIRE'); - g_Texture_CreateWAD(WeaponID[a][W_POS_DOWN][W_ACT_NORMAL], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_DN'); - g_Texture_CreateWAD(WeaponID[a][W_POS_DOWN][W_ACT_FIRE], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_DN_FIRE'); - end; -end; - -function GetPoint(var str: String; var point: TPoint): Boolean; +function GetPoint(var str: String; var point: TDFPoint): Boolean; var a, x, y: Integer; s: String; @@ -215,7 +262,7 @@ begin begin X := X - WEAPONBASE[weapon].X; Y := Y - WEAPONBASE[weapon].Y; - if dir = D_LEFT then + if dir = TDirection.D_LEFT then X := -X; end; end; @@ -228,23 +275,126 @@ begin Result := True; end; +procedure ExtAnimFromBaseAnim(MName: String; AIdx: Integer); +const + CopyAnim: array [A_LASTBASE+1..A_LASTEXT] of Integer = ( + A_WALK, A_WALK, A_WALK, A_WALK, A_WALK, + A_STAND, A_WALK, A_ATTACK, A_WALK, A_SEEUP, A_SEEDOWN, + A_ATTACKUP, A_ATTACKDOWN + ); +var + OIdx, W, I: Integer; + D: TDirection; + AName, OName: String; +begin + // HACK: shitty workaround to duplicate base animations + // in place of extended, replace with something better later + + Assert((AIdx > A_LASTBASE) and (AIdx <= A_LASTEXT)); + OIdx := CopyAnim[AIdx]; + + AName := MName + '_RIGHTANIM' + IntToStr(AIdx); + OName := MName + '_RIGHTANIM' + IntToStr(OIdx); + Assert(g_Frames_Dup(AName, OName)); + Assert(g_Frames_Dup(AName + '_MASK', OName + '_MASK')); + AName := MName + '_LEFTANIM' + IntToStr(AIdx); + OName := MName + '_LEFTANIM' + IntToStr(OIdx); + if g_Frames_Exists(AName) then + begin + g_Frames_Dup(AName, OName); + g_Frames_Dup(AName + '_MASK', OName + '_MASK'); + end; + + with PlayerModelsArray[High(PlayerModelsArray)] do + begin + for W := WP_FIRST + 1 to WP_LAST do + begin + for D := TDirection.D_LEFT to TDirection.D_RIGHT do + begin + SetLength(WeaponPoints[W, AIdx, D], Length(WeaponPoints[W, OIdx, D])); + for I := 0 to High(WeaponPoints[W, AIdx, D]) do + WeaponPoints[W, AIdx, D, I] := WeaponPoints[W, OIdx, D, I] + end; + end; + end; +end; + +function g_PlayerModel_CalcGibSize (pData: Pointer; dataSize, x, y, w, h: Integer): TRectWH; + var i, j: Integer; done: Boolean; img: TImageData; + + function IsVoid (i, j: Integer): Boolean; + begin + result := Byte((PByte(img.bits) + (y+j)*img.width*4 + (x+i)*4 + 3)^) = 0 + end; + +begin + InitImage(img); + assert(LoadImageFromMemory(pData, dataSize, img)); + + (* trace x from right to left *) + done := false; i := 0; + while not done and (i < w) do + begin + j := 0; + while (j < h) and IsVoid(i, j) do inc(j); + done := (j < h) and (IsVoid(i, j) = false); + result.x := i; + inc(i); + end; + + (* trace y from up to down *) + done := false; j := 0; + while not done and (j < h) do + begin + i := 0; + while (i < w) and IsVoid(i, j) do inc(i); + done := (i < w) and (IsVoid(i, j) = false); + result.y := j; + inc(j); + end; + + (* trace x from right to left *) + done := false; i := w - 1; + while not done and (i >= 0) do + begin + j := 0; + while (j < h) and IsVoid(i, j) do inc(j); + done := (j < h) and (IsVoid(i, j) = false); + result.width := i - result.x + 1; + dec(i); + end; + + (* trace y from down to up *) + done := false; j := h - 1; + while not done and (j >= 0) do + begin + i := 0; + while (i < w) and IsVoid(i, j) do inc(i); + done := (i < w) and (IsVoid(i, j) = false); + result.height := j - result.y + 1; + dec(j); + end; + + FreeImage(img); +end; + function g_PlayerModel_Load(FileName: string): Boolean; var ID: DWORD; - a, b, len, aa, bb, f: Integer; + a, b, len, lenpd, lenpd2, aa, bb, f: Integer; cc: TDirection; config: TConfig; pData, pData2: Pointer; - WAD: TWADEditor_1; - s: string; + WAD: TWADFile; + s, aname: string; prefix: string; - ok: Boolean; + ok, chk: Boolean; begin - e_WriteLog(Format('Loading player model: %s', [ExtractFileName(FileName)]), MSG_NOTIFY); + e_WriteLog(Format('Loading player model "%s"...', [FileName]), TMsgType.Notify); Result := False; - WAD := TWADEditor_1.Create; + WAD := TWADFile.Create; WAD.ReadFile(FileName); if {WAD.GetLastError <> DFWAD_NOERROR} not WAD.isOpen then @@ -253,7 +403,7 @@ begin Exit; end; - if not WAD.GetResource('TEXT', 'MODEL', pData, len) then + if not WAD.GetResource('TEXT/MODEL', pData, len) then begin WAD.Free(); Exit; @@ -282,25 +432,49 @@ begin Description := config.ReadStr('Model', 'description', ''); end; - for b := A_STAND to A_PAIN do + with PlayerModelsArray[ID] do + begin + Blood.R := MAX(0, MIN(255, config.ReadInt('Blood', 'R', 150))); + Blood.G := MAX(0, MIN(255, config.ReadInt('Blood', 'G', 0))); + Blood.B := MAX(0, MIN(255, config.ReadInt('Blood', 'B', 0))); + case config.ReadStr('Blood', 'Kind', 'NORMAL') of + 'NORMAL': Blood.Kind := BLOOD_NORMAL; + 'SPARKS': Blood.Kind := BLOOD_CSPARKS; + 'COMBINE': Blood.Kind := BLOOD_COMBINE; + else + Blood.Kind := BLOOD_NORMAL + end + end; + + for b := A_STAND to A_LAST do begin - if not (g_Frames_CreateWAD(nil, s+'_RIGHTANIM'+IntToStr(b), + aname := s+'_RIGHTANIM'+IntToStr(b); + //e_LogWritefln('### MODEL FILE: [%s]', [prefix+config.ReadStr(AnimNames[b], 'resource', '')]); + if not (g_Frames_CreateWAD(nil, aname, prefix+config.ReadStr(AnimNames[b], 'resource', ''), 64, 64, config.ReadInt(AnimNames[b], 'frames', 1), config.ReadBool(AnimNames[b], 'backanim', False)) and - g_Frames_CreateWAD(nil, s+'_RIGHTANIM'+IntToStr(b)+'_MASK', + g_Frames_CreateWAD(nil, aname+'_MASK', prefix+config.ReadStr(AnimNames[b], 'mask', ''), 64, 64, config.ReadInt(AnimNames[b], 'frames', 1), config.ReadBool(AnimNames[b], 'backanim', False))) then begin - config.Free(); - WAD.Free(); - Exit; + if b <= A_LASTBASE then + begin + config.Free(); + WAD.Free(); + Exit; + end + else + begin + ExtAnimFromBaseAnim(s, b); + continue; + end; end; - for aa := WEAPON_SAW to WEAPON_SUPERPULEMET do - for bb := A_STAND to A_PAIN do - for cc := D_LEFT to D_RIGHT do + for aa := WP_FIRST + 1 to WP_LAST do + for bb := A_STAND to A_LAST do + for cc := TDirection.D_LEFT to TDirection.D_RIGHT do begin f := config.ReadInt(AnimNames[bb], 'frames', 1); if config.ReadBool(AnimNames[bb], 'backanim', False) then @@ -311,12 +485,13 @@ begin if (config.ReadStr(AnimNames[b], 'resource2', '') <> '') and (config.ReadStr(AnimNames[b], 'mask2', '') <> '') then begin - g_Frames_CreateWAD(nil, s+'_LEFTANIM'+IntToStr(b), + aname := s+'_LEFTANIM'+IntToStr(b); + g_Frames_CreateWAD(nil, aname, prefix+config.ReadStr(AnimNames[b], 'resource2', ''), 64, 64, config.ReadInt(AnimNames[b], 'frames', 1), config.ReadBool(AnimNames[b], 'backanim', False)); - g_Frames_CreateWAD(nil, s+'_LEFTANIM'+IntToStr(b)+'_MASK', + g_Frames_CreateWAD(nil, aname+'_MASK', prefix+config.ReadStr(AnimNames[b], 'mask2', ''), 64, 64, config.ReadInt(AnimNames[b], 'frames', 1), config.ReadBool(AnimNames[b], 'backanim', False)); @@ -358,14 +533,15 @@ begin SetLength(Gibs, ReadInt('Gibs', 'count', 0)); if (Gibs <> nil) and - (WAD.GetResource('TEXTURES', config.ReadStr('Gibs', 'resource', 'GIBS'), pData, len)) and - (WAD.GetResource('TEXTURES', config.ReadStr('Gibs', 'mask', 'GIBSMASK'), pData2, len)) then + (WAD.GetResource('TEXTURES/'+config.ReadStr('Gibs', 'resource', 'GIBS'), pData, lenpd)) and + (WAD.GetResource('TEXTURES/'+config.ReadStr('Gibs', 'mask', 'GIBSMASK'), pData2, lenpd2)) then begin for a := 0 to High(Gibs) do - if e_CreateTextureMemEx(pData, Gibs[a].ID, a*32, 0, 32, 32) and - e_CreateTextureMemEx(pData2, Gibs[a].MaskID, a*32, 0, 32, 32) then + if e_CreateTextureMemEx(pData, lenpd, Gibs[a].ID, a*32, 0, 32, 32) and + e_CreateTextureMemEx(pData2, lenpd2, Gibs[a].MaskID, a*32, 0, 32, 32) then begin - Gibs[a].Rect := e_GetTextureSize2(Gibs[a].ID); + //Gibs[a].Rect := e_GetTextureSize2(Gibs[a].ID); + Gibs[a].Rect := g_PlayerModel_CalcGibSize(pData, lenpd, a*32, 0, 32, 32); with Gibs[a].Rect do if Height > 3 then Height := Height-1-Random(2); Gibs[a].OnlyOne := config.ReadInt('Gibs', 'once', -1) = a+1; @@ -376,23 +552,73 @@ begin end; ok := True; - for aa := WEAPON_SAW to WEAPON_SUPERPULEMET do - for bb := A_STAND to A_PAIN do + for aa := WP_FIRST + 1 to WP_LAST do + for bb := A_STAND to A_LAST do if not (bb in [A_DIE1, A_DIE2, A_PAIN]) then begin - ok := ok and GetWeapPoints(config.ReadStr(AnimNames[bb], WeapNames[aa]+'_points', ''), aa, bb, D_RIGHT, - config.ReadInt(AnimNames[bb], 'frames', 0), - config.ReadBool(AnimNames[bb], 'backanim', False), - WeaponPoints); + chk := GetWeapPoints(config.ReadStr(AnimNames[bb], WeapNames[aa]+'_points', ''), aa, bb, TDirection.D_RIGHT, + config.ReadInt(AnimNames[bb], 'frames', 0), + config.ReadBool(AnimNames[bb], 'backanim', False), + WeaponPoints); + if ok and (not chk) and (aa = WEAPON_FLAMETHROWER) then + begin + // workaround for flamethrower + chk := GetWeapPoints(config.ReadStr(AnimNames[bb], WeapNames[WEAPON_PLASMA]+'_points', ''), aa, bb, TDirection.D_RIGHT, + config.ReadInt(AnimNames[bb], 'frames', 0), + config.ReadBool(AnimNames[bb], 'backanim', False), + WeaponPoints); + if chk then + for f := 0 to High(WeaponPoints[aa, bb, TDirection.D_RIGHT]) do + begin + case bb of + A_STAND, A_PAIN: + begin + Dec(WeaponPoints[aa, bb, TDirection.D_RIGHT, f].X, 6); + Dec(WeaponPoints[aa, bb, TDirection.D_RIGHT, f].Y, 8); + end; + A_WALKATTACK, A_WALK: + begin + Dec(WeaponPoints[aa, bb, TDirection.D_RIGHT, f].X, 9); + Dec(WeaponPoints[aa, bb, TDirection.D_RIGHT, f].Y, 9); + end; + A_ATTACK: + begin + Dec(WeaponPoints[aa, bb, TDirection.D_RIGHT, f].X, 5); + Dec(WeaponPoints[aa, bb, TDirection.D_RIGHT, f].Y, 8); + end; + A_WALKSEEUP, A_SEEUP: + begin + Dec(WeaponPoints[aa, bb, TDirection.D_RIGHT, f].X, 5); + Dec(WeaponPoints[aa, bb, TDirection.D_RIGHT, f].Y, 16); + end; + A_WALKSEEDOWN, A_SEEDOWN: + begin + Dec(WeaponPoints[aa, bb, TDirection.D_RIGHT, f].X, 6); + Dec(WeaponPoints[aa, bb, TDirection.D_RIGHT, f].Y, 5); + end; + A_WALKATTACKUP, A_ATTACKUP: + begin + Dec(WeaponPoints[aa, bb, TDirection.D_RIGHT, f].X, 5); + Dec(WeaponPoints[aa, bb, TDirection.D_RIGHT, f].Y, 16); + end; + A_WALKATTACKDOWN, A_ATTACKDOWN: + begin + Dec(WeaponPoints[aa, bb, TDirection.D_RIGHT, f].X, 6); + Dec(WeaponPoints[aa, bb, TDirection.D_RIGHT, f].Y, 4); + end; + end; + end; + end; + ok := ok and (chk or (bb > A_LASTBASE)); - if not GetWeapPoints(config.ReadStr(AnimNames[bb], WeapNames[aa]+'2_points', ''), aa, bb, D_LEFT, + if not GetWeapPoints(config.ReadStr(AnimNames[bb], WeapNames[aa]+'2_points', ''), aa, bb, TDirection.D_LEFT, config.ReadInt(AnimNames[bb], 'frames', 0), config.ReadBool(AnimNames[bb], 'backanim', False), WeaponPoints) then - for f := 0 to High(WeaponPoints[aa, bb, D_RIGHT]) do + for f := 0 to High(WeaponPoints[aa, bb, TDirection.D_RIGHT]) do begin - WeaponPoints[aa, bb, D_LEFT, f].X := -WeaponPoints[aa, bb, D_RIGHT, f].X; - WeaponPoints[aa, bb, D_LEFT, f].Y := WeaponPoints[aa, bb, D_RIGHT, f].Y; + WeaponPoints[aa, bb, TDirection.D_LEFT, f].X := -WeaponPoints[aa, bb, TDirection.D_RIGHT, f].X; + WeaponPoints[aa, bb, TDirection.D_LEFT, f].Y := WeaponPoints[aa, bb, TDirection.D_RIGHT, f].Y; end; if not ok then Break; @@ -431,44 +657,44 @@ begin with PlayerModelsArray[a] do begin Result.FName := Info.Name; + Result.FBlood := Blood; - for b := A_STAND to A_PAIN do + for b := A_STAND to A_LAST do begin if not (g_Frames_Get(ID, Info.Name+'_RIGHTANIM'+IntToStr(b)) and g_Frames_Get(ID2, Info.Name+'_RIGHTANIM'+IntToStr(b)+'_MASK')) then begin Result.Free(); Result := nil; - Exit; - end; + Exit; + end; - Result.FAnim[D_RIGHT][b] := TAnimation.Create(ID, b in [A_STAND, A_WALK], ModelSpeed[b]); + Result.FAnim[TDirection.D_RIGHT][b] := TAnimation.Create(ID, b in [A_STAND, A_WALK], ModelSpeed[b]); - Result.FMaskAnim[D_RIGHT][b] := TAnimation.Create(ID2, b in [A_STAND, A_WALK], ModelSpeed[b]); + Result.FMaskAnim[TDirection.D_RIGHT][b] := TAnimation.Create(ID2, b in [A_STAND, A_WALK], ModelSpeed[b]); - if g_Frames_Exists(Info.Name+'_LEFTANIM'+IntToStr(b)) and - g_Frames_Exists(Info.Name+'_LEFTANIM'+IntToStr(b)+'_MASK') then - if g_Frames_Get(ID, Info.Name+'_LEFTANIM'+IntToStr(b)) and - g_Frames_Get(ID2, Info.Name+'_LEFTANIM'+IntToStr(b)+'_MASK') then - begin - Result.FAnim[D_LEFT][b] := TAnimation.Create(ID, b in [A_STAND, A_WALK], ModelSpeed[b]); + if g_Frames_Exists(Info.Name+'_LEFTANIM'+IntToStr(b)) and + g_Frames_Exists(Info.Name+'_LEFTANIM'+IntToStr(b)+'_MASK') then + if g_Frames_Get(ID, Info.Name+'_LEFTANIM'+IntToStr(b)) and + g_Frames_Get(ID2, Info.Name+'_LEFTANIM'+IntToStr(b)+'_MASK') then + begin + Result.FAnim[TDirection.D_LEFT][b] := TAnimation.Create(ID, b in [A_STAND, A_WALK], ModelSpeed[b]); - Result.FMaskAnim[D_LEFT][b] := TAnimation.Create(ID2, b in [A_STAND, A_WALK], ModelSpeed[b]); + Result.FMaskAnim[TDirection.D_LEFT][b] := TAnimation.Create(ID2, b in [A_STAND, A_WALK], ModelSpeed[b]); + end; end; Result.FPainSounds := PainSounds; Result.FDieSounds := DieSounds; Result.FSlopSound := SlopSound; - end; - - Result.FDrawWeapon := Info.HaveWeapon; - Result.FWeaponPoints := WeaponPoints; + Result.FDrawWeapon := Info.HaveWeapon; + Result.FWeaponPoints := WeaponPoints; - Result.FFlagPoint := FlagPoint; - Result.FFlagAngle := FlagAngle; + Result.FFlagPoint := FlagPoint; + Result.FFlagAngle := FlagAngle; - Break; - end; + Break; + end; end; end; @@ -544,7 +770,7 @@ begin end; end; -function g_PlayerModel_GetNames(): SArray; +function g_PlayerModel_GetNames(): SSArray; var i: DWORD; begin @@ -574,24 +800,37 @@ begin end; end; +function g_PlayerModel_GetBlood(ModelName: string): TModelBlood; +var + a: Integer; +begin + Result.R := 150; + Result.G := 0; + Result.B := 0; + Result.Kind := BLOOD_NORMAL; + if PlayerModelsArray = nil then Exit; + + for a := 0 to High(PlayerModelsArray) do + if PlayerModelsArray[a].Info.Name = ModelName then + begin + Result := PlayerModelsArray[a].Blood; + Break; + end; +end; + procedure g_PlayerModel_FreeData(); var i: DWORD; - a, b, c: Integer; + a, b: Integer; begin - for a := WEAPON_SAW to WEAPON_SUPERPULEMET do - for b := W_POS_NORMAL to W_POS_DOWN do - for c := W_ACT_NORMAL to W_ACT_FIRE do - e_DeleteTexture(WeaponID[a][b][c]); - - e_WriteLog('Releasing models...', MSG_NOTIFY); + e_WriteLog('Releasing models...', TMsgType.Notify); if PlayerModelsArray = nil then Exit; for i := 0 to High(PlayerModelsArray) do with PlayerModelsArray[i] do begin - for a := A_STAND to A_PAIN do + for a := A_STAND to A_LAST do begin g_Frames_DeleteByName(Info.Name+'_LEFTANIM'+IntToStr(a)); g_Frames_DeleteByName(Info.Name+'_LEFTANIM'+IntToStr(a)+'_MASK'); @@ -626,17 +865,17 @@ begin FCurrentAnimation := Animation; - if (FDirection = D_LEFT) and - (FAnim[D_LEFT][FCurrentAnimation] <> nil) and - (FMaskAnim[D_LEFT][FCurrentAnimation] <> nil) then + if (FDirection = TDirection.D_LEFT) and + (FAnim[TDirection.D_LEFT][FCurrentAnimation] <> nil) and + (FMaskAnim[TDirection.D_LEFT][FCurrentAnimation] <> nil) then begin - FAnim[D_LEFT][FCurrentAnimation].Reset; - FMaskAnim[D_LEFT][FCurrentAnimation].Reset; + FAnim[TDirection.D_LEFT][FCurrentAnimation].Reset; + FMaskAnim[TDirection.D_LEFT][FCurrentAnimation].Reset; end else begin - FAnim[D_RIGHT][FCurrentAnimation].Reset; - FMaskAnim[D_RIGHT][FCurrentAnimation].Reset; + FAnim[TDirection.D_RIGHT][FCurrentAnimation].Reset; + FMaskAnim[TDirection.D_RIGHT][FCurrentAnimation].Reset; end; end; @@ -644,122 +883,31 @@ destructor TPlayerModel.Destroy(); var a: Byte; begin - for a := A_STAND to A_PAIN do + for a := A_STAND to A_LAST do begin - FAnim[D_LEFT][a].Free(); - FMaskAnim[D_LEFT][a].Free(); - FAnim[D_RIGHT][a].Free(); - FMaskAnim[D_RIGHT][a].Free(); + FAnim[TDirection.D_LEFT][a].Free(); + FMaskAnim[TDirection.D_LEFT][a].Free(); + FAnim[TDirection.D_RIGHT][a].Free(); + FMaskAnim[TDirection.D_RIGHT][a].Free(); end; inherited; end; -procedure TPlayerModel.Draw(X, Y: Integer; Alpha: Byte = 0); -var - Mirror: TMirrorType; - pos, act: Byte; - p: TPoint; -begin -// Ôëàãè: - if Direction = D_LEFT then - Mirror := M_NONE - else - Mirror := M_HORIZONTAL; - - if (FFlag <> FLAG_NONE) and (FFlagAnim <> nil) and - (not (FCurrentAnimation in [A_DIE1, A_DIE2])) then - begin - p.X := IfThen(Direction = D_LEFT, - FLAG_BASEPOINT.X, - 64-FLAG_BASEPOINT.X); - p.Y := FLAG_BASEPOINT.Y; - - FFlagAnim.DrawEx(X+IfThen(Direction = D_LEFT, FFlagPoint.X-1, 2*FLAG_BASEPOINT.X-FFlagPoint.X+1)-FLAG_BASEPOINT.X, - Y+FFlagPoint.Y-FLAG_BASEPOINT.Y+1, Mirror, p, - IfThen(FDirection = D_RIGHT, FFlagAngle, -FFlagAngle)); - end; - -// Îðóæèå: - if Direction = D_RIGHT then - Mirror := M_NONE - else - Mirror := M_HORIZONTAL; - - if FDrawWeapon and - (not (FCurrentAnimation in [A_DIE1, A_DIE2, A_PAIN])) and - (FCurrentWeapon in [WEAPON_SAW..WEAPON_SUPERPULEMET]) then - begin - if FCurrentAnimation in [A_SEEUP, A_ATTACKUP] then - pos := W_POS_UP - else - if FCurrentAnimation in [A_SEEDOWN, A_ATTACKDOWN] then - pos := W_POS_DOWN - else - pos := W_POS_NORMAL; - - if (FCurrentAnimation in [A_ATTACK, A_ATTACKUP, A_ATTACKDOWN]) or - FFire then - act := W_ACT_FIRE - else - act := W_ACT_NORMAL; - - if Alpha < 201 then - e_Draw(WeaponID[FCurrentWeapon][pos][act], - X+FWeaponPoints[FCurrentWeapon, FCurrentAnimation, FDirection, - FAnim[D_RIGHT][FCurrentAnimation].CurrentFrame].X, - Y+FWeaponPoints[FCurrentWeapon, FCurrentAnimation, FDirection, - FAnim[D_RIGHT][FCurrentAnimation].CurrentFrame].Y, - 0, True, False, Mirror); - end; - -// Ìîäåëü: - if (FDirection = D_LEFT) and - (FAnim[D_LEFT][FCurrentAnimation] <> nil) then - begin - FAnim[D_LEFT][FCurrentAnimation].Alpha := Alpha; - FAnim[D_LEFT][FCurrentAnimation].Draw(X, Y, M_NONE); - end - else - begin - FAnim[D_RIGHT][FCurrentAnimation].Alpha := Alpha; - FAnim[D_RIGHT][FCurrentAnimation].Draw(X, Y, Mirror); - end; - -// Ìàñêà ìîäåëè: - e_Colors := FColor; - - if (FDirection = D_LEFT) and - (FMaskAnim[D_LEFT][FCurrentAnimation] <> nil) then - begin - FMaskAnim[D_LEFT][FCurrentAnimation].Alpha := Alpha; - FMaskAnim[D_LEFT][FCurrentAnimation].Draw(X, Y, M_NONE); - end - else - begin - FMaskAnim[D_RIGHT][FCurrentAnimation].Alpha := Alpha; - FMaskAnim[D_RIGHT][FCurrentAnimation].Draw(X, Y, Mirror); - end; - - e_Colors.R := 255; - e_Colors.G := 255; - e_Colors.B := 255; -end; - function TPlayerModel.GetCurrentAnimation: TAnimation; begin - if (FDirection = D_LEFT) and (FAnim[D_LEFT][FCurrentAnimation] <> nil) then - Result := FAnim[D_LEFT][FCurrentAnimation] + if (FDirection = TDirection.D_LEFT) and (FAnim[TDirection.D_LEFT][FCurrentAnimation] <> nil) then + Result := FAnim[TDirection.D_LEFT][FCurrentAnimation] else - Result := FAnim[D_RIGHT][FCurrentAnimation]; + Result := FAnim[TDirection.D_RIGHT][FCurrentAnimation]; end; function TPlayerModel.GetCurrentAnimationMask: TAnimation; begin - if (FDirection = D_LEFT) and (FMaskAnim[D_LEFT][FCurrentAnimation] <> nil) then - Result := FMaskAnim[D_LEFT][FCurrentAnimation] + if (FDirection = TDirection.D_LEFT) and (FMaskAnim[TDirection.D_LEFT][FCurrentAnimation] <> nil) then + Result := FMaskAnim[TDirection.D_LEFT][FCurrentAnimation] else - Result := FMaskAnim[D_RIGHT][FCurrentAnimation]; + Result := FMaskAnim[TDirection.D_RIGHT][FCurrentAnimation]; end; function TPlayerModel.PlaySound(SoundType, Level: Byte; X, Y: Integer): Boolean; @@ -783,7 +931,7 @@ begin end else begin - if (Level in [2, 3]) and (FSlopSound > 0) then + if (Level in [2, 3, 5]) and (FSlopSound > 0) then begin g_Sound_PlayExAt('SOUND_MONSTER_SLOP', X, Y); if FSlopSound = 1 then @@ -800,6 +948,12 @@ begin SetLength(TempArray, Length(TempArray)+1); TempArray[High(TempArray)] := FDieSounds[a].ID; end; + if (TempArray = nil) and (Level = 5) then + begin + g_Sound_PlayExAt('SOUND_MONSTER_SLOP', X, Y); + Result := True; + Exit; + end; end; if TempArray = nil then Exit; @@ -820,7 +974,7 @@ procedure TPlayerModel.SetFire(Fire: Boolean); begin FFire := Fire; - if FFire then FFireCounter := FAnim[D_RIGHT, A_ATTACK].Speed*FAnim[D_RIGHT, A_ATTACK].TotalFrames + if FFire then FFireCounter := FAnim[TDirection.D_RIGHT, A_ATTACK].Speed*FAnim[TDirection.D_RIGHT, A_ATTACK].TotalFrames else FFireCounter := 0; end; @@ -849,11 +1003,11 @@ end; procedure TPlayerModel.Update(); begin - if (FDirection = D_LEFT) and (FAnim[D_LEFT][FCurrentAnimation] <> nil) then - FAnim[D_LEFT][FCurrentAnimation].Update else FAnim[D_RIGHT][FCurrentAnimation].Update; + if (FDirection = TDirection.D_LEFT) and (FAnim[TDirection.D_LEFT][FCurrentAnimation] <> nil) then + FAnim[TDirection.D_LEFT][FCurrentAnimation].Update else FAnim[TDirection.D_RIGHT][FCurrentAnimation].Update; - if (FDirection = D_LEFT) and (FMaskAnim[D_LEFT][FCurrentAnimation] <> nil) then - FMaskAnim[D_LEFT][FCurrentAnimation].Update else FMaskAnim[D_RIGHT][FCurrentAnimation].Update; + if (FDirection = TDirection.D_LEFT) and (FMaskAnim[TDirection.D_LEFT][FCurrentAnimation] <> nil) then + FMaskAnim[TDirection.D_LEFT][FCurrentAnimation].Update else FMaskAnim[TDirection.D_RIGHT][FCurrentAnimation].Update; if FFlagAnim <> nil then FFlagAnim.Update;