DEADSOFTWARE

mapdef cleanup; renamed some fields; mapdef.txt is RC0 now
[d2df-sdl.git] / src / game / g_map.pas
index 395a2ccbc4320a256545a286de9b34bb5e8e3137..33571b8bcd182fb5b61cbae55bfabfcd3c9f4a33 100644 (file)
@@ -109,7 +109,7 @@ function g_Map_traceToNearestWall (x0, y0, x1, y1: Integer; hitx: PInteger=nil;
 function g_Map_traceToNearest (x0, y0, x1, y1: Integer; tag: Integer; hitx: PInteger=nil; hity: PInteger=nil): TPanel;
 
 type
-  TForEachPanelCB = function (pan: TPanel): Boolean; // return `true` to stop
+  TForEachPanelCB = function (pan: TPanel): Boolean is nested; // return `true` to stop
 
 function g_Map_HasAnyPanelAtPoint (x, y: Integer; panelType: Word): Boolean;
 function g_Map_PanelAtPoint (x, y: Integer; tagmask: Integer=-1): TPanel;
@@ -119,6 +119,12 @@ function g_Map_PanelAtPoint (x, y: Integer; tagmask: Integer=-1): TPanel;
 function g_Map_TraceLiquidNonPrecise (x, y, dx, dy: Integer; out topx, topy: Integer): Boolean;
 
 
+// return `true` from `cb` to stop
+function g_Map_ForEachPanel (cb: TForEachPanelCB): TPanel;
+
+procedure g_Map_NetSendInterestingPanels (); // yay!
+
+
 procedure g_Map_ProfilersBegin ();
 procedure g_Map_ProfilersEnd ();
 
@@ -262,6 +268,34 @@ begin
 end;
 
 
+// return `true` from `cb` to stop
+function g_Map_ForEachPanel (cb: TForEachPanelCB): TPanel;
+var
+  pan: TPanel;
+begin
+  result := nil;
+  if not assigned(cb) then exit;
+  for pan in panByGUID do
+  begin
+    if cb(pan) then begin result := pan; exit; end;
+  end;
+end;
+
+
+procedure g_Map_NetSendInterestingPanels ();
+var
+  pan: TPanel;
+begin
+  if g_Game_IsServer and g_Game_IsNet then
+  begin
+    for pan in panByGUID do
+    begin
+      if pan.gncNeedSend then MH_SEND_PanelState(pan.guid);
+    end;
+  end;
+end;
+
+
 // ////////////////////////////////////////////////////////////////////////// //
 function g_Map_MinX (): Integer; inline; begin if (mapGrid <> nil) then result := mapGrid.gridX0 else result := 0; end;
 function g_Map_MinY (): Integer; inline; begin if (mapGrid <> nil) then result := mapGrid.gridY0 else result := 0; end;
@@ -273,6 +307,7 @@ function g_Map_MaxY (): Integer; inline; begin if (mapGrid <> nil) then result :
 var
   dfmapdef: TDynMapDef = nil;
 
+
 procedure loadMapDefinition ();
 var
   pr: TTextParser = nil;
@@ -280,13 +315,15 @@ var
   WAD: TWADFile = nil;
 begin
   if (dfmapdef <> nil) then exit;
+
   try
     e_LogWritefln('parsing "mapdef.txt"...', []);
     st := openDiskFileRO(DataDir+'mapdef.txt');
+    e_LogWritefln('found local "%smapdef.txt"', [DataDir]);
   except
     st := nil;
-    e_LogWritefln('local "%smapdef.txt" not found', [DataDir]);
   end;
+
   if (st = nil) then
   begin
     WAD := TWADFile.Create();
@@ -301,15 +338,22 @@ begin
     end;
   end;
 
-  if (st = nil) then
-  begin
-    //raise Exception.Create('cannot open "mapdef.txt"');
-    e_LogWritefln('using default "mapdef.txt"...', [], MSG_WARNING);
-    pr := TStrTextParser.Create(defaultMapDef);
-  end
-  else
-  begin
-    pr := TFileTextParser.Create(st);
+  try
+    if (st = nil) then
+    begin
+      //raise Exception.Create('cannot open "mapdef.txt"');
+      e_LogWriteln('using default "mapdef.txt"...');
+      pr := TStrTextParser.Create(defaultMapDef);
+    end
+    else
+    begin
+      pr := TFileTextParser.Create(st);
+    end;
+  except on e: Exception do
+    begin
+      e_LogWritefln('something is VERY wrong here! -- ', [e.message]);
+      raise;
+    end;
   end;
 
   try
@@ -331,6 +375,8 @@ var
 begin
   result := nil;
   if (dataLen < 4) then exit;
+
+  if (dfmapdef = nil) then writeln('need to load mapdef');
   loadMapDefinition();
   if (dfmapdef = nil) then raise Exception.Create('internal map loader error');
 
@@ -340,6 +386,7 @@ begin
   begin
     // binary map
     try
+      //e_LogWriteln('parsing binary map...');
       result := dfmapdef.parseBinMap(wst);
     except on e: Exception do
       begin
@@ -356,10 +403,11 @@ begin
     // text map
     pr := TFileTextParser.Create(wst);
     try
+      //e_LogWriteln('parsing text map...');
       result := dfmapdef.parseMap(pr);
     except on e: Exception do
       begin
-        if (pr <> nil) then e_LogWritefln('ERROR at (%s,%s): %s', [pr.line, pr.col, e.message])
+        if (pr <> nil) then e_LogWritefln('ERROR at (%s,%s): %s', [pr.tokLine, pr.tokCol, e.message])
         else e_LogWritefln('ERROR: %s', [e.message]);
         pr.Free(); // will free `wst`
         result := nil;
@@ -368,6 +416,7 @@ begin
     end;
     pr.Free(); // will free `wst`
   end;
+  //e_LogWriteln('map parsed.');
 end;
 
 
@@ -772,7 +821,7 @@ begin
   PanelArray := nil;
 end;
 
-function CreatePanel (PanelRec: TDynRecord; AddTextures: TAddTextureArray; CurTex: Integer; sav: Boolean): Integer;
+function CreatePanel (PanelRec: TDynRecord; AddTextures: TAddTextureArray; CurTex: Integer): Integer;
 var
   len: Integer;
   panels: ^TPanelArray;
@@ -807,7 +856,6 @@ begin
   pan.arrIdx := len;
   pan.proxyId := -1;
   pan.tag := panelTypeToTag(PanelRec.PanelType);
-  if sav then pan.SaveIt := True;
 
   PanelRec.user['panel_guid'] := pguid;
 
@@ -1278,10 +1326,11 @@ begin
   end;
 end;
 
-procedure CreateTrigger (amapIdx: Integer; Trigger: TDynRecord; atpanid, atrigpanid: Integer; fTexturePanel1Type, fTexturePanel2Type: Word);
+function CreateTrigger (amapIdx: Integer; Trigger: TDynRecord; atpanid, atrigpanid: Integer; fTexturePanel1Type, fTexturePanel2Type: Word): Integer;
 var
   _trigger: TTrigger;
 begin
+  result := -1;
   if g_Game_IsClient and not (Trigger.TriggerType in [TRIGGER_SOUND, TRIGGER_MUSIC]) then Exit;
 
   with _trigger do
@@ -1313,11 +1362,11 @@ begin
     end
     else
     begin
-      trigData := Trigger.trigRec.clone();
+      trigData := Trigger.trigRec.clone(nil);
     end;
   end;
 
-  g_Triggers_Create(_trigger);
+  result := Integer(g_Triggers_Create(_trigger));
 end;
 
 procedure CreateMonster(monster: TDynRecord);
@@ -1562,6 +1611,8 @@ type
   PTRec = ^TTRec;
   TTRec = record
     //TexturePanel: Integer;
+    tnum: Integer;
+    id: Integer;
     texPanIdx: Integer;
     LiftPanelIdx: Integer;
     DoorPanelIdx: Integer;
@@ -1590,7 +1641,7 @@ var
   FileName, mapResName, s, TexName: String;
   Data: Pointer;
   Len: Integer;
-  ok, isAnim, trigRef: Boolean;
+  ok, isAnim: Boolean;
   CurTex, ntn: Integer;
   rec, texrec: TDynRecord;
   pttit: PTRec;
@@ -1598,6 +1649,7 @@ var
   stt: UInt64;
   moveSpeed{, moveStart, moveEnd}: TDFPoint;
   //moveActive: Boolean;
+  pan: TPanel;
 begin
   mapGrid.Free();
   mapGrid := nil;
@@ -1662,6 +1714,12 @@ begin
 
     FreeMem(Data);
 
+    if (mapReader = nil) then
+    begin
+      e_LogWritefln('invalid map file: ''%s''', [mapResName]);
+      exit;
+    end;
+
     generateExternalResourcesList(mapReader);
     mapTextureList := mapReader['texture'];
     // get all other lists here too
@@ -1822,7 +1880,6 @@ begin
         //e_LogWritefln('PANSTART: pannum=%s', [pannum]);
         texrec := nil;
         SetLength(AddTextures, 0);
-        trigRef := False;
         CurTex := -1;
         ok := false;
 
@@ -1839,21 +1896,9 @@ begin
           ok := false;
           if (TriggersTable <> nil) and (mapTextureList <> nil) then
           begin
-            {
-            for b := 0 to High(TriggersTable) do
-            begin
-              if (TriggersTable[b].texPan = rec) or (TriggersTable[b].shotPan = rec) then
-              begin
-                trigRef := True;
-                ok := True;
-                break;
-              end;
-            end;
-            }
             if rec.userPanelTrigRef then
             begin
               // e_LogWritefln('trigref for panel %s', [pannum]);
-              trigRef := True;
               ok := True;
             end;
           end;
@@ -1981,7 +2026,7 @@ begin
         //e_LogWritefln('PANADD: pannum=%s', [pannum]);
 
         // Ñîçäàåì ïàíåëü è çàïîìèíàåì åå GUID
-        PanelID := CreatePanel(rec, AddTextures, CurTex, trigRef);
+        PanelID := CreatePanel(rec, AddTextures, CurTex);
         //e_LogWritefln('panel #%s of type %s got guid #%s', [pannum, rec.PanelType, PanelID]);
         rec.userPanelId := PanelID; // remember game panel id, we'll fix triggers later
 
@@ -2036,7 +2081,21 @@ begin
         else if (TriggersTable[trignum].MPlatPanelIdx <> -1) then tgpid := TriggersTable[trignum].MPlatPanelIdx
         else tgpid := -1;
         //e_LogWritefln('creating trigger #%s; texpantype=%s; shotpantype=%s (%d,%d)', [trignum, b, c, TriggersTable[trignum].texPanIdx, TriggersTable[trignum].ShotPanelIdx]);
-        CreateTrigger(trignum, rec, TriggersTable[trignum].texPanIdx, tgpid, Word(b), Word(c));
+        TriggersTable[trignum].tnum := trignum;
+        TriggersTable[trignum].id := CreateTrigger(trignum, rec, TriggersTable[trignum].texPanIdx, tgpid, Word(b), Word(c));
+      end;
+    end;
+
+    //FIXME: use hashtable!
+    for pan in panByGUID do
+    begin
+      if (pan.endPosTrigId >= 0) and (pan.endPosTrigId < Length(TriggersTable)) then
+      begin
+        pan.endPosTrigId := TriggersTable[pan.endPosTrigId].id;
+      end;
+      if (pan.endSizeTrigId >= 0) and (pan.endSizeTrigId < Length(TriggersTable)) then
+      begin
+        pan.endSizeTrigId := TriggersTable[pan.endSizeTrigId].id;
       end;
     end;
 
@@ -2203,10 +2262,14 @@ begin
     mapReader := g_Map_ParseMap(Data, Len);
   except
     mapReader := nil;
+    FreeMem(Data);
+    exit;
   end;
 
   FreeMem(Data);
 
+  if (mapReader = nil) then exit;
+
   if (mapReader.Width > 0) and (mapReader.Height > 0) then
   begin
     Result.Name := mapReader.MapName;
@@ -2413,6 +2476,8 @@ var
   end;
 
 begin
+  if g_dbgpan_mplat_step then g_dbgpan_mplat_active := true;
+
   UpdatePanelArray(gWalls);
   UpdatePanelArray(gRenderBackgrounds);
   UpdatePanelArray(gRenderForegrounds);
@@ -2421,6 +2486,8 @@ begin
   UpdatePanelArray(gAcid2);
   UpdatePanelArray(gSteps);
 
+  if g_dbgpan_mplat_step then begin g_dbgpan_mplat_step := false; g_dbgpan_mplat_active := false; end;
+
   if gGameSettings.GameMode = GM_CTF then
   begin
     for a := FLAG_RED to FLAG_BLUE do
@@ -2466,7 +2533,7 @@ begin
               if j > High(gPlayers) then j := 0;
               if gPlayers[j] <> nil then
               begin
-                if gPlayers[j].Live and g_Obj_Collide(@Obj, @gPlayers[j].Obj) then
+                if gPlayers[j].alive and g_Obj_Collide(@Obj, @gPlayers[j].Obj) then
                 begin
                   if gPlayers[j].GetFlag(a) then Break;
                 end;
@@ -2850,6 +2917,8 @@ begin
   //pan := gWalls[ID];
   pan := g_Map_PanelByGUID(pguid);
   if (pan = nil) then exit;
+  if pan.Enabled and mapGrid.proxyEnabled[pan.proxyId] then exit;
+
   pan.Enabled := True;
   g_Mark(pan.X, pan.Y, pan.Width, pan.Height, MARK_DOOR, true);
 
@@ -2857,7 +2926,9 @@ begin
   //if (pan.proxyId >= 0) then mapGrid.proxyEnabled[pan.proxyId] := true
   //else pan.proxyId := mapGrid.insertBody(pan, pan.X, pan.Y, pan.Width, pan.Height, GridTagDoor);
 
-  if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState({gWalls[ID]}pan.PanelType, pguid);
+  //if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(pguid);
+  // mark platform as interesting
+  pan.setDirty();
 
   {$IFDEF MAP_DEBUG_ENABLED_FLAG}
   //e_WriteLog(Format('ENABLE: wall #%d(%d) enabled (%d)  (%d,%d)-(%d,%d)', [Integer(ID), Integer(pan.proxyId), Integer(mapGrid.proxyEnabled[pan.proxyId]), pan.x, pan.y, pan.width, pan.height]), MSG_NOTIFY);
@@ -2872,13 +2943,17 @@ begin
   //pan := gWalls[ID];
   pan := g_Map_PanelByGUID(pguid);
   if (pan = nil) then exit;
+  if (not pan.Enabled) and (not mapGrid.proxyEnabled[pan.proxyId]) then exit;
+
   pan.Enabled := False;
   g_Mark(pan.X, pan.Y, pan.Width, pan.Height, MARK_DOOR, false);
 
   mapGrid.proxyEnabled[pan.proxyId] := false;
   //if (pan.proxyId >= 0) then begin mapGrid.removeBody(pan.proxyId); pan.proxyId := -1; end;
 
-  if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(pan.PanelType, pguid);
+  //if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(pguid);
+  // mark platform as interesting
+  pan.setDirty();
 
   {$IFDEF MAP_DEBUG_ENABLED_FLAG}
   //e_WriteLog(Format('DISABLE: wall #%d(%d) disabled (%d)  (%d,%d)-(%d,%d)', [Integer(ID), Integer(pan.proxyId), Integer(mapGrid.proxyEnabled[pan.proxyId]), pan.x, pan.y, pan.width, pan.height]), MSG_NOTIFY);
@@ -2906,7 +2981,7 @@ begin
   }
 
   tp.NextTexture(AnimLoop);
-  if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelTexture(PanelType, pguid, AnimLoop);
+  if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelTexture(pguid, AnimLoop);
 end;
 
 
@@ -2935,7 +3010,9 @@ begin
       3: g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT);
     end;
 
-    if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, pguid);
+    //if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(pguid);
+    // mark platform as interesting
+    pan.setDirty();
   end;
 end;
 
@@ -3056,20 +3133,15 @@ var
   var
     PAMem: TBinMemoryWriter;
     pan: TPanel;
+    count: Integer;
   begin
     // Ñîçäàåì íîâûé ñïèñîê ñîõðàíÿåìûõ ïàíåëåé
     PAMem := TBinMemoryWriter.Create((Length(panByGUID)+1) * 40);
 
-    for pan in panByGUID do
-    begin
-      if true{pan.SaveIt} then
-      begin
-        // ID ïàíåëè
-        //PAMem.WriteInt(i);
-        // Ñîõðàíÿåì ïàíåëü
-        pan.SaveState(PAMem);
-      end;
-    end;
+    // Ñîõðàíÿåì ïàíåëè
+    count := Length(panByGUID);
+    Mem.WriteInt(count);
+    for pan in panByGUID do pan.SaveState(PAMem);
 
     // Ñîõðàíÿåì ýòîò ñïèñîê ïàíåëåé
     PAMem.SaveToMemory(Mem);
@@ -3152,25 +3224,19 @@ var
   var
     PAMem: TBinMemoryReader;
     pan: TPanel;
+    count: LongInt;
   begin
     // Çàãðóæàåì òåêóùèé ñïèñîê ïàíåëåé
     PAMem := TBinMemoryReader.Create();
     PAMem.LoadFromMemory(Mem);
 
+    // Çàãðóæàåì ïàíåëè
+    PAMem.ReadInt(count);
+    if (count <> Length(panByGUID)) then raise EBinSizeError.Create('g_Map_LoadState: LoadPanelArray: invalid number of panels');
     for pan in panByGUID do
     begin
-      if true{pan.SaveIt} then
-      begin
-        // ID ïàíåëè:
-        //PAMem.ReadInt(id);
-        {
-        if id <> i then raise EBinSizeError.Create('g_Map_LoadState: LoadPanelArray: Wrong Panel ID');
-        }
-        // Çàãðóæàåì ïàíåëü
-        pan.LoadState(PAMem);
-        //if (panels[i].arrIdx <> i) then raise Exception.Create('g_Map_LoadState: LoadPanelArray: Wrong Panel arrIdx');
-        if (pan.proxyId >= 0) then mapGrid.proxyEnabled[pan.proxyId] := pan.Enabled;
-      end;
+      pan.LoadState(PAMem);
+      if (pan.proxyId >= 0) then mapGrid.proxyEnabled[pan.proxyId] := pan.Enabled;
     end;
 
     // Ýòîò ñïèñîê ïàíåëåé çàãðóæåí