X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_monsters.pas;h=3b1aad732636098f528204c006badae4448c2e8c;hb=abda6900c041e39944de6a49aa088a60c170715e;hp=02e7ed589ae6fa4b69b7b686ebd50f69ee5752af;hpb=dffafd305d0df029f317cc92c1968ba0065c0cd8;p=d2df-sdl.git diff --git a/src/game/g_monsters.pas b/src/game/g_monsters.pas index 02e7ed5..3b1aad7 100644 --- a/src/game/g_monsters.pas +++ b/src/game/g_monsters.pas @@ -22,7 +22,8 @@ interface uses SysUtils, Classes, mempool, - g_basic, e_graphics, g_phys, g_textures, g_grid, + MAPDEF, + g_base, g_basic, g_phys, g_textures, g_grid, g_saveload, g_panel, xprofiler; const @@ -51,6 +52,8 @@ const } type + ADirectedAnim = Array of Array [TDirection.D_LEFT..TDirection.D_RIGHT] of TAnimationState; + PMonster = ^TMonster; TMonster = class{$IFDEF USE_MEMPOOL}(TPoolObject){$ENDIF} private @@ -64,7 +67,7 @@ type FMaxHealth: Integer; FState: Byte; FCurAnim: Byte; - FAnim: Array of Array [TDirection.D_LEFT..TDirection.D_RIGHT] of TAnimation; + FAnim: ADirectedAnim; FTargetUID: Word; FTargetTime: Integer; FBehaviour: Byte; @@ -86,7 +89,7 @@ type FShellType: Byte; FFirePainTime: Integer; FFireAttacker: Word; - vilefire: TAnimation; + vilefire: TAnimationState; mProxyId: Integer; // node in dyntree or -1 mArrIdx: Integer; // in gMonsters @@ -129,7 +132,6 @@ type procedure ClientUpdate(); procedure ClientAttack(wx, wy, atx, aty: Integer); procedure SetDeadAnim; - procedure Draw(); procedure WakeUp(); procedure WakeUpSound(); procedure DieSound(); @@ -192,6 +194,9 @@ type property StartID: Integer read FStartID; + property VileFireAnim: TAnimationState read vilefire; + property DirAnim: ADirectedAnim read FAnim; + published property eMonsterType: Byte read FMonsterType; property eMonsterHealth: Integer read FHealth write FHealth; @@ -235,8 +240,6 @@ function g_Monsters_Create (MonsterType: Byte; X, Y: Integer; Direction: TDirect AdjCoord: Boolean = False; ForcedUID: Integer = -1): TMonster; procedure g_Monsters_PreUpdate (); procedure g_Monsters_Update (); -procedure g_Monsters_Draw (); -procedure g_Monsters_DrawHealth (); function g_Monsters_ByUID (UID: Word): TMonster; procedure g_Monsters_killedp (); procedure g_Monsters_SaveState (st: TStream); @@ -310,151 +313,19 @@ var gmon_debug_think: Boolean = true; gmon_debug_one_think_step: Boolean = false; + var (* private state *) + gMonsters: array of TMonster; -implementation - -uses - e_log, e_texture, g_main, g_sound, g_gfx, g_player, g_game, - g_weapons, g_triggers, MAPDEF, g_items, g_options, - g_console, g_map, Math, g_menu, wadreader, - g_language, g_netmsg, idpool, utils, xstreams; - - - -// ////////////////////////////////////////////////////////////////////////// // -procedure g_Mons_ProfilersBegin (); -begin - if (profMonsLOS = nil) then profMonsLOS := TProfiler.Create('LOS CALC', g_profile_history_size); - if (profMonsLOS <> nil) then profMonsLOS.mainBegin(g_profile_los); - if g_profile_los and (profMonsLOS <> nil) then - begin - profMonsLOS.sectionBegin('loscalc'); - profMonsLOS.sectionEnd(); - end; -end; - -procedure g_Mons_ProfilersEnd (); -begin - if (profMonsLOS <> nil) and (g_profile_los) then profMonsLOS.mainEnd(); -end; - -procedure g_Mons_LOS_Start (); inline; -begin - if (profMonsLOS <> nil) then profMonsLOS.sectionBeginAccum('loscalc'); -end; - -procedure g_Mons_LOS_End (); inline; -begin - if (profMonsLOS <> nil) then profMonsLOS.sectionEnd(); -end; - - -// ////////////////////////////////////////////////////////////////////////// // -var - monCheckTrapLastFrameId: DWord = 0; - monCheckMPlatLastFrameId: LongWord = 0; - - -procedure TMonster.getMapBox (out x, y, w, h: Integer); inline; -begin - x := FObj.X+FObj.Rect.X; - y := FObj.Y+FObj.Rect.Y; - w := FObj.Rect.Width; - h := FObj.Rect.Height; -end; - -function TMonster.gncNeedSend (): Boolean; inline; begin result := mNeedSend; mNeedSend := false; end; - -procedure TMonster.setDirty (); inline; begin mNeedSend := true; end; - + const + ANIM_SLEEP = 0; + ANIM_GO = 1; + ANIM_DIE = 2; + ANIM_MESS = 3; + ANIM_ATTACK = 4; + ANIM_ATTACK2 = 5; + ANIM_PAIN = 6; -// ////////////////////////////////////////////////////////////////////////// // -{ -function g_Mons_AlongLine (x0, y0, x1, y1: Integer; cb: TMonsAlongLineCB; log: Boolean=false): TMonster; -begin - if not assigned(cb) then begin result := nil; exit; end; - result := monsGrid.forEachAlongLine(x0, y0, x1, y1, cb, -1, log); -end; -} - - -//WARNING! call this after monster position was changed, or coldet will not work right! -procedure TMonster.positionChanged (); -var - x, y, w, h: Integer; - nx, ny, nw, nh: Integer; -begin - {$IF DEFINED(D2F_DEBUG_MONS_MOVE)} - //e_WriteLog(Format('monster #%d(%u): pos=(%d,%d); rpos=(%d,%d)', [mArrIdx, UID, FObj.X, FObj.Y, FObj.Rect.X, FObj.Rect.Y]), MSG_NOTIFY); - {$ENDIF} - if (mProxyId = -1) then - begin - //mNeedSend := true; - mProxyId := monsGrid.insertBody(self, FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y, FObj.Rect.Width, FObj.Rect.Height); - {$IF DEFINED(D2F_DEBUG_MONS_MOVE)} - monsGrid.getBodyXY(mProxyId, x, y); - e_WriteLog(Format('monster #%d:(%u): inserted into the grid; mProxyid=%d; gx=%d; gy=%d', [mArrIdx, UID, mProxyId, x-monsGrid.gridX0, y-monsGrid.gridY0]), MSG_NOTIFY); - {$ENDIF} - end - else - begin - monsGrid.getBodyDims(mProxyId, x, y, w, h); - getMapBox(nx, ny, nw, nh); - - if (w <> nw) or (h <> nh) then - begin - //mNeedSend := true; - {$IF DEFINED(D2F_DEBUG_MONS_MOVE)} - e_WriteLog(Format('monster #%d:(%u): resized; mProxyid=%d; gx=%d; gy=%d', [mArrIdx, UID, mProxyId, x-monsGrid.gridX0, y-monsGrid.gridY0]), MSG_NOTIFY); - {$ENDIF} - monsGrid.moveResizeBody(mProxyId, nx, ny, nw, nh); - end - else if (x <> nx) or (y <> ny) then - begin - //mNeedSend := true; - {$IF DEFINED(D2F_DEBUG_MONS_MOVE)} - e_WriteLog(Format('monster #%d:(%u): updating grid; mProxyid=%d; gx=%d; gy=%d', [mArrIdx, UID, mProxyId, x-monsGrid.gridX0, y-monsGrid.gridY0]), MSG_NOTIFY); - {$ENDIF} - monsGrid.moveBody(mProxyId, nx, ny); - end - else - begin - exit; // nothing to do - end; - {$IF DEFINED(D2F_DEBUG_MONS_MOVE)} - monsGrid.getBodyXY(mProxyId, x, y); - e_WriteLog(Format('monster #%d:(%u): updated grid; mProxyid=%d; gx=%d; gy=%d', [mArrIdx, UID, mProxyId, x-monsGrid.gridX0, y-monsGrid.gridY0]), MSG_NOTIFY); - {$ENDIF} - end; -end; - - -// ////////////////////////////////////////////////////////////////////////// // -const - ANIM_SLEEP = 0; - ANIM_GO = 1; - ANIM_DIE = 2; - ANIM_MESS = 3; - ANIM_ATTACK = 4; - ANIM_ATTACK2 = 5; - ANIM_PAIN = 6; - - MONSTER_SIGNATURE = $534E4F4D; // 'MONS' - -// Òàáëèöà òèïîâ àíèìàöèè ìîíñòðîâ: - ANIMTABLE: Array [ANIM_SLEEP..ANIM_PAIN] of - record - name: String; - loop: Boolean; - end = ((name: 'SLEEP'; loop: True), - (name: 'GO'; loop: True), - (name: 'DIE'; loop: False), - (name: 'MESS'; loop: False), - (name: 'ATTACK'; loop: False), - (name: 'ATTACK2'; loop: False), - (name: 'PAIN'; loop: False)); - -// Òàáëèöà õàðàêòåðèñòèê ìîíñòðîâ: +// Таблица характеристик монстров: MONSTERTABLE: Array [MONSTER_DEMON..MONSTER_MAN] of record Name: String; @@ -525,102 +396,272 @@ const (Name:'MAN'; Rect:(X:15; Y:6; Width:34; Height:52); Health:400; RunVel: 8; MinPain: 50; Pain: 70; Jump: 10)); -// Òàáëèöà ïàðàìåòðîâ àíèìàöèè ìîíñòðîâ: +// Таблица параметров анимации монстров: MONSTER_ANIMTABLE: Array [MONSTER_DEMON..MONSTER_MAN] of record LeftAnim: Boolean; - wX, wY: Integer; // Îòêóäà âûëåòèò ïóëÿ + wX, wY: Integer; // Откуда вылетит пуля AnimSpeed: Array [ANIM_SLEEP..ANIM_PAIN] of Byte; + AnimCount: Array [ANIM_SLEEP..ANIM_PAIN] of Byte; AnimDeltaRight: Array [ANIM_SLEEP..ANIM_PAIN] of TDFPoint; AnimDeltaLeft: Array [ANIM_SLEEP..ANIM_PAIN] of TDFPoint; end = // SLEEP GO DIE MESS ATTACK ATTACK2 PAIN ((LeftAnim: False; wX: 54; wY: 32; AnimSpeed:(3, 2, 3, 2, 3, 0, 4); //DEMON + AnimCount: (2, 4, 6, 6, 3, 0, 1); AnimDeltaRight: ((X: 1; Y: 4), (X: 1; Y: 4), (X: 0; Y: 4), (X: 0; Y: 4), (X: 2; Y: 6), (X: 2; Y: 6), (X: 2; Y: 5)); AnimDeltaLeft: ((X: 1; Y: 4), (X: 1; Y: 4), (X: 0; Y: 4), (X: 0; Y: 4), (X: 2; Y: 6), (X: 2; Y: 6), (X: 2; Y: 5))), (LeftAnim: False; wX: 32; wY: 32; AnimSpeed:(3, 2, 3, 2, 3, 0, 4); //IMP + AnimCount: (2, 4, 5, 8, 3, 0, 1); AnimDeltaRight: ((X: 8; Y: -4), (X: 8; Y: -4), (X: -2; Y: -1), (X: 3; Y: -2), (X: 14; Y: -4), (X: 14; Y: -4), (X: -5; Y: -4)); AnimDeltaLeft: ((X: 8; Y: -4), (X: 8; Y: -4), (X: -2; Y: -1), (X: 3; Y: -2), (X: 14; Y: -4), (X: 14; Y: -4), (X: -5; Y: -4))), (LeftAnim: True; wX: 32; wY: 32; AnimSpeed:(3, 2, 3, 2, 3, 0, 4); //ZOMBY + AnimCount: (2, 4, 6, 9, 2, 0, 1); AnimDeltaRight: ((X: 1; Y: -4), (X: 1; Y: -4), (X: 3; Y: -1), (X: 2; Y: -1), (X: 2; Y: -4), (X: 2; Y: -4), (X: 1; Y: -4)); AnimDeltaLeft: ((X: 1; Y: -4), (X: 1; Y: -4), (X: 3; Y: -1), (X: 2; Y: -1), (X: 2; Y: -4), (X: 2; Y: -4), (X: 1; Y: -4))), (LeftAnim: True; wX: 32; wY: 32; AnimSpeed:(3, 2, 3, 2, 3, 0, 4); //SERG + AnimCount: (2, 4, 5, 9, 2, 0, 1); AnimDeltaRight: ((X: 0; Y: -4), (X: 0; Y: -4), (X: -3; Y: -1), (X: -4; Y: -1), (X: 1; Y: -4), (X: 1; Y: -4), (X: 0; Y: -4)); AnimDeltaLeft: ((X: 0; Y: -4), (X: 0; Y: -4), (X: -3; Y: -1), (X: -4; Y: -1), (X: 1; Y: -4), (X: 1; Y: -4), (X: 0; Y: -4))), (LeftAnim: True; wX: 70; wY: 73; AnimSpeed:(3, 3, 3, 3, 3, 4, 3); //CYBER + AnimCount: (2, 4, 9, 9, 2, 2, 1); AnimDeltaRight: ((X: 2; Y: -6), (X: 2; Y: -6), (X: -3; Y: -4), (X: -3; Y: -4), (X: 25; Y: -6), (X: 0; Y: -6), (X: -2; Y: -6)); AnimDeltaLeft: ((X: 3; Y: -3), (X: 3; Y: -3), (X: -3; Y: -4), (X: -3; Y: -4), (X:-26; Y: -3), (X:-1; Y: -3), (X: 1; Y: -3))), (LeftAnim: True; wX: 32; wY: 32; AnimSpeed:(3, 2, 2, 2, 1, 0, 4); //CGUN + AnimCount: (2, 4, 7, 6, 2, 0, 1); AnimDeltaRight: ((X: -1; Y: -2), (X: -1; Y: -2), (X: -2; Y: 0), (X: -2; Y: 0), (X: 0; Y: -3), (X: 0; Y: -3), (X: -1; Y: -2)); AnimDeltaLeft: ((X: -1; Y: -2), (X: -1; Y: -2), (X: -2; Y: 0), (X: -2; Y: 0), (X: -1; Y: -4), (X: -1; Y: -4), (X: 2; Y: -4))), (LeftAnim: True; wX: 64; wY: 64; AnimSpeed:(3, 2, 3, 4, 2, 0, 4); //BARON + AnimCount: (2, 4, 7, 7, 3, 0, 1); AnimDeltaRight: ((X: 4; Y: 0), (X: 2; Y: 0), (X: -1; Y: -1), (X: -1; Y: -1), (X: 1; Y: 0), (X: 1; Y: 0), (X: -1; Y: 0)); AnimDeltaLeft: ((X: 0; Y: 0), (X: 2; Y: 0), (X: -1; Y: -1), (X: -1; Y: -1), (X: -2; Y: 0), (X: -2; Y: 0), (X: 1; Y: 0))), (LeftAnim: True; wX: 64; wY: 64; AnimSpeed:(3, 2, 3, 4, 2, 0, 4); //KNIGHT + AnimCount: (2, 4, 7, 7, 3, 0, 1); AnimDeltaRight: ((X: 4; Y: 0), (X: 2; Y: 0), (X: -1; Y: -1), (X: -1; Y: -1), (X: 1; Y: 0), (X: 1; Y: 0), (X: -1; Y: 0)); AnimDeltaLeft: ((X: 0; Y: 0), (X: 2; Y: 0), (X: -1; Y: -1), (X: -1; Y: -1), (X: -2; Y: 0), (X: -2; Y: 0), (X: 1; Y: 0))), (LeftAnim: False; wX: 88; wY: 69; AnimSpeed:(3, 2, 3, 4, 2, 0, 4); //CACO + AnimCount: (1, 1, 7, 7, 6, 0, 1); AnimDeltaRight: ((X: 0; Y: -4), (X: 0; Y: -4), (X: 0; Y: -5), (X: 0; Y: -5), (X: 0; Y: -4), (X: 0; Y: -4), (X: 0; Y: -4)); AnimDeltaLeft: ((X: 0; Y: -4), (X: 0; Y: -4), (X: 0; Y: -5), (X: 0; Y: -5), (X: 0; Y: -4), (X: 0; Y: -4), (X: 0; Y: -4))), (LeftAnim: False; wX: 32; wY: 32; AnimSpeed:(3, 2, 3, 4, 1, 0, 4); //SOUL + AnimCount: (2, 2, 7, 7, 2, 0, 1); // 10 AnimDeltaRight: ((X: 1; Y:-10), (X: 1; Y:-10), (X:-33; Y:-34), (X:-33; Y:-34), (X:-16; Y:-10), (X:-16; Y:-10), (X: -1; Y: -7)); AnimDeltaLeft: ((X: 1; Y:-10), (X: 1; Y:-10), (X:-33; Y:-34), (X:-33; Y:-34), (X:-16; Y:-10), (X:-16; Y:-10), (X: -1; Y: -7))), (LeftAnim: False; wX: 64; wY: 64; AnimSpeed:(3, 2, 3, 4, 2, 0, 4); //PAIN + AnimCount: (4, 4, 7, 7, 4, 0, 1); AnimDeltaRight: ((X: -1; Y: -3), (X: -1; Y: -3), (X: -3; Y: 0), (X: -3; Y: 0), (X: -1; Y: -3), (X: -1; Y: -3), (X: -1; Y: -4)); AnimDeltaLeft: ((X: -1; Y: -3), (X: -1; Y: -3), (X: -3; Y: 0), (X: -3; Y: 0), (X: -1; Y: -3), (X: -1; Y: -3), (X: -1; Y: -4))), (LeftAnim: True; wX: 128; wY: 64; AnimSpeed:(3, 2, 4, 4, 1, 0, 4); //SPIDER + AnimCount: (2, 6, 10, 10, 2, 0, 1); AnimDeltaRight: ((X: -4; Y: -4), (X: -4; Y: -4), (X: -2; Y: 8), (X: -2; Y: 8), (X: -3; Y: -3), (X: -3; Y: -3), (X: -3; Y: -4)); AnimDeltaLeft: ((X: -4; Y: -4), (X: -4; Y: -4), (X: -2; Y: 8), (X: -2; Y: 8), (X: -3; Y: -3), (X: -3; Y: -3), (X: 18; Y: -5))), (LeftAnim: True; wX: 64; wY: 32; AnimSpeed:(3, 2, 3, 4, 1, 0, 4); //BSP + AnimCount: (2, 6, 7, 7, 2, 0, 1); AnimDeltaRight: ((X: 0; Y: -1), (X: 0; Y: -1), (X: -3; Y: 5), (X: -3; Y: 5), (X: 7; Y: -1), (X: 7; Y: -1), (X: 1; Y: -3)); AnimDeltaLeft: ((X: 0; Y: -1), (X: 0; Y: -1), (X: -3; Y: 5), (X: -3; Y: 5), (X: 7; Y: -1), (X: 7; Y: -1), (X: 6; Y: -3))), (LeftAnim: False; wX: 64; wY: 64; AnimSpeed:(3, 2, 2, 4, 2, 0, 4); //MANCUB + AnimCount: (2, 6, 10, 10, 3, 0, 1); AnimDeltaRight: ((X: -2; Y: -7), (X: -2; Y: -7), (X: -4; Y: -2), (X: -4; Y: -2), (X: -4; Y: -7), (X: -4; Y: -7), (X:-14; Y: -7)); AnimDeltaLeft: ((X: -2; Y: -7), (X: -2; Y: -7), (X: -4; Y: -2), (X: -4; Y: -2), (X: -4; Y: -7), (X: -4; Y: -7), (X:-14; Y: -7))), (LeftAnim: True; wX: 64; wY: 32; AnimSpeed:(3, 3, 3, 3, 3, 3, 3); //SKEL + AnimCount: (2, 6, 5, 5, 2, 2, 1); AnimDeltaRight: ((X: -1; Y: 4), (X: -1; Y: 4), (X: -2; Y: 4), (X: -2; Y: 4), (X: -1; Y: 4), (X: 6; Y: 2), (X:-24; Y: 4)); AnimDeltaLeft: ((X: 1; Y: 4), (X: -1; Y: 4), (X: -2; Y: 4), (X: -2; Y: 4), (X: -2; Y: 2), (X: -5; Y: 4), (X: 26; Y: 4))), (LeftAnim: True; wX: 64; wY: 32; AnimSpeed:(3, 3, 3, 3, 3, 3, 3); //VILE + AnimCount: (2, 6, 9, 9, 10, 3, 1); AnimDeltaRight: ((X: 5; Y:-21), (X: 5; Y:-21), (X: 1; Y:-21), (X: 1; Y:-21), (X: 8; Y:-23), (X: -1; Y:-23), (X: 4; Y:-20)); AnimDeltaLeft: ((X: -8; Y:-21), (X: 5; Y:-21), (X: 1; Y:-21), (X: 1; Y:-21), (X:-10; Y:-24), (X: 3; Y:-23), (X: -4; Y:-22))), (LeftAnim: False; wX: 8; wY: 8; AnimSpeed:(2, 2, 2, 2, 3, 0, 1); //FISH + AnimCount: (2, 4, 1, 1, 2, 0, 3); AnimDeltaRight: ((X: -1; Y: 0), (X: -1; Y: 0), (X: -2; Y: -1), (X: -2; Y: -1), (X: -1; Y: -1), (X: -1; Y: -1), (X: -1; Y: -1)); AnimDeltaLeft: ((X: -1; Y: 0), (X: -1; Y: 0), (X: -2; Y: -1), (X: -2; Y: -1), (X: -1; Y: -1), (X: -1; Y: -1), (X: -1; Y: -1 ))), (LeftAnim: False; wX: 32; wY: 32; AnimSpeed:(3, 0, 3, 0, 0, 0, 5); //BARREL + AnimCount: (3, 0, 4, 0, 0, 0, 1); AnimDeltaRight: ((X: 0; Y:-15), (X: 0; Y:-15), (X: -1; Y:-15), (X: -1; Y:-15), (X: 0; Y:-15), (X: 0; Y:-15), (X: 0; Y:-15)); AnimDeltaLeft: ((X: 0; Y:-15), (X: 0; Y:-15), (X: -1; Y:-15), (X: -1; Y:-15), (X: 0; Y:-15), (X: 0; Y:-15), (X: 0; Y:-15))), (LeftAnim: False; wX: 95; wY: 57; AnimSpeed:(1, 2, 1, 0, 1, 1, 0); //ROBO + AnimCount: (1, 12, 1, 0, 2, 4, 0); AnimDeltaRight: ((X: -2; Y:-26), (X: -2; Y:-26), (X: 0; Y:-26), (X: 0; Y:-26), (X: 2; Y:-26), (X: 15; Y:-26), (X: -2; Y:-26)); AnimDeltaLeft: ((X: -2; Y:-26), (X: -2; Y:-26), (X: 0; Y:-26), (X: 0; Y:-26), (X: 2; Y:-26), (X: 15; Y:-26), (X: -2; Y:-26))), (LeftAnim: False; wX: 32; wY: 32; AnimSpeed:(3, 2, 2, 2, 2, 0, 5); //MAN + AnimCount: (2, 4, 7, 9, 2, 0, 1); AnimDeltaRight: ((X: 0; Y: -6), (X: 0; Y: -6), (X: -2; Y: 0), (X: 2; Y: 0), (X: 1; Y: -6), (X: 1; Y: -6), (X: 0; Y: -6)); AnimDeltaLeft: ((X: 0; Y: -6), (X: 0; Y: -6), (X: -2; Y: 0), (X: 2; Y: 0), (X: 1; Y: -6), (X: 1; Y: -6), (X: 0; Y: -6))) ); - MAX_ATM = 89; // Âðåìÿ îæèäàíèÿ ïîñëå ïîòåðè öåëè - MAX_SOUL = 512; // Îãðàíè÷åíèå Lost_Soul'îâ +// Таблица типов анимации монстров: + ANIMTABLE: Array [ANIM_SLEEP..ANIM_PAIN] of + record + name: String; + loop: Boolean; + end = ((name: 'SLEEP'; loop: True), + (name: 'GO'; loop: True), + (name: 'DIE'; loop: False), + (name: 'MESS'; loop: False), + (name: 'ATTACK'; loop: False), + (name: 'ATTACK2'; loop: False), + (name: 'PAIN'; loop: False)); +implementation + +uses + e_log, g_sound, g_gfx, g_player, g_game, r_gfx, + g_weapons, g_triggers, g_items, g_options, + g_console, g_map, Math, g_menu, wadreader, + g_language, g_netmsg, idpool, utils, xstreams; + + +function g_Look(a, b: PObj; d: TDirection): Boolean; +begin + if not gmon_dbg_los_enabled then begin result := false; exit; end; // always "wall hit" + + if ((b^.X > a^.X) and (d = TDirection.D_LEFT)) or + ((b^.X < a^.X) and (d = TDirection.D_RIGHT)) then + begin + Result := False; + Exit; + end; + + Result := g_TraceVector(a^.X+a^.Rect.X+(a^.Rect.Width div 2), + a^.Y+a^.Rect.Y+(a^.Rect.Height div 2), + b^.X+b^.Rect.X+(b^.Rect.Width div 2), + b^.Y+b^.Rect.Y+(b^.Rect.Height div 2)); +end; + +// ////////////////////////////////////////////////////////////////////////// // +procedure g_Mons_ProfilersBegin (); +begin + if (profMonsLOS = nil) then profMonsLOS := TProfiler.Create('LOS CALC', g_profile_history_size); + if (profMonsLOS <> nil) then profMonsLOS.mainBegin(g_profile_los); + if g_profile_los and (profMonsLOS <> nil) then + begin + profMonsLOS.sectionBegin('loscalc'); + profMonsLOS.sectionEnd(); + end; +end; + +procedure g_Mons_ProfilersEnd (); +begin + if (profMonsLOS <> nil) and (g_profile_los) then profMonsLOS.mainEnd(); +end; + +procedure g_Mons_LOS_Start (); inline; +begin + if (profMonsLOS <> nil) then profMonsLOS.sectionBeginAccum('loscalc'); +end; + +procedure g_Mons_LOS_End (); inline; +begin + if (profMonsLOS <> nil) then profMonsLOS.sectionEnd(); +end; + + +// ////////////////////////////////////////////////////////////////////////// // +var + monCheckTrapLastFrameId: DWord = 0; + monCheckMPlatLastFrameId: LongWord = 0; + + +procedure TMonster.getMapBox (out x, y, w, h: Integer); inline; +begin + x := FObj.X+FObj.Rect.X; + y := FObj.Y+FObj.Rect.Y; + w := FObj.Rect.Width; + h := FObj.Rect.Height; +end; + +function TMonster.gncNeedSend (): Boolean; inline; begin result := mNeedSend; mNeedSend := false; end; + +procedure TMonster.setDirty (); inline; begin mNeedSend := true; end; + + +// ////////////////////////////////////////////////////////////////////////// // +{ +function g_Mons_AlongLine (x0, y0, x1, y1: Integer; cb: TMonsAlongLineCB; log: Boolean=false): TMonster; +begin + if not assigned(cb) then begin result := nil; exit; end; + result := monsGrid.forEachAlongLine(x0, y0, x1, y1, cb, -1, log); +end; +} + + +//WARNING! call this after monster position was changed, or coldet will not work right! +procedure TMonster.positionChanged (); +var + x, y, w, h: Integer; + nx, ny, nw, nh: Integer; +begin + {$IF DEFINED(D2F_DEBUG_MONS_MOVE)} + //e_WriteLog(Format('monster #%d(%u): pos=(%d,%d); rpos=(%d,%d)', [mArrIdx, UID, FObj.X, FObj.Y, FObj.Rect.X, FObj.Rect.Y]), MSG_NOTIFY); + {$ENDIF} + if (mProxyId = -1) then + begin + //mNeedSend := true; + mProxyId := monsGrid.insertBody(self, FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y, FObj.Rect.Width, FObj.Rect.Height); + {$IF DEFINED(D2F_DEBUG_MONS_MOVE)} + monsGrid.getBodyXY(mProxyId, x, y); + e_WriteLog(Format('monster #%d:(%u): inserted into the grid; mProxyid=%d; gx=%d; gy=%d', [mArrIdx, UID, mProxyId, x-monsGrid.gridX0, y-monsGrid.gridY0]), MSG_NOTIFY); + {$ENDIF} + end + else + begin + monsGrid.getBodyDims(mProxyId, x, y, w, h); + getMapBox(nx, ny, nw, nh); + + if (w <> nw) or (h <> nh) then + begin + //mNeedSend := true; + {$IF DEFINED(D2F_DEBUG_MONS_MOVE)} + e_WriteLog(Format('monster #%d:(%u): resized; mProxyid=%d; gx=%d; gy=%d', [mArrIdx, UID, mProxyId, x-monsGrid.gridX0, y-monsGrid.gridY0]), MSG_NOTIFY); + {$ENDIF} + monsGrid.moveResizeBody(mProxyId, nx, ny, nw, nh); + end + else if (x <> nx) or (y <> ny) then + begin + //mNeedSend := true; + {$IF DEFINED(D2F_DEBUG_MONS_MOVE)} + e_WriteLog(Format('monster #%d:(%u): updating grid; mProxyid=%d; gx=%d; gy=%d', [mArrIdx, UID, mProxyId, x-monsGrid.gridX0, y-monsGrid.gridY0]), MSG_NOTIFY); + {$ENDIF} + monsGrid.moveBody(mProxyId, nx, ny); + end + else + begin + exit; // nothing to do + end; + {$IF DEFINED(D2F_DEBUG_MONS_MOVE)} + monsGrid.getBodyXY(mProxyId, x, y); + e_WriteLog(Format('monster #%d:(%u): updated grid; mProxyid=%d; gx=%d; gy=%d', [mArrIdx, UID, mProxyId, x-monsGrid.gridX0, y-monsGrid.gridY0]), MSG_NOTIFY); + {$ENDIF} + end; +end; + + +// ////////////////////////////////////////////////////////////////////////// // +const + MONSTER_SIGNATURE = $534E4F4D; // 'MONS' + + MAX_ATM = 89; // Время ожидания после потери цели + MAX_SOUL = 512; // Ограничение Lost_Soul'ов // ////////////////////////////////////////////////////////////////////////// // var - gMonsters: array of TMonster; uidMap: array [0..65535] of TMonster; // monster knows it's index freeInds: TIdPool = nil; @@ -696,26 +737,26 @@ function IsFriend(a, b: Byte): Boolean; begin Result := True; -// Áî÷êà - âñåì äðóã: +// Бочка - всем друг: if (a = MONSTER_BARREL) or (b = MONSTER_BARREL) then Exit; -// Ìîíñòðû îäíîãî âèäà: +// Монстры одного вида: if a = b then case a of MONSTER_IMP, MONSTER_DEMON, MONSTER_BARON, MONSTER_KNIGHT, MONSTER_CACO, MONSTER_SOUL, MONSTER_PAIN, MONSTER_MANCUB, MONSTER_SKEL, MONSTER_FISH: - Exit; // Ýòè íå áüþò ñâîèõ + Exit; // Эти не бьют своих end; -// Lost_Soul íå ìîæåò ðàíèòü Pain_Elemental'à: +// Lost_Soul не может ранить Pain_Elemental'а: if (a = MONSTER_SOUL) and (b = MONSTER_PAIN) then Exit; -// Pain_Elemental íå ìîæåò ðàíèòü Lost_Soul'à: +// Pain_Elemental не может ранить Lost_Soul'а: if (b = MONSTER_SOUL) and (a = MONSTER_PAIN) then Exit; -//  îñòàëüíûõ ñëó÷àÿõ - áóäóò áèòü äðóã äðóãà: +// В остальных случаях - будут бить друг друга: Result := False; end; @@ -772,11 +813,11 @@ function isCorpse (o: PObj; immediately: Boolean): Integer; result := false; // don't stop if (mon.FState = MONSTATE_DEAD) and g_Obj_Collide(o, @mon.FObj) then begin - case mon.FMonsterType of // Íå âîñêðåñèòü: + case mon.FMonsterType of // Не воскресить: MONSTER_SOUL, MONSTER_PAIN, MONSTER_CYBER, MONSTER_SPIDER, MONSTER_VILE, MONSTER_BARREL, MONSTER_ROBO: exit; end; - // Îñòàëüíûõ ìîæíî âîñêðåñèòü + // Остальных можно воскресить result := true; end; end; @@ -790,10 +831,10 @@ var begin result := -1; - // Åñëè íóæíà âåðîÿòíîñòü + // Если нужна вероятность if not immediately and (Random(8) <> 0) then exit; - // Èùåì ìåðòâûõ ìîíñòðîâ ïîáëèçîñòè + // Ищем мертвых монстров поблизости if gmon_debug_use_sqaccel then begin //mon := monsGrid.forEachInAABB(o.X+o.Rect.X, o.Y+o.Rect.Y, o.Rect.Width, o.Rect.Height, monsCollCheck); @@ -801,10 +842,10 @@ begin it := monsGrid.forEachInAABB(o.X+o.Rect.X, o.Y+o.Rect.Y, o.Rect.Width, o.Rect.Height); for mon in it do begin - case mon.FMonsterType of // Íå âîñêðåñèòü: + case mon.FMonsterType of // Не воскресить: MONSTER_SOUL, MONSTER_PAIN, MONSTER_CYBER, MONSTER_SPIDER, MONSTER_VILE, MONSTER_BARREL, MONSTER_ROBO: begin end; - // Îñòàëüíûõ ìîæíî âîñêðåñèòü + // Остальных можно воскресить else mres := mon^; end; if (mres <> nil) then break; @@ -818,10 +859,10 @@ begin begin if (gMonsters[a] <> nil) and (gMonsters[a].FState = MONSTATE_DEAD) and g_Obj_Collide(o, @gMonsters[a].FObj) then begin - case gMonsters[a].FMonsterType of // Íå âîñêðåñèòü: + case gMonsters[a].FMonsterType of // Не воскресить: MONSTER_SOUL, MONSTER_PAIN, MONSTER_CYBER, MONSTER_SPIDER, MONSTER_VILE, MONSTER_BARREL, MONSTER_ROBO: Continue; - else // Îñòàëüíûõ ìîæíî âîñêðåñèòü + else // Остальных можно воскресить begin Result := a; Exit; @@ -837,160 +878,6 @@ begin e_WriteLog('Loading monsters data...', TMsgType.Notify); g_Game_SetLoadingText(_lc[I_LOAD_MONSTER_TEXTURES], 133, False); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_BARREL_SLEEP', GameWAD+':MTEXTURES\BARREL_SLEEP', 64, 64, 3); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_BARREL_DIE', GameWAD+':MTEXTURES\BARREL_DIE', 64, 64, 4); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_BARREL_PAIN', GameWAD+':MTEXTURES\BARREL_PAIN', 64, 64, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_ZOMBY_SLEEP', GameWAD+':MTEXTURES\ZOMBY_SLEEP', 64, 64, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_ZOMBY_GO', GameWAD+':MTEXTURES\ZOMBY_GO', 64, 64, 4); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_ZOMBY_DIE', GameWAD+':MTEXTURES\ZOMBY_DIE', 64, 64, 6); - g_Game_StepLoading(6); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_ZOMBY_MESS', GameWAD+':MTEXTURES\ZOMBY_MESS', 64, 64, 9); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_ZOMBY_ATTACK', GameWAD+':MTEXTURES\ZOMBY_ATTACK', 64, 64, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_ZOMBY_ATTACK_L', GameWAD+':MTEXTURES\ZOMBY_ATTACK_L', 64, 64, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_ZOMBY_PAIN', GameWAD+':MTEXTURES\ZOMBY_PAIN', 64, 64, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SERG_SLEEP', GameWAD+':MTEXTURES\SERG_SLEEP', 64, 64, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SERG_GO', GameWAD+':MTEXTURES\SERG_GO', 64, 64, 4); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SERG_DIE', GameWAD+':MTEXTURES\SERG_DIE', 64, 64, 5); - g_Game_StepLoading(13); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SERG_MESS', GameWAD+':MTEXTURES\SERG_MESS', 64, 64, 9); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SERG_ATTACK', GameWAD+':MTEXTURES\SERG_ATTACK', 64, 64, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SERG_ATTACK_L', GameWAD+':MTEXTURES\SERG_ATTACK_L', 64, 64, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SERG_PAIN', GameWAD+':MTEXTURES\SERG_PAIN', 64, 64, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_MAN_SLEEP', GameWAD+':MTEXTURES\MAN_SLEEP', 64, 64, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_MAN_GO', GameWAD+':MTEXTURES\MAN_GO', 64, 64, 4); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_MAN_DIE', GameWAD+':MTEXTURES\MAN_DIE', 64, 64, 7); - g_Game_StepLoading(20); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_MAN_MESS', GameWAD+':MTEXTURES\MAN_MESS', 64, 64, 9); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_MAN_ATTACK', GameWAD+':MTEXTURES\MAN_ATTACK', 64, 64, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_MAN_PAIN', GameWAD+':MTEXTURES\MAN_PAIN', 64, 64, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CGUN_SLEEP', GameWAD+':MTEXTURES\CGUN_SLEEP', 64, 64, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CGUN_SLEEP_L', GameWAD+':MTEXTURES\CGUN_SLEEP_L', 64, 64, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CGUN_GO', GameWAD+':MTEXTURES\CGUN_GO', 64, 64, 4); - g_Game_StepLoading(26); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CGUN_GO_L', GameWAD+':MTEXTURES\CGUN_GO_L', 64, 64, 4); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CGUN_DIE', GameWAD+':MTEXTURES\CGUN_DIE', 64, 64, 7); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CGUN_MESS', GameWAD+':MTEXTURES\CGUN_MESS', 64, 64, 6); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CGUN_ATTACK', GameWAD+':MTEXTURES\CGUN_ATTACK', 64, 64, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CGUN_ATTACK_L', GameWAD+':MTEXTURES\CGUN_ATTACK_L', 64, 64, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CGUN_PAIN', GameWAD+':MTEXTURES\CGUN_PAIN', 64, 64, 1); - g_Game_StepLoading(32); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CGUN_PAIN_L', GameWAD+':MTEXTURES\CGUN_PAIN_L', 64, 64, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_IMP_SLEEP', GameWAD+':MTEXTURES\IMP_SLEEP', 64, 64, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_IMP_GO', GameWAD+':MTEXTURES\IMP_GO', 64, 64, 4); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_IMP_DIE', GameWAD+':MTEXTURES\IMP_DIE', 64, 64, 5); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_IMP_MESS', GameWAD+':MTEXTURES\IMP_MESS', 64, 64, 8); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_IMP_ATTACK', GameWAD+':MTEXTURES\IMP_ATTACK', 64, 64, 3); - g_Game_StepLoading(38); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_IMP_PAIN', GameWAD+':MTEXTURES\IMP_PAIN', 64, 64, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_DEMON_SLEEP', GameWAD+':MTEXTURES\DEMON_SLEEP', 64, 64, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_DEMON_GO', GameWAD+':MTEXTURES\DEMON_GO', 64, 64, 4); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_DEMON_DIE', GameWAD+':MTEXTURES\DEMON_DIE', 64, 64, 6); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_DEMON_ATTACK', GameWAD+':MTEXTURES\DEMON_ATTACK', 64, 64, 3); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_DEMON_PAIN', GameWAD+':MTEXTURES\DEMON_PAIN', 64, 64, 1); - g_Game_StepLoading(44); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SOUL_SLEEP', GameWAD+':MTEXTURES\SOUL_SLEEP', 64, 64, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SOUL_GO', GameWAD+':MTEXTURES\SOUL_GO', 64, 64, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SOUL_PAIN', GameWAD+':MTEXTURES\SOUL_PAIN', 64, 64, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SOUL_ATTACK', GameWAD+':MTEXTURES\SOUL_ATTACK', 64, 64, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SOUL_DIE', GameWAD+':MTEXTURES\SOUL_DIE', 128, 128, 7); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_FISH_SLEEP', GameWAD+':MTEXTURES\FISH_SLEEP', 32, 32, 2); - g_Game_StepLoading(50); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_FISH_GO', GameWAD+':MTEXTURES\FISH_GO', 32, 32, 4); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_FISH_PAIN', GameWAD+':MTEXTURES\FISH_PAIN', 32, 32, 3); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_FISH_ATTACK', GameWAD+':MTEXTURES\FISH_ATTACK', 32, 32, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_FISH_DIE', GameWAD+':MTEXTURES\FISH_DIE', 32, 32, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SPIDER_SLEEP', GameWAD+':MTEXTURES\SPIDER_SLEEP', 256, 128, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SPIDER_GO', GameWAD+':MTEXTURES\SPIDER_GO', 256, 128, 6); - g_Game_StepLoading(56); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SPIDER_PAIN', GameWAD+':MTEXTURES\SPIDER_PAIN', 256, 128, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SPIDER_PAIN_L', GameWAD+':MTEXTURES\SPIDER_PAIN_L', 256, 128, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SPIDER_ATTACK', GameWAD+':MTEXTURES\SPIDER_ATTACK', 256, 128, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SPIDER_DIE', GameWAD+':MTEXTURES\SPIDER_DIE', 256, 128, 10); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_BSP_SLEEP', GameWAD+':MTEXTURES\BSP_SLEEP', 128, 64, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_BSP_GO', GameWAD+':MTEXTURES\BSP_GO', 128, 64, 6); - g_Game_StepLoading(62); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_BSP_PAIN', GameWAD+':MTEXTURES\BSP_PAIN', 128, 64, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_BSP_PAIN_L', GameWAD+':MTEXTURES\BSP_PAIN_L', 128, 64, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_BSP_ATTACK', GameWAD+':MTEXTURES\BSP_ATTACK', 128, 64, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_BSP_DIE', GameWAD+':MTEXTURES\BSP_DIE', 128, 64, 7); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CACO_SLEEP', GameWAD+':MTEXTURES\CACO_SLEEP', 128, 128, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CACO_GO', GameWAD+':MTEXTURES\CACO_GO', 128, 128, 1); - g_Game_StepLoading(68); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CACO_PAIN', GameWAD+':MTEXTURES\CACO_PAIN', 128, 128, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CACO_ATTACK', GameWAD+':MTEXTURES\CACO_ATTACK', 128, 128, 6); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CACO_DIE', GameWAD+':MTEXTURES\CACO_DIE', 128, 128, 7); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_PAIN_SLEEP', GameWAD+':MTEXTURES\PAIN_SLEEP', 128, 128, 4); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_PAIN_GO', GameWAD+':MTEXTURES\PAIN_GO', 128, 128, 4); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_PAIN_PAIN', GameWAD+':MTEXTURES\PAIN_PAIN', 128, 128, 1); - g_Game_StepLoading(74); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_PAIN_ATTACK', GameWAD+':MTEXTURES\PAIN_ATTACK', 128, 128, 4); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_PAIN_DIE', GameWAD+':MTEXTURES\PAIN_DIE', 128, 128, 7); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_BARON_SLEEP', GameWAD+':MTEXTURES\BARON_SLEEP', 128, 128, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_BARON_SLEEP_L', GameWAD+':MTEXTURES\BARON_SLEEP_L', 128, 128, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_BARON_GO', GameWAD+':MTEXTURES\BARON_GO', 128, 128, 4); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_BARON_PAIN', GameWAD+':MTEXTURES\BARON_PAIN', 128, 128, 1); - g_Game_StepLoading(80); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_BARON_PAIN_L', GameWAD+':MTEXTURES\BARON_PAIN_L', 128, 128, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_BARON_ATTACK', GameWAD+':MTEXTURES\BARON_ATTACK', 128, 128, 3); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_BARON_ATTACK_L', GameWAD+':MTEXTURES\BARON_ATTACK_L', 128, 128, 3); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_BARON_DIE', GameWAD+':MTEXTURES\BARON_DIE', 128, 128, 7); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_KNIGHT_SLEEP', GameWAD+':MTEXTURES\KNIGHT_SLEEP', 128, 128, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_KNIGHT_SLEEP_L', GameWAD+':MTEXTURES\KNIGHT_SLEEP_L', 128, 128, 2); - g_Game_StepLoading(86); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_KNIGHT_GO', GameWAD+':MTEXTURES\KNIGHT_GO', 128, 128, 4); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_KNIGHT_PAIN', GameWAD+':MTEXTURES\KNIGHT_PAIN', 128, 128, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_KNIGHT_PAIN_L', GameWAD+':MTEXTURES\KNIGHT_PAIN_L', 128, 128, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_KNIGHT_ATTACK', GameWAD+':MTEXTURES\KNIGHT_ATTACK', 128, 128, 3); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_KNIGHT_ATTACK_L', GameWAD+':MTEXTURES\KNIGHT_ATTACK_L', 128, 128, 3); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_KNIGHT_DIE', GameWAD+':MTEXTURES\KNIGHT_DIE', 128, 128, 7); - g_Game_StepLoading(92); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_MANCUB_SLEEP', GameWAD+':MTEXTURES\MANCUB_SLEEP', 128, 128, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_MANCUB_GO', GameWAD+':MTEXTURES\MANCUB_GO', 128, 128, 6); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_MANCUB_PAIN', GameWAD+':MTEXTURES\MANCUB_PAIN', 128, 128, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_MANCUB_ATTACK', GameWAD+':MTEXTURES\MANCUB_ATTACK', 128, 128, 3); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_MANCUB_DIE', GameWAD+':MTEXTURES\MANCUB_DIE', 128, 128, 10); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SKEL_SLEEP', GameWAD+':MTEXTURES\SKEL_SLEEP', 128, 128, 2); - g_Game_StepLoading(98); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SKEL_SLEEP_L', GameWAD+':MTEXTURES\SKEL_SLEEP_L', 128, 128, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SKEL_GO', GameWAD+':MTEXTURES\SKEL_GO', 128, 128, 6); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SKEL_PAIN', GameWAD+':MTEXTURES\SKEL_PAIN', 128, 128, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SKEL_PAIN_L', GameWAD+':MTEXTURES\SKEL_PAIN_L', 128, 128, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SKEL_ATTACK', GameWAD+':MTEXTURES\SKEL_ATTACK', 128, 128, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SKEL_ATTACK_L', GameWAD+':MTEXTURES\SKEL_ATTACK_L', 128, 128, 2); - g_Game_StepLoading(104); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SKEL_ATTACK2', GameWAD+':MTEXTURES\SKEL_ATTACK2', 128, 128, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SKEL_ATTACK2_L', GameWAD+':MTEXTURES\SKEL_ATTACK2_L', 128, 128, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_SKEL_DIE', GameWAD+':MTEXTURES\SKEL_DIE', 128, 128, 5); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_VILE_SLEEP', GameWAD+':MTEXTURES\VILE_SLEEP', 128, 128, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_VILE_SLEEP_L', GameWAD+':MTEXTURES\VILE_SLEEP_L', 128, 128, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_VILE_GO', GameWAD+':MTEXTURES\VILE_GO', 128, 128, 6); - g_Game_StepLoading(110); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_VILE_PAIN', GameWAD+':MTEXTURES\VILE_PAIN', 128, 128, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_VILE_PAIN_L', GameWAD+':MTEXTURES\VILE_PAIN_L', 128, 128, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_VILE_ATTACK', GameWAD+':MTEXTURES\VILE_ATTACK', 128, 128, 10); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_VILE_ATTACK_L', GameWAD+':MTEXTURES\VILE_ATTACK_L', 128, 128, 10); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_VILE_ATTACK2', GameWAD+':MTEXTURES\VILE_ATTACK2', 128, 128, 3); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_VILE_ATTACK2_L', GameWAD+':MTEXTURES\VILE_ATTACK2_L', 128, 128, 3); - g_Game_StepLoading(116); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_VILE_DIE', GameWAD+':MTEXTURES\VILE_DIE', 128, 128, 9); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_ROBO_SLEEP', GameWAD+':MTEXTURES\ROBO_SLEEP', 128, 128, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_ROBO_GO', GameWAD+':MTEXTURES\ROBO_GO', 128, 128, 12); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_ROBO_ATTACK', GameWAD+':MTEXTURES\ROBO_ATTACK', 128, 128, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_ROBO_ATTACK2', GameWAD+':MTEXTURES\ROBO_ATTACK2', 128, 128, 4); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_ROBO_DIE', GameWAD+':MTEXTURES\ROBO_DIE', 128, 128, 1); - g_Game_StepLoading(122); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CYBER_SLEEP', GameWAD+':MTEXTURES\CYBER_SLEEP', 128, 128, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CYBER_SLEEP_L', GameWAD+':MTEXTURES\CYBER_SLEEP_L', 128, 128, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CYBER_GO', GameWAD+':MTEXTURES\CYBER_GO', 128, 128, 4); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CYBER_GO_L', GameWAD+':MTEXTURES\CYBER_GO_L', 128, 128, 4); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CYBER_PAIN', GameWAD+':MTEXTURES\CYBER_PAIN', 128, 128, 1); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CYBER_PAIN_L', GameWAD+':MTEXTURES\CYBER_PAIN_L', 128, 128, 1); - g_Game_StepLoading(128); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CYBER_ATTACK', GameWAD+':MTEXTURES\CYBER_ATTACK', 128, 128, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CYBER_ATTACK_L', GameWAD+':MTEXTURES\CYBER_ATTACK_L', 128, 128, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CYBER_ATTACK2', GameWAD+':MTEXTURES\CYBER_ATTACK2', 128, 128, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CYBER_ATTACK2_L', GameWAD+':MTEXTURES\CYBER_ATTACK2_L', 128, 128, 2); - g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CYBER_DIE', GameWAD+':MTEXTURES\CYBER_DIE', 128, 128, 9); g_Game_StepLoading(133); g_Game_SetLoadingText(_lc[I_LOAD_MONSTER_SOUNDS], 0, False); @@ -1084,140 +971,6 @@ procedure g_Monsters_FreeData(); begin e_WriteLog('Releasing monsters data...', TMsgType.Notify); - g_Frames_DeleteByName('FRAMES_MONSTER_BARREL_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_BARREL_PAIN'); - g_Frames_DeleteByName('FRAMES_MONSTER_BARREL_DIE'); - g_Frames_DeleteByName('FRAMES_MONSTER_ZOMBY_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_ZOMBY_GO'); - g_Frames_DeleteByName('FRAMES_MONSTER_ZOMBY_DIE'); - g_Frames_DeleteByName('FRAMES_MONSTER_ZOMBY_MESS'); - g_Frames_DeleteByName('FRAMES_MONSTER_ZOMBY_ATTACK'); - g_Frames_DeleteByName('FRAMES_MONSTER_ZOMBY_ATTACK_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_ZOMBY_PAIN'); - g_Frames_DeleteByName('FRAMES_MONSTER_SERG_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_SERG_GO'); - g_Frames_DeleteByName('FRAMES_MONSTER_SERG_DIE'); - g_Frames_DeleteByName('FRAMES_MONSTER_SERG_MESS'); - g_Frames_DeleteByName('FRAMES_MONSTER_SERG_ATTACK'); - g_Frames_DeleteByName('FRAMES_MONSTER_SERG_ATTACK_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_SERG_PAIN'); - g_Frames_DeleteByName('FRAMES_MONSTER_MAN_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_MAN_GO'); - g_Frames_DeleteByName('FRAMES_MONSTER_MAN_DIE'); - g_Frames_DeleteByName('FRAMES_MONSTER_MAN_MESS'); - g_Frames_DeleteByName('FRAMES_MONSTER_MAN_ATTACK'); - g_Frames_DeleteByName('FRAMES_MONSTER_MAN_PAIN'); - g_Frames_DeleteByName('FRAMES_MONSTER_CGUN_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_CGUN_SLEEP_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_CGUN_GO'); - g_Frames_DeleteByName('FRAMES_MONSTER_CGUN_GO_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_CGUN_DIE'); - g_Frames_DeleteByName('FRAMES_MONSTER_CGUN_MESS'); - g_Frames_DeleteByName('FRAMES_MONSTER_CGUN_ATTACK'); - g_Frames_DeleteByName('FRAMES_MONSTER_CGUN_ATTACK_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_CGUN_PAIN'); - g_Frames_DeleteByName('FRAMES_MONSTER_CGUN_PAIN_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_IMP_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_IMP_GO'); - g_Frames_DeleteByName('FRAMES_MONSTER_IMP_DIE'); - g_Frames_DeleteByName('FRAMES_MONSTER_IMP_MESS'); - g_Frames_DeleteByName('FRAMES_MONSTER_IMP_ATTACK'); - g_Frames_DeleteByName('FRAMES_MONSTER_IMP_PAIN'); - g_Frames_DeleteByName('FRAMES_MONSTER_DEMON_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_DEMON_GO'); - g_Frames_DeleteByName('FRAMES_MONSTER_DEMON_DIE'); - g_Frames_DeleteByName('FRAMES_MONSTER_DEMON_ATTACK'); - g_Frames_DeleteByName('FRAMES_MONSTER_DEMON_PAIN'); - g_Frames_DeleteByName('FRAMES_MONSTER_SOUL_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_SOUL_GO'); - g_Frames_DeleteByName('FRAMES_MONSTER_SOUL_PAIN'); - g_Frames_DeleteByName('FRAMES_MONSTER_SOUL_ATTACK'); - g_Frames_DeleteByName('FRAMES_MONSTER_SOUL_DIE'); - g_Frames_DeleteByName('FRAMES_MONSTER_FISH_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_FISH_GO'); - g_Frames_DeleteByName('FRAMES_MONSTER_FISH_PAIN'); - g_Frames_DeleteByName('FRAMES_MONSTER_FISH_ATTACK'); - g_Frames_DeleteByName('FRAMES_MONSTER_FISH_DIE'); - g_Frames_DeleteByName('FRAMES_MONSTER_SPIDER_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_SPIDER_GO'); - g_Frames_DeleteByName('FRAMES_MONSTER_SPIDER_PAIN'); - g_Frames_DeleteByName('FRAMES_MONSTER_SPIDER_PAIN_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_SPIDER_ATTACK'); - g_Frames_DeleteByName('FRAMES_MONSTER_SPIDER_DIE'); - g_Frames_DeleteByName('FRAMES_MONSTER_BSP_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_BSP_GO'); - g_Frames_DeleteByName('FRAMES_MONSTER_BSP_PAIN'); - g_Frames_DeleteByName('FRAMES_MONSTER_BSP_PAIN_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_BSP_ATTACK'); - g_Frames_DeleteByName('FRAMES_MONSTER_BSP_DIE'); - g_Frames_DeleteByName('FRAMES_MONSTER_CACO_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_CACO_GO'); - g_Frames_DeleteByName('FRAMES_MONSTER_CACO_PAIN'); - g_Frames_DeleteByName('FRAMES_MONSTER_CACO_ATTACK'); - g_Frames_DeleteByName('FRAMES_MONSTER_CACO_DIE'); - g_Frames_DeleteByName('FRAMES_MONSTER_PAIN_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_PAIN_GO'); - g_Frames_DeleteByName('FRAMES_MONSTER_PAIN_PAIN'); - g_Frames_DeleteByName('FRAMES_MONSTER_PAIN_ATTACK'); - g_Frames_DeleteByName('FRAMES_MONSTER_PAIN_DIE'); - g_Frames_DeleteByName('FRAMES_MONSTER_BARON_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_BARON_SLEEP_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_BARON_GO'); - g_Frames_DeleteByName('FRAMES_MONSTER_BARON_PAIN'); - g_Frames_DeleteByName('FRAMES_MONSTER_BARON_PAIN_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_BARON_ATTACK'); - g_Frames_DeleteByName('FRAMES_MONSTER_BARON_ATTACK_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_BARON_DIE'); - g_Frames_DeleteByName('FRAMES_MONSTER_KNIGHT_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_KNIGHT_SLEEP_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_KNIGHT_GO'); - g_Frames_DeleteByName('FRAMES_MONSTER_KNIGHT_PAIN'); - g_Frames_DeleteByName('FRAMES_MONSTER_KNIGHT_PAIN_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_KNIGHT_ATTACK'); - g_Frames_DeleteByName('FRAMES_MONSTER_KNIGHT_ATTACK_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_KNIGHT_DIE'); - g_Frames_DeleteByName('FRAMES_MONSTER_MANCUB_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_MANCUB_GO'); - g_Frames_DeleteByName('FRAMES_MONSTER_MANCUB_PAIN'); - g_Frames_DeleteByName('FRAMES_MONSTER_MANCUB_ATTACK'); - g_Frames_DeleteByName('FRAMES_MONSTER_MANCUB_DIE'); - g_Frames_DeleteByName('FRAMES_MONSTER_SKEL_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_SKEL_SLEEP_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_SKEL_GO'); - g_Frames_DeleteByName('FRAMES_MONSTER_SKEL_PAIN'); - g_Frames_DeleteByName('FRAMES_MONSTER_SKEL_PAIN_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_SKEL_ATTACK'); - g_Frames_DeleteByName('FRAMES_MONSTER_SKEL_ATTACK_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_SKEL_ATTACK2'); - g_Frames_DeleteByName('FRAMES_MONSTER_SKEL_ATTACK2_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_SKEL_DIE'); - g_Frames_DeleteByName('FRAMES_MONSTER_VILE_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_VILE_SLEEP_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_VILE_GO'); - g_Frames_DeleteByName('FRAMES_MONSTER_VILE_PAIN'); - g_Frames_DeleteByName('FRAMES_MONSTER_VILE_PAIN_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_VILE_ATTACK'); - g_Frames_DeleteByName('FRAMES_MONSTER_VILE_ATTACK_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_VILE_ATTACK2'); - g_Frames_DeleteByName('FRAMES_MONSTER_VILE_ATTACK2_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_VILE_DIE'); - g_Frames_DeleteByName('FRAMES_MONSTER_ROBO_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_ROBO_GO'); - g_Frames_DeleteByName('FRAMES_MONSTER_ROBO_ATTACK'); - g_Frames_DeleteByName('FRAMES_MONSTER_ROBO_ATTACK2'); - g_Frames_DeleteByName('FRAMES_MONSTER_ROBO_DIE'); - g_Frames_DeleteByName('FRAMES_MONSTER_CYBER_SLEEP'); - g_Frames_DeleteByName('FRAMES_MONSTER_CYBER_SLEEP_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_CYBER_GO'); - g_Frames_DeleteByName('FRAMES_MONSTER_CYBER_GO_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_CYBER_PAIN'); - g_Frames_DeleteByName('FRAMES_MONSTER_CYBER_PAIN_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_CYBER_ATTACK'); - g_Frames_DeleteByName('FRAMES_MONSTER_CYBER_ATTACK_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_CYBER_ATTACK2'); - g_Frames_DeleteByName('FRAMES_MONSTER_CYBER_ATTACK2_L'); - g_Frames_DeleteByName('FRAMES_MONSTER_CYBER_DIE'); - g_Sound_Delete('SOUND_MONSTER_BARREL_DIE'); g_Sound_Delete('SOUND_MONSTER_PAIN'); @@ -1342,10 +1095,10 @@ var begin result := nil; - // Íåò òàêîãî ìîíñòðà + // Нет такого монстра if (MonsterType > MONSTER_MAN) or (MonsterType = 0) then exit; - // Ñîáëþäàåì îãðàíè÷åíèå Lost_Soul'îâ + // Соблюдаем ограничение Lost_Soul'ов if MonsterType = MONSTER_SOUL then begin if soulcount > MAX_SOUL then exit; @@ -1361,7 +1114,7 @@ begin uidMap[mon.FUID] := mon; - // Íàñòðàèâàåì ïîëîæåíèå + // Настраиваем положение with mon do begin if AdjCoord then @@ -1395,7 +1148,7 @@ begin if gMonsters = nil then Exit; - // Ïðèêîëèñò ñìååòñÿ íàä ñìåðòüþ èãðîêà: + // Приколист смеется над смертью игрока: h := High(gMonsters); for a := 0 to h do begin @@ -1430,7 +1183,7 @@ procedure g_Monsters_Update(); var a: Integer; begin - // Öåëåóêàçàòåëü + // Целеуказатель if gTime mod (GAME_TICK*2) = 0 then begin pt_x := pt_x+pt_xs; @@ -1439,7 +1192,7 @@ begin if abs(pt_y) > 100 then pt_ys := -pt_ys; end; - gMon := True; // Äëÿ ðàáîòû BlockMon'à + gMon := True; // Для работы BlockMon'а if gmon_debug_think or gmon_debug_one_think_step then begin @@ -1465,38 +1218,6 @@ begin gMon := False; end; -procedure g_Monsters_Draw(); -var - a: Integer; -begin - if gMonsters <> nil then - begin - for a := 0 to High(gMonsters) do - begin - if (gMonsters[a] <> nil) then gMonsters[a].Draw(); - end; - end; -end; - -procedure g_Monsters_DrawHealth(); -var - a: Integer; - fW, fH: Byte; -begin - if gMonsters = nil then Exit; - e_TextureFontGetSize(gStdFont, fW, fH); - - for a := 0 to High(gMonsters) do - begin - if gMonsters[a] <> nil then - begin - e_TextureFontPrint(gMonsters[a].FObj.X + gMonsters[a].FObj.Rect.X, - gMonsters[a].FObj.Y + gMonsters[a].FObj.Rect.Y + gMonsters[a].FObj.Rect.Height - fH, - IntToStr(gMonsters[a].FHealth), gStdFont); - end; - end; -end; - function g_Monsters_ByUID (UID: Word): TMonster; begin result := uidMap[UID]; @@ -1506,32 +1227,32 @@ procedure g_Monsters_SaveState (st: TStream); var count, i: Integer; begin - // Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ ìîíñòðîâ + // Считаем количество существующих монстров count := 0; for i := 0 to High(gMonsters) do begin if (gMonsters[i] <> nil) and (gMonsters[i].FMonsterType <> MONSTER_NONE) then count += 1; end; - // Ñîõðàíÿåì èíôîðìàöèþ öåëåóêàçàòåëÿ + // Сохраняем информацию целеуказателя utils.writeInt(st, LongInt(pt_x)); utils.writeInt(st, LongInt(pt_xs)); utils.writeInt(st, LongInt(pt_y)); utils.writeInt(st, LongInt(pt_ys)); - // Êîëè÷åñòâî ìîíñòðîâ + // Количество монстров utils.writeInt(st, LongInt(count)); if (count = 0) then exit; - // Ñîõðàíÿåì ìîíñòðîâ + // Сохраняем монстров for i := 0 to High(gMonsters) do begin if (gMonsters[i] <> nil) and (gMonsters[i].FMonsterType <> MONSTER_NONE) then begin - // Òèï ìîíñòðà + // Тип монстра utils.writeInt(st, Byte(gMonsters[i].MonsterType)); - // Ñîõðàíÿåì äàííûå ìîíñòðà: + // Сохраняем данные монстра: gMonsters[i].SaveState(st); end; end; @@ -1548,27 +1269,27 @@ begin g_Monsters_Free(false); - // Çàãðóæàåì èíôîðìàöèþ öåëåóêàçàòåëÿ + // Загружаем информацию целеуказателя pt_x := utils.readLongInt(st); pt_xs := utils.readLongInt(st); pt_y := utils.readLongInt(st); pt_ys := utils.readLongInt(st); - // Êîëè÷åñòâî ìîíñòðîâ + // Количество монстров count := utils.readLongInt(st); if (count = 0) then exit; if (count < 0) or (count > 1024*1024) then raise XStreamError.Create('invalid monster count'); - // Çàãðóæàåì ìîíñòðîâ + // Загружаем монстров for a := 0 to count-1 do begin - // Òèï ìîíñòðà + // Тип монстра b := utils.readByte(st); - // Ñîçäàåì ìîíñòðà + // Создаем монстра mon := g_Monsters_Create(b, 0, 0, TDirection.D_LEFT); if (mon = nil) then raise XStreamError.Create('g_Monsters_LoadState: ID = -1 (can''t create)'); - // Çàãðóæàåì äàííûå ìîíñòðà + // Загружаем данные монстра mon.LoadState(st); end; end; @@ -1874,11 +1595,7 @@ begin end; constructor TMonster.Create(MonsterType: Byte; aID: Integer; ForcedUID: Integer = -1); -var - a: Integer; - FramesID: DWORD = 0; - s: String; - res: Boolean; + var a: Integer; begin if ForcedUID < 0 then FUID := g_CreateUID(UID_MONSTER) @@ -1937,67 +1654,13 @@ begin end; SetLength(FAnim, Length(ANIMTABLE)); - - for a := 0 to High(FAnim) do + for a := ANIM_SLEEP to ANIM_PAIN do begin - FAnim[a, TDirection.D_LEFT] := nil; - FAnim[a, TDirection.D_RIGHT] := nil; + FAnim[a, TDirection.D_RIGHT] := TAnimationState.Create(ANIMTABLE[a].loop, MONSTER_ANIMTABLE[MonsterType].AnimSpeed[a], MONSTER_ANIMTABLE[MonsterType].AnimCount[a]); + FAnim[a, TDirection.D_LEFT] := TAnimationState.Create(ANIMTABLE[a].loop, MONSTER_ANIMTABLE[MonsterType].AnimSpeed[a], MONSTER_ANIMTABLE[MonsterType].AnimCount[a]); end; - - for a := ANIM_SLEEP to ANIM_PAIN do - if (ANIMTABLE[a].name <> '') and - (MONSTER_ANIMTABLE[MonsterType].AnimSpeed[a] <> 0) then - begin - s := 'FRAMES_MONSTER_'+MONSTERTABLE[MonsterType].Name+ - '_'+ANIMTABLE[a].name; - - res := g_Frames_Exists(s); - - if res then - res := g_Frames_Get(FramesID, s); - - // Åñëè íåò òàêîé àíèìàöèè, òî ïðîáóåì çàìåíèòü åå íà àíèìàöèþ ñìåðòè: - if (not res) then - begin - // Çàìåíÿåì òîëüêî ANIM_MESS íà ANIM_DIE: - if a <> ANIM_MESS then - Continue; - - if g_Frames_Get(FramesID, 'FRAMES_MONSTER_'+MONSTERTABLE[MonsterType].Name+ - '_'+ANIMTABLE[ANIM_DIE].name) then - begin - FAnim[a, TDirection.D_RIGHT] := TAnimation.Create(FramesID, ANIMTABLE[ANIM_DIE].loop, - MONSTER_ANIMTABLE[MonsterType].AnimSpeed[ANIM_DIE]); - FAnim[a, TDirection.D_LEFT] := TAnimation.Create(FramesID, ANIMTABLE[ANIM_DIE].loop, - MONSTER_ANIMTABLE[MonsterType].AnimSpeed[ANIM_DIE]); - Continue; - end; - end; - - FAnim[a, TDirection.D_RIGHT] := TAnimation.Create(FramesID, ANIMTABLE[a].loop, - MONSTER_ANIMTABLE[MonsterType].AnimSpeed[a]); - - // Åñëè åñòü îòäåëüíàÿ ëåâàÿ àíèìàöèÿ - çàãðóæàåì: - if MONSTER_ANIMTABLE[MonsterType].LeftAnim then - begin - s := 'FRAMES_MONSTER_'+MONSTERTABLE[MonsterType].Name+ - '_'+ANIMTABLE[a].name+'_L'; - if g_Frames_Exists(s) then - g_Frames_Get(FramesID, s); - end; - - FAnim[a, TDirection.D_LEFT] := TAnimation.Create(FramesID, ANIMTABLE[a].loop, - MONSTER_ANIMTABLE[MonsterType].AnimSpeed[a]); - end; - -// Äëÿ êîëäóíà çàãðóæàåì òàêæå àíèìàöèþ îãíÿ: if MonsterType = MONSTER_VILE then - begin - g_Frames_Get(FramesID, 'FRAMES_FIRE'); - vilefire := TAnimation.Create(FramesID, True, 2); - end - else - vilefire := nil; + vilefire := TAnimationState.Create(True, 2, 0); // !!! len end; function TMonster.Damage(aDamage: Word; VelX, VelY: Integer; SpawnerUID: Word; t: Byte): Boolean; @@ -2007,14 +1670,14 @@ var begin Result := False; -// Ìîíñòð ñòàòè÷åí ïîêà èäåò warmup +// Монстр статичен пока идет warmup if (gLMSRespawn > LMS_RESPAWN_NONE) then exit; -// Óìèðàåò, óìåð èëè âîñêðåøàåòñÿ => óðîí äåëàòü íåêîìó: +// Умирает, умер или воскрешается => урон делать некому: if (FState = MONSTATE_DEAD) or (FState = MONSTATE_DIE) or (FState = MONSTATE_REVIVE) then Exit; -// Ðûáó â âîäå áüåò òîêîì => ïàíèêà áåç óðîíà: +// Рыбу в воде бьет током => паника без урона: if (t = HIT_ELECTRO) and (FMonsterType = MONSTER_FISH) and g_Game_IsServer then begin FSleep := 20; @@ -2024,38 +1687,38 @@ begin Exit; end; -// Àð÷è íå ãîðÿò, ÷åðåïà óæå ãîðÿò +// Арчи не горят, черепа уже горят if (t = HIT_FLAME) and (FMonsterType in [MONSTER_VILE, MONSTER_SOUL]) then begin - // Ïðîñíóòüñÿ âñå-òàêè ñòîèò + // Проснуться все-таки стоит if FState = MONSTATE_SLEEP then SetState(MONSTATE_GO); Exit; end; -// Ëîâóøêà óáèâàåò ñðàçó: +// Ловушка убивает сразу: if t = HIT_TRAP then FHealth := -100; -// Ðîáîòó óðîíà íåò: +// Роботу урона нет: if FMonsterType = MONSTER_ROBO then aDamage := 0; -// Íàíîñèì óðîí: +// Наносим урон: if g_Game_IsServer then Dec(FHealth, aDamage); -// Óñèëèâàåì áîëü ìîíñòðà îò óðîíà: +// Усиливаем боль монстра от урона: if FPain = 0 then FPain := 3; FPain := FPain+aDamage; -// Åñëè áîëü ñóùåñòâåííàÿ, òî ìåíÿåì ñîñòîÿíèå íà áîëåâîå: +// Если боль существенная, то меняем состояние на болевое: if FState <> MONSTATE_PAIN then if (FPain >= MONSTERTABLE[FMonsterType].MinPain) and (FMonsterType <> MONSTER_BARREL) then SetState(MONSTATE_PAIN); -// Åñëè ðàçðåøåíà êðîâü - ñîçäàåì áðûçãè êðîâè: +// Если разрешена кровь - создаем брызги крови: if (gBloodCount > 0) then begin c := Min(aDamage, 200); @@ -2070,17 +1733,17 @@ begin end; end; -// Òåïåðü öåëü - óäàðèâøèé, åñëè òîëüêî íå ñàì ñåáÿ: +// Теперь цель - ударивший, если только не сам себя: if (SpawnerUID <> FUID) and (BehaviourDamage(SpawnerUID, FBehaviour, FMonsterType)) then begin FTargetUID := SpawnerUID; FTargetTime := 0; end; -// Çäîðîâüå çàêîí÷èëîñü: +// Здоровье закончилось: if FHealth <= 0 then begin - // Åñëè ýòî íå áî÷êà è óáèë èãðîê, òî åìó +1: + // Если это не бочка и убил игрок, то ему +1: if (FMonsterType <> MONSTER_BARREL) then begin if (g_GetUIDType(SpawnerUID) = UID_PLAYER) then @@ -2103,7 +1766,7 @@ begin end; end; - // Âûáèðàåì ëóò: + // Выбираем лут: case FMonsterType of MONSTER_ZOMBY: c := ITEM_AMMO_BULLETS; MONSTER_SERG: c := ITEM_WEAPON_SHOTGUN1; @@ -2112,7 +1775,7 @@ begin else c := 0; end; - // Áðîñàåì ëóò: + // Бросаем лут: if c <> 0 then begin it := g_Items_Create(FObj.X + (FObj.Rect.Width div 2), @@ -2126,10 +1789,10 @@ begin MH_SEND_ItemSpawn(True, it); end; - // Òðóï äàëüøå íå èäåò: + // Труп дальше не идет: FObj.Vel.X := 0; - // Ó òðóïà ðàçìåðû ìåíüøå: + // У трупа размеры меньше: if (FMonsterType <> MONSTER_FISH) and (FMonsterType <> MONSTER_PAIN) then begin FObj.Rect.Y := FObj.Rect.Y + FObj.Rect.Height-12; @@ -2137,7 +1800,7 @@ begin positionChanged(); end; - // Óðîí áûë ñèëüíûì => ñëàáûå - â êàøó: + // Урон был сильным => слабые - в кашу: if (FHealth <= -30) and ((FMonsterType = MONSTER_IMP) or (FMonsterType = MONSTER_ZOMBY) or (FMonsterType = MONSTER_SERG) or (FMonsterType = MONSTER_CGUN) or @@ -2152,14 +1815,14 @@ begin SetState(MONSTATE_DIE); end; - // Àêòèâèðîâàòü òðèããåðû, æäóùèå ñìåðòè ýòîãî ìîíñòðà: + // Активировать триггеры, ждущие смерти этого монстра: if g_Game_IsServer then ActivateTriggers(); FHealth := 0; end else if FState = MONSTATE_SLEEP then - begin // Ñïàë, ðàçáóäèëè íåñìåðòåëüíûì óäàðîì: + begin // Спал, разбудили несмертельным ударом: FPain := MONSTERTABLE[FMonsterType].Pain; SetState(MONSTATE_GO); end; @@ -2220,89 +1883,6 @@ begin inherited Destroy(); end; -procedure TMonster.Draw(); -var - m: TMirrorType; - dx, dy, c, fX, fY: Integer; - o: TObj; -begin - //e_CharFont_Print(gMenuSmallFont, Obj.X+Obj.Rect.X, Obj.Y+Obj.Rect.Y, 'TYPE: '+IntToStr(FMonsterType)); - //e_CharFont_Print(gMenuSmallFont, Obj.X+Obj.Rect.X, Obj.Y+Obj.Rect.Y+16, 'STATE: '+IntToStr(FState)); - - FObj.lerp(gLerpFactor, fX, fY); - -// Åñëè êîëäóí ñòðåëÿåò, òî ðèñóåì îãîíü: - if FMonsterType = MONSTER_VILE then - if FState = MONSTATE_SHOOT then - if GetPos(FTargetUID, @o) then - vilefire.Draw(o.X+o.Rect.X+(o.Rect.Width div 2)-32, - o.Y+o.Rect.Y+o.Rect.Height-128, TMirrorType.None); - -// Íå â îáëàñòè ðèñîâàíèÿ íå ðåñóåì: -//FIXME! - if (g_dbg_scale = 1.0) then - begin - if not g_Collide(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y, FObj.Rect.Width, FObj.Rect.Height, - sX-128, sY-128, sWidth+256, sHeight+256) then - Exit; - end; - -// Ýòè ìîíñòðû, óìèðàÿ, íå îñòàâëÿþò òðóïîâ: - if FState = MONSTATE_DEAD then - case FMonsterType of - MONSTER_BARREL, MONSTER_SOUL, MONSTER_PAIN: Exit; - end; - -// Åñòü ÷òî ðèñîâàòü ïðè òåêóùåì ïîâåäåíèè: - if FAnim[FCurAnim, FDirection] <> nil then - begin - // Åñëè íåò ëåâîé àíèìàöèè èëè îíà ñîâïàäàåò ñ ïðàâîé => îòðàæàåì ïðàâóþ: - if (FDirection = TDirection.D_LEFT) and - ((not MONSTER_ANIMTABLE[FMonsterType].LeftAnim) or - (FAnim[FCurAnim, TDirection.D_LEFT].FramesID = FAnim[FCurAnim, TDirection.D_RIGHT].FramesID)) and - (FMonsterType <> MONSTER_BARREL) then - m := TMirrorType.Horizontal - else - m := TMirrorType.None; - - // Ëåâàÿ àíèìàöèÿ => ìåíÿåì ñìåùåíèå îòíîñèòåëüíî öåíòðà: - if (FDirection = TDirection.D_LEFT) and - (FMonsterType <> MONSTER_BARREL) then - begin - dx := MONSTER_ANIMTABLE[FMonsterType].AnimDeltaLeft[FCurAnim].X; - dy := MONSTER_ANIMTABLE[FMonsterType].AnimDeltaLeft[FCurAnim].Y; - - if m = TMirrorType.Horizontal then - begin // Íåò îòäåëüíîé ëåâîé àíèìàöèè - // Ðàññòîÿíèå îò êðàÿ òåêñòóðû äî êðàÿ âèçóàëüíîãî ïîëîæåíèÿ îáúåêòà íà òåêñòóðå: - c := (MONSTERTABLE[FMonsterType].Rect.X - dx) + MONSTERTABLE[FMonsterType].Rect.Width; - // Ðàññòîÿíèå îò êðàÿ õèò áîêñà äî êðàÿ âèçóàëüíîãî ïîëîæåíèÿ îáúåêòà íà òåêñòóðå: - dx := FAnim[FCurAnim, FDirection].Width - c - MONSTERTABLE[FMonsterType].Rect.X; - // Ò.ê. äâèãàòü òåêñòóðó íóæíî áóäåò â ïðîòèâîïîëîæíîì íàïðàâëåíèè: - dx := -dx; - // Ýòî çíà÷èò: dX := -frameWidth - animDeltaX + hitX + hitWidth + hitX - end; - end - else // Ïðàâàÿ àíèìàöèÿ - begin - dx := MONSTER_ANIMTABLE[FMonsterType].AnimDeltaRight[FCurAnim].X; - dy := MONSTER_ANIMTABLE[FMonsterType].AnimDeltaRight[FCurAnim].Y; - end; - - // Ðèñóåì: - FAnim[FCurAnim, FDirection].Draw(fX+dx, fY+dy, m); - end; - - if g_debug_Frames then - begin - e_DrawQuad(FObj.X+FObj.Rect.X, - FObj.Y+FObj.Rect.Y, - FObj.X+FObj.Rect.X+FObj.Rect.Width-1, - FObj.Y+FObj.Rect.Y+FObj.Rect.Height-1, - 0, 255, 0); - end; -end; - procedure TMonster.MakeBloodSimple(Count: Word); begin g_GFX_Blood(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)+8, @@ -2334,12 +1914,12 @@ procedure TMonster.SetState(State: Byte; ForceAnim: Byte = 255); var Anim: Byte; begin -// Åñëè ñîñòîÿíèå = íà÷àëè óìèðàòü, à ýòîò ìîíñòð = Lost_Soul, -// òî ñîáëþäàåì îãðàíè÷åíèå êîëè÷åñòâà Lost_Soul'îâ: +// Если состояние = начали умирать, а этот монстр = Lost_Soul, +// то соблюдаем ограничение количества Lost_Soul'ов: if (State = MONSTATE_DIE) and (MonsterType = MONSTER_SOUL) then soulcount := soulcount-1; -// Ïðèñìåðòè - íåëüçÿ ñðàçó íà÷èíàòü àòàêîâàòü èëè áåãàòü: +// Присмерти - нельзя сразу начинать атаковать или бегать: case FState of MONSTATE_DIE, MONSTATE_DEAD, MONSTATE_REVIVE: if (State <> MONSTATE_DEAD) and (State <> MONSTATE_REVIVE) and @@ -2347,12 +1927,12 @@ begin Exit; end; -// Ñìåíà ñîñòîÿíèÿ: +// Смена состояния: FState := State; if g_Game_IsServer and g_Game_IsNet then MH_SEND_MonsterState(FUID, ForceAnim); -// Íîâàÿ àíèìàöèÿ ïðè íîâîì ñîñòîÿíèè: +// Новая анимация при новом состоянии: case FState of MONSTATE_SLEEP: Anim := ANIM_SLEEP; MONSTATE_PAIN: Anim := ANIM_PAIN; @@ -2362,7 +1942,7 @@ begin MONSTATE_ATTACK: Anim := ANIM_ATTACK; MONSTATE_DIE: Anim := ANIM_DIE; MONSTATE_REVIVE: - begin // íà÷àëè âîñðåøàòüñÿ + begin // начали восрешаться Anim := FCurAnim; FAnim[Anim, FDirection].Revert(True); @@ -2374,11 +1954,11 @@ begin else Exit; end; -// Íàäî ñìåíèòü àíèìàöèþ íà íåñòàíäàðòíóþ: +// Надо сменить анимацию на нестандартную: if ForceAnim <> 255 then Anim := ForceAnim; -// Åñëè àíèìàöèÿ íîâàÿ - ïåðåçàïóñêàåì å¸: +// Если анимация новая - перезапускаем её: if FCurAnim <> Anim then if FAnim[Anim, FDirection] <> nil then begin @@ -2388,13 +1968,10 @@ begin end; function TMonster.TeleportTo(X, Y: Integer; silent: Boolean; dir: Byte): Boolean; -var - TA: TAnimation; - FramesID: DWORD; begin Result := False; -//  òî÷êå íàçíà÷åíèÿ ñòåíà: +// В точке назначения стена: if g_CollideLevel(X, Y, FObj.Rect.Width, FObj.Rect.Height) then begin g_Sound_PlayExAt('SOUND_GAME_NOTELEPORT', FObj.X, FObj.Y); @@ -2403,16 +1980,15 @@ begin Exit; end; - TA := nil; - -// Ýôôåêò òåëåïîðòà â ïîçèöèè ìîíñòðà: +// Эффект телепорта в позиции монстра: if not silent then begin - if g_Frames_Get(FramesID, 'FRAMES_TELEPORT') then - TA := TAnimation.Create(FramesID, False, 6); g_Sound_PlayExAt('SOUND_GAME_TELEPORT', Obj.X, Obj.Y); - g_GFX_OnceAnim(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)-32, - FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2)-32, TA); + r_GFX_OnceAnim( + R_GFX_TELEPORT, + FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)-32, + FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2)-32 + ); if g_Game_IsServer and g_Game_IsNet then MH_SEND_Effect(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)-32, @@ -2433,19 +2009,21 @@ begin FDirection := TDirection.D_RIGHT else if dir = 3 then - begin // îáðàòíîå + begin // обратное if FDirection = TDirection.D_RIGHT then FDirection := TDirection.D_LEFT else FDirection := TDirection.D_RIGHT; end; -// Ýôôåêò òåëåïîðòà â òî÷êå íàçíà÷åíèÿ: - if not silent and (TA <> nil) then +// Эффект телепорта в точке назначения: + if not silent then begin - g_GFX_OnceAnim(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)-32, - FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2)-32, TA); - TA.Free(); + r_GFX_OnceAnim( + R_GFX_TELEPORT, + FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)-32, + FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2)-32 + ); if g_Game_IsServer and g_Game_IsNet then MH_SEND_Effect(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)-32, @@ -2477,16 +2055,16 @@ label begin fall := True; -// Ìîíñòð ñòàòè÷åí ïîêà èäåò warmup +// Монстр статичен пока идет warmup if (gLMSRespawn > LMS_RESPAWN_NONE) then exit; -// Ðûáû "ëåòàþò" òîëüêî â âîäå: +// Рыбы "летают" только в воде: if FMonsterType = MONSTER_FISH then if g_Obj_CollidePanel(@FObj, 0, 0, PANEL_WATER or PANEL_ACID1 or PANEL_ACID2) then if (FState <> MONSTATE_DIE) and (FState <> MONSTATE_DEAD) then fall := False; -// Ëåòàþùèå ìîíòñðû: +// Летающие монтсры: if ((FMonsterType = MONSTER_SOUL) or (FMonsterType = MONSTER_PAIN) or (FMonsterType = MONSTER_CACO)) and @@ -2494,7 +2072,7 @@ begin (FState <> MONSTATE_DEAD) then fall := False; -// Ìåíÿåì ñêîðîñòü òîëüêî ïî ÷åòíûì êàäðàì: +// Меняем скорость только по четным кадрам: if gTime mod (GAME_TICK*2) <> 0 then begin g_Obj_Move(@FObj, fall, True, True); @@ -2507,11 +2085,11 @@ begin else FPainSound := False; -// Äâèãàåìñÿ: +// Двигаемся: st := g_Obj_Move(@FObj, fall, True, True); positionChanged(); // this updates spatial accelerators -// Åñëè ãîðèì - ïîäæèãàåì äðóãèõ ìîíñòðîâ, íî íå íà 100 òèêîâ êàæäûé ðàç: +// Если горим - поджигаем других монстров, но не на 100 тиков каждый раз: if FFireTime > 0 then begin it := monsGrid.forEachInAABB(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y, FObj.Rect.Width, FObj.Rect.Height); @@ -2520,7 +2098,7 @@ begin mit.CatchFire(FFireAttacker, FFireTime); end; -// Âûëåòåë çà êàðòó - óäàëÿåì è çàïóñêàåì òðèããåðû: +// Вылетел за карту - удаляем и запускаем триггеры: if WordBool(st and MOVE_FALLOUT) or (FObj.X < -1000) or (FObj.X > gMapInfo.Width+1000) or (FObj.Y < -1000) then begin @@ -2537,7 +2115,7 @@ begin oldvelx := FObj.Vel.X; -// Ñîïðîòèâëåíèå âîçäóõà äëÿ òðóïà: +// Сопротивление воздуха для трупа: if (FState = MONSTATE_DIE) or (FState = MONSTATE_DEAD) then FObj.Vel.X := z_dec(FObj.Vel.X, 1); @@ -2560,11 +2138,11 @@ begin end; end; -// Ìåðòâûé íè÷åãî íå äåëàåò: +// Мертвый ничего не делает: if (FState = MONSTATE_DEAD) then goto _end; -// AI ìîíñòðîâ âûêëþ÷åí: +// AI монстров выключен: if g_debug_MonsterOff then begin FSleep := 1; @@ -2572,7 +2150,7 @@ begin SetState(MONSTATE_SLEEP); end; -// Âîçìîæíî, ñîçäàåì ïóçûðüêè â âîäå: +// Возможно, создаем пузырьки в воде: if WordBool(st and MOVE_INWATER) and (Random(32) = 0) then case FMonsterType of MONSTER_FISH: @@ -2592,7 +2170,7 @@ begin end; end; -// Åñëè ïðîøåë ïåðâûé êàäð àíèìàöèè âçðûâà áî÷êè, òî âçðûâ: +// Если прошел первый кадр анимации взрыва бочки, то взрыв: if FMonsterType = MONSTER_BARREL then begin if (FState = MONSTATE_DIE) and (FAnim[FCurAnim, FDirection].CurrentFrame = 1) and @@ -2602,7 +2180,7 @@ begin 60, FUID); end; -// Lost_Soul âûëåòåë èç âîäû => óñêîðÿåòñÿ: +// Lost_Soul вылетел из воды => ускоряется: if FMonsterType = MONSTER_SOUL then if WordBool(st and MOVE_HITAIR) then g_Obj_SetSpeed(@FObj, 16); @@ -2610,15 +2188,15 @@ begin if FAmmo < 0 then FAmmo := FAmmo + 1; -// Åñëè íà÷àëè âñïëûâàòü, òî ïðîäîëæàåì: +// Если начали всплывать, то продолжаем: if FObj.Vel.Y < 0 then if WordBool(st and MOVE_INWATER) then FObj.Vel.Y := -4; -// Òàéìåð - æäåì ïîñëå ïîòåðè öåëè: +// Таймер - ждем после потери цели: FTargetTime := FTargetTime + 1; -// Ãèëüçû +// Гильзы if FShellTimer > -1 then if FShellTimer = 0 then begin @@ -2638,7 +2216,7 @@ begin FShellTimer := -1; end else Dec(FShellTimer); -// Ïðîáóåì óâåðíóòüñÿ îò ëåòÿùåé ïóëè: +// Пробуем увернуться от летящей пули: if fall then if (FState in [MONSTATE_GO, MONSTATE_RUN, MONSTATE_RUNOUT, MONSTATE_ATTACK, MONSTATE_SHOOT]) then @@ -2649,9 +2227,9 @@ begin FObj.Vel.Y := -MONSTERTABLE[FMonsterType].Jump; case FState of - MONSTATE_PAIN: // Ñîñòîÿíèå - Áîëü + MONSTATE_PAIN: // Состояние - Боль begin - // Áîëü ñèëüíàÿ => ìîíñòð êðè÷èò: + // Боль сильная => монстр кричит: if FPain >= MONSTERTABLE[FMonsterType].Pain then begin FPain := MONSTERTABLE[FMonsterType].Pain; @@ -2660,10 +2238,10 @@ begin if (not gSoundEffectsDF) and (FPain >= MONSTERTABLE[FMonsterType].MinPain) then PainSound(); - // Ñíèæàåì áîëü ñî âðåìåíåì: + // Снижаем боль со временем: FPain := FPain - 5; - // Áîëü óæå íå îøóòèìàÿ => èäåì äàëüøå: + // Боль уже не ошутимая => идем дальше: if FPain <= MONSTERTABLE[FMonsterType].MinPain then begin FPain := 0; @@ -2672,20 +2250,20 @@ begin end; end; - MONSTATE_SLEEP: // Ñîñòîÿíèå - Ñîí + MONSTATE_SLEEP: // Состояние - Сон begin - // Ñïèì: + // Спим: FSleep := FSleep + 1; - // Ïðîñïàëè äîñòàòî÷íî: + // Проспали достаточно: if FSleep >= 18 then FSleep := 0 - else // åùå ñïèì + else // еще спим goto _end; - // Íà èãðîêîâ èäóò òîëüêî îáû÷íûå ìîíñòðû, êèëëåðû è ìàíüÿêè + // На игроков идут только обычные монстры, киллеры и маньяки if (FBehaviour = BH_NORMAL) or (FBehaviour = BH_KILLER) or (FBehaviour = BH_MANIAC) then - // Åñëè åñòü èãðîê ðÿäîì, ïðîñûïàåìñÿ è èäåì ê íåìó: + // Если есть игрок рядом, просыпаемся и идем к нему: if (gPlayers <> nil) then for a := 0 to High(gPlayers) do if (gPlayers[a] <> nil) and (gPlayers[a].alive) @@ -2700,24 +2278,24 @@ begin Break; end; - // Íà ìîíñòðîâ òÿíåò ìàíüÿêîâ, ïîåõàâøèõ è êàííèáàëîâ + // На монстров тянет маньяков, поехавших и каннибалов if (FTargetUID = 0) and ((FBehaviour = BH_MANIAC) or (FBehaviour = BH_INSANE) or (FBehaviour = BH_CANNIBAL)) then - // Åñëè åñòü ïîäõîäÿùèé ìîíñòð ðÿäîì: + // Если есть подходящий монстр рядом: if gMonsters <> nil then for a := 0 to High(gMonsters) do if (gMonsters[a] <> nil) and (gMonsters[a].alive) and (gMonsters[a].FUID <> FUID) then begin - // Ìàíüÿêè íàïàäàþò íà âñåõ ìîíñòðîâ, êðîìå äðóçåé + // Маньяки нападают на всех монстров, кроме друзей if (FBehaviour = BH_MANIAC) and (IsFriend(gMonsters[a].FMonsterType, FMonsterType)) then Continue; - // Ïîåõàâøèå òàêæå, íî ìîãóò îáîçëèòüñÿ íà áî÷êó + // Поехавшие также, но могут обозлиться на бочку if (FBehaviour = BH_INSANE) and (gMonsters[a].FMonsterType <> MONSTER_BARREL) and (IsFriend(gMonsters[a].FMonsterType, FMonsterType)) then Continue; - // Êàííèáàëû íàïàäàþò íà ñåáå ïîäîáíûõ + // Каннибалы нападают на себе подобных if (FBehaviour = BH_CANNIBAL) and (gMonsters[a].FMonsterType <> FMonsterType) then Continue; if g_Look(@FObj, @gMonsters[a].Obj, FDirection) then @@ -2731,19 +2309,19 @@ begin end; end; - MONSTATE_WAIT: // Ñîñòîÿíèå - Îæèäàíèå + MONSTATE_WAIT: // Состояние - Ожидание begin - // Æäåì: + // Ждем: FSleep := FSleep - 1; - // Âûæäàëè äîñòàòî÷íî - èäåì: + // Выждали достаточно - идем: if FSleep < 0 then SetState(MONSTATE_GO); end; - MONSTATE_GO: // Ñîñòîÿíèå - Äâèæåíèå (ñ îñìîòðîì ñèòóàöèè) + MONSTATE_GO: // Состояние - Движение (с осмотром ситуации) begin - // Åñëè íàòêíóëèñü íà ÁëîêÌîí - óáåãàåì îò íåãî: + // Если наткнулись на БлокМон - убегаем от него: if WordBool(st and MOVE_BLOCK) then begin Turn(); @@ -2753,7 +2331,7 @@ begin goto _end; end; - // Åñëè ìîíñòð - êîëäóí, òî ïðîáóåì âîñêðåñèòü êîãî-íèáóäü: + // Если монстр - колдун, то пробуем воскресить кого-нибудь: if (FMonsterType = MONSTER_VILE) then if isCorpse(@FObj, False) <> -1 then begin @@ -2763,10 +2341,10 @@ begin goto _end; end; - // Öåëü ïîãèáëà èëè äàâíî æäåì: + // Цель погибла или давно ждем: if (not GetPos(FTargetUID, @o)) or (FTargetTime > MAX_ATM) then if not findNewPrey() then - begin // Íîâûõ öåëåé íåò + begin // Новых целей нет FTargetUID := 0; o.X := FObj.X+pt_x; o.Y := FObj.Y+pt_y; @@ -2776,10 +2354,10 @@ begin o.Accel.Y := 0; o.Rect := _Rect(0, 0, 0, 1); end - else // Íîâàÿ öåëü åñòü - áåðåì åå êîîðäèíàòû + else // Новая цель есть - берем ее координаты GetPos(FTargetUID, @o); - // Öåëü î÷åíü áëèçêî - ïèíàåì: + // Цель очень близко - пинаем: if g_Obj_Collide(@FObj, @o) and (FTargetUID <> 0) then begin FTargetTime := 0; @@ -2790,23 +2368,23 @@ begin end; end; - // Ðàññòîÿíèå äî öåëè: + // Расстояние до цели: sx := o.X+o.Rect.X+(o.Rect.Width div 2)-(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)); sy := o.Y+o.Rect.Y+(o.Rect.Height div 2)-(FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2)); - // Ïîâîðà÷èâàåìñÿ â ñòîðîíó öåëè: + // Поворачиваемся в сторону цели: if sx > 0 then FDirection := TDirection.D_RIGHT else FDirection := TDirection.D_LEFT; - // Åñëè ìîíñòð óìååò ñòðåëÿòü è åñòü ïî êîìó - ñòðåëÿåì: + // Если монстр умеет стрелять и есть по кому - стреляем: if canShoot(FMonsterType) and (FTargetUID <> 0) then - if Abs(sx) > Abs(sy) then // óãîë âûñòðåëà óäîáíûé + if Abs(sx) > Abs(sy) then // угол выстрела удобный if shoot(@o, False) then goto _end; - // Åñëè öåëü ïî÷òè íà îäíîé âåðòèêàëè - áåãàåì òóäà-ñþäà: + // Если цель почти на одной вертикали - бегаем туда-сюда: if Abs(sx) < 40 then if FMonsterType <> MONSTER_FISH then begin @@ -2820,12 +2398,12 @@ begin goto _end; end; - // Óïåðëèñü â ñòåíó: + // Уперлись в стену: if WordBool(st and MOVE_HITWALL) then begin if g_Triggers_PressR(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y, FObj.Rect.Width, FObj.Rect.Height, FUID, ACTIVATE_MONSTERPRESS) <> nil then - begin // Ñìîãëè íàæàòü êíîïêó - íåáîëüøîå îæèäàíèå + begin // Смогли нажать кнопку - небольшое ожидание FSleep := 4; SetState(MONSTATE_WAIT); @@ -2834,11 +2412,11 @@ begin case FMonsterType of MONSTER_CACO, MONSTER_SOUL, MONSTER_PAIN, MONSTER_FISH: ; - else // Íå ëåòàþò: + else // Не летают: if (g_Obj_CollideLevel(@FObj, 0, 1) or g_Obj_StayOnStep(@FObj)) and (FObj.Accel.Y = 0) then - begin // Ñòîèì íà òâåðäîì ïîëó èëè ñòóïåíè - // Ïðûæîê ÷åðåç ñòåíó: + begin // Стоим на твердом полу или ступени + // Прыжок через стену: FObj.Vel.Y := -MONSTERTABLE[FMonsterType].Jump; SetState(MONSTATE_CLIMB); end; @@ -2847,40 +2425,40 @@ begin goto _end; end; - // Ìîíñòðû, íå ïîäâåðæåííûå ãðàâèòàöèè: + // Монстры, не подверженные гравитации: if (FMonsterType = MONSTER_CACO) or (FMonsterType = MONSTER_SOUL) or (FMonsterType = MONSTER_PAIN) or (FMonsterType = MONSTER_FISH) then begin if FMonsterType = MONSTER_FISH then - begin // Ðûáà + begin // Рыба if not WordBool(st and MOVE_INWATER) then - begin // Ðûáà âíå âîäû: + begin // Рыба вне воды: if g_Obj_CollideLevel(@FObj, 0, 1) or g_Obj_StayOnStep(@FObj) then - begin // "Ñòîèò" òâåðäî - // Ðûáà òðåïûõàåòñÿ íà ïîâåðõíîñòè: + begin // "Стоит" твердо + // Рыба трепыхается на поверхности: if FObj.Accel.Y = 0 then FObj.Vel.Y := -6; FObj.Accel.X := FObj.Accel.X - 8 + Random(17); end; - // Ðûáå áîëüíî: + // Рыбе больно: SetState(MONSTATE_PAIN); FPain := FPain + 50; end - else // Ðûáà â âîäå + else // Рыба в воде begin - // Ïëûâåì â ñòîðîíó öåëè ïî-âåðòèêàëè: + // Плывем в сторону цели по-вертикали: if Abs(sy) > 8 then FObj.Vel.Y := g_basic.Sign(sy)*4 else FObj.Vel.Y := 0; - // Ðûáà ïëûâåò ââåðõ: + // Рыба плывет вверх: if FObj.Vel.Y < 0 then if not g_Obj_CollideLiquid(@FObj, 0, -16) then begin - // Âñïëûëè äî ïîâåðõíîñòè - ñòîï: + // Всплыли до поверхности - стоп: FObj.Vel.Y := 0; - // Ïëàâàåì òóäà-ñþäà: + // Плаваем туда-сюда: if Random(2) = 0 then FDirection := TDirection.D_LEFT else @@ -2890,18 +2468,18 @@ begin end; end; end - else // Ëåòàþùèå ìîíñòðû + else // Летающие монстры begin - // Ëåòèì â ñòîðîíó öåëè ïî-âåðòèêàëè: + // Летим в сторону цели по-вертикали: if Abs(sy) > 8 then FObj.Vel.Y := g_basic.Sign(sy)*4 else FObj.Vel.Y := 0; end; end - else // "Íàçåìíûå" ìîíñòðû + else // "Наземные" монстры begin - // Âîçìîæíî, ïèíàåì êóñêè: + // Возможно, пинаем куски: if (FObj.Vel.X <> 0) and (gGibs <> nil) then begin b := Abs(FObj.Vel.X); @@ -2912,19 +2490,19 @@ begin g_Obj_Collide(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y+FObj.Rect.Height-4, FObj.Rect.Width, 8, @gGibs[a].Obj) and (Random(3) = 0) then begin - // Ïèíàåì êóñêè + // Пинаем куски if FObj.Vel.X < 0 then begin - g_Obj_PushA(@gGibs[a].Obj, b, Random(61)+120); // íàëåâî + g_Obj_PushA(@gGibs[a].Obj, b, Random(61)+120); // налево end else begin - g_Obj_PushA(@gGibs[a].Obj, b, Random(61)); // íàïðàâî + g_Obj_PushA(@gGibs[a].Obj, b, Random(61)); // направо end; end; end; end; - // Áîññû ìîãóò ïèíàòü òðóïû: + // Боссы могут пинать трупы: if (FMonsterType in [MONSTER_CYBER, MONSTER_SPIDER, MONSTER_ROBO]) and (FObj.Vel.X <> 0) and (gCorpses <> nil) then begin @@ -2936,24 +2514,24 @@ begin co := gCorpses[a].Obj; if g_Obj_Collide(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y+FObj.Rect.Height-4, FObj.Rect.Width, 8, @co) and (Random(3) = 0) then - // Ïèíàåì òðóïû + // Пинаем трупы if FObj.Vel.X < 0 then - gCorpses[a].Damage(b*2, -b, Random(7)) // íàëåâî + gCorpses[a].Damage(b*2, FUID, -b, Random(7)) // налево else - gCorpses[a].Damage(b*2, b, Random(7)); // íàïðàâî + gCorpses[a].Damage(b*2, FUID, b, Random(7)); // направо end; end; - // Åñëè öåëü âûñîêî, òî, âîçìîæíî, ïðûãàåì: + // Если цель высоко, то, возможно, прыгаем: if sy < -40 then if g_Obj_CollideLevel(@FObj, 0, 1) or g_Obj_StayOnStep(@FObj) then - // ñòîèò òâåðäî + // стоит твердо if (Random(4) = 0) and (FObj.Accel.Y = 0) then FObj.Vel.Y := -MONSTERTABLE[FMonsterType].Jump; end; FSleep := FSleep + 1; - // Èíîãäà ðû÷èì: + // Иногда рычим: if FSleep >= 8 then begin FSleep := 0; @@ -2961,23 +2539,23 @@ begin ActionSound(); end; - // Áåæèì â âûáðàííóþ ñòîðîíó: + // Бежим в выбранную сторону: if FDirection = TDirection.D_RIGHT then FObj.Vel.X := MONSTERTABLE[FMonsterType].RunVel else FObj.Vel.X := -MONSTERTABLE[FMonsterType].RunVel; - // Åñëè â âîäå, òî çàìåäëÿåìñÿ: + // Если в воде, то замедляемся: if WordBool(st and MOVE_INWATER) then FObj.Vel.X := FObj.Vel.X div 2 - else // Ðûáàì íå íóæíî çàìåäëÿòüñÿ + else // Рыбам не нужно замедляться if FMonsterType = MONSTER_FISH then FObj.Vel.X := 0; end; - MONSTATE_RUN: // Ñîñòîÿíèå - Áåã + MONSTATE_RUN: // Состояние - Бег begin - // Åñëè íàòêíóëèñü íà ÁëîêÌîí - óáåãàåì îò íåãî: + // Если наткнулись на БлокМон - убегаем от него: if WordBool(st and MOVE_BLOCK) then begin Turn(); @@ -2989,78 +2567,78 @@ begin FSleep := FSleep - 1; - // Ïðîáåæàëè äîñòàòî÷íî èëè âðåçàëèñü â ñòåíó => ïåðåõîäèì íà øàã: + // Пробежали достаточно или врезались в стену => переходим на шаг: if (FSleep <= 0) or (WordBool(st and MOVE_HITWALL) and ((FObj.Vel.Y+FObj.Accel.Y) = 0)) then begin FSleep := 0; SetState(MONSTATE_GO); - // Ñòåíà - èäåì îáðàòíî: + // Стена - идем обратно: if WordBool(st and (MOVE_HITWALL or MOVE_BLOCK)) then Turn(); - // Èíîãäà ðû÷èì: + // Иногда рычим: if Random(8) = 0 then ActionSound(); end; - // Áåæèì â âûáðàííóþ ñòîðîíó: + // Бежим в выбранную сторону: if FDirection = TDirection.D_RIGHT then FObj.Vel.X := MONSTERTABLE[FMonsterType].RunVel else FObj.Vel.X := -MONSTERTABLE[FMonsterType].RunVel; - // Åñëè â âîäå, òî çàìåäëÿåìñÿ: + // Если в воде, то замедляемся: if WordBool(st and MOVE_INWATER) then FObj.Vel.X := FObj.Vel.X div 2 - else // Ðûáàì íå íóæíî çàìåäëÿòüñÿ + else // Рыбам не нужно замедляться if FMonsterType = MONSTER_FISH then FObj.Vel.X := 0; end; - MONSTATE_RUNOUT: // Ñîñòîÿíèå - Óáåãàåò îò ÷åãî-òî + MONSTATE_RUNOUT: // Состояние - Убегает от чего-то begin - // Âûøëè èç ÁëîêÌîíà: + // Вышли из БлокМона: if (not WordBool(st and MOVE_BLOCK)) and (FSleep > 0) then FSleep := 0; FSleep := FSleep - 1; - // Óáàæåëè äîñòàòî÷íî äàëåêî => ïåðåõîäèì íà øàã: + // Убажели достаточно далеко => переходим на шаг: if FSleep <= -18 then begin FSleep := 0; SetState(MONSTATE_GO); - // Ñòåíà/ÁëîêÌîí - èäåì îáðàòíî: + // Стена/БлокМон - идем обратно: if WordBool(st and (MOVE_HITWALL or MOVE_BLOCK)) then Turn(); - // Èíîãäà ðû÷èì: + // Иногда рычим: if Random(8) = 0 then ActionSound(); end; - // Áåæèì â âûáðàííóþ ñòîðîíó: + // Бежим в выбранную сторону: if FDirection = TDirection.D_RIGHT then FObj.Vel.X := MONSTERTABLE[FMonsterType].RunVel else FObj.Vel.X := -MONSTERTABLE[FMonsterType].RunVel; - // Åñëè â âîäå, òî çàìåäëÿåìñÿ: + // Если в воде, то замедляемся: if WordBool(st and MOVE_INWATER) then FObj.Vel.X := FObj.Vel.X div 2 - else // Ðûáàì íå íóæíî çàìåäëÿòüñÿ + else // Рыбам не нужно замедляться if FMonsterType = MONSTER_FISH then FObj.Vel.X := 0; end; - MONSTATE_CLIMB: // Ñîñòîÿíèå - Ïðûæîê (÷òîáû îáîéòè ñòåíó) + MONSTATE_CLIMB: // Состояние - Прыжок (чтобы обойти стену) begin - // Äîñòèãëè âûñøåé òî÷êè ïðûæêà èëè ñòåíà êîí÷èëàñü => ïåðåõîäèì íà øàã: + // Достигли высшей точки прыжка или стена кончилась => переходим на шаг: if ((FObj.Vel.Y+FObj.Accel.Y) >= 0) or (not WordBool(st and MOVE_HITWALL)) then begin FSleep := 0; SetState(MONSTATE_GO); - // Ñòåíà íå êîí÷èëàñü => áåæèì îò íåå: + // Стена не кончилась => бежим от нее: if WordBool(st and (MOVE_HITWALL or MOVE_BLOCK)) then begin Turn(); @@ -3069,24 +2647,24 @@ begin end; end; - // Áåæèì â âûáðàííóþ ñòîðîíó: + // Бежим в выбранную сторону: if FDirection = TDirection.D_RIGHT then FObj.Vel.X := MONSTERTABLE[FMonsterType].RunVel else FObj.Vel.X := -MONSTERTABLE[FMonsterType].RunVel; - // Åñëè â âîäå, òî çàìåäëÿåìñÿ: + // Если в воде, то замедляемся: if WordBool(st and MOVE_INWATER) then FObj.Vel.X := FObj.Vel.X div 2 - else // Ðûáàì íå íóæíî çàìåäëÿòüñÿ + else // Рыбам не нужно замедляться if FMonsterType = MONSTER_FISH then FObj.Vel.X := 0; end; - MONSTATE_ATTACK, // Ñîñòîÿíèå - Àòàêà - MONSTATE_SHOOT: // Ñîñòîÿíèå - Ñòðåëüáà + MONSTATE_ATTACK, // Состояние - Атака + MONSTATE_SHOOT: // Состояние - Стрельба begin - // Lost_Soul âðåçàëñÿ â ñòåíó ïðè àòàêå => ïåðåõîäèò íà øàã: + // Lost_Soul врезался в стену при атаке => переходит на шаг: if FMonsterType = MONSTER_SOUL then begin if WordBool(st and (MOVE_HITWALL or MOVE_HITCEIL or MOVE_HITLAND)) then @@ -3095,14 +2673,14 @@ begin goto _end; end; - // Çàìåäëÿåìñÿ ïðè àòàêå: + // Замедляемся при атаке: if FMonsterType <> MONSTER_FISH then FObj.Vel.X := z_dec(FObj.Vel.X, 1); - // Íóæíî ñòðåëÿòü, à ìîíñòð - êîëäóí: + // Нужно стрелять, а монстр - колдун: if (FMonsterType = MONSTER_VILE) and (FState = MONSTATE_SHOOT) then begin - // Öåëü ïîãèáëà => èäåì äàëüøå: + // Цель погибла => идем дальше: if not GetPos(FTargetUID, @o) then begin SetState(MONSTATE_GO); @@ -3110,7 +2688,7 @@ begin goto _end; end; - // Öåëü íå âèäíî => èäåì äàëüøå: + // Цель не видно => идем дальше: if not g_Look(@FObj, @o, FDirection) then begin SetState(MONSTATE_GO); @@ -3118,7 +2696,7 @@ begin goto _end; end; - // Öåëü â âîäå - íå çàãîðèòñÿ => èäåì äàëüøå: + // Цель в воде - не загорится => идем дальше: if g_Obj_CollideWater(@o, 0, 0) then begin SetState(MONSTATE_GO); @@ -3126,7 +2704,7 @@ begin goto _end; end; - // Æàðèì öåëü: + // Жарим цель: tx := o.X+o.Rect.X+(o.Rect.Width div 2); ty := o.Y+o.Rect.Y+(o.Rect.Height div 2); g_Weapon_HitUID(FTargetUID, 2, FUID, HIT_SOME); @@ -3136,27 +2714,27 @@ begin _end: -// Ñîñòîÿíèå - Âîñêðåøåíèå: +// Состояние - Воскрешение: if FState = MONSTATE_REVIVE then if FAnim[FCurAnim, FDirection].Played then - begin // Îáðàòíàÿ àíèìàöèÿ óìèðàíèÿ çàêîí÷èëàñü - èäåì äàëüøå: + begin // Обратная анимация умирания закончилась - идем дальше: FAnim[FCurAnim, FDirection].Revert(False); SetState(MONSTATE_GO); end; -// Åñëè åñòü àíèìàöèÿ îãíÿ êîëäóíà - ïóñòü îíà èäåò: +// Если есть анимация огня колдуна - пусть она идет: if vilefire <> nil then vilefire.Update(); -// Ñîñòîÿíèå - Óìèðàåò è òåêóùàÿ àíèìàöèÿ ïðîèãðàíà: +// Состояние - Умирает и текущая анимация проиграна: if (FState = MONSTATE_DIE) and (FAnim[FCurAnim, FDirection] <> nil) and (FAnim[FCurAnim, FDirection].Played) then begin - // Óìåð: + // Умер: SetState(MONSTATE_DEAD); - // Pain_Elemental ïðè ñìåðòè âûïóñêàåò 3 Lost_Soul'à: + // Pain_Elemental при смерти выпускает 3 Lost_Soul'а: if (FMonsterType = MONSTER_PAIN) then begin mon := g_Monsters_Create(MONSTER_SOUL, FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)-30, @@ -3192,35 +2770,35 @@ _end: if g_Game_IsNet then MH_SEND_CoopStats(); end; - // Ó ýòèõ ìîíñòðîâ íåò òðóïîâ: + // У этих монстров нет трупов: if (FMonsterType = MONSTER_PAIN) or (FMonsterType = MONSTER_SOUL) or (FMonsterType = MONSTER_BARREL) then FRemoved := True; end; -// Ñîâåðøåíèå àòàêè è ñòðåëüáû: +// Совершение атаки и стрельбы: if (FState = MONSTATE_ATTACK) or (FState = MONSTATE_SHOOT) then if (FAnim[FCurAnim, FDirection] <> nil) then - // Àíèìàöèÿ àòàêè åñòü - ìîæíî àòàêîâàòü + // Анимация атаки есть - можно атаковать if (FAnim[FCurAnim, FDirection].Played) then - begin // Àíèìàöèÿ àòàêè çàêîí÷èëàñü => ïåðåõîäèì íà øàã + begin // Анимация атаки закончилась => переходим на шаг if FState = MONSTATE_ATTACK then - begin // Ñîñòîÿíèå - Àòàêà - // Åñëè ìîíñòð íå Lost_Soul, òî ïîñëå àòàêè ïåðåõîäèì íà øàã: + begin // Состояние - Атака + // Если монстр не Lost_Soul, то после атаки переходим на шаг: if FMonsterType <> MONSTER_SOUL then SetState(MONSTATE_GO); end - else // Ñîñòîÿíèå - Ñòðåëüáà + else // Состояние - Стрельба begin - // Ïåðåõîäèì íà øàã, åñëè íå íàäî ñòðåëÿòü åùå ðàç: + // Переходим на шаг, если не надо стрелять еще раз: if not FChainFire then SetState(MONSTATE_GO) else - begin // Íàäî ñòðåëÿòü åùå + begin // Надо стрелять еще FChainFire := False; - // Ò.ê. ñîñòîÿíèå íå èçìåíèëîñü, è íóæåí - // íîâûé öèêë îæèäàíèÿ çàâåðøåíèÿ àíèìàöèè: + // Т.к. состояние не изменилось, и нужен + // новый цикл ожидания завершения анимации: FAnim[FCurAnim, FDirection].Reset(); end; end; @@ -3228,34 +2806,34 @@ _end: FWaitAttackAnim := False; end - else // Àíèìàöèÿ àòàêè åùå èäåò (èñêëþ÷åíèå - Lost_Soul): + else // Анимация атаки еще идет (исключение - Lost_Soul): if (FMonsterType = MONSTER_SOUL) or ( (not FWaitAttackAnim) and (FAnim[FCurAnim, FDirection].CurrentFrame = (FAnim[FCurAnim, FDirection].TotalFrames div 2)) ) then - begin // Àòàêè åùå íå áûëî è ýòî ñåðåäèíà àíèìàöèè àòàêè + begin // Атаки еще не было и это середина анимации атаки if FState = MONSTATE_ATTACK then - begin // Ñîñòîÿíèå - Àòàêà - // Åñëè ýòî Lost_Soul, òî ñáðàñûâàåì àíèìàöèþ àòàêè: + begin // Состояние - Атака + // Если это Lost_Soul, то сбрасываем анимацию атаки: if FMonsterType = MONSTER_SOUL then FAnim[FCurAnim, FDirection].Reset(); case FMonsterType of MONSTER_SOUL, MONSTER_IMP, MONSTER_DEMON: - // Ãðûçåì ïåðâîãî ïîïàâøåãîñÿ: + // Грызем первого попавшегося: if g_Weapon_Hit(@FObj, 15, FUID, HIT_SOME) <> 0 then - // Lost_Soul óêóñèë êîãî-òî => ïåðåõîäèò íà øàã: + // Lost_Soul укусил кого-то => переходит на шаг: if FMonsterType = MONSTER_SOUL then SetState(MONSTATE_GO); MONSTER_FISH: - // Ðûáà êóñàåò ïåðâîãî ïîïàâøåãîñÿ ñî çâóêîì: + // Рыба кусает первого попавшегося со звуком: if g_Weapon_Hit(@FObj, 10, FUID, HIT_SOME) <> 0 then g_Sound_PlayExAt('SOUND_MONSTER_FISH_ATTACK', FObj.X, FObj.Y); MONSTER_SKEL, MONSTER_ROBO, MONSTER_CYBER: - // Ðîáîò, êèáåð èëè ñêåëåò ñèëüíî ïèíàþòñÿ: + // Робот, кибер или скелет сильно пинаются: if FCurAnim = ANIM_ATTACK2 then begin o := FObj; @@ -3265,49 +2843,49 @@ _end: end; MONSTER_VILE: - // Êîëäóí ïûòàåòñÿ âîñêðåøàòü: + // Колдун пытается воскрешать: if FCurAnim = ANIM_ATTACK2 then begin sx := isCorpse(@FObj, True); if sx <> -1 then - begin // Íàøëè, êîãî âîñêðåñèòü + begin // Нашли, кого воскресить gMonsters[sx].SetState(MONSTATE_REVIVE); g_Sound_PlayExAt('SOUND_MONSTER_SLOP', FObj.X, FObj.Y); - // Âîñêðåøàòü - ñåáå âðåäèòü: + // Воскрешать - себе вредить: {g_Weapon_HitUID(FUID, 5, 0, HIT_SOME);} end; end; end; end - else // Ñîñòîÿíèå - Ñòðåëüáà + else // Состояние - Стрельба begin - // Âû÷èñëÿåì êîîðäèíàòû, îòêóäà âûëåòèò ïóëÿ: + // Вычисляем координаты, откуда вылетит пуля: wx := MONSTER_ANIMTABLE[FMonsterType].wX; if FDirection = TDirection.D_LEFT then begin wx := MONSTER_ANIMTABLE[FMonsterType].wX-(MONSTERTABLE[FMonsterType].Rect.X+(MONSTERTABLE[FMonsterType].Rect.Width div 2)); wx := MONSTERTABLE[FMonsterType].Rect.X+(MONSTERTABLE[FMonsterType].Rect.Width div 2)-wx; - end; // Ýòî çíà÷èò: wx := hitX + (hitWidth / 2) - (wx - (hitX + (hitWidth / 2))) + end; // Это значит: wx := hitX + (hitWidth / 2) - (wx - (hitX + (hitWidth / 2))) wx := FObj.X + wx; wy := FObj.Y + MONSTER_ANIMTABLE[FMonsterType].wY; - // Ìîíñòð íå ìîæåò öåëèòüñÿ â îáúåêò çà ñïèíîé, ñòðåëÿÿ âëåâî: + // Монстр не может целиться в объект за спиной, стреляя влево: if (FDirection = TDirection.D_LEFT) and (tx > wx) then begin tx := wx - 32; ty := wy + Random(11) - 5; end; - // È àíàëîãè÷íî, ñòðåëÿÿ âïðàâî: + // И аналогично, стреляя вправо: if (FDirection = TDirection.D_RIGHT) and (tx < wx) then begin tx := wx + 32; ty := wy + Random(11) - 5; end; - // Äåëàåì âûñòðåë íóæíûì îðóæèåì: + // Делаем выстрел нужным оружием: case FMonsterType of MONSTER_IMP: g_Weapon_ball1(wx, wy, tx, ty, FUID); @@ -3361,12 +2939,12 @@ _end: MONSTER_CACO: g_Weapon_ball2(wx, wy, tx, ty, FUID); MONSTER_PAIN: - begin // Ñîçäàåì Lost_Soul: + begin // Создаем Lost_Soul: mon := g_Monsters_Create(MONSTER_SOUL, FObj.X+(FObj.Rect.Width div 2), FObj.Y+FObj.Rect.Y, FDirection); if mon <> nil then - begin // Öåëü - öåëü Pain_Elemental'à. Ëåòèì ê íåé: + begin // Цель - цель Pain_Elemental'а. Летим к ней: mon.FTargetUID := FTargetUID; GetPos(FTargetUID, @o); mon.FTargetTime := 0; @@ -3384,29 +2962,29 @@ _end: if g_Game_IsNet then MH_SEND_MonsterShot(FUID, wx, wy, tx, ty); - // Ñêîðîñòðåëüíûå ìîíñòðû: + // Скорострельные монстры: if (FMonsterType = MONSTER_CGUN) or (FMonsterType = MONSTER_SPIDER) or (FMonsterType = MONSTER_BSP) or (FMonsterType = MONSTER_MANCUB) or (FMonsterType = MONSTER_ROBO) then if not GetPos(FTargetUID, @o) then - // Öåëü ìåðòâà - èùåì íîâóþ: + // Цель мертва - ищем новую: findNewPrey() - else // Öåëü æèâà - ïðîäîëæàåì ñòðåëÿòü: + else // Цель жива - продолжаем стрелять: if shoot(@o, False) then FChainFire := True; end; - // Àòàêà òîëüêî 1 ðàç çà àíèìàöèþ àòàêè: + // Атака только 1 раз за анимацию атаки: FWaitAttackAnim := True; end; -// Ïîñëåäíèé êàäð òåêóùåé àíèìàöèè: +// Последний кадр текущей анимации: if FAnim[FCurAnim, FDirection].Counter = FAnim[FCurAnim, FDirection].Speed-1 then case FState of MONSTATE_GO, MONSTATE_RUN, MONSTATE_CLIMB, MONSTATE_RUNOUT: - // Çâóêè ïðè ïåðåäâèæåíèè: + // Звуки при передвижении: case FMonsterType of MONSTER_CYBER: if (FAnim[FCurAnim, FDirection].CurrentFrame = 0) or @@ -3431,7 +3009,7 @@ _end: not ((FState = MONSTATE_DEAD) or (FState = MONSTATE_DIE)) then FObj.Vel.X := oldvelx; -// Åñëè åñòü àíèìàöèÿ, òî ïóñòü îíà èäåò: +// Если есть анимация, то пусть она идет: if FAnim[FCurAnim, FDirection] <> nil then FAnim[FCurAnim, FDirection].Update(); end; @@ -3470,16 +3048,16 @@ begin sy := 0; fall := True; -// Ìîíñòð ñòàòè÷åí ïîêà èäåò warmup +// Монстр статичен пока идет warmup if (gLMSRespawn > LMS_RESPAWN_NONE) then exit; -// Ðûáû "ëåòàþò" òîëüêî â âîäå: +// Рыбы "летают" только в воде: if FMonsterType = MONSTER_FISH then if g_Obj_CollidePanel(@FObj, 0, 0, PANEL_WATER or PANEL_ACID1 or PANEL_ACID2) then if (FState <> MONSTATE_DIE) and (FState <> MONSTATE_DEAD) then fall := False; -// Ëåòàþùèå ìîíòñðû: +// Летающие монтсры: if ((FMonsterType = MONSTER_SOUL) or (FMonsterType = MONSTER_PAIN) or (FMonsterType = MONSTER_CACO)) and @@ -3487,7 +3065,7 @@ begin (FState <> MONSTATE_DEAD) then fall := False; -// Ìåíÿåì ñêîðîñòü òîëüêî ïî ÷åòíûì êàäðàì: +// Меняем скорость только по четным кадрам: if gTime mod (GAME_TICK*2) <> 0 then begin g_Obj_Move(@FObj, fall, True, True); @@ -3500,11 +3078,11 @@ begin else FPainSound := False; -// Äâèãàåìñÿ: +// Двигаемся: st := g_Obj_Move(@FObj, fall, True, True); positionChanged(); // this updates spatial accelerators -// Âûëåòåë çà êàðòó - óäàëÿåì è çàïóñêàåì òðèããåðû: +// Вылетел за карту - удаляем и запускаем триггеры: if WordBool(st and MOVE_FALLOUT) or (FObj.X < -1000) or (FObj.X > gMapInfo.Width+1000) or (FObj.Y < -1000) then begin @@ -3514,7 +3092,7 @@ begin oldvelx := FObj.Vel.X; -// Ñîïðîòèâëåíèå âîçäóõà äëÿ òðóïà: +// Сопротивление воздуха для трупа: if (FState = MONSTATE_DIE) or (FState = MONSTATE_DEAD) then FObj.Vel.X := z_dec(FObj.Vel.X, 1); @@ -3529,11 +3107,11 @@ begin end; end; -// Ìåðòâûé íè÷åãî íå äåëàåò: +// Мертвый ничего не делает: if (FState = MONSTATE_DEAD) then goto _end; -// Âîçìîæíî, ñîçäàåì ïóçûðüêè â âîäå: +// Возможно, создаем пузырьки в воде: if WordBool(st and MOVE_INWATER) and (Random(32) = 0) then case FMonsterType of MONSTER_FISH: @@ -3553,7 +3131,7 @@ begin end; end; -// Åñëè ïðîøåë ïåðâûé êàäð àíèìàöèè âçðûâà áî÷êè, òî âçðûâ: +// Если прошел первый кадр анимации взрыва бочки, то взрыв: if FMonsterType = MONSTER_BARREL then begin if (FState = MONSTATE_DIE) and (FAnim[FCurAnim, FDirection].CurrentFrame = 1) and @@ -3563,7 +3141,7 @@ begin 60, FUID); end; -// Lost_Soul âûëåòåë èç âîäû => óñêîðÿåòñÿ: +// Lost_Soul вылетел из воды => ускоряется: if FMonsterType = MONSTER_SOUL then if WordBool(st and MOVE_HITAIR) then g_Obj_SetSpeed(@FObj, 16); @@ -3571,12 +3149,12 @@ begin if FAmmo < 0 then FAmmo := FAmmo + 1; -// Åñëè íà÷àëè âñïëûâàòü, òî ïðîäîëæàåì: +// Если начали всплывать, то продолжаем: if FObj.Vel.Y < 0 then if WordBool(st and MOVE_INWATER) then FObj.Vel.Y := -4; -// Òàéìåð - æäåì ïîñëå ïîòåðè öåëè: +// Таймер - ждем после потери цели: FTargetTime := FTargetTime + 1; if FShellTimer > -1 then @@ -3598,7 +3176,7 @@ begin FShellTimer := -1; end else Dec(FShellTimer); -// Ïðîáóåì óâåðíóòüñÿ îò ëåòÿùåé ïóëè: +// Пробуем увернуться от летящей пули: if fall then if (FState in [MONSTATE_GO, MONSTATE_RUN, MONSTATE_RUNOUT, MONSTATE_ATTACK, MONSTATE_SHOOT]) then @@ -3609,9 +3187,9 @@ begin FObj.Vel.Y := -MONSTERTABLE[FMonsterType].Jump; case FState of - MONSTATE_PAIN: // Ñîñòîÿíèå - Áîëü + MONSTATE_PAIN: // Состояние - Боль begin - // Áîëü ñèëüíàÿ => ìîíñòð êðè÷èò: + // Боль сильная => монстр кричит: if FPain >= MONSTERTABLE[FMonsterType].Pain then begin FPain := MONSTERTABLE[FMonsterType].Pain; @@ -3620,10 +3198,10 @@ begin if (not gSoundEffectsDF) and (FPain >= MONSTERTABLE[FMonsterType].MinPain) then PainSound(); - // Ñíèæàåì áîëü ñî âðåìåíåì: + // Снижаем боль со временем: FPain := FPain - 5; - // Áîëü óæå íå îøóòèìàÿ => èäåì äàëüøå: + // Боль уже не ошутимая => идем дальше: if FPain <= MONSTERTABLE[FMonsterType].MinPain then begin SetState(MONSTATE_GO); @@ -3631,27 +3209,27 @@ begin end; end; - MONSTATE_SLEEP: // Ñîñòîÿíèå - Ñîí + MONSTATE_SLEEP: // Состояние - Сон begin - // Ñïèì: + // Спим: FSleep := FSleep + 1; - // Ïðîñïàëè äîñòàòî÷íî: + // Проспали достаточно: if FSleep >= 18 then FSleep := 0 - else // åùå ñïèì + else // еще спим goto _end; end; - MONSTATE_WAIT: // Ñîñòîÿíèå - Îæèäàíèå + MONSTATE_WAIT: // Состояние - Ожидание begin - // Æäåì: + // Ждем: FSleep := FSleep - 1; end; - MONSTATE_GO: // Ñîñòîÿíèå - Äâèæåíèå (ñ îñìîòðîì ñèòóàöèè) + MONSTATE_GO: // Состояние - Движение (с осмотром ситуации) begin - // Åñëè íàòêíóëèñü íà ÁëîêÌîí - óáåãàåì îò íåãî: + // Если наткнулись на БлокМон - убегаем от него: if WordBool(st and MOVE_BLOCK) then begin Turn(); @@ -3661,7 +3239,7 @@ begin goto _end; end; - // Åñëè ìîíñòð - êîëäóí, òî ïðîáóåì âîñêðåñèòü êîãî-íèáóäü: + // Если монстр - колдун, то пробуем воскресить кого-нибудь: if (FMonsterType = MONSTER_VILE) then if isCorpse(@FObj, False) <> -1 then begin @@ -3671,7 +3249,7 @@ begin goto _end; end; - // Åñëè öåëü ïî÷òè íà îäíîé âåðòèêàëè - áåãàåì òóäà-ñþäà: + // Если цель почти на одной вертикали - бегаем туда-сюда: if Abs(sx) < 40 then if FMonsterType <> MONSTER_FISH then begin @@ -3681,16 +3259,16 @@ begin goto _end; end; - // Óïåðëèñü â ñòåíó: + // Уперлись в стену: if WordBool(st and MOVE_HITWALL) then begin case FMonsterType of MONSTER_CACO, MONSTER_SOUL, MONSTER_PAIN, MONSTER_FISH: ; - else // Íå ëåòàþò: + else // Не летают: if (g_Obj_CollideLevel(@FObj, 0, 1) or g_Obj_StayOnStep(@FObj)) and (FObj.Accel.Y = 0) then - begin // Ñòîèì íà òâåðäîì ïîëó èëè ñòóïåíè - // Ïðûæîê ÷åðåç ñòåíó: + begin // Стоим на твердом полу или ступени + // Прыжок через стену: FObj.Vel.Y := -MONSTERTABLE[FMonsterType].Jump; SetState(MONSTATE_CLIMB); end; @@ -3699,58 +3277,58 @@ begin goto _end; end; - // Ìîíñòðû, íå ïîäâåðæåííûå ãðàâèòàöèè: + // Монстры, не подверженные гравитации: if (FMonsterType = MONSTER_CACO) or (FMonsterType = MONSTER_SOUL) or (FMonsterType = MONSTER_PAIN) or (FMonsterType = MONSTER_FISH) then begin if FMonsterType = MONSTER_FISH then - begin // Ðûáà + begin // Рыба if not WordBool(st and MOVE_INWATER) then - begin // Ðûáà âíå âîäû: + begin // Рыба вне воды: if g_Obj_CollideLevel(@FObj, 0, 1) or g_Obj_StayOnStep(@FObj) then - begin // "Ñòîèò" òâåðäî - // Ðûáà òðåïûõàåòñÿ íà ïîâåðõíîñòè: + begin // "Стоит" твердо + // Рыба трепыхается на поверхности: if FObj.Accel.Y = 0 then FObj.Vel.Y := -6; FObj.Accel.X := FObj.Accel.X - 8 + Random(17); end; - // Ðûáå áîëüíî: + // Рыбе больно: SetState(MONSTATE_PAIN); FPain := FPain + 50; end - else // Ðûáà â âîäå + else // Рыба в воде begin - // Ïëûâåì â ñòîðîíó öåëè ïî-âåðòèêàëè: + // Плывем в сторону цели по-вертикали: if Abs(sy) > 8 then FObj.Vel.Y := g_basic.Sign(sy)*4 else FObj.Vel.Y := 0; - // Ðûáà ïëûâåò ââåðõ: + // Рыба плывет вверх: if FObj.Vel.Y < 0 then if not g_Obj_CollideLiquid(@FObj, 0, -16) then begin - // Âñïëûëè äî ïîâåðõíîñòè - ñòîï: + // Всплыли до поверхности - стоп: FObj.Vel.Y := 0; - // Ïëàâàåì òóäà-ñþäà: + // Плаваем туда-сюда: SetState(MONSTATE_RUN); FSleep := 20; end; end; end - else // Ëåòàþùèå ìîíñòðû + else // Летающие монстры begin - // Ëåòèì â ñòîðîíó öåëè ïî-âåðòèêàëè: + // Летим в сторону цели по-вертикали: if Abs(sy) > 8 then FObj.Vel.Y := g_basic.Sign(sy)*4 else FObj.Vel.Y := 0; end; end - else // "Íàçåìíûå" ìîíñòðû + else // "Наземные" монстры begin - // Âîçìîæíî, ïèíàåì êóñêè: + // Возможно, пинаем куски: if (FObj.Vel.X <> 0) and (gGibs <> nil) then begin b := Abs(FObj.Vel.X); @@ -3761,20 +3339,20 @@ begin g_Obj_Collide(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y+FObj.Rect.Height-4, FObj.Rect.Width, 8, @gGibs[a].Obj) and (Random(3) = 0) then begin - // Ïèíàåì êóñêè + // Пинаем куски if FObj.Vel.X < 0 then begin - g_Obj_PushA(@gGibs[a].Obj, b, Random(61)+120); // íàëåâî + g_Obj_PushA(@gGibs[a].Obj, b, Random(61)+120); // налево end else begin - g_Obj_PushA(@gGibs[a].Obj, b, Random(61)); // íàïðàâî + g_Obj_PushA(@gGibs[a].Obj, b, Random(61)); // направо end; positionChanged(); // this updates spatial accelerators end; end; end; - // Áîññû ìîãóò ïèíàòü òðóïû: + // Боссы могут пинать трупы: if (FMonsterType in [MONSTER_CYBER, MONSTER_SPIDER, MONSTER_ROBO]) and (FObj.Vel.X <> 0) and (gCorpses <> nil) then begin @@ -3786,18 +3364,18 @@ begin co := gCorpses[a].Obj; if g_Obj_Collide(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y+FObj.Rect.Height-4, FObj.Rect.Width, 8, @co) and (Random(3) = 0) then - // Ïèíàåì òðóïû + // Пинаем трупы if FObj.Vel.X < 0 then - gCorpses[a].Damage(b*2, -b, Random(7)) // íàëåâî + gCorpses[a].Damage(b*2, FUID, -b, Random(7)) // налево else - gCorpses[a].Damage(b*2, b, Random(7)); // íàïðàâî + gCorpses[a].Damage(b*2, FUID, b, Random(7)); // направо end; end; end; FSleep := FSleep + 1; - // Èíîãäà ðû÷èì: + // Иногда рычим: if FSleep >= 8 then begin FSleep := 0; @@ -3805,23 +3383,23 @@ begin ActionSound(); end; - // Áåæèì â âûáðàííóþ ñòîðîíó: + // Бежим в выбранную сторону: if FDirection = TDirection.D_RIGHT then FObj.Vel.X := MONSTERTABLE[FMonsterType].RunVel else FObj.Vel.X := -MONSTERTABLE[FMonsterType].RunVel; - // Åñëè â âîäå, òî çàìåäëÿåìñÿ: + // Если в воде, то замедляемся: if WordBool(st and MOVE_INWATER) then FObj.Vel.X := FObj.Vel.X div 2 - else // Ðûáàì íå íóæíî çàìåäëÿòüñÿ + else // Рыбам не нужно замедляться if FMonsterType = MONSTER_FISH then FObj.Vel.X := 0; end; - MONSTATE_RUN: // Ñîñòîÿíèå - Áåã + MONSTATE_RUN: // Состояние - Бег begin - // Åñëè íàòêíóëèñü íà ÁëîêÌîí - óáåãàåì îò íåãî: + // Если наткнулись на БлокМон - убегаем от него: if WordBool(st and MOVE_BLOCK) then begin SetState(MONSTATE_RUNOUT); @@ -3832,74 +3410,74 @@ begin FSleep := FSleep - 1; - // Ïðîáåæàëè äîñòàòî÷íî èëè âðåçàëèñü â ñòåíó => ïåðåõîäèì íà øàã: + // Пробежали достаточно или врезались в стену => переходим на шаг: if (FSleep <= 0) or (WordBool(st and MOVE_HITWALL) and ((FObj.Vel.Y+FObj.Accel.Y) = 0)) then begin SetState(MONSTATE_GO); FSleep := 0; - // Èíîãäà ðû÷èì: + // Иногда рычим: if Random(8) = 0 then ActionSound(); end; - // Áåæèì â âûáðàííóþ ñòîðîíó: + // Бежим в выбранную сторону: if FDirection = TDirection.D_RIGHT then FObj.Vel.X := MONSTERTABLE[FMonsterType].RunVel else FObj.Vel.X := -MONSTERTABLE[FMonsterType].RunVel; - // Åñëè â âîäå, òî çàìåäëÿåìñÿ: + // Если в воде, то замедляемся: if WordBool(st and MOVE_INWATER) then FObj.Vel.X := FObj.Vel.X div 2 - else // Ðûáàì íå íóæíî çàìåäëÿòüñÿ + else // Рыбам не нужно замедляться if FMonsterType = MONSTER_FISH then FObj.Vel.X := 0; end; - MONSTATE_RUNOUT: // Ñîñòîÿíèå - Óáåãàåò îò ÷åãî-òî + MONSTATE_RUNOUT: // Состояние - Убегает от чего-то begin - // Âûøëè èç ÁëîêÌîíà: + // Вышли из БлокМона: if (not WordBool(st and MOVE_BLOCK)) and (FSleep > 0) then FSleep := 0; FSleep := FSleep - 1; - // Óáàæåëè äîñòàòî÷íî äàëåêî => ïåðåõîäèì íà øàã: + // Убажели достаточно далеко => переходим на шаг: if FSleep <= -18 then begin SetState(MONSTATE_GO); FSleep := 0; - // Èíîãäà ðû÷èì: + // Иногда рычим: if Random(8) = 0 then ActionSound(); end; - // Áåæèì â âûáðàííóþ ñòîðîíó: + // Бежим в выбранную сторону: if FDirection = TDirection.D_RIGHT then FObj.Vel.X := MONSTERTABLE[FMonsterType].RunVel else FObj.Vel.X := -MONSTERTABLE[FMonsterType].RunVel; - // Åñëè â âîäå, òî çàìåäëÿåìñÿ: + // Если в воде, то замедляемся: if WordBool(st and MOVE_INWATER) then FObj.Vel.X := FObj.Vel.X div 2 - else // Ðûáàì íå íóæíî çàìåäëÿòüñÿ + else // Рыбам не нужно замедляться if FMonsterType = MONSTER_FISH then FObj.Vel.X := 0; end; - MONSTATE_CLIMB: // Ñîñòîÿíèå - Ïðûæîê (÷òîáû îáîéòè ñòåíó) + MONSTATE_CLIMB: // Состояние - Прыжок (чтобы обойти стену) begin - // Äîñòèãëè âûñøåé òî÷êè ïðûæêà èëè ñòåíà êîí÷èëàñü => ïåðåõîäèì íà øàã: + // Достигли высшей точки прыжка или стена кончилась => переходим на шаг: if ((FObj.Vel.Y+FObj.Accel.Y) >= 0) or (not WordBool(st and MOVE_HITWALL)) then begin SetState(MONSTATE_GO); FSleep := 0; - // Ñòåíà íå êîí÷èëàñü => áåæèì îò íåå: + // Стена не кончилась => бежим от нее: if WordBool(st and (MOVE_HITWALL or MOVE_BLOCK)) then begin SetState(MONSTATE_RUN); @@ -3907,24 +3485,24 @@ begin end; end; - // Áåæèì â âûáðàííóþ ñòîðîíó: + // Бежим в выбранную сторону: if FDirection = TDirection.D_RIGHT then FObj.Vel.X := MONSTERTABLE[FMonsterType].RunVel else FObj.Vel.X := -MONSTERTABLE[FMonsterType].RunVel; - // Åñëè â âîäå, òî çàìåäëÿåìñÿ: + // Если в воде, то замедляемся: if WordBool(st and MOVE_INWATER) then FObj.Vel.X := FObj.Vel.X div 2 - else // Ðûáàì íå íóæíî çàìåäëÿòüñÿ + else // Рыбам не нужно замедляться if FMonsterType = MONSTER_FISH then FObj.Vel.X := 0; end; - MONSTATE_ATTACK, // Ñîñòîÿíèå - Àòàêà - MONSTATE_SHOOT: // Ñîñòîÿíèå - Ñòðåëüáà + MONSTATE_ATTACK, // Состояние - Атака + MONSTATE_SHOOT: // Состояние - Стрельба begin - // Lost_Soul âðåçàëñÿ â ñòåíó ïðè àòàêå => ïåðåõîäèò íà øàã: + // Lost_Soul врезался в стену при атаке => переходит на шаг: if FMonsterType = MONSTER_SOUL then begin if WordBool(st and (MOVE_HITWALL or MOVE_HITCEIL or MOVE_HITLAND)) then @@ -3933,14 +3511,14 @@ begin goto _end; end; - // Çàìåäëÿåìñÿ ïðè àòàêå: + // Замедляемся при атаке: if FMonsterType <> MONSTER_FISH then FObj.Vel.X := z_dec(FObj.Vel.X, 1); - // Íóæíî ñòðåëÿòü, à ìîíñòð - êîëäóí: + // Нужно стрелять, а монстр - колдун: if (FMonsterType = MONSTER_VILE) and (FState = MONSTATE_SHOOT) then begin - // Öåëü ïîãèáëà => èäåì äàëüøå: + // Цель погибла => идем дальше: if not GetPos(FTargetUID, @o) then begin SetState(MONSTATE_GO); @@ -3948,7 +3526,7 @@ begin goto _end; end; - // Öåëü íå âèäíî => èäåì äàëüøå: + // Цель не видно => идем дальше: if not g_Look(@FObj, @o, FDirection) then begin SetState(MONSTATE_GO); @@ -3956,7 +3534,7 @@ begin goto _end; end; - // Öåëü â âîäå - íå çàãîðèòñÿ => èäåì äàëüøå: + // Цель в воде - не загорится => идем дальше: if g_Obj_CollideWater(@o, 0, 0) then begin SetState(MONSTATE_GO); @@ -3969,27 +3547,27 @@ begin _end: -// Ñîñòîÿíèå - Âîñêðåøåíèå: +// Состояние - Воскрешение: if FState = MONSTATE_REVIVE then if FAnim[FCurAnim, FDirection].Played then - begin // Îáðàòíàÿ àíèìàöèÿ óìèðàíèÿ çàêîí÷èëàñü - èäåì äàëüøå: + begin // Обратная анимация умирания закончилась - идем дальше: FAnim[FCurAnim, FDirection].Revert(False); SetState(MONSTATE_GO); end; -// Åñëè åñòü àíèìàöèÿ îãíÿ êîëäóíà - ïóñòü îíà èäåò: +// Если есть анимация огня колдуна - пусть она идет: if vilefire <> nil then vilefire.Update(); -// Ñîñòîÿíèå - Óìèðàåò è òåêóùàÿ àíèìàöèÿ ïðîèãðàíà: +// Состояние - Умирает и текущая анимация проиграна: if (FState = MONSTATE_DIE) and (FAnim[FCurAnim, FDirection] <> nil) and (FAnim[FCurAnim, FDirection].Played) then begin - // Óìåð: + // Умер: SetState(MONSTATE_DEAD); - // Ó ýòèõ ìîíñòðîâ íåò òðóïîâ: + // У этих монстров нет трупов: if (FMonsterType = MONSTER_PAIN) or (FMonsterType = MONSTER_SOUL) or (FMonsterType = MONSTER_BARREL) then @@ -3998,28 +3576,28 @@ _end: FAnim[FCurAnim, FDirection].CurrentFrame := FAnim[FCurAnim, FDirection].TotalFrames - 1; end; -// Ñîâåðøåíèå àòàêè è ñòðåëüáû: +// Совершение атаки и стрельбы: if (FState = MONSTATE_ATTACK) or (FState = MONSTATE_SHOOT) then if (FAnim[FCurAnim, FDirection] <> nil) then - // Àíèìàöèÿ àòàêè åñòü - ìîæíî àòàêîâàòü + // Анимация атаки есть - можно атаковать if (FAnim[FCurAnim, FDirection].Played) then - begin // Àíèìàöèÿ àòàêè çàêîí÷èëàñü => ïåðåõîäèì íà øàã + begin // Анимация атаки закончилась => переходим на шаг if FState = MONSTATE_ATTACK then - begin // Ñîñòîÿíèå - Àòàêà - // Åñëè ìîíñòð íå Lost_Soul, òî ïîñëå àòàêè ïåðåõîäèì íà øàã: + begin // Состояние - Атака + // Если монстр не Lost_Soul, то после атаки переходим на шаг: if FMonsterType <> MONSTER_SOUL then SetState(MONSTATE_GO); end - else // Ñîñòîÿíèå - Ñòðåëüáà + else // Состояние - Стрельба begin - // Ïåðåõîäèì íà øàã, åñëè íå íàäî ñòðåëÿòü åùå ðàç: + // Переходим на шаг, если не надо стрелять еще раз: if not FChainFire then SetState(MONSTATE_GO) else - begin // Íàäî ñòðåëÿòü åùå + begin // Надо стрелять еще FChainFire := False; - // Ò.ê. ñîñòîÿíèå íå èçìåíèëîñü, è íóæåí - // íîâûé öèêë îæèäàíèÿ çàâåðøåíèÿ àíèìàöèè: + // Т.к. состояние не изменилось, и нужен + // новый цикл ожидания завершения анимации: FAnim[FCurAnim, FDirection].Reset(); end; end; @@ -4027,24 +3605,24 @@ _end: FWaitAttackAnim := False; end - else // Àíèìàöèÿ àòàêè åùå èäåò (èñêëþ÷åíèå - Lost_Soul): + else // Анимация атаки еще идет (исключение - Lost_Soul): if (FMonsterType = MONSTER_SOUL) or ( (not FWaitAttackAnim) and (FAnim[FCurAnim, FDirection].CurrentFrame = (FAnim[FCurAnim, FDirection].TotalFrames div 2)) ) then - begin // Àòàêè åùå íå áûëî è ýòî ñåðåäèíà àíèìàöèè àòàêè + begin // Атаки еще не было и это середина анимации атаки if FState = MONSTATE_ATTACK then - begin // Ñîñòîÿíèå - Àòàêà - // Åñëè ýòî Lost_Soul, òî ñáðàñûâàåì àíèìàöèþ àòàêè: + begin // Состояние - Атака + // Если это Lost_Soul, то сбрасываем анимацию атаки: if FMonsterType = MONSTER_SOUL then FAnim[FCurAnim, FDirection].Reset(); case FMonsterType of MONSTER_SOUL, MONSTER_IMP, MONSTER_DEMON: - // Ãðûçåì ïåðâîãî ïîïàâøåãîñÿ: + // Грызем первого попавшегося: if g_Weapon_Hit(@FObj, 15, FUID, HIT_SOME) <> 0 then - // Lost_Soul óêóñèë êîãî-òî => ïåðåõîäèò íà øàã: + // Lost_Soul укусил кого-то => переходит на шаг: if FMonsterType = MONSTER_SOUL then SetState(MONSTATE_GO); @@ -4052,7 +3630,7 @@ _end: g_Weapon_Hit(@FObj, 10, FUID, HIT_SOME); MONSTER_SKEL, MONSTER_ROBO, MONSTER_CYBER: - // Ðîáîò, êèáåð èëè ñêåëåò ñèëüíî ïèíàþòñÿ: + // Робот, кибер или скелет сильно пинаются: if FCurAnim = ANIM_ATTACK2 then begin o := FObj; @@ -4061,45 +3639,45 @@ _end: end; MONSTER_VILE: - // Êîëäóí ïûòàåòñÿ âîñêðåøàòü: + // Колдун пытается воскрешать: if FCurAnim = ANIM_ATTACK2 then begin sx := isCorpse(@FObj, True); if sx <> -1 then - begin // Íàøëè, êîãî âîñêðåñèòü + begin // Нашли, кого воскресить g_Sound_PlayExAt('SOUND_MONSTER_SLOP', FObj.X, FObj.Y); - // Âîñêðåøàòü - ñåáå âðåäèòü: + // Воскрешать - себе вредить: {g_Weapon_HitUID(FUID, 5, 0, HIT_SOME);} end; end; end; end - else // Ñîñòîÿíèå - Ñòðåëüáà + else // Состояние - Стрельба begin - // Ñêîðîñòðåëüíûå ìîíñòðû: + // Скорострельные монстры: if (FMonsterType = MONSTER_CGUN) or (FMonsterType = MONSTER_SPIDER) or (FMonsterType = MONSTER_BSP) or (FMonsterType = MONSTER_MANCUB) or (FMonsterType = MONSTER_ROBO) then if not GetPos(FTargetUID, @o) then - // Öåëü ìåðòâà - èùåì íîâóþ: + // Цель мертва - ищем новую: findNewPrey() - else // Öåëü æèâà - ïðîäîëæàåì ñòðåëÿòü: + else // Цель жива - продолжаем стрелять: if shoot(@o, False) then FChainFire := True; end; - // Àòàêà òîëüêî 1 ðàç çà àíèìàöèþ àòàêè: + // Атака только 1 раз за анимацию атаки: FWaitAttackAnim := True; end; -// Ïîñëåäíèé êàäð òåêóùåé àíèìàöèè: +// Последний кадр текущей анимации: if FAnim[FCurAnim, FDirection].Counter = FAnim[FCurAnim, FDirection].Speed-1 then case FState of MONSTATE_GO, MONSTATE_RUN, MONSTATE_CLIMB, MONSTATE_RUNOUT: - // Çâóêè ïðè ïåðåäâèæåíèè: + // Звуки при передвижении: case FMonsterType of MONSTER_CYBER: if (FAnim[FCurAnim, FDirection].CurrentFrame = 0) or @@ -4120,12 +3698,12 @@ _end: end; end; -// Êîñòûëü äëÿ ïîòîêîâ +// Костыль для потоков if g_Obj_CollidePanel(@FObj, 0, 0, PANEL_LIFTLEFT or PANEL_LIFTRIGHT) and not ((FState = MONSTATE_DEAD) or (FState = MONSTATE_DIE)) then FObj.Vel.X := oldvelx; -// Åñëè åñòü àíèìàöèÿ, òî ïóñòü îíà èäåò: +// Если есть анимация, то пусть она идет: if FAnim[FCurAnim, FDirection] <> nil then FAnim[FCurAnim, FDirection].Update(); end; @@ -4176,10 +3754,10 @@ end; procedure TMonster.Turn(); begin -// Ðàçâîðà÷èâàåìñÿ: +// Разворачиваемся: if FDirection = TDirection.D_LEFT then FDirection := TDirection.D_RIGHT else FDirection := TDirection.D_LEFT; -// Áåæèì â âûáðàííóþ ñòîðîíó: +// Бежим в выбранную сторону: if FDirection = TDirection.D_RIGHT then FObj.Vel.X := MONSTERTABLE[FMonsterType].RunVel else @@ -4202,7 +3780,7 @@ begin PlayerNear := -1; MonsterNear := -1; - // Ïîåõàâøèå, êàííèáàëû, è äîáðûå èãðîêîâ íå òðîãàþò + // Поехавшие, каннибалы, и добрые игроков не трогают if (gPlayers <> nil) and (FBehaviour <> BH_INSANE) and (FBehaviour <> BH_CANNIBAL) and (FBehaviour <> BH_GOOD) then for a := 0 to High(gPlayers) do @@ -4223,20 +3801,20 @@ begin end; end; - // Êèëëåðû è äîáðûå íå òðîãàþò ìîíñòðîâ + // Киллеры и добрые не трогают монстров if (gMonsters <> nil) and (FBehaviour <> BH_KILLER) and (FBehaviour <> BH_GOOD) then for a := 0 to High(gMonsters) do if (gMonsters[a] <> nil) and (gMonsters[a].alive) and (gMonsters[a].FUID <> FUID) then begin if (FBehaviour = BH_CANNIBAL) and (gMonsters[a].FMonsterType <> FMonsterType) then - Continue; // Êàííèáàëû àòàêóþò òîëüêî ñîðîäè÷åé + Continue; // Каннибалы атакуют только сородичей if (FBehaviour = BH_INSANE) and (gMonsters[a].FMonsterType <> MONSTER_BARREL) and (IsFriend(gMonsters[a].FMonsterType, FMonsterType)) then - Continue; // Ïîåõàâøèå íå òðîãàþò äðóçåé, íî èì íå íðàâÿòñÿ áî÷êè + Continue; // Поехавшие не трогают друзей, но им не нравятся бочки if ((FBehaviour = BH_NORMAL) or (FBehaviour = BH_MANIAC)) and (IsFriend(gMonsters[a].FMonsterType, FMonsterType)) then - Continue; // Îñòàâøèåñÿ òèïû, êðîìå êàííèáàëîâ, íå òðîãàþò ñâîèõ äðóçåé + Continue; // Оставшиеся типы, кроме каннибалов, не трогают своих друзей if g_Look(@FObj, @gMonsters[a].Obj, FDirection) then begin @@ -4255,25 +3833,25 @@ begin case FBehaviour of BH_NORMAL, BH_KILLER: begin - // Îáû÷íûé è êèëëåð ñíà÷àëà èùóò èãðîêîâ â ïîëå çðåíèÿ + // Обычный и киллер сначала ищут игроков в поле зрения if (FTargetUID = 0) and (Length(PlayersSee) > 0) then begin a := PlayersSee[Random(Length(PlayersSee))]; FTargetUID := gPlayers[a].UID; end; - // Çàòåì ïîáëèçîñòè + // Затем поблизости if (FTargetUID = 0) and (PlayerNear > -1) then begin a := PlayerNear; FTargetUID := gPlayers[a].UID; end; - // Ïîòîì îáû÷íûå èùóò ìîíñòðîâ â ïîëå çðåíèÿ + // Потом обычные ищут монстров в поле зрения if (FTargetUID = 0) and (Length(MonstersSee) > 0) then begin a := MonstersSee[Random(Length(MonstersSee))]; FTargetUID := gMonsters[a].UID; end; - // Çàòåì ïîáëèçîñòè + // Затем поблизости if (FTargetUID = 0) and (MonsterNear > -1) then begin a := MonsterNear; @@ -4282,7 +3860,7 @@ begin end; BH_MANIAC, BH_INSANE, BH_CANNIBAL: begin - // Ìàíüÿêè, ïîåõàâøèå è êàííèáàëû ñíà÷àëà èñòðåáëÿþò âñ¸ â ïîëå çðåíèÿ + // Маньяки, поехавшие и каннибалы сначала истребляют всё в поле зрения if (FTargetUID = 0) and (Length(PlayersSee) > 0) then begin a := PlayersSee[Random(Length(PlayersSee))]; @@ -4293,7 +3871,7 @@ begin a := MonstersSee[Random(Length(MonstersSee))]; FTargetUID := gMonsters[a].UID; end; - // Çàòåì èùóò êîãî-òî ïîáëèçîñòè + // Затем ищут кого-то поблизости if (FTargetUID = 0) and (PlayerNear > -1) then begin a := PlayerNear; @@ -4307,17 +3885,17 @@ begin end; end; -// Åñëè è ìîíñòðîâ íåò - íà÷èíàåì æäàòü öåëü: +// Если и монстров нет - начинаем ждать цель: if FTargetUID = 0 then begin - // Ïîåõàâøèé ïûòàåòñÿ ñàìîóáèòüñÿ + // Поехавший пытается самоубиться if FBehaviour = BH_INSANE then FTargetUID := FUID else FTargetTime := MAX_ATM; end else - begin // Öåëü íàøëè + begin // Цель нашли FTargetTime := 0; Result := True; end; @@ -4353,7 +3931,7 @@ begin end; MONSTER_BARON, MONSTER_KNIGHT, MONSTER_CACO, MONSTER_MANCUB: - // Ýòè ìîíñòðû íå ïèíàþò - îíè ñòðåëÿþò â óïîð: + // Эти монстры не пинают - они стреляют в упор: if not g_Game_IsClient then Result := shoot(o, True); end; end; @@ -4364,19 +3942,19 @@ var begin Result := False; -// Ñòðåëÿòü ðàíî: +// Стрелять рано: if FAmmo < 0 then Exit; -// Æäàòü âðåìåíè ãîòîâíîñòè ê âûñòðåëó: +// Ждать времени готовности к выстрелу: if not immediately then case FMonsterType of MONSTER_FISH, MONSTER_BARREL, MONSTER_DEMON: - Exit; // íå ñòðåëÿþò + Exit; // не стреляют MONSTER_CGUN, MONSTER_BSP, MONSTER_ROBO: begin FAmmo := FAmmo + 1; - // Âðåìÿ âûñòðåëà óïóùåíî: + // Время выстрела упущено: if FAmmo >= 50 then FAmmo := IfThen(FMonsterType = MONSTER_ROBO, -200, -50); end; @@ -4384,24 +3962,24 @@ begin MONSTER_MANCUB: begin FAmmo := FAmmo + 1; - // Âðåìÿ âûñòðåëà óïóùåíî: + // Время выстрела упущено: if FAmmo >= 5 then FAmmo := -50; end; MONSTER_SPIDER: begin FAmmo := FAmmo + 1; - // Âðåìÿ âûñòðåëà óïóùåíî: + // Время выстрела упущено: if FAmmo >= 100 then FAmmo := -50; end; MONSTER_CYBER: begin - // Ñòðåëÿåò íå âñåãäà: + // Стреляет не всегда: if Random(2) = 0 then Exit; FAmmo := FAmmo + 1; - // Âðåìÿ âûñòðåëà óïóùåíî: + // Время выстрела упущено: if FAmmo >= 10 then FAmmo := -50; end; @@ -4412,7 +3990,7 @@ begin else if Random(16) <> 0 then Exit; end; -// Öåëè íå âèäíî: +// Цели не видно: if not g_Look(@FObj, o, FDirection) then Exit; @@ -4421,8 +3999,8 @@ begin tx := o^.X+o^.Rect.X+(o^.Rect.Width div 2)+((o^.Vel.X{+o^.Accel.X})*12); ty := o^.Y+o^.Rect.Y+(o^.Rect.Height div 2)+((o^.Vel.Y{+o^.Accel.Y})*12); -// Ðàçíèöà ïî âûñîòå áîëüøå ðàçíèöû ïî ãîðèçîíòàëè -// (íå ìîæåò ñòðåëÿòü ïîä òàêèì áîëüøèì óãëîì): +// Разница по высоте больше разницы по горизонтали +// (не может стрелять под таким большим углом): if Abs(tx-(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2))) < Abs(ty-(FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2))) then Exit; @@ -4439,7 +4017,7 @@ begin {nn} end; MONSTER_VILE: - begin // Çàæèãàåì îãîíü + begin // Зажигаем огонь tx := o^.X+o^.Rect.X+(o^.Rect.Width div 2); ty := o^.Y+o^.Rect.Y; SetState(MONSTATE_SHOOT); @@ -4450,7 +4028,7 @@ begin g_Sound_PlayExAt('SOUND_FIRE', o^.X, o^.Y); end; MONSTER_SOUL: - begin // Ëåòèò â ñòîðîíó öåëè: + begin // Летит в сторону цели: SetState(MONSTATE_ATTACK); g_Sound_PlayExAt('SOUND_MONSTER_SOUL_ATTACK', FObj.X, FObj.Y); @@ -4466,7 +4044,7 @@ begin MONSTER_MANCUB, MONSTER_ZOMBY, MONSTER_SERG, MONSTER_BSP, MONSTER_ROBO, MONSTER_CYBER, MONSTER_CGUN, MONSTER_SPIDER, MONSTER_PAIN, MONSTER_MAN: begin - // Ìàíêóáóñ ðÿâêàåò ïåðåä ïåðâîé àòàêîé: + // Манкубус рявкает перед первой атакой: if FMonsterType = MONSTER_MANCUB then if FAmmo = 1 then g_Sound_PlayExAt('SOUND_MONSTER_MANCUB_ATTACK', FObj.X, FObj.Y); @@ -4510,68 +4088,68 @@ var begin assert(st <> nil); - // Ñèãíàòóðà ìîíñòðà: + // Сигнатура монстра: utils.writeSign(st, 'MONS'); utils.writeInt(st, Byte(0)); // version - // UID ìîíñòðà: + // UID монстра: utils.writeInt(st, Word(FUID)); - // Íàïðàâëåíèå + // Направление if FDirection = TDirection.D_LEFT then b := 1 else b := 2; // D_RIGHT utils.writeInt(st, Byte(b)); - // Íàäî ëè óäàëèòü åãî + // Надо ли удалить его utils.writeBool(st, FRemoved); - // Îñòàëîñü çäîðîâüÿ + // Осталось здоровья utils.writeInt(st, LongInt(FHealth)); - // Ñîñòîÿíèå + // Состояние utils.writeInt(st, Byte(FState)); - // Òåêóùàÿ àíèìàöèÿ + // Текущая анимация utils.writeInt(st, Byte(FCurAnim)); - // UID öåëè + // UID цели utils.writeInt(st, Word(FTargetUID)); - // Âðåìÿ ïîñëå ïîòåðè öåëè + // Время после потери цели utils.writeInt(st, LongInt(FTargetTime)); - // Ïîâåäåíèå ìîíñòðà + // Поведение монстра utils.writeInt(st, Byte(FBehaviour)); - // Ãîòîâíîñòü ê âûñòðåëó + // Готовность к выстрелу utils.writeInt(st, LongInt(FAmmo)); - // Áîëü + // Боль utils.writeInt(st, LongInt(FPain)); - // Âðåìÿ îæèäàíèÿ + // Время ожидания utils.writeInt(st, LongInt(FSleep)); - // Îçâó÷èâàòü ëè áîëü + // Озвучивать ли боль utils.writeBool(st, FPainSound); - // Áûëà ëè àòàêà âî âðåìÿ àíèìàöèè àòàêè + // Была ли атака во время анимации атаки utils.writeBool(st, FWaitAttackAnim); - // Íàäî ëè ñòðåëÿòü íà ñëåäóþùåì øàãå + // Надо ли стрелять на следующем шаге utils.writeBool(st, FChainFire); - // Ïîäëåæèò ëè ðåñïàâíó + // Подлежит ли респавну utils.writeBool(st, FNoRespawn); - // Êîîðäèíàòû öåëè + // Координаты цели utils.writeInt(st, LongInt(tx)); utils.writeInt(st, LongInt(ty)); - // ID ìîíñòðà ïðè ñòàðòå êàðòû + // ID монстра при старте карты utils.writeInt(st, LongInt(FStartID)); - // Èíäåêñ òðèããåðà, ñîçäàâøåãî ìîíñòðà + // Индекс триггера, создавшего монстра utils.writeInt(st, LongInt(FSpawnTrigger)); - // Îáúåêò ìîíñòðà + // Объект монстра Obj_SaveState(st, @FObj); - // Åñòü ëè àíèìàöèÿ îãíÿ êîëäóíà + // Есть ли анимация огня колдуна anim := (vilefire <> nil); utils.writeBool(st, anim); - // Åñëè åñòü - ñîõðàíÿåì: + // Если есть - сохраняем: if anim then vilefire.SaveState(st); - // Àíèìàöèè + // Анимации for i := ANIM_SLEEP to ANIM_PAIN do begin - // Åñòü ëè ëåâàÿ àíèìàöèÿ + // Есть ли левая анимация anim := (FAnim[i, TDirection.D_LEFT] <> nil); utils.writeBool(st, anim); - // Åñëè åñòü - ñîõðàíÿåì + // Если есть - сохраняем if anim then FAnim[i, TDirection.D_LEFT].SaveState(st); - // Åñòü ëè ïðàâàÿ àíèìàöèÿ + // Есть ли правая анимация anim := (FAnim[i, TDirection.D_RIGHT] <> nil); utils.writeBool(st, anim); - // Åñëè åñòü - ñîõðàíÿåì + // Если есть - сохраняем if anim then FAnim[i, TDirection.D_RIGHT].SaveState(st); end; end; @@ -4585,78 +4163,78 @@ var begin assert(st <> nil); - // Ñèãíàòóðà ìîíñòðà: + // Сигнатура монстра: if not utils.checkSign(st, 'MONS') then raise XStreamError.Create('invalid monster signature'); if (utils.readByte(st) <> 0) then raise XStreamError.Create('invalid monster version'); if (uidMap[FUID] <> nil) and (uidMap[FUID] <> self) then raise Exception.Create('internal error in monster loader (0)'); uidMap[FUID] := nil; - // UID ìîíñòðà: + // UID монстра: FUID := utils.readWord(st); //if (arrIdx = -1) then raise Exception.Create('internal error in monster loader'); if (uidMap[FUID] <> nil) then raise Exception.Create('internal error in monster loader (1)'); uidMap[FUID] := self; - // Íàïðàâëåíèå + // Направление b := utils.readByte(st); if b = 1 then FDirection := TDirection.D_LEFT else FDirection := TDirection.D_RIGHT; // b = 2 - // Íàäî ëè óäàëèòü åãî + // Надо ли удалить его FRemoved := utils.readBool(st); - // Îñòàëîñü çäîðîâüÿ + // Осталось здоровья FHealth := utils.readLongInt(st); - // Ñîñòîÿíèå + // Состояние FState := utils.readByte(st); - // Òåêóùàÿ àíèìàöèÿ + // Текущая анимация FCurAnim := utils.readByte(st); - // UID öåëè + // UID цели FTargetUID := utils.readWord(st); - // Âðåìÿ ïîñëå ïîòåðè öåëè + // Время после потери цели FTargetTime := utils.readLongInt(st); - // Ïîâåäåíèå ìîíñòðà + // Поведение монстра FBehaviour := utils.readByte(st); - // Ãîòîâíîñòü ê âûñòðåëó + // Готовность к выстрелу FAmmo := utils.readLongInt(st); - // Áîëü + // Боль FPain := utils.readLongInt(st); - // Âðåìÿ îæèäàíèÿ + // Время ожидания FSleep := utils.readLongInt(st); - // Îçâó÷èâàòü ëè áîëü + // Озвучивать ли боль FPainSound := utils.readBool(st); - // Áûëà ëè àòàêà âî âðåìÿ àíèìàöèè àòàêè + // Была ли атака во время анимации атаки FWaitAttackAnim := utils.readBool(st); - // Íàäî ëè ñòðåëÿòü íà ñëåäóþùåì øàãå + // Надо ли стрелять на следующем шаге FChainFire := utils.readBool(st); - // Ïîäëåæèò ëè ðåñïàâíó + // Подлежит ли респавну FNoRespawn := utils.readBool(st); - // Êîîðäèíàòû öåëè + // Координаты цели tx := utils.readLongInt(st); ty := utils.readLongInt(st); - // ID ìîíñòðà ïðè ñòàðòå êàðòû + // ID монстра при старте карты FStartID := utils.readLongInt(st); - // Èíäåêñ òðèããåðà, ñîçäàâøåãî ìîíñòðà + // Индекс триггера, создавшего монстра FSpawnTrigger := utils.readLongInt(st); - // Îáúåêò ìîíñòðà + // Объект монстра Obj_LoadState(@FObj, st); - // Åñòü ëè àíèìàöèÿ îãíÿ êîëäóíà + // Есть ли анимация огня колдуна anim := utils.readBool(st); - // Åñëè åñòü - çàãðóæàåì: + // Если есть - загружаем: if anim then begin Assert(vilefire <> nil, 'TMonster.LoadState: no vilefire anim'); vilefire.LoadState(st); end; - // Àíèìàöèè + // Анимации for i := ANIM_SLEEP to ANIM_PAIN do begin - // Åñòü ëè ëåâàÿ àíèìàöèÿ + // Есть ли левая анимация anim := utils.readBool(st); - // Åñëè åñòü - çàãðóæàåì + // Если есть - загружаем if anim then begin Assert(FAnim[i, TDirection.D_LEFT] <> nil, 'TMonster.LoadState: no '+IntToStr(i)+'_left anim'); FAnim[i, TDirection.D_LEFT].LoadState(st); end; - // Åñòü ëè ïðàâàÿ àíèìàöèÿ + // Есть ли правая анимация anim := utils.readBool(st); - // Åñëè åñòü - çàãðóæàåì + // Если есть - загружаем if anim then begin Assert(FAnim[i, TDirection.D_RIGHT] <> nil, 'TMonster.LoadState: no '+IntToStr(i)+'_right anim'); @@ -4694,10 +4272,10 @@ end; procedure TMonster.CatchFire(Attacker: Word; Timeout: Integer = MON_BURN_TIME); begin if FMonsterType in [MONSTER_SOUL, MONSTER_VILE] then - exit; // àð÷è íå ãîðÿò, ÷åðåïà óæå ãîðÿò + exit; // арчи не горят, черепа уже горят if Timeout <= 0 then exit; if g_Obj_CollidePanel(@FObj, 0, 0, PANEL_WATER or PANEL_ACID1 or PANEL_ACID2) then - exit; // íå ïîäãîðàåì â âîäå íà âñÿêèé ñëó÷àé + exit; // не подгораем в воде на всякий случай if FFireTime <= 0 then g_Sound_PlayExAt('SOUND_IGNITE', FObj.X, FObj.Y); FFireTime := Timeout; @@ -4706,23 +4284,16 @@ begin end; procedure TMonster.OnFireFlame(Times: DWORD = 1); -var - id, i: DWORD; - Anim: TAnimation; + var i: DWORD; x, y: Integer; begin if (Random(10) = 1) and (Times = 1) then Exit; - if g_Frames_Get(id, 'FRAMES_FLAME') then + for i := 1 to Times do begin - for i := 1 to Times do - begin - Anim := TAnimation.Create(id, False, 3); - Anim.Alpha := 0; - g_GFX_OnceAnim(Obj.X+Obj.Rect.X+Random(Obj.Rect.Width+Times*2)-(Anim.Width div 2), - Obj.Y+8+Random(8+Times*2)+IfThen(FState = MONSTATE_DEAD, 16, 0), Anim, ONCEANIM_SMOKE); - Anim.Free(); - end; + x := Obj.X + Obj.Rect.X + Random(Obj.Rect.Width + Times * 2) - (R_GFX_FLAME_WIDTH div 2); + y := Obj.Y + 8 + Random(8 + Times * 2) + IfThen(FState = MONSTATE_DEAD, 16, 0); + r_GFX_OnceAnim(R_GFX_FLAME, x, y); end; end;