index 507a56024cf75640394dbe91dd3bd4ccaa45b45a..e37e2e448b5115c204097f6c81c5467e5e01d5ae 100644 (file)
--- a/src/game/g_monsters.pas
+++ b/src/game/g_monsters.pas
+(* Copyright (C) DooM 2D:Forever Developers
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *)
+{$MODE DELPHI}
unit g_monsters;
interface
FPain: Integer;
FSleep: Integer;
FPainSound: Boolean;
+ FPainTicks: Integer;
FWaitAttackAnim: Boolean;
FChainFire: Boolean;
tx, ty: Integer;
FBloodKind: Byte;
FShellTimer: Integer;
FShellType: Byte;
+ FFirePainTime: Integer;
+ FFireAttacker: Word;
vilefire: TAnimation;
FDieTriggers: Array of Integer;
public
FNoRespawn: Boolean;
+ FFireTime: Integer;
constructor Create(MonsterType: Byte; aID: Integer; ForcedUID: Integer = -1);
destructor Destroy(); override;
function AnimIsReverse: Boolean;
function shoot(o: PObj; immediately: Boolean): Boolean;
function kick(o: PObj): Boolean;
+ procedure CatchFire(Attacker: Word);
+ procedure OnFireFlame(Times: DWORD = 1);
property MonsterType: Byte read FMonsterType;
property MonsterHealth: Integer read FHealth write FHealth;
uses
e_log, g_main, g_sound, g_gfx, g_player, g_game,
g_weapons, g_triggers, MAPDEF, g_items, g_options,
- g_console, g_map, Math, SysUtils, g_menu, WADEDITOR,
+ g_console, g_map, Math, SysUtils, g_menu, wadreader,
g_language, g_netmsg;
const
(Name:'SERG'; Rect:(X:15; Y:8; Width:34; Height:52); Health:20;
RunVel: 3; MinPain: 0; Pain: 10; Jump: 10),
-
+
(Name:'CYBER'; Rect:(X:24; Y:9; Width:80; Height:110); Health:500;
RunVel: 5; MinPain: 50; Pain: 70; Jump: 10),
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, 0, 3); //CYBER
- AnimDeltaRight: ((X: 2; Y: -6), (X: 2; Y: -6), (X: -3; Y: -4), (X: -3; Y: -4), (X: 25; Y: -6), (X: 25; 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:-26; Y: -3), (X: 1; Y: -3))),
+ (LeftAnim: True; wX: 70; wY: 73; AnimSpeed:(3, 3, 3, 3, 3, 4, 3); //CYBER
+ 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
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));
g_Frames_CreateWAD(nil, 'FRAMES_MONSTER_CYBER_PAIN_L', GameWAD+':MTEXTURES\CYBER_PAIN_L', 128, 128, 1);
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_SetLoadingText(_lc[I_LOAD_MONSTER_SOUNDS], 0, False);
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');
gMonsters[a].Update();
end
else
- begin
+ begin
gMonsters[a].Free();
gMonsters[a] := nil;
end;
function g_Monsters_GetNameByID(MonsterType: Byte): String;
begin
if MonsterType in [MONSTER_DEMON..MONSTER_MAN] then
- Result := MONSTERTABLE[MonsterType].Name;
+ Result := MONSTERTABLE[MonsterType].Name
+ else
+ Result := '?';
end;
function g_Monsters_GetKilledBy(MonsterType: Byte): String;
Exit;
FPainSound := True;
+ FPainTicks := 20;
case FMonsterType of
MONSTER_IMP, MONSTER_ZOMBY, MONSTER_SERG,
g_Sound_PlayExAt('SOUND_MONSTER_PAIN', FObj.X, FObj.Y);
MONSTER_SOUL, MONSTER_BARON, MONSTER_CACO,
MONSTER_KNIGHT, MONSTER_DEMON, MONSTER_SPIDER,
- MONSTER_CYBER:
+ MONSTER_BSP, MONSTER_CYBER:
g_Sound_PlayExAt('SOUND_MONSTER_PAIN2', FObj.X, FObj.Y);
MONSTER_VILE:
g_Sound_PlayExAt('SOUND_MONSTER_VILE_PAIN', FObj.X, FObj.Y);
FWaitAttackAnim := False;
FChainFire := False;
FShellTimer := -1;
-
+
FState := STATE_SLEEP;
FCurAnim := ANIM_SLEEP;
FNoRespawn := False;
FShellTimer := -1;
FBehaviour := BH_NORMAL;
+ FFireTime := 0;
+ FFirePainTime := 0;
+ FFireAttacker := 0;
if FMonsterType in [MONSTER_ROBO, MONSTER_BARREL] then
FBloodKind := BLOOD_SPARKS
// Ýòî çíà÷èò: dX := -frameWidth - animDeltaX + hitX + hitWidth + hitX
end;
end
- else // Ïðàâàÿ àíèìàöèÿ
+ else // Ïðàâàÿ àíèìàöèÿ
begin
dx := MONSTER_ANIMTABLE[FMonsterType].AnimDeltaRight[FCurAnim].X;
dy := MONSTER_ANIMTABLE[FMonsterType].AnimDeltaRight[FCurAnim].Y;
FObj.Rect := MONSTERTABLE[FMonsterType].Rect;
FHealth := MONSTERTABLE[FMonsterType].Health;
- FAmmo := 0;
+ FAmmo := 0;
FPain := 0;
end;
else Exit;
if ForceAnim <> 255 then
Anim := ForceAnim;
-// Åñëè àíèìàöèÿ íîâàÿ - ïåðåçàïóñêàåì å¸:
+// Åñëè àíèìàöèÿ íîâàÿ - ïåðåçàïóñêàåì å¸:
if FCurAnim <> Anim then
if FAnim[Anim, FDirection] <> nil then
begin
Exit;
end;
- FPainSound := False;
+ if FPainTicks > 0 then
+ Dec(FPainTicks)
+ else
+ FPainSound := False;
// Äâèãàåìñÿ:
st := g_Obj_Move(@FObj, fall, True, True);
if (FState = STATE_DIE) or (FState = STATE_DEAD) then
FObj.Vel.X := z_dec(FObj.Vel.X, 1);
+ if FFireTime > 0 then
+ begin
+ if WordBool(st and MOVE_INWATER) then
+ FFireTime := 0
+ else
+ begin
+ OnFireFlame(1);
+ FFireTime := FFireTime - 1;
+ if (FState <> STATE_DIE) and (FState <> STATE_DEAD) then
+ if FFirePainTime = 0 then
+ begin
+ Damage(5, FFireAttacker, 0, 0, HIT_FLAME);
+ FFirePainTime := 18;
+ end
+ else
+ FFirePainTime := FFirePainTime - 1;
+ end;
+ end;
+
// Ìåðòâûé íè÷åãî íå äåëàåò:
if (FState = STATE_DEAD) then
goto _end;
FPain := MONSTERTABLE[FMonsterType].Pain;
if gSoundEffectsDF then PainSound();
end;
+ if (not gSoundEffectsDF) and (FPain >= MONSTERTABLE[FMonsterType].MinPain) then
+ PainSound();
// Ñíèæàåì áîëü ñî âðåìåíåì:
FPain := FPain - 5;
if g_Obj_Collide(@FObj, @o) and (FTargetUID <> 0) then
begin
FTargetTime := 0;
- if kick(@o) then
- goto _end;
+ if (FMonsterType <> MONSTER_CYBER) or (Random(2) = 0) then
+ begin
+ if kick(@o) then
+ goto _end;
+ end;
end;
// Ðàññòîÿíèå äî öåëè:
FDirection := D_LEFT
else
FDirection := D_RIGHT;
-
+
goto _end;
end;
FWaitAttackAnim := False;
end
-
+
else // Àíèìàöèÿ àòàêè åùå èäåò (èñêëþ÷åíèå - Lost_Soul):
if (FMonsterType = MONSTER_SOUL) or
( (not FWaitAttackAnim) and
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_SKEL, MONSTER_ROBO, MONSTER_CYBER:
+ // Ðîáîò, êèáåð èëè ñêåëåò ñèëüíî ïèíàþòñÿ:
if FCurAnim = ANIM_ATTACK2 then
begin
o := FObj;
- o.Vel.X := IfThen(FDirection = D_RIGHT, 1, -1)*50;
- if g_Weapon_Hit(@o, 50, FUID, HIT_SOME) <> 0 then
+ o.Vel.X := IfThen(FDirection = D_RIGHT, 1, -1)*IfThen(FMonsterType = MONSTER_CYBER, 60, 50);
+ if g_Weapon_Hit(@o, IfThen(FMonsterType = MONSTER_CYBER, 33, 50), FUID, HIT_SOME) <> 0 then
g_Sound_PlayExAt('SOUND_MONSTER_SKEL_HIT', FObj.X, FObj.Y);
end;
Exit;
end;
- FPainSound := False;
+ if FPainTicks > 0 then
+ Dec(FPainTicks)
+ else
+ FPainSound := False;
// Äâèãàåìñÿ:
st := g_Obj_Move(@FObj, fall, True, True);
if (FState = STATE_DIE) or (FState = STATE_DEAD) then
FObj.Vel.X := z_dec(FObj.Vel.X, 1);
+ if FFireTime > 0 then
+ begin
+ if WordBool(st and MOVE_INWATER) then
+ FFireTime := 0
+ else
+ begin
+ OnFireFlame(1);
+ FFireTime := FFireTime - 1;
+ end;
+ end;
+
// Ìåðòâûé íè÷åãî íå äåëàåò:
if (FState = STATE_DEAD) then
goto _end;
if FPain >= MONSTERTABLE[FMonsterType].Pain then
begin
FPain := MONSTERTABLE[FMonsterType].Pain;
- PainSound();
+ if gSoundEffectsDF then PainSound();
end;
+ if (not gSoundEffectsDF) and (FPain >= MONSTERTABLE[FMonsterType].MinPain) then
+ PainSound();
// Ñíèæàåì áîëü ñî âðåìåíåì:
FPain := FPain - 5;
FWaitAttackAnim := False;
end
-
+
else // Àíèìàöèÿ àòàêè åùå èäåò (èñêëþ÷åíèå - Lost_Soul):
if (FMonsterType = MONSTER_SOUL) or
( (not FWaitAttackAnim) and
// Lost_Soul óêóñèë êîãî-òî => ïåðåõîäèò íà øàã:
if FMonsterType = MONSTER_SOUL then
SetState(STATE_GO);
-
+
MONSTER_FISH:
g_Weapon_Hit(@FObj, 10, FUID, HIT_SOME);
- MONSTER_SKEL, MONSTER_ROBO:
- // Ðîáîò èëè ñêåëåò ñèëüíî ïèíàþòñÿ:
+ MONSTER_SKEL, MONSTER_ROBO, MONSTER_CYBER:
+ // Ðîáîò, êèáåð èëè ñêåëåò ñèëüíî ïèíàþòñÿ:
if FCurAnim = ANIM_ATTACK2 then
begin
o := FObj;
- o.Vel.X := IfThen(FDirection = D_RIGHT, 1, -1)*50;
- g_Weapon_Hit(@o, 50, FUID, HIT_SOME);
+ o.Vel.X := IfThen(FDirection = D_RIGHT, 1, -1)*IfThen(FMonsterType = MONSTER_CYBER, 60, 50);
+ g_Weapon_Hit(@o, IfThen(FMonsterType = MONSTER_CYBER, 33, 50), FUID, HIT_SOME);
end;
MONSTER_VILE:
if g_Obj_CollidePanel(@FObj, 0, 0, PANEL_LIFTLEFT or PANEL_LIFTRIGHT) and
not ((FState = STATE_DEAD) or (FState = STATE_DIE)) then
FObj.Vel.X := oldvelx;
-
+
// Åñëè åñòü àíèìàöèÿ, òî ïóñòü îíà èäåò:
if FAnim[FCurAnim, FDirection] <> nil then
FAnim[FCurAnim, FDirection].Update();
g_Sound_PlayExAt('SOUND_MONSTER_IMP_ATTACK', FObj.X, FObj.Y);
Result := True;
end;
- MONSTER_SKEL:
- begin
- SetState(STATE_ATTACK, ANIM_ATTACK2);
- g_Sound_PlayExAt('SOUND_MONSTER_SKEL_ATTACK', FObj.X, FObj.Y);
- Result := True;
- end;
- MONSTER_ROBO:
+ MONSTER_SKEL, MONSTER_ROBO, MONSTER_CYBER:
begin
SetState(STATE_ATTACK, ANIM_ATTACK2);
g_Sound_PlayExAt('SOUND_MONSTER_SKEL_ATTACK', FObj.X, FObj.Y);
SetLength(FDieTriggers, 0);
end;
+procedure TMonster.CatchFire(Attacker: Word);
+begin
+ FFireTime := 100;
+ FFireAttacker := Attacker;
+ if g_Game_IsNet and g_Game_IsServer then
+ MH_SEND_MonsterState(FUID);
+end;
+
+procedure TMonster.OnFireFlame(Times: DWORD = 1);
+var
+ id, i: DWORD;
+ Anim: TAnimation;
+begin
+ if (Random(10) = 1) and (Times = 1) then
+ Exit;
+
+ if g_Frames_Get(id, 'FRAMES_FLAME') then
+ 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 = STATE_DEAD, 16, 0), Anim, ONCEANIM_SMOKE);
+ Anim.Free();
+ end;
+ end;
+end;
+
end.