DEADSOFTWARE

g_weapons.g_Weapon_gun: faster traces (i hope)
[d2df-sdl.git] / src / game / g_player.pas
index f4c54db99b1deaa191ea23dd9a5bb92c650ae7bc..f277a4e8ab74fa5ce9992b49c8af0b215c4e5e27 100644 (file)
@@ -21,7 +21,7 @@ interface
 uses
   e_graphics, g_playermodel, g_basic, g_textures,
   g_weapons, g_phys, g_sound, g_saveload, MAPSTRUCT,
-  BinEditor, g_panel;
+  BinEditor, g_panel, z_aabbtree;
 
 const
   KEY_LEFT       = 1;
@@ -222,6 +222,8 @@ type
     procedure resetWeaponQueue ();
     function hasAmmoForWeapon (weapon: Byte): Boolean;
 
+    function getMapAABB (): AABB2D;
+
   public
     FDamageBuffer:   Integer;
 
@@ -311,6 +313,9 @@ type
     procedure   JetpackOff;
     procedure   CatchFire(Attacker: Word);
 
+    //WARNING! this does nothing for now, but still call it!
+    procedure positionChanged (); //WARNING! call this after monster position was changed, or coldet will not work right!
+
     property    Name: String read FName write FName;
     property    Model: TPlayerModel read FModel;
     property    Health: Integer read FHealth write FHealth;
@@ -343,6 +348,8 @@ type
     property    UID: Word read FUID write FUID;
     property    JustTeleported: Boolean read FJustTeleported write FJustTeleported;
     property    NetTime: LongWord read FNetTime write FNetTime;
+
+    property mapAABB: AABB2D read getMapAABB;
   end;
 
   TDifficult = record
@@ -406,8 +413,11 @@ type
     RAngle:   Integer;
     Color:    TRGB;
     Obj:      TObj;
+
+    procedure positionChanged (); //WARNING! call this after monster position was changed, or coldet will not work right!
   end;
 
+
   TShell = record
     SpriteID: DWORD;
     Live:     Boolean;
@@ -416,6 +426,8 @@ type
     Timeout:  Cardinal;
     CX, CY:   Integer;
     Obj:      TObj;
+
+    procedure positionChanged (); //WARNING! call this after monster position was changed, or coldet will not work right!
   end;
 
   TCorpse = class (TObject)
@@ -438,6 +450,8 @@ type
     procedure   SaveState(var Mem: TBinMemoryWriter);
     procedure   LoadState(var Mem: TBinMemoryReader);
 
+    procedure positionChanged (); //WARNING! call this after monster position was changed, or coldet will not work right!
+
     property    Obj: TObj read FObj;
     property    State: Byte read FState;
     property    Mess: Boolean read FMess;
@@ -593,6 +607,11 @@ var
   BotNames: Array of String;
   BotList: Array of TBotProfile;
 
+
+procedure TGib.positionChanged (); begin end;
+procedure TShell.positionChanged (); begin end;
+
+
 function Lerp(X, Y, Factor: Integer): Integer;
 begin
   Result := X + ((Y - X) div Factor);
@@ -1521,6 +1540,7 @@ begin
     Obj.X := fX;
     Obj.Y := fY;
     g_Obj_Push(@Obj, dX + Random(4)-Random(4), dY-Random(4));
+    positionChanged(); // this updates spatial accelerators
     RAngle := Random(360);
     Timeout := gTime + SHELL_TIMEOUT;
 
@@ -1553,6 +1573,7 @@ begin
       Obj.X := fX-GibsArray[a].Rect.X-(GibsArray[a].Rect.Width div 2);
       Obj.Y := fY-GibsArray[a].Rect.Y-(GibsArray[a].Rect.Height div 2);
       g_Obj_PushA(@Obj, 25 + Random(10), Random(361));
+      positionChanged(); // this updates spatial accelerators
       RAngle := Random(360);
 
       if gBloodCount > 0 then
@@ -1592,6 +1613,7 @@ begin
         begin
           vel := Obj.Vel;
           mr := g_Obj_Move(@Obj, True, False, True);
+          positionChanged(); // this updates spatial accelerators
 
           if WordBool(mr and MOVE_FALLOUT) then
           begin
@@ -1641,6 +1663,7 @@ begin
         begin
           vel := Obj.Vel;
           mr := g_Obj_Move(@Obj, True, False, True);
+          positionChanged(); // this updates spatial accelerators
 
           if WordBool(mr and MOVE_FALLOUT) or (gShells[i].Timeout < gTime) then
           begin
@@ -2008,6 +2031,10 @@ begin
   resetWeaponQueue();
 end;
 
+procedure TPlayer.positionChanged ();
+begin
+end;
+
 procedure TPlayer.Damage(value: Word; SpawnerUID: Word; vx, vy: Integer; t: Byte);
 var
   c: Word;
@@ -2950,22 +2977,34 @@ var
   DoFrags: Boolean;
   OldLR: Byte;
   KP: TPlayer;
+  it: PItem;
 
   procedure PushItem(t: Byte);
   var
     id: DWORD;
   begin
     id := g_Items_Create(FObj.X, FObj.Y, t, True, False);
+    it := g_Items_ByIdx(id);
     if KillType = K_EXTRAHARDKILL then // -7..+7; -8..0
-      g_Obj_Push(@gItems[id].Obj, (FObj.Vel.X div 2)-7+Random(15),
-                                  (FObj.Vel.Y div 2)-Random(9))
+    begin
+      g_Obj_Push(@it.Obj, (FObj.Vel.X div 2)-7+Random(15),
+                          (FObj.Vel.Y div 2)-Random(9));
+      it.positionChanged(); // this updates spatial accelerators
+    end
     else
+    begin
       if KillType = K_HARDKILL then // -5..+5; -5..0
-        g_Obj_Push(@gItems[id].Obj, (FObj.Vel.X div 2)-5+Random(11),
-                                    (FObj.Vel.Y div 2)-Random(6))
+      begin
+        g_Obj_Push(@it.Obj, (FObj.Vel.X div 2)-5+Random(11),
+                            (FObj.Vel.Y div 2)-Random(6));
+      end
       else // -3..+3; -3..0
-        g_Obj_Push(@gItems[id].Obj, (FObj.Vel.X div 2)-3+Random(7),
-                                    (FObj.Vel.Y div 2)-Random(4));
+      begin
+        g_Obj_Push(@it.Obj, (FObj.Vel.X div 2)-3+Random(7),
+                            (FObj.Vel.Y div 2)-Random(4));
+      end;
+      it.positionChanged(); // this updates spatial accelerators
+    end;
 
     if g_Game_IsNet and g_Game_IsServer then
       MH_SEND_ItemSpawn(True, id);
@@ -3086,7 +3125,7 @@ begin
       end
     else if g_GetUIDType(SpawnerUID) = UID_MONSTER then
       begin // Óáèò ìîíñòðîì
-        mon := g_Monsters_Get(SpawnerUID);
+        mon := g_Monsters_ByUID(SpawnerUID);
         if mon = nil then
           s := '?'
         else
@@ -4377,14 +4416,23 @@ begin
     b := Abs(FObj.Vel.X);
     if b > 1 then b := b * (Random(8 div b) + 1);
     for a := 0 to High(gGibs) do
+    begin
       if gGibs[a].Live and
          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) // íàëåâî
+        end
         else
+        begin
           g_Obj_PushA(@gGibs[a].Obj, b, Random(61));    // íàïðàâî
+        end;
+        gGibs[a].positionChanged(); // this updates spatial accelerators
+      end;
+    end;
   end;
 
   SetAction(A_WALK);
@@ -4611,7 +4659,10 @@ begin
     end;
 
     if FPhysics then
+    begin
       g_Obj_Move(@FObj, True, True, True);
+      positionChanged(); // this updates spatial accelerators
+    end;
 
     Exit;
   end;
@@ -4734,7 +4785,10 @@ begin
   end;
 
   if FPhysics then
-    g_Obj_Move(@FObj, True, True, True)
+  begin
+    g_Obj_Move(@FObj, True, True, True);
+    positionChanged(); // this updates spatial accelerators
+  end
   else
   begin
     FObj.Vel.X := 0;
@@ -4948,6 +5002,11 @@ begin
     if FKeys[b].Time = 0 then FKeys[b].Pressed := False else Dec(FKeys[b].Time);
 end;
 
+function TPlayer.getMapAABB (): AABB2D; inline;
+begin
+  result := AABB2D.CreateWH(FObj.X+PLAYER_RECT.X, FObj.Y+PLAYER_RECT.Y, PLAYER_RECT.Width, PLAYER_RECT.Height);
+end;
+
 function TPlayer.Collide(X, Y: Integer; Width, Height: Word): Boolean;
 begin
   Result := g_Collide(FObj.X+PLAYER_RECT.X,
@@ -5342,6 +5401,7 @@ begin
     Count := FLAG_TIME;
     g_Obj_Push(@Obj, (FObj.Vel.X div 2)-2+Random(5),
                      (FObj.Vel.Y div 2)-2+Random(5));
+    positionChanged(); // this updates spatial accelerators
 
     if FFlag = FLAG_RED then
       s := _lc[I_PLAYER_FLAG_RED]
@@ -5992,6 +6052,8 @@ begin
   inherited;
 end;
 
+procedure TCorpse.positionChanged (); begin end;
+
 procedure TCorpse.Damage(Value: Word; vx, vy: Integer);
 var
   pm: TPlayerModel;
@@ -6058,7 +6120,7 @@ begin
   if gTime mod (GAME_TICK*2) <> 0 then
   begin
     g_Obj_Move(@FObj, True, True, True);
-
+    positionChanged(); // this updates spatial accelerators
     Exit;
   end;
 
@@ -6066,6 +6128,7 @@ begin
   FObj.Vel.X := z_dec(FObj.Vel.X, 1);
 
   st := g_Obj_Move(@FObj, True, True, True);
+  positionChanged(); // this updates spatial accelerators
 
   if WordBool(st and MOVE_FALLOUT) then
   begin
@@ -6248,6 +6311,41 @@ var
   mon: TMonster;
   pla, tpla: TPlayer;
   vsPlayer, vsMonster, ok: Boolean;
+
+
+  function monsUpdate (mon: TMonster): Boolean;
+  begin
+    result := false; // don't stop
+    if mon.Live and (mon.MonsterType <> MONSTER_BARREL) then
+    begin
+      if not TargetOnScreen(mon.Obj.X+mon.Obj.Rect.X, mon.Obj.Y+mon.Obj.Rect.Y) then exit;
+
+      x2 := mon.Obj.X+mon.Obj.Rect.X+(mon.Obj.Rect.Width div 2);
+      y2 := mon.Obj.Y+mon.Obj.Rect.Y+(mon.Obj.Rect.Height div 2);
+
+      // Åñëè ìîíñòð íà ýêðàíå è íå ïðèêðûò ñòåíîé
+      if g_TraceVector(x1, y1, x2, y2) then
+      begin
+        // Äîáàâëÿåì ê ñïèñêó âîçìîæíûõ öåëåé
+        SetLength(targets, Length(targets)+1);
+        with targets[High(targets)] do
+        begin
+          UID := mon.UID;
+          X := mon.Obj.X;
+          Y := mon.Obj.Y;
+          cX := x2;
+          cY := y2;
+          Rect := mon.Obj.Rect;
+          Dist := g_PatchLength(x1, y1, x2, y2);
+          Line := (y1+4 < Target.Y + mon.Obj.Rect.Y + mon.Obj.Rect.Height) and
+                  (y1-4 > Target.Y + mon.Obj.Rect.Y);
+          Visible := True;
+          IsPlayer := False;
+        end;
+      end;
+    end;
+  end;
+
 begin
   vsPlayer := LongBool(gGameSettings.Options and GAME_OPTION_BOTVSPLAYER);
   vsMonster := LongBool(gGameSettings.Options and GAME_OPTION_BOTVSMONSTER);
@@ -6304,7 +6402,7 @@ begin
         if (g_GetUIDType(Target.UID) = UID_MONSTER) and
             vsMonster then
           begin // Ìîíñòð
-            mon := g_Monsters_Get(Target.UID);
+            mon := g_Monsters_ByUID(Target.UID);
             if mon <> nil then
               begin
                 Target.X := mon.Obj.X;
@@ -6377,41 +6475,7 @@ begin
           end;
 
   // Ìîíñòðû:
-    if vsMonster and (gMonsters <> nil) then
-      for a := 0 to High(gMonsters) do
-        if (gMonsters[a] <> nil) and (gMonsters[a].Live) and
-           (gMonsters[a].MonsterType <> MONSTER_BARREL) then
-          begin
-            mon := gMonsters[a];
-
-            if not TargetOnScreen(mon.Obj.X + mon.Obj.Rect.X,
-                                  mon.Obj.Y + mon.Obj.Rect.Y) then
-              Continue;
-
-            x2 := mon.Obj.X + mon.Obj.Rect.X + (mon.Obj.Rect.Width div 2);
-            y2 := mon.Obj.Y + mon.Obj.Rect.Y + (mon.Obj.Rect.Height div 2);
-
-          // Åñëè ìîíñòð íà ýêðàíå è íå ïðèêðûò ñòåíîé:
-            if g_TraceVector(x1, y1, x2, y2) then
-              begin
-              // Äîáàâëÿåì ê ñïèñêó âîçìîæíûõ öåëåé:
-                SetLength(targets, Length(targets)+1);
-                with targets[High(targets)] do
-                  begin
-                    UID := mon.UID;
-                    X := mon.Obj.X;
-                    Y := mon.Obj.Y;
-                    cX := x2;
-                    cY := y2;
-                    Rect := mon.Obj.Rect;
-                    Dist := g_PatchLength(x1, y1, x2, y2);
-                    Line := (y1+4 < Target.Y + mon.Obj.Rect.Y + mon.Obj.Rect.Height) and
-                            (y1-4 > Target.Y + mon.Obj.Rect.Y);
-                    Visible := True;
-                    IsPlayer := False;
-                  end;
-              end;
-          end;
+    if vsMonster then g_Mons_ForEach(monsUpdate);
   end;
 
 // Åñëè åñòü âîçìîæíûå öåëè:
@@ -6571,7 +6635,7 @@ begin
             end
           else
             begin // Öåëü - ìîíñòð
-              mon := g_Monsters_Get(Target.UID);
+              mon := g_Monsters_ByUID(Target.UID);
               if (mon = nil) or (not mon.Live) then
                 Target.UID := 0; // òî çàáûòü öåëü
             end;
@@ -7323,7 +7387,7 @@ begin
         if (g_GetUIDType(FLastSpawnerUID) = UID_MONSTER) and
            LongBool(gGameSettings.Options and GAME_OPTION_BOTVSMONSTER) then
         begin // Ìîíñòð
-          mon := g_Monsters_Get(FLastSpawnerUID);
+          mon := g_Monsters_ByUID(FLastSpawnerUID);
           ok := not TargetOnScreen(mon.Obj.X + mon.Obj.Rect.X,
                                    mon.Obj.Y + mon.Obj.Rect.Y);
         end;