DEADSOFTWARE

uidmap for monsters, so we don't have to do linear searches
[d2df-sdl.git] / src / game / g_weapons.pas
index 504a1766747c7c54c1c206a10fc0b57566c2d20f..f3accc605fb3ad2cf654c3b8811462cb98139931 100644 (file)
@@ -13,7 +13,7 @@
  * 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}
+{$INCLUDE ../shared/a_modes.inc}
 unit g_weapons;
 
 interface
@@ -45,8 +45,11 @@ type
     TextureID: DWORD;
     Timeout: DWORD;
     Stopped: Byte;
+
+    procedure positionChanged (); //WARNING! call this after monster position was changed, or coldet will not work right!
   end;
 
+
 var
   Shots: array of TShot = nil;
   LastShotID: Integer = 0;
@@ -88,6 +91,8 @@ procedure g_Weapon_DestroyShot(I: Integer; X, Y: Integer; Loud: Boolean = True);
 procedure g_Weapon_SaveState(var Mem: TBinMemoryWriter);
 procedure g_Weapon_LoadState(var Mem: TBinMemoryReader);
 
+procedure g_Weapon_AddDynLights();
+
 const
   WEAPON_KASTET         = 0;
   WEAPON_SAW            = 1;
@@ -143,7 +148,7 @@ const
 
   SHOT_FLAME_WIDTH = 4;
   SHOT_FLAME_HEIGHT = 4;
-  SHOT_FLAME_LIFETIME = 180; 
+  SHOT_FLAME_LIFETIME = 180;
 
   SHOT_SIGNATURE = $544F4853; // 'SHOT'
 
@@ -242,6 +247,29 @@ procedure CheckTrap(ID: DWORD; dm: Integer; t: Byte);
 var
   a, b, c, d, i1, i2: Integer;
   pl, mn: WArray;
+
+  {
+  function monsWaterCheck (monidx: Integer; mon: TMonster): Boolean;
+  begin
+    result := false; // don't stop
+    if mon.Live and mon.Collide(gWater[WaterMap[a][c]]) and (not InWArray(monidx, mn)) and (i2 < 1023) then //FIXME
+    begin
+      i2 += 1;
+      mn[i2] := monidx;
+    end;
+  end;
+  }
+
+  function monsWaterCheck (monidx: Integer; mon: TMonster): Boolean;
+  begin
+    result := false; // don't stop
+    if (not InWArray(monidx, mn)) and (i2 < 1023) then //FIXME
+    begin
+      i2 += 1;
+      mn[i2] := monidx;
+    end;
+  end;
+
 begin
   if (gWater = nil) or (WaterMap = nil) then Exit;
 
@@ -275,27 +303,22 @@ begin
                   end;
         end;
 
-        if gMonsters <> nil then
-        begin
-          for d := 0 to High(gMonsters) do
-            if (gMonsters[d] <> nil) and (gMonsters[d].Live) then
-              if gMonsters[d].Collide(gWater[WaterMap[a][c]]) then
-                if not InWArray(d, mn) then
-                  if i2 < 1023 then
-                  begin
-                    i2 := i2+1;
-                    mn[i2] := d;
-                  end;
-        end;
+        //g_Mons_ForEach(monsWaterCheck);
+        g_Mons_ForEachAtAlive(
+          gWater[WaterMap[a][c]].X, gWater[WaterMap[a][c]].Y,
+          gWater[WaterMap[a][c]].Width, gWater[WaterMap[a][c]].Height,
+          monsWaterCheck);
       end;
 
       if i1 <> -1 then
-        for d := 0 to i1 do
-          gPlayers[pl[d]].Damage(dm, Shots[ID].SpawnerUID, 0, 0, t);
+      begin
+        for d := 0 to i1 do gPlayers[pl[d]].Damage(dm, Shots[ID].SpawnerUID, 0, 0, t);
+      end;
 
       if i2 <> -1 then
-        for d := 0 to i2 do
-          gMonsters[mn[d]].Damage(dm, 0, 0, Shots[ID].SpawnerUID, t);
+      begin
+        for d := 0 to i2 do g_Mons_ByIdx(mn[d]).Damage(dm, 0, 0, Shots[ID].SpawnerUID, t);
+      end;
     end;
 
   pl := nil;
@@ -312,9 +335,9 @@ begin
   tt := g_GetUIDType(SpawnerUID);
   if tt = UID_MONSTER then
   begin
-    mon := g_Monsters_Get(SpawnerUID);
+    mon := g_Monsters_ByUID(SpawnerUID);
     if mon <> nil then
-      mt := g_Monsters_Get(SpawnerUID).MonsterType
+      mt := g_Monsters_ByUID(SpawnerUID).MonsterType
     else
       mt := 0;
   end
@@ -372,7 +395,7 @@ begin
   if (p.UID = SpawnerUID) and (t <> HIT_ROCKET) and (t <> HIT_ELECTRO) then
     Exit;
 
-  if g_Game_IsServer then 
+  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);
@@ -385,6 +408,30 @@ end;
 
 function GunHit(X, Y: Integer; vx, vy: Integer; dmg: Integer;
   SpawnerUID: Word; AllowPush: Boolean): Byte;
+
+  {function monsCheck (monidx: Integer; mon: TMonster): Boolean;
+  begin
+    result := false; // don't stop
+    if mon.Live and mon.Collide(X, Y) then
+    begin
+      if HitMonster(mon, dmg, vx*10, vy*10-3, SpawnerUID, HIT_SOME) then
+      begin
+        if AllowPush then mon.Push(vx, vy);
+        result := true;
+      end;
+    end;
+  end;}
+
+  function monsCheck (monidx: Integer; mon: TMonster): Boolean;
+  begin
+    result := false; // don't stop
+    if HitMonster(mon, dmg, vx*10, vy*10-3, SpawnerUID, HIT_SOME) then
+    begin
+      if AllowPush then mon.Push(vx, vy);
+      result := true;
+    end;
+  end;
+
 var
   i, h: Integer;
 begin
@@ -403,20 +450,30 @@ begin
 
   if Result <> 0 then Exit;
 
-  h := High(gMonsters);
+  //if g_Mons_ForEach(monsCheck) then result := 2;
+  if g_Mons_ForEachAtAlive(X, Y, 1, 1, monsCheck) then result := 2;
+end;
+
+procedure g_Weapon_BFG9000(X, Y: Integer; SpawnerUID: Word);
 
-  if h <> -1 then
-    for i := 0 to h do
-      if (gMonsters[i] <> nil) and gMonsters[i].Live and gMonsters[i].Collide(X, Y) then
-        if HitMonster(gMonsters[i], dmg, vx*10, vy*10-3, SpawnerUID, HIT_SOME) then
+  function monsCheck (monidx: Integer; mon: TMonster): Boolean;
+  begin
+    result := false; // don't stop
+    if (mon <> nil) and (mon.Live) and (mon.UID <> SpawnerUID) then
+    begin
+      with mon do
+      begin
+        if (g_PatchLength(X, Y, Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
+                                Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)) <= SHOT_BFG_RADIUS) and
+            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
-          if AllowPush then gMonsters[i].Push(vx, vy);
-          Result := 2;
-          Exit;
+          if HitMonster(mon, 50, 0, 0, SpawnerUID, HIT_SOME) then mon.BFGHit();
         end;
-end;
+      end;
+    end;
+  end;
 
-procedure g_Weapon_BFG9000(X, Y: Integer; SpawnerUID: Word);
 var
   i, h: Integer;
   st: Byte;
@@ -465,17 +522,7 @@ begin
               gPlayers[i].BFGHit();
           end;
 
-  h := High(gMonsters);
-
-  if h <> -1 then
-    for i := 0 to h do
-      if (gMonsters[i] <> nil) and (gMonsters[i].Live) and (gMonsters[i].UID <> SpawnerUID) then
-        with gMonsters[i] do
-          if (g_PatchLength(X, Y, Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
-                            Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)) <= SHOT_BFG_RADIUS) and
-              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
-            if HitMonster(gMonsters[i], 50, 0, 0, SpawnerUID, HIT_SOME) then gMonsters[i].BFGHit();
+  g_Mons_ForEach(monsCheck);
 end;
 
 function g_Weapon_CreateShot(I: Integer; ShotType: Byte; Spawner, TargetUID: Word; X, Y, XV, YV: Integer): LongWord;
@@ -553,7 +600,7 @@ begin
         ShotType := WEAPON_FLAMETHROWER;
         Animation := nil;
         TextureID := 0;
-        Stopped := 0;
+        g_Frames_Get(TextureID, 'FRAMES_FLAME');
       end;
     end;
 
@@ -662,6 +709,10 @@ begin
   Shots[find_id].Obj.Accel.X := 0;
   Shots[find_id].Obj.Accel.Y := 0;
   Shots[find_id].SpawnerUID := Spawner;
+  if (ShotType = WEAPON_FLAMETHROWER) and (XV = 0) and (YV = 0) then
+    Shots[find_id].Stopped := 255
+  else
+    Shots[find_id].Stopped := 0;
   Result := find_id;
 end;
 
@@ -682,9 +733,10 @@ begin
   Shots[i].Obj.Vel.Y := (yd*s) div a;
   Shots[i].Obj.Accel.X := 0;
   Shots[i].Obj.Accel.Y := 0;
+  Shots[i].Stopped := 0;
   if Shots[i].ShotType in [WEAPON_ROCKETLAUNCHER, WEAPON_BFG] then
     Shots[i].Timeout := 900 // ~25 sec
-  else 
+  else
   begin
     if Shots[i].ShotType = WEAPON_FLAMETHROWER then
       Shots[i].Timeout := SHOT_FLAME_LIFETIME
@@ -720,8 +772,9 @@ var
           if ChkTeam then
             if HitPlayer(gPlayers[i], d, obj^.Vel.X, obj^.Vel.Y, SpawnerUID, t) then
             begin
-              gPlayers[i].Push((obj^.Vel.X+obj^.Accel.X)*IfThen(t = HIT_BFG, 8, 1) div 4,
-                               (obj^.Vel.Y+obj^.Accel.Y)*IfThen(t = HIT_BFG, 8, 1) div 4);
+              if t <> HIT_FLAME then
+                gPlayers[i].Push((obj^.Vel.X+obj^.Accel.X)*IfThen(t = HIT_BFG, 8, 1) div 4,
+                                 (obj^.Vel.Y+obj^.Accel.Y)*IfThen(t = HIT_BFG, 8, 1) div 4);
               if t = HIT_BFG then
                 g_Game_DelayEvent(DE_BFGHIT, 1000, SpawnerUID);
               Result := True;
@@ -729,24 +782,29 @@ var
             end;
         end;
   end;
-  function MonsterHit(): Boolean;
-  var
-    i: Integer;
-  begin
-    Result := False;
-    h := High(gMonsters);
 
-    if h <> -1 then
-      for i := 0 to h do
-        if (gMonsters[i] <> nil) and gMonsters[i].Live and g_Obj_Collide(obj, @gMonsters[i].Obj) then
-          if HitMonster(gMonsters[i], d, obj^.Vel.X, obj^.Vel.Y, SpawnerUID, t) then
-          begin
-            gMonsters[i].Push((obj^.Vel.X+obj^.Accel.X)*IfThen(t = HIT_BFG, 8, 1) div 4,
+  function monsCheckHit (monidx: Integer; mon: TMonster): Boolean;
+  begin
+    result := false; // don't stop
+    if (mon <> nil) and mon.Live and g_Obj_Collide(obj, @mon.Obj) then
+    begin
+      if HitMonster(mon, d, obj^.Vel.X, obj^.Vel.Y, SpawnerUID, t) then
+      begin
+        if (t <> HIT_FLAME) then
+        begin
+          mon.Push((obj^.Vel.X+obj^.Accel.X)*IfThen(t = HIT_BFG, 8, 1) div 4,
                               (obj^.Vel.Y+obj^.Accel.Y)*IfThen(t = HIT_BFG, 8, 1) div 4);
-            Result := True;
-            break;
-          end;
+        end;
+        result := True;
+      end;
+    end;
   end;
+
+  function MonsterHit(): Boolean;
+  begin
+    result := g_Mons_ForEach(monsCheckHit);
+  end;
+
 begin
   Result := 0;
 
@@ -835,15 +893,51 @@ begin
 
   case g_GetUIDType(UID) of
     UID_PLAYER: Result := HitPlayer(g_Player_Get(UID), d, 0, 0, SpawnerUID, t);
-    UID_MONSTER: Result := HitMonster(g_Monsters_Get(UID), d, 0, 0, SpawnerUID, t);
+    UID_MONSTER: Result := HitMonster(g_Monsters_ByUID(UID), d, 0, 0, SpawnerUID, t);
     else Exit;
   end;
 end;
 
 function g_Weapon_Explode(X, Y: Integer; rad: Integer; SpawnerUID: Word): Boolean;
 var
-  i, h, r, dx, dy, m, mm: Integer;
+  r: Integer;
+
+  function monsExCheck (monidx: Integer; mon: TMonster): Boolean;
+  var
+    dx, dy, mm: Integer;
+  begin
+    result := false; // don't stop
+    if mon <> nil then
+    begin
+      with mon do
+      begin
+        dx := Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2)-X;
+        dy := Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)-Y;
+
+        if dx > 1000 then dx := 1000;
+        if dy > 1000 then dy := 1000;
+
+        if (dx*dx+dy*dy < r) then
+        begin
+          //m := PointToRect(X, Y, Obj.X+Obj.Rect.X, Obj.Y+Obj.Rect.Y, Obj.Rect.Width, Obj.Rect.Height);
+
+          mm := Max(abs(dx), abs(dy));
+          if mm = 0 then mm := 1;
+
+          if mon.Live then
+            HitMonster(mon, ((mon.Obj.Rect.Width div 4)*10*(rad-mm)) div rad,
+                       0, 0, SpawnerUID, HIT_ROCKET);
+
+          mon.Push((dx*7) div mm, (dy*7) div mm);
+        end;
+      end;
+    end;
+  end;
+
+var
+  i, h, dx, dy, m, mm: Integer;
   _angle: SmallInt;
+
 begin
   Result := False;
 
@@ -877,34 +971,8 @@ begin
           end;
         end;
 
-  h := High(gMonsters);
-
-  if h <> -1 then
-    for i := 0 to h do
-      if gMonsters[i] <> nil then
-        with gMonsters[i] do
-        begin
-          dx := Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2)-X;
-          dy := Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)-Y;
+  g_Mons_ForEach(monsExCheck);
 
-          if dx > 1000 then dx := 1000;
-          if dy > 1000 then dy := 1000;
-
-          if dx*dx+dy*dy < r then
-          begin
-            //m := PointToRect(X, Y, Obj.X+Obj.Rect.X, Obj.Y+Obj.Rect.Y,
-            //                 Obj.Rect.Width, Obj.Rect.Height);
-
-            mm := Max(abs(dx), abs(dy));
-            if mm = 0 then mm := 1;
-
-            if gMonsters[i].Live then
-              HitMonster(gMonsters[i], ((gMonsters[i].Obj.Rect.Width div 4)*10*(rad-mm)) div rad,
-                         0, 0, SpawnerUID, HIT_ROCKET);
-
-            gMonsters[i].Push((dx*7) div mm, (dy*7) div mm);
-          end;
-        end;
 
   h := High(gCorpses);
 
@@ -952,6 +1020,7 @@ begin
                                Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2), X, Y);
 
             g_Obj_PushA(@Obj, Round(15*(rad-m)/rad), _angle);
+            positionChanged(); // this updates spatial accelerators
           end;
         end;
 end;
@@ -1349,7 +1418,7 @@ end;
 procedure g_Weapon_flame(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
   Silent: Boolean = False);
 var
-  find_id, FramesID: DWORD;
+  find_id: DWORD;
   dx, dy: Integer;
 begin
   if WID < 0 then
@@ -1377,7 +1446,7 @@ begin
     triggers := nil;
     Animation := nil;
     TextureID := 0;
-    Stopped := 0;
+    g_Frames_Get(TextureID, 'FRAMES_FLAME');
   end;
 
   Shots[find_id].SpawnerUID := SpawnerUID;
@@ -1532,7 +1601,7 @@ begin
     throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 16);
 
     triggers := nil;
-    
+
     g_Frames_Get(FramesID, 'FRAMES_WEAPON_BSPFIRE');
     Animation := TAnimation.Create(FramesID, True, 4);
   end;
@@ -1697,7 +1766,7 @@ end;
 
 procedure g_Weapon_Update();
 var
-  i, a, h, cx, cy, oldvx, oldvy: Integer;
+  i, a, h, cx, cy, oldvx, oldvy, tf: Integer;
   _id: DWORD;
   Anim: TAnimation;
   t: DWArray;
@@ -1706,6 +1775,7 @@ var
   o: TObj;
   spl: Boolean;
   Loud: Boolean;
+  tcx, tcy: Integer;
 begin
   if Shots = nil then
     Exit;
@@ -1723,7 +1793,7 @@ begin
       oldvx := Obj.Vel.X;
       oldvy := Obj.Vel.Y;
     // Àêòèâèðîâàòü òðèããåðû ïî ïóòè (êðîìå óæå àêòèâèðîâàííûõ):
-      if g_Game_IsServer then
+      if (Stopped = 0) and g_Game_IsServer then
         t := g_Triggers_PressR(Obj.X, Obj.Y, Obj.Rect.Width, Obj.Rect.Height,
                                SpawnerUID, ACTIVATE_SHOT, triggers)
       else
@@ -1757,7 +1827,15 @@ begin
              (ShotType <> WEAPON_BSP_FIRE) and
              (ShotType <> WEAPON_FLAMETHROWER);
 
-      st := g_Obj_Move(@Obj, False, spl);
+      if Stopped = 0 then
+      begin
+        st := g_Obj_Move(@Obj, False, spl);
+      end
+      else
+      begin
+        st := 0;
+      end;
+      positionChanged(); // this updates spatial accelerators
 
       if WordBool(st and MOVE_FALLOUT) or (Obj.X < -1000) or
         (Obj.X > gMapInfo.Width+1000) or (Obj.Y < -1000) then
@@ -1811,6 +1889,7 @@ begin
                     Anim := TAnimation.Create(TextureID, False, 8);
                     Anim.Blending := False;
                     g_GFX_OnceAnim((Obj.X+32)-58, (Obj.Y+8)-36, Anim);
+                    g_DynLightExplosion((Obj.X+32), (Obj.Y+8), 64, 1, 0, 0);
                     Anim.Free();
                   end;
                 end
@@ -1821,6 +1900,7 @@ begin
                     Anim := TAnimation.Create(TextureID, False, 6);
                     Anim.Blending := False;
                     g_GFX_OnceAnim(cx-64, cy-64, Anim);
+                    g_DynLightExplosion(cx, cy, 64, 1, 0, 0);
                     Anim.Free();
                   end;
                 end;
@@ -1878,6 +1958,7 @@ begin
                 Anim.Blending := False;
                 g_GFX_OnceAnim(cx-16, cy-16, Anim);
                 Anim.Free();
+                g_DynLightExplosion(cx, cy, 32, 0, 0.5, 0.5);
               end;
 
               g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEPLASMA', Obj.X, Obj.Y);
@@ -1903,8 +1984,10 @@ begin
                 begin
                   Anim := TAnimation.Create(_id, False, 3);
                   Anim.Alpha := 0;
-                  g_GFX_OnceAnim(cx-4+Random(8)-(Anim.Width div 2),
-                    cy-4+Random(8)-(Anim.Height div 2),
+                  tcx := Random(8);
+                  tcy := Random(8);
+                  g_GFX_OnceAnim(cx-4+tcx-(Anim.Width div 2),
+                    cy-4+tcy-(Anim.Height div 2),
                     Anim, ONCEANIM_SMOKE);
                   Anim.Free();
                 end;
@@ -1943,25 +2026,24 @@ begin
                 ShotType := 0;
             end;
 
-            if g_Frames_Get(_id, 'FRAMES_FLAME') and (gTime mod 3 = 0) then
+            if Stopped = 0 then
+              tf := 2
+            else
+              tf := 3;
+
+            if (gTime mod tf = 0) then
             begin
-              Anim := TAnimation.Create(_id, False, 2 + Random(2));
+              Anim := TAnimation.Create(TextureID, False, 2 + Random(2));
               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);
-                MOVE_HITWALL:  g_GFX_OnceAnim(cx-4+Random(8)-(Anim.Width div 2),
-                                 cy-12+Random(24)-(Anim.Height div 2),
-                                 Anim, ONCEANIM_SMOKE);
-                MOVE_HITLAND:  g_GFX_OnceAnim(cx-12+Random(24)-(Anim.Width div 2),
-                                 cy-10+Random(8)-(Anim.Height div 2),
-                                 Anim, ONCEANIM_SMOKE);
-                MOVE_HITCEIL:  g_GFX_OnceAnim(cx-12+Random(24)-(Anim.Width div 2),
-                                 cy+6+Random(8)-(Anim.Height div 2),
-                                 Anim, ONCEANIM_SMOKE);
+                MOVE_HITWALL: begin tcx := cx-4+Random(8); tcy := cy-12+Random(24); end;
+                MOVE_HITLAND: begin tcx := cx-12+Random(24); tcy := cy-10+Random(8); end;
+                MOVE_HITCEIL: begin tcx := cx-12+Random(24); tcy := cy+6+Random(8); end;
+                else begin tcx := cx-4+Random(8); tcy := cy-4+Random(8); end;
               end;
+              g_GFX_OnceAnim(tcx-(Anim.Width div 2), tcy-(Anim.Height div 2), Anim, ONCEANIM_SMOKE);
               Anim.Free();
+              //g_DynLightExplosion(tcx, tcy, 1, 1, 0.8, 0.3);
             end;
           end;
 
@@ -1991,6 +2073,7 @@ begin
                 Anim.Blending := False;
                 g_GFX_OnceAnim(cx-64, cy-64, Anim);
                 Anim.Free();
+                g_DynLightExplosion(cx, cy, 96, 0, 1, 0);
               end;
 
               g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEBFG', Obj.X, Obj.Y);
@@ -2124,7 +2207,7 @@ begin
           begin
             if (Shots[i].ShotType = WEAPON_ROCKETLAUNCHER) then
               e_DrawAdv(TextureID, Obj.X, Obj.Y, 0, True, False, a, @p, M_NONE)
-            else
+            else if (Shots[i].ShotType <> WEAPON_FLAMETHROWER) then
               e_Draw(TextureID, Obj.X, Obj.Y, 0, True, False);
           end;
 
@@ -2415,4 +2498,42 @@ begin
   end;
 end;
 
+
+procedure g_Weapon_AddDynLights();
+var
+  i: Integer;
+begin
+  if Shots = nil then Exit;
+  for i := 0 to High(Shots) do
+  begin
+    if Shots[i].ShotType = 0 then continue;
+    if (Shots[i].ShotType = WEAPON_ROCKETLAUNCHER) or
+       (Shots[i].ShotType = WEAPON_BARON_FIRE) or
+       (Shots[i].ShotType = WEAPON_MANCUB_FIRE) or
+       (Shots[i].ShotType = WEAPON_SKEL_FIRE) or
+       (Shots[i].ShotType = WEAPON_IMP_FIRE) or
+       (Shots[i].ShotType = WEAPON_CACO_FIRE) or
+       (Shots[i].ShotType = WEAPON_MANCUB_FIRE) or
+       (Shots[i].ShotType = WEAPON_BSP_FIRE) or
+       (Shots[i].ShotType = WEAPON_PLASMA) or
+       (Shots[i].ShotType = WEAPON_BFG) or
+       (Shots[i].ShotType = WEAPON_FLAMETHROWER) or
+       false then
+    begin
+      if (Shots[i].ShotType = WEAPON_PLASMA) then
+        g_AddDynLight(Shots[i].Obj.X+(Shots[i].Obj.Rect.Width div 2), Shots[i].Obj.Y+(Shots[i].Obj.Rect.Height div 2), 128,  0, 0.3, 1, 0.4)
+      else if (Shots[i].ShotType = WEAPON_BFG) then
+        g_AddDynLight(Shots[i].Obj.X+(Shots[i].Obj.Rect.Width div 2), Shots[i].Obj.Y+(Shots[i].Obj.Rect.Height div 2), 128,  0, 1, 0, 0.5)
+      else if (Shots[i].ShotType = WEAPON_FLAMETHROWER) then
+        g_AddDynLight(Shots[i].Obj.X+(Shots[i].Obj.Rect.Width div 2), Shots[i].Obj.Y+(Shots[i].Obj.Rect.Height div 2), 42,  1, 0.8, 0, 0.4)
+      else
+        g_AddDynLight(Shots[i].Obj.X+(Shots[i].Obj.Rect.Width div 2), Shots[i].Obj.Y+(Shots[i].Obj.Rect.Height div 2), 128,  1, 0, 0, 0.4);
+    end;
+  end;
+end;
+
+
+procedure TShot.positionChanged (); begin end;
+
+
 end.