DEADSOFTWARE

Game: add damage absorption
[d2df-sdl.git] / src / game / g_weapons.pas
index bb17a4138972d82f07ac7674dc966e543cec69d3..1dd468824ba1b023ad7e514c86ac166654a45a9f 100644 (file)
@@ -51,7 +51,7 @@ function g_Weapon_Hit(obj: PObj; d: Integer; SpawnerUID: Word; t: Byte; HitCorps
 function g_Weapon_HitUID(UID: Word; d: Integer; SpawnerUID: Word; t: Byte): Boolean;
 function g_Weapon_CreateShot(I: Integer; ShotType: Byte; Spawner, TargetUID: Word; X, Y, XV, YV: Integer): LongWord;
 
-procedure g_Weapon_gun(const x, y, xd, yd, v, dmg: Integer; SpawnerUID: Word; CheckTrigger: Boolean);
+procedure g_Weapon_gun(const x, y, xd, yd, v, indmg: Integer; SpawnerUID: Word; CheckTrigger: Boolean);
 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);
@@ -527,7 +527,7 @@ begin
               g_TraceVector(X, Y, Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
                             Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)) then
           begin
-            Damage(50, 0, 0);
+            Damage(50, SpawnerUID, 0, 0);
             g_Weapon_BFGHit(Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
                             Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2));
           end;
@@ -876,8 +876,8 @@ begin
            g_Obj_Collide(obj, @gCorpses[i].Obj) then
         begin
           // Ðàñïèëèâàåì òðóï:
-          gCorpses[i].Damage(d, (obj^.Vel.X+obj^.Accel.X) div 4,
-                                (obj^.Vel.Y+obj^.Accel.Y) div 4);
+          gCorpses[i].Damage(d, SpawnerUID, (obj^.Vel.X+obj^.Accel.X) div 4,
+                                            (obj^.Vel.Y+obj^.Accel.Y) div 4);
           Result := 1;
         end;
   end;
@@ -893,10 +893,16 @@ begin
         Exit;
       end;
 
-      if PlayerHit() then
+      // È â êîíöå èãðîêîâ, íî òîëüêî åñëè ïîëîæåíî
+      // (èëè ñíàðÿä îò ìîíñòðà, èëè friendlyfire, èëè friendly_hit_projectile)
+      if (g_GetUIDType(SpawnerUID) <> UID_PLAYER) or
+         LongBool(gGameSettings.Options and (GAME_OPTION_TEAMDAMAGE or GAME_OPTION_TEAMHITPROJECTILE)) then
       begin
-        Result := 1;
-        Exit;
+        if PlayerHit() then
+        begin
+          Result := 1;
+          Exit;
+        end;
       end;
     end;
 
@@ -934,11 +940,15 @@ begin
         Exit;
       end;
 
-      // È â êîíöå ñâîèõ èãðîêîâ
-      if PlayerHit(1) then
+      // È â êîíöå ñâîèõ èãðîêîâ, íî òîëüêî åñëè ïîëîæåíî
+      // (èëè friendlyfire, èëè friendly_hit_projectile)
+      if LongBool(gGameSettings.Options and (GAME_OPTION_TEAMDAMAGE or GAME_OPTION_TEAMHITPROJECTILE)) then
       begin
-        Result := 1;
-        Exit;
+        if PlayerHit(1) then
+        begin
+          Result := 1;
+          Exit;
+        end;
       end;
     end;
 
@@ -1050,7 +1060,7 @@ begin
             mm := Max(abs(dx), abs(dy));
             if mm = 0 then mm := 1;
 
-            Damage(Round(100*(rad-m)/rad), (dx*10) div mm, (dy*10) div mm);
+            Damage(Round(100*(rad-m)/rad), SpawnerUID, (dx*10) div mm, (dy*10) div mm);
           end;
         end;
 
@@ -1388,18 +1398,30 @@ end;
 
 
 //!!!FIXME!!!
-procedure g_Weapon_gun (const x, y, xd, yd, v, dmg: Integer; SpawnerUID: Word; CheckTrigger: Boolean);
+procedure g_Weapon_gun (const x, y, xd, yd, v, indmg: Integer; SpawnerUID: Word; CheckTrigger: Boolean);
 var
   x0, y0: Integer;
   x2, y2: Integer;
   xi, yi: Integer;
   wallDistSq: Integer = $3fffffff;
+  spawnerPlr: TPlayer = nil;
+  dmg: Integer;
 
   function doPlayerHit (idx: Integer; hx, hy: Integer): Boolean;
   begin
     result := false;
     if (idx < 0) or (idx > High(gPlayers)) then exit;
     if (gPlayers[idx] = nil) or not gPlayers[idx].alive then exit;
+    if (spawnerPlr <> nil) then
+    begin
+      if ((gGameSettings.Options and (GAME_OPTION_TEAMHITTRACE or GAME_OPTION_TEAMDAMAGE)) = 0) and
+         (spawnerPlr.Team <> TEAM_NONE) and (spawnerPlr.Team = gPlayers[idx].Team) then
+          begin
+            if (spawnerPlr <> gPlayers[idx]) and ((gGameSettings.Options and GAME_OPTION_TEAMABSORBDAMAGE) = 0) then
+              dmg := Max(1, dmg div 2);
+            exit;
+        end;
+    end;
     result := HitPlayer(gPlayers[idx], dmg, (xi*v)*10, (yi*v)*10-3, SpawnerUID, HIT_SOME);
     if result and (v <> 0) then gPlayers[idx].Push((xi*v), (yi*v));
     {$IF DEFINED(D2F_DEBUG)}
@@ -1492,6 +1514,11 @@ begin
 
   if (xd = 0) and (yd = 0) then exit;
 
+  if (g_GetUIDType(SpawnerUID) = UID_PLAYER) then
+    spawnerPlr := g_Player_Get(SpawnerUID);
+
+  dmg := indmg;
+
   //wgunMonHash.reset(); //FIXME: clear hash on level change
   wgunHitHeap.clear();
   wgunHitTimeUsed := 0;