DEADSOFTWARE

added flamer functionality
authorfgsfds <pvt.fgsfds@gmail.com>
Sat, 12 Aug 2017 15:21:46 +0000 (18:21 +0300)
committerfgsfds <pvt.fgsfds@gmail.com>
Sat, 12 Aug 2017 15:21:46 +0000 (18:21 +0300)
src/game/g_monsters.pas
src/game/g_net.pas
src/game/g_netmsg.pas
src/game/g_player.pas
src/game/g_weapons.pas

index cde1aad4dff139c91b8ffdf65997fa9ce4ba1a3e..cc4926a3135a2a5a97cfa4a3e06e71907eea6008 100644 (file)
@@ -76,6 +76,7 @@ type
     FBloodKind: Byte;
     FShellTimer: Integer;
     FShellType: Byte;
+    FFirePainTime: Integer;
     vilefire: TAnimation;
 
     FDieTriggers: Array of Integer;
@@ -87,6 +88,7 @@ type
 
   public
     FNoRespawn: Boolean;
+    FFireTime: Integer;
 
     constructor Create(MonsterType: Byte; aID: Integer; ForcedUID: Integer = -1);
     destructor Destroy(); override;
@@ -122,6 +124,8 @@ type
     function  AnimIsReverse: Boolean;
     function  shoot(o: PObj; immediately: Boolean): Boolean;
     function  kick(o: PObj): Boolean;
+    procedure CatchFire();
+    procedure OnFireFlame(Times: DWORD = 1);
 
     property MonsterType: Byte read FMonsterType;
     property MonsterHealth: Integer read FHealth write FHealth;
@@ -1478,6 +1482,8 @@ begin
   FNoRespawn := False;
   FShellTimer := -1;
   FBehaviour := BH_NORMAL;
+  FFireTime := 0;
+  FFirePainTime := 0;
 
   if FMonsterType in [MONSTER_ROBO, MONSTER_BARREL] then
     FBloodKind := BLOOD_SPARKS
@@ -2046,6 +2052,25 @@ begin
   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, 0, 0, 0, HIT_FLAME);
+          FFirePainTime := 18;
+        end
+        else
+          FFirePainTime := FFirePainTime - 1;
+    end;
+  end;
+
 // Ìåðòâûé íè÷åãî íå äåëàåò:
   if (FState = STATE_DEAD) then
     goto _end;
@@ -2977,6 +3002,17 @@ begin
   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;
@@ -4144,4 +4180,32 @@ begin
   SetLength(FDieTriggers, 0);
 end;
 
+procedure TMonster.CatchFire();
+begin
+  FFireTime := 360;
+  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.
index 0ea107b875028752a826f3043227275af8a834c5..c9e40400fea7511762dee5f673a05b820b13d776 100644 (file)
@@ -22,7 +22,7 @@ uses
   e_log, e_fixedbuffer, ENet, Classes;
 
 const
-  NET_PROTOCOL_VER = 170;
+  NET_PROTOCOL_VER = 171;
 
   NET_MAXCLIENTS = 24;
   NET_CHANS = 11;
index f8ec00a801c09757c9ed897566a53ff116beba7e..a5bd880c0e817a6c91756c18377b6d94699c26f7 100644 (file)
@@ -1102,6 +1102,7 @@ begin
     e_Buffer_Write(@NetOut, Byte(FPhysics));
     e_Buffer_Write(@NetOut, Byte(FNoRespawn));
     e_Buffer_Write(@NetOut, Byte(FJetpack));
+    e_Buffer_Write(@NetOut, FFireTime);
   end;
 
   g_Net_Host_Send(ID, True, NET_CHAN_PLAYER);
@@ -1378,6 +1379,7 @@ begin
     e_Buffer_Write(@NetOut, MonsterAmmo);
     e_Buffer_Write(@NetOut, MonsterPain);
     e_Buffer_Write(@NetOut, Byte(AnimIsReverse));
+    e_Buffer_Write(@NetOut, FFireTime);
   end;
 
   g_Net_Host_Send(ID, True, NET_CHAN_MONSTER);
@@ -2182,6 +2184,7 @@ begin
     FNoRespawn := e_Raw_Read_Byte(P) <> 0;
     OldJet := FJetpack;
     FJetpack := e_Raw_Read_Byte(P) <> 0;
+    FFireTime := e_Raw_Read_LongInt(P);
     if OldJet and not FJetpack then
       JetpackOff
     else if not OldJet and FJetpack then
@@ -2668,6 +2671,7 @@ begin
     MonsterAmmo := e_Raw_Read_LongInt(P);
     MonsterPain := e_Raw_Read_LongInt(P);
     AnimRevert := e_Raw_Read_Byte(P) <> 0;
+    FFireTime := e_Raw_Read_LongInt(P);
     RevertAnim(AnimRevert);
 
     if MonsterState <> MState then
index d03247cdc5e4e3f2505078aa28ccd5f165f70f55..a0496da85e63e8314c938bcea0aa18bd7a957495 100644 (file)
@@ -167,6 +167,7 @@ type
     FObj:       TObj;
     FXTo, FYTo: Integer;
     FSpectatePlayer: Integer;
+    FFirePainTime:   Integer;
 
     FSavedState: TPlayerSavedState;
 
@@ -201,6 +202,7 @@ type
     function    FullInLift(XInc, YInc: Integer): Integer;
     {procedure   CollideItem();}
     procedure   FlySmoke(Times: DWORD = 1);
+    procedure   OnFireFlame(Times: DWORD = 1);
     function    GetAmmoByWeapon(Weapon: Byte): Word;
     procedure   SetAction(Action: Byte; Force: Boolean = False);
     procedure   OnDamage(Angle: SmallInt); virtual;
@@ -244,6 +246,7 @@ type
     FPing:      Word;
     FLoss:      Byte;
     FDummy:     Boolean;
+    FFireTime:  Integer;
 
     constructor Create(); virtual;
     destructor  Destroy(); override;
@@ -305,6 +308,7 @@ type
     procedure   RealizeCurrentWeapon();
     procedure   JetpackOn;
     procedure   JetpackOff;
+    procedure   CatchFire();
 
     property    Name: String read FName write FName;
     property    Model: TPlayerModel read FModel;
@@ -1987,6 +1991,8 @@ begin
   FLoss := 0;
   FSavedState.WaitRecall := False;
   FShellTimer := -1;
+  FFireTime := 0;
+  FFirePainTime := 0;
 
   FActualModelName := 'doomer';
 
@@ -2808,6 +2814,7 @@ begin
     WEAPON_FLAMETHROWER:
       if FAmmo[A_FUEL] > 0 then
       begin
+        g_Weapon_flame(wx, wy, xd, yd, FUID);
         FReloading[FCurrWeap] := WEAPON_RELOAD[FCurrWeap];
         Dec(FAmmo[A_FUEL]);
         FFireAngle := FAngle;
@@ -2873,6 +2880,13 @@ begin
   FJetSoundOff.PlayAt(FObj.X, FObj.Y);
 end;
 
+procedure TPlayer.CatchFire();
+begin
+  FFireTime := 360;
+  if g_Game_IsNet and g_Game_IsServer then
+    MH_SEND_PlayerStats(FUID);
+end;
+
 procedure TPlayer.Jump();
 begin
   if gFly or FJetpack then
@@ -4813,6 +4827,29 @@ begin
     end else if FAir < AIR_DEF then
       FAir := AIR_DEF;
 
+    if FFireTime > 0 then
+    begin
+      if BodyInLiquid(0, 0) then
+      begin
+        FFireTime := 0;
+        FFirePainTime := 0;
+      end
+      else
+      begin
+        OnFireFlame(1);
+        if FFirePainTime <= 0 then
+        begin
+          if g_Game_IsServer then
+            Damage(5, 0, 0, 0, HIT_FLAME);
+          FFirePainTime := 18;
+        end;
+        FFirePainTime := FFirePainTime - 1;
+        FFireTime := FFireTime - 1;
+        if (FFireTime = 0) and g_Game_IsNet and g_Game_IsServer then
+          MH_SEND_PlayerStats(FUID);
+      end;
+    end;
+
     if FDamageBuffer > 0 then
     begin
       if FDamageBuffer >= 9 then
@@ -5087,6 +5124,7 @@ begin
 
     WEAPON_FLAMETHROWER:
     begin
+      g_Weapon_flame(wx, wy, xd, yd, FUID, WID);
       FFireAngle := FAngle;
       f := True;
     end;
@@ -5853,6 +5891,27 @@ begin
   end;
 end;
 
+procedure TPlayer.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), Anim, ONCEANIM_SMOKE);
+      Anim.Free();
+    end;
+  end;
+end;
+
 procedure TPlayer.PauseSounds(Enable: Boolean);
 begin
   FSawSound.Pause(Enable);
index 38d33e3b5c713244a7c978857c816d1d39d2f35a..6021daff58ecda40d6a0aceb210d69520ae25395 100644 (file)
@@ -44,6 +44,7 @@ type
     Animation: TAnimation;
     TextureID: DWORD;
     Timeout: DWORD;
+    Stopped: Byte;
   end;
 
 var
@@ -63,6 +64,7 @@ procedure g_Weapon_punch(x, y: Integer; d, SpawnerUID: Word);
 function g_Weapon_chainsaw(x, y: Integer; d, SpawnerUID: Word): Integer;
 procedure g_Weapon_rocket(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
 procedure g_Weapon_revf(x, y, xd, yd: Integer; SpawnerUID, TargetUID: Word; WID: Integer = -1; Silent: Boolean = False);
+procedure g_Weapon_flame(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
 procedure g_Weapon_plasma(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
 procedure g_Weapon_ball1(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
 procedure g_Weapon_ball2(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
@@ -139,6 +141,10 @@ const
   SHOT_BFG_DAMAGE = 100;
   SHOT_BFG_RADIUS = 256;
 
+  SHOT_FLAME_WIDTH = 4;
+  SHOT_FLAME_HEIGHT = 4;
+  SHOT_FLAME_LIFETIME = 360; 
+
   SHOT_SIGNATURE = $544F4853; // 'SHOT'
 
 var
@@ -346,7 +352,14 @@ begin
   end;
 
   if g_Game_IsServer then
-    Result := m.Damage(d, vx, vy, SpawnerUID, t)
+  begin
+    if (t <> HIT_FLAME) or (m.FFireTime = 0) or (vx <> 0) or (vy <> 0) then
+      Result := m.Damage(d, vx, vy, SpawnerUID, t)
+    else
+      Result := True;
+    if t = HIT_FLAME then
+      m.CatchFire();
+  end
   else
     Result := True;
 end;
@@ -359,7 +372,13 @@ begin
   if (p.UID = SpawnerUID) and (t <> HIT_ROCKET) and (t <> HIT_ELECTRO) then
     Exit;
 
-  if g_Game_IsServer then p.Damage(d, SpawnerUID, vx, vy, t);
+  if g_Game_IsServer then 
+  begin
+    if (t <> HIT_FLAME) or (p.FFireTime = 0) or (vx <> 0) or (vy <> 0) then
+      p.Damage(d, SpawnerUID, vx, vy, t);
+    if (t = HIT_FLAME) then
+      p.CatchFire();
+  end;
 
   Result := True;
 end;
@@ -521,6 +540,23 @@ begin
       end;
     end;
 
+    WEAPON_FLAMETHROWER:
+    begin
+      with Shots[find_id] do
+      begin
+        g_Obj_Init(@Obj);
+
+        Obj.Rect.Width := SHOT_FLAME_WIDTH;
+        Obj.Rect.Height := SHOT_FLAME_HEIGHT;
+
+        Triggers := nil;
+        ShotType := WEAPON_FLAMETHROWER;
+        Animation := nil;
+        TextureID := 0;
+        Stopped := 0;
+      end;
+    end;
+
     WEAPON_IMP_FIRE:
     begin
       with Shots[find_id] do
@@ -648,6 +684,8 @@ begin
   Shots[i].Obj.Accel.Y := 0;
   if Shots[i].ShotType in [WEAPON_ROCKETLAUNCHER, WEAPON_BFG] then
     Shots[i].Timeout := 900 // ~25 sec
+  else if Shots[i].ShotType = WEAPON_FLAMETHROWER then
+    Shots[i].Timeout := SHOT_FLAME_LIFETIME
   else
     Shots[i].Timeout := 550 // ~15 sec
 end;
@@ -988,6 +1026,7 @@ begin
   g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_IMPFIRE', GameWAD+':TEXTURES\EIMPFIRE', 64, 64, 3);
   g_Frames_CreateWAD(nil, 'FRAMES_BFGHIT', GameWAD+':TEXTURES\BFGHIT', 64, 64, 4);
   g_Frames_CreateWAD(nil, 'FRAMES_FIRE', GameWAD+':TEXTURES\FIRE', 64, 128, 8);
+  g_Frames_CreateWAD(nil, 'FRAMES_FLAME', GameWAD+':TEXTURES\FLAME', 32, 32, 11);
   g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_PLASMA', GameWAD+':TEXTURES\EPLASMA', 32, 32, 4, True);
   g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_BSPFIRE', GameWAD+':TEXTURES\EBSPFIRE', 32, 32, 5);
   g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_CACOFIRE', GameWAD+':TEXTURES\ECACOFIRE', 64, 64, 3);
@@ -1301,6 +1340,45 @@ begin
     g_Sound_PlayExAt('SOUND_WEAPON_FIREPLASMA', x, y);
 end;
 
+procedure g_Weapon_flame(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
+  Silent: Boolean = False);
+var
+  find_id, FramesID: DWORD;
+  dx, dy: Integer;
+begin
+  if WID < 0 then
+    find_id := FindShot()
+  else
+  begin
+    find_id := WID;
+    if Integer(find_id) >= High(Shots) then
+      SetLength(Shots, find_id + 64);
+  end;
+
+  with Shots[find_id] do
+  begin
+    g_Obj_Init(@Obj);
+
+    Obj.Rect.Width := SHOT_FLAME_WIDTH;
+    Obj.Rect.Height := SHOT_FLAME_HEIGHT;
+
+    dx := IfThen(xd>x, -Obj.Rect.Width, 0);
+    dy := -(Obj.Rect.Height div 2);
+    throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 16);
+
+    triggers := nil;
+    ShotType := WEAPON_FLAMETHROWER;
+    Animation := nil;
+    TextureID := 0;
+    Stopped := 0;
+  end;
+
+  Shots[find_id].SpawnerUID := SpawnerUID;
+
+  // if not Silent then
+  //  g_Sound_PlayExAt('SOUND_WEAPON_FIREPLASMA', x, y);
+end;
+
 procedure g_Weapon_ball1(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
   Silent: Boolean = False);
 var
@@ -1792,6 +1870,60 @@ begin
             end;
           end;
 
+        WEAPON_FLAMETHROWER: // Îãíåìåò
+          begin
+          // Ïîä âîäîé íå ñòðåëÿåò, ñî âðåìåíåì óìèðàåò
+            if (Timeout < 1) or WordBool(st and (MOVE_INWATER)) then
+            begin
+              ShotType := 0;
+              Continue;
+            end;
+
+          // Ãðàâèòàöèÿ
+            if Stopped = 0 then
+              Obj.Accel.Y := Obj.Accel.Y + 1;
+          // Ïîïàëè â ñòåíó èëè â âîäó:
+            if WordBool(st and (MOVE_HITWALL or MOVE_HITLAND or MOVE_HITCEIL or MOVE_HITWATER)) then
+            begin
+            // Ïðèëèïàåì:
+              Obj.Vel.X := 0;
+              Obj.Vel.Y := 0;
+              Obj.Accel.Y := 0;
+              if WordBool(st and (MOVE_HITWALL or MOVE_HITWATER)) then
+                Stopped := 1
+              else
+                Stopped := 2;
+            end;
+
+            a := IfThen(Stopped = 0, 2, 1);
+          // Åñëè â êîãî-òî ïîïàëè
+            if g_Weapon_Hit(@Obj, a, SpawnerUID, HIT_FLAME, False) <> 0 then
+            begin
+            // HIT_FLAME ñàì ïîäîææåò
+            // Åñëè â ïîëåòå ïîïàëè, èñ÷åçàåì
+              if Stopped = 0 then
+                ShotType := 0;
+            end;
+
+            if g_Frames_Get(_id, 'FRAMES_FLAME') then
+            begin
+              Anim := TAnimation.Create(_id, False, 3);
+              Anim.Alpha := 0;
+              case Stopped of
+                0: g_GFX_OnceAnim(cx-4+Random(8)-(Anim.Width div 2),
+                               cy-4+Random(8)-(Anim.Height div 2),
+                               Anim, ONCEANIM_SMOKE);
+                1: g_GFX_OnceAnim(cx-4+Random(8)-(Anim.Width div 2),
+                               cy-12+Random(24)-(Anim.Height div 2),
+                               Anim, ONCEANIM_SMOKE);
+                2: g_GFX_OnceAnim(cx-12+Random(24)-(Anim.Width div 2),
+                               cy-4+Random(8)-(Anim.Height div 2),
+                               Anim, ONCEANIM_SMOKE);
+              end;
+              Anim.Free();
+            end;
+          end;
+
         WEAPON_BFG: // BFG
           begin
           // Ïîïàëà â âîäó - ýëåêòðîøîê ïî âîäå:
@@ -1901,10 +2033,13 @@ begin
       begin
         if gGameSettings.GameType = GT_SERVER then
           MH_SEND_DeleteShot(i, Obj.X, Obj.Y, Loud);
-        Animation.Free();
-        Animation := nil;
+        if Animation <> nil then
+        begin
+          Animation.Free();
+          Animation := nil;
+        end;
       end
-      else if (oldvx <> Obj.Vel.X) or (oldvy <> Obj.Vel.Y) then
+      else if (ShotType <> WEAPON_FLAMETHROWER) and ((oldvx <> Obj.Vel.X) or (oldvy <> Obj.Vel.Y)) then
         if gGameSettings.GameType = GT_SERVER then
           MH_SEND_UpdateShot(i);
     end;
@@ -1944,7 +2079,7 @@ begin
             else
               Animation.Draw(Obj.X, Obj.Y, M_NONE);
           end
-        else
+        else if TextureID <> 0 then
           begin
             if (Shots[i].ShotType = WEAPON_ROCKETLAUNCHER) then
               e_DrawAdv(TextureID, Obj.X, Obj.Y, 0, True, False, a, @p, M_NONE)
@@ -2026,6 +2161,8 @@ begin
         Mem.WriteDWORD(Shots[i].Triggers[j]);
     // Îáúåêò ñíàðÿäà:
       Obj_SaveState(@Shots[i].Obj, Mem);
+    // Êîñòûëèíà åáàíàÿ:
+      Mem.WriteByte(Shots[i].Stopped);
     end;
 end;
 
@@ -2067,6 +2204,8 @@ begin
       Mem.ReadDWORD(Shots[i].Triggers[j]);
   // Îáúåêò ïðåäìåòà:
     Obj_LoadState(@Shots[i].Obj, Mem);
+  // Êîñòûëèíà åáàíàÿ:
+    Mem.ReadByte(Shots[i].Stopped);
 
   // Óñòàíîâêà òåêñòóðû èëè àíèìàöèè:
     Shots[i].TextureID := DWORD(-1);