DEADSOFTWARE

map: fix map loading on big endian machines
[d2df-editor.git] / src / shared / MAPREADER.pas
1 unit MAPREADER;
3 {$INCLUDE ../shared/a_modes.inc}
5 {
6 -----------------------------------
7 MAPREADER.PAS ÂÅÐÑÈß ÎÒ 13.11.07
9 Ïîääåðæêà êàðò âåðñèè 1
10 -----------------------------------
11 }
13 interface
15 uses
16 MAPSTRUCT;
18 type
19 TDataBlock = packed record
20 Block: TBlock;
21 Data: Pointer;
22 end;
24 TDataBlocksArray = packed array of TDataBlock;
26 TMapReader = class(TObject)
27 private
28 FError: Byte;
29 FVersion: Byte;
30 FDataBlocks: TDataBlocksArray;
31 function GetBlocks(BlocksType: Byte): TDataBlocksArray;
32 public
33 constructor Create();
34 destructor Destroy(); override;
35 function LoadMap(Data: Pointer): Boolean;
36 procedure FreeMap();
37 function HandledVersion(): Byte; virtual;
39 property GetError: Byte read FError;
40 property GetVersion: Byte read FVersion;
41 end;
43 TMapReader_1 = class(TMapReader)
44 private
45 public
46 function GetMapHeader(): TMapHeaderRec_1;
47 function GetTextures(): TTexturesRec1Array;
48 function GetPanels(): TPanelsRec1Array;
49 function GetItems(): TItemsRec1Array;
50 function GetAreas(): TAreasRec1Array;
51 function GetMonsters(): TMonsterRec1Array;
52 function GetTriggers(): TTriggersRec1Array;
53 function HandledVersion(): Byte; override;
54 end;
56 const
57 MAP_ERROR_NONE = $00;
58 MAP_ERROR_SIGNATURE = $01;
59 MAP_ERROR_VERSION = $02;
61 NNF_NO_NAME = 0;
62 NNF_NAME_BEFORE = 1;
63 NNF_NAME_EQUALS = 2;
64 NNF_NAME_AFTER = 3;
66 function g_Texture_NumNameFindStart(name: String): Boolean;
67 function g_Texture_NumNameFindNext(var newName: String): Byte;
69 implementation
71 uses
72 SysUtils, BinEditor, MAPDEF;
74 var
75 NNF_PureName: String; // Èìÿ òåêñòóðû áåç öèôð â êîíöå
76 NNF_FirstNum: Integer; // ×èñëî ó íà÷àëüíîé òåêñòóðû
77 NNF_CurrentNum: Integer; // Ñëåäóþùåå ÷èñëî ó òåêñòóðû
79 function g_Texture_NumNameFindStart(name: String): Boolean;
80 var
81 i: Integer;
83 begin
84 Result := False;
85 NNF_PureName := '';
86 NNF_FirstNum := -1;
87 NNF_CurrentNum := -1;
89 for i := Length(name) downto 1 do
90 if (name[i] = '_') then // "_" - ñèìâîë íà÷àëà íîìåðíîãî ïîñòôèêñà
91 begin
92 if i = Length(name) then
93 begin // Íåò öèôð â êîíöå ñòðîêè
94 Exit;
95 end
96 else
97 begin
98 NNF_PureName := Copy(name, 1, i);
99 Delete(name, 1, i);
100 Break;
101 end;
102 end;
104 // Íå ïåðåâåñòè â ÷èñëî:
105 if not TryStrToInt(name, NNF_FirstNum) then
106 Exit;
108 NNF_CurrentNum := 0;
110 Result := True;
111 end;
113 function g_Texture_NumNameFindNext(var newName: String): Byte;
114 begin
115 if (NNF_PureName = '') or (NNF_CurrentNum < 0) then
116 begin
117 newName := '';
118 Result := NNF_NO_NAME;
119 Exit;
120 end;
122 newName := NNF_PureName + IntToStr(NNF_CurrentNum);
124 if NNF_CurrentNum < NNF_FirstNum then
125 Result := NNF_NAME_BEFORE
126 else
127 if NNF_CurrentNum > NNF_FirstNum then
128 Result := NNF_NAME_AFTER
129 else
130 Result := NNF_NAME_EQUALS;
132 Inc(NNF_CurrentNum);
133 end;
135 { T M a p R e a d e r _ 1 : }
137 function TMapReader_1.GetAreas(): TAreasRec1Array;
138 var
139 TempDataBlocks: TDataBlocksArray;
140 a: Integer;
141 b, Size: LongWord;
142 begin
143 Result := nil;
145 TempDataBlocks := GetBlocks(BLOCK_AREAS);
147 if TempDataBlocks = nil then Exit;
149 size := SizeOf(TAreaRec_1);
151 for a := 0 to High(TempDataBlocks) do
152 for b := 0 to (TempDataBlocks[a].Block.BlockSize div size)-1 do
153 begin
154 SetLength(Result, Length(Result)+1);
155 CopyMemory(@Result[High(Result)], Pointer(PtrUInt(TempDataBlocks[a].Data)+b*size), size);
156 end;
158 {$IFDEF FPC_BIG_ENDIAN}
159 for a := 0 to High(Result) do
160 begin
161 Result[a].X := LEtoN(Result[a].X);
162 Result[a].Y := LEtoN(Result[a].Y);
163 end;
164 {$ENDIF}
166 TempDataBlocks := nil;
167 end;
169 function TMapReader_1.GetItems(): TItemsRec1Array;
170 var
171 TempDataBlocks: TDataBlocksArray;
172 a: Integer;
173 b, Size: LongWord;
174 begin
175 Result := nil;
177 TempDataBlocks := GetBlocks(BLOCK_ITEMS);
179 if TempDataBlocks = nil then Exit;
181 size := SizeOf(TItemRec_1);
183 for a := 0 to High(TempDataBlocks) do
184 for b := 0 to (TempDataBlocks[a].Block.BlockSize div size)-1 do
185 begin
186 SetLength(Result, Length(Result)+1);
187 CopyMemory(@Result[High(Result)], Pointer(PtrUInt(TempDataBlocks[a].Data)+b*size), size);
188 end;
190 {$IFDEF FPC_BIG_ENDIAN}
191 for a := 0 to High(Result) do
192 begin
193 Result[a].X := LEtoN(Result[a].X);
194 Result[a].Y := LEtoN(Result[a].Y);
195 end;
196 {$ENDIF}
198 TempDataBlocks := nil;
199 end;
201 function TMapReader_1.GetMapHeader(): TMapHeaderRec_1;
202 var
203 TempDataBlocks: TDataBlocksArray;
204 begin
205 ZeroMemory(@Result, SizeOf(TMapHeaderRec_1));
207 TempDataBlocks := GetBlocks(BLOCK_HEADER);
209 if TempDataBlocks = nil then Exit;
211 CopyMemory(@Result, TempDataBlocks[0].Data, SizeOf(TMapHeaderRec_1));
213 {$IFDEF FPC_BIG_ENDIAN}
214 Result.Width := LEtoN(Result.Width);
215 Result.Height := LEtoN(Result.Height);
216 {$ENDIF}
218 TempDataBlocks := nil;
219 end;
221 function TMapReader_1.GetMonsters(): TMonsterRec1Array;
222 var
223 TempDataBlocks: TDataBlocksArray;
224 a: Integer;
225 b, Size: LongWord;
226 begin
227 Result := nil;
229 TempDataBlocks := GetBlocks(BLOCK_MONSTERS);
231 if TempDataBlocks = nil then Exit;
233 size := SizeOf(TMonsterRec_1);
235 for a := 0 to High(TempDataBlocks) do
236 for b := 0 to (TempDataBlocks[a].Block.BlockSize div size)-1 do
237 begin
238 SetLength(Result, Length(Result)+1);
239 CopyMemory(@Result[High(Result)], Pointer(PtrUInt(TempDataBlocks[a].Data)+b*size), size);
240 end;
242 {$IFDEF FPC_BIG_ENDIAN}
243 for a := 0 to High(Result) do
244 begin
245 Result[a].X := LEtoN(Result[a].X);
246 Result[a].Y := LEtoN(Result[a].Y);
247 end;
248 {$ENDIF}
250 TempDataBlocks := nil;
251 end;
253 function TMapReader_1.GetPanels(): TPanelsRec1Array;
254 var
255 TempDataBlocks: TDataBlocksArray;
256 a: Integer;
257 b, Size: LongWord;
258 begin
259 Result := nil;
261 TempDataBlocks := GetBlocks(BLOCK_PANELS);
263 if TempDataBlocks = nil then Exit;
265 size := SizeOf(TPanelRec_1);
267 for a := 0 to High(TempDataBlocks) do
268 for b := 0 to (TempDataBlocks[a].Block.BlockSize div size)-1 do
269 begin
270 SetLength(Result, Length(Result)+1);
271 CopyMemory(@Result[High(Result)], Pointer(PtrUInt(TempDataBlocks[a].Data)+b*size), size);
272 end;
274 {$IFDEF FPC_BIG_ENDIAN}
275 for a := 0 to High(Result) do
276 begin
277 Result[a].X := LEtoN(Result[a].X);
278 Result[a].Y := LEtoN(Result[a].Y);
279 Result[a].Width := LEtoN(Result[a].Width);
280 Result[a].Height := LEtoN(Result[a].Height);
281 Result[a].TextureNum := LEtoN(Result[a].TextureNum);
282 Result[a].PanelType := LEtoN(Result[a].PanelType);
283 end;
284 {$ENDIF}
286 TempDataBlocks := nil;
287 end;
289 function TMapReader_1.GetTextures(): TTexturesRec1Array;
290 var
291 TempDataBlocks: TDataBlocksArray;
292 a: Integer;
293 b, Size: LongWord;
294 begin
295 Result := nil;
297 TempDataBlocks := GetBlocks(BLOCK_TEXTURES);
299 if TempDataBlocks = nil then Exit;
301 size := SizeOf(TTextureRec_1);
303 for a := 0 to High(TempDataBlocks) do
304 for b := 0 to (TempDataBlocks[a].Block.BlockSize div size)-1 do
305 begin
306 SetLength(Result, Length(Result)+1);
307 CopyMemory(@Result[High(Result)], Pointer(PtrUInt(TempDataBlocks[a].Data)+b*size), size);
308 end;
310 TempDataBlocks := nil;
311 end;
313 function TMapReader_1.GetTriggers(): TTriggersRec1Array;
314 type
315 PTriggerData = ^TTriggerData;
316 var
317 TempDataBlocks: TDataBlocksArray;
318 a: Integer;
319 b, Size: LongWord;
320 data: PTriggerData;
321 begin
322 Result := nil;
324 TempDataBlocks := GetBlocks(BLOCK_TRIGGERS);
326 if TempDataBlocks = nil then Exit;
328 size := SizeOf(TTriggerRec_1);
330 for a := 0 to High(TempDataBlocks) do
331 for b := 0 to (TempDataBlocks[a].Block.BlockSize div size)-1 do
332 begin
333 SetLength(Result, Length(Result)+1);
334 CopyMemory(@Result[High(Result)], Pointer(PtrUInt(TempDataBlocks[a].Data)+b*size), size);
335 end;
337 {$IFDEF FPC_BIG_ENDIAN}
338 for a := 0 to High(Result) do
339 begin
340 Result[a].X := LEtoN(Result[a].X);
341 Result[a].Y := LEtoN(Result[a].Y);
342 Result[a].Width := LEtoN(Result[a].Width);
343 Result[a].Height := LEtoN(Result[a].Height);
344 Result[a].TexturePanel := LEtoN(Result[a].TexturePanel);
345 data := PTriggerData(@Result[a].DATA);
346 case Result[a].TriggerType of
347 //TRIGGER_EXIT: ;
348 TRIGGER_TELEPORT:
349 begin
350 data.TargetPoint.X := LEtoN(data.TargetPoint.X);
351 data.TargetPoint.Y := LEtoN(data.TargetPoint.Y);
352 end;
353 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
354 TRIGGER_CLOSETRAP, TRIGGER_TRAP, TRIGGER_LIFTUP, TRIGGER_LIFTDOWN,
355 TRIGGER_LIFT:
356 data.PanelID := LEtoN(data.PanelID);
357 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
358 begin
359 data.tX := LEtoN(data.tX);
360 data.tY := LEtoN(data.tY);
361 data.tWidth := LEtoN(data.tWidth);
362 data.tHeight := LEtoN(data.tHeight);
363 data.Wait := LEtoN(data.Wait);
364 data.Count := LEtoN(data.Count);
365 data.MonsterID := LEtoN(data.MonsterID);
366 end;
367 //TRIGGER_SECRET: ;
368 //TRIGGER_TEXTURE: ;
369 //TRIGGER_SOUND: ;
370 TRIGGER_SPAWNMONSTER:
371 begin
372 data.MonPos.X := LEtoN(data.MonPos.X);
373 data.MonPos.Y := LEtoN(data.MonPos.Y);
374 data.MonHealth := LEtoN(data.MonHealth);
375 data.MonCount := LEtoN(data.MonCount);
376 data.MonMax := LEtoN(data.MonMax);
377 data.MonDelay := LEtoN(data.MonDelay);
378 end;
379 TRIGGER_SPAWNITEM:
380 begin
381 data.ItemPos.X := LEtoN(data.ItemPos.X);
382 data.ItemPos.Y := LEtoN(data.ItemPos.Y);
383 data.ItemCount := LEtoN(data.ItemCount);
384 data.ItemMax := LEtoN(data.ItemMax);
385 data.ItemDelay := LEtoN(data.ItemDelay);
386 end;
387 //TRIGGER_MUSIC:
388 TRIGGER_PUSH:
389 data.PushAngle := LEtoN(data.PushAngle);
390 //TRIGGER_SCORE:
391 TRIGGER_MESSAGE:
392 data.MessageTime := LEtoN(data.MessageTime);
393 TRIGGER_DAMAGE:
394 begin
395 data.DamageValue := LEtoN(data.DamageValue);
396 data.DamageInterval := LEtoN(data.DamageInterval);
397 end;
398 TRIGGER_HEALTH:
399 begin
400 data.HealValue := LEtoN(data.HealValue);
401 data.HealInterval := LEtoN(data.HealInterval);
402 end;
403 TRIGGER_SHOT:
404 begin
405 data.ShotPos.X := LEtoN(data.ShotPos.X);
406 data.ShotPos.Y := LEtoN(data.ShotPos.Y);
407 data.ShotPanelID := LEtoN(data.ShotPanelID);
408 data.ShotIntSight := LEtoN(data.ShotIntSight);
409 data.ShotAngle := LEtoN(data.ShotAngle);
410 data.ShotWait := LEtoN(data.ShotWait);
411 data.ShotAccuracy := LEtoN(data.ShotAccuracy);
412 data.ShotAmmo := LEtoN(data.ShotAmmo);
413 data.ShotIntReload := LEtoN(data.ShotIntReload);
414 end;
415 TRIGGER_EFFECT:
416 begin
417 data.FXWait := LEtoN(data.FXWait);
418 data.FXVelX := LEtoN(data.FXVelX);
419 data.FXVelY := LEtoN(data.FXVelY);
420 end;
421 end;
422 end;
423 {$ENDIF}
425 TempDataBlocks := nil;
426 end;
428 function TMapReader_1.HandledVersion: Byte;
429 begin
430 Result := $01;
431 end;
433 { T M a p R e a d e r : }
435 constructor TMapReader.Create();
436 begin
437 FDataBlocks := nil;
438 FError := MAP_ERROR_NONE;
439 FVersion := $00;
440 end;
442 destructor TMapReader.Destroy();
443 begin
444 FreeMap();
446 inherited;
447 end;
449 procedure TMapReader.FreeMap();
450 var
451 a: Integer;
452 begin
453 if FDataBlocks <> nil then
454 for a := 0 to High(FDataBlocks) do
455 if FDataBlocks[a].Data <> nil then FreeMem(FDataBlocks[a].Data);
457 FDataBlocks := nil;
458 FVersion := $00;
459 FError := MAP_ERROR_NONE;
460 end;
462 function TMapReader.GetBlocks(BlocksType: Byte): TDataBlocksArray;
463 var
464 a: Integer;
465 begin
466 Result := nil;
468 if FDataBlocks = nil then Exit;
470 for a := 0 to High(FDataBlocks) do
471 if FDataBlocks[a].Block.BlockType = BlocksType then
472 begin
473 SetLength(Result, Length(Result)+1);
474 Result[High(Result)] := FDataBlocks[a];
475 end;
476 end;
478 function TMapReader.HandledVersion(): Byte;
479 begin
480 Result := $00;
481 end;
483 function TMapReader.LoadMap(Data: Pointer): Boolean;
484 var
485 adr: LongWord;
486 _id: Integer;
487 Sign: array[0..2] of Char;
488 Ver: Byte;
489 begin
490 Result := False;
492 CopyMemory(@Sign[0], Data, 3);
493 if Sign <> MAP_SIGNATURE then
494 begin
495 FError := MAP_ERROR_SIGNATURE;
496 Exit;
497 end;
498 adr := 3;
500 CopyMemory(@Ver, Pointer(PtrUInt(Data)+adr), 1);
501 FVersion := Ver;
502 if Ver > HandledVersion() then
503 begin
504 FError := MAP_ERROR_VERSION;
505 Exit;
506 end;
507 adr := adr+1;
509 repeat
510 SetLength(FDataBlocks, Length(FDataBlocks)+1);
511 _id := High(FDataBlocks);
513 CopyMemory(@FDataBlocks[_id].Block, Pointer(PtrUInt(Data)+adr), SizeOf(TBlock));
514 {$IFDEF FPC_BIG_ENDIAN}
515 FDataBlocks[_id].Block.Reserved := LEtoN(FDataBlocks[_id].Block.Reserved);
516 FDataBlocks[_id].Block.BlockSize := LEtoN(FDataBlocks[_id].Block.BlockSize);
517 {$ENDIF}
518 adr := adr+SizeOf(TBlock);
520 FDataBlocks[_id].Data := GetMemory(FDataBlocks[_id].Block.BlockSize);
522 CopyMemory(FDataBlocks[_id].Data, Pointer(PtrUInt(Data)+adr), FDataBlocks[_id].Block.BlockSize);
524 adr := adr+FDataBlocks[_id].Block.BlockSize;
525 until FDataBlocks[_id].Block.BlockType = BLOCK_NONE;
527 Result := True;
528 end;
530 end.