DEADSOFTWARE

map: fix map saving on big endian machines
[d2df-editor.git] / src / shared / MAPWRITER.pas
1 unit MAPWRITER;
3 {$INCLUDE ../shared/a_modes.inc}
5 {
6 -----------------------------------
7 MAPWRITER.PAS ÂÅÐÑÈß ÎÒ 24.09.06
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 TMapWriter = class(TObject)
27 private
28 FDataBlocks: TDataBlocksArray;
29 public
30 constructor Create();
31 destructor Destroy(); override;
32 procedure FreeMap();
33 function SaveMap(var Data: Pointer): LongWord;
34 function HandledVersion(): Byte; virtual;
35 end;
37 TMapWriter_1 = class(TMapWriter)
38 public
39 function AddTextures(Textures: TTexturesRec1Array): Boolean;
40 function AddPanels(Panels: TPanelsRec1Array): Boolean;
41 function AddItems(Items: TItemsRec1Array): Boolean;
42 function AddMonsters(Monsters: TMonsterRec1Array): Boolean;
43 function AddAreas(Areas: TAreasRec1Array): Boolean;
44 function AddTriggers(Triggers: TTriggersRec1Array): Boolean;
45 function AddHeader(MapHeader: TMapHeaderRec_1): Boolean;
46 function HandledVersion(): Byte; override;
47 end;
50 implementation
52 uses
53 MAPDEF, BinEditor, SysUtils, Math;
55 { TMapWriter }
57 constructor TMapWriter.Create();
58 begin
59 FDataBlocks := nil;
60 end;
62 destructor TMapWriter.Destroy();
63 begin
64 FreeMap();
66 inherited;
67 end;
69 procedure TMapWriter.FreeMap();
70 var
71 a: Integer;
72 begin
73 if FDataBlocks <> nil then
74 for a := 0 to High(FDataBlocks) do
75 if FDataBlocks[a].Data <> nil then FreeMem(FDataBlocks[a].Data);
77 FDataBlocks := nil;
78 end;
80 function TMapWriter.SaveMap(var Data: Pointer): LongWord;
81 var
82 a: Integer;
83 b, c: LongWord;
84 Sign: array[0..2] of Char;
85 Ver: Byte;
86 blk: TBlock;
87 begin
88 b := 3+1+SizeOf(TBlock)*(Length(FDataBlocks)+1);
90 if FDataBlocks <> nil then
91 for a := 0 to High(FDataBlocks) do
92 b := b+FDataBlocks[a].Block.BlockSize;
94 Result := b;
96 GetMem(Data, b);
98 Sign := MAP_SIGNATURE;
99 CopyMemory(Data, @Sign[0], 3);
100 c := 3;
102 Ver := HandledVersion();
103 CopyMemory(Pointer(PtrUInt(Data)+c), @Ver, 1);
104 c := c+1;
106 if FDataBlocks <> nil then
107 for a := 0 to High(FDataBlocks) do
108 begin
109 blk := FDataBlocks[a].Block;
110 {$IFDEF FPC_BIG_ENDIAN}
111 blk.Reserved := NtoLE(blk.Reserved);
112 blk.BlockSize := NtoLE(blk.BlockSize);
113 {$ENDIF}
114 CopyMemory(Pointer(PtrUInt(Data)+c), @blk, SizeOf(TBlock));
115 c := c+SizeOf(TBlock);
116 CopyMemory(Pointer(PtrUInt(Data)+c), FDataBlocks[a].Data, FDataBlocks[a].Block.BlockSize);
117 c := c+FDataBlocks[a].Block.BlockSize;
118 end;
120 ZeroMemory(Pointer(PtrUInt(Data)+c), SizeOf(TBlock));
121 end;
123 function TMapWriter.HandledVersion(): Byte;
124 begin
125 Result := $00;
126 end;
128 { TMapWriter_1 }
130 function TMapWriter_1.AddAreas(Areas: TAreasRec1Array): Boolean;
131 var
132 a, size: LongWord;
133 area: TAreaRec_1;
134 begin
135 if Areas = nil then
136 begin
137 Result := True;
138 Exit;
139 end;
141 SetLength(FDataBlocks, Length(FDataBlocks)+1);
143 size := SizeOf(TAreaRec_1);
145 with FDataBlocks[High(FDataBlocks)] do
146 begin
147 Block.BlockType := BLOCK_AREAS;
148 Block.Reserved := $00000000;
149 Block.BlockSize := LongWord(Length(Areas))*size;
151 Data := GetMemory(Block.BlockSize);
153 for a := 0 to High(Areas) do
154 begin
155 area := Areas[a];
156 {$IFDEF FPC_BIG_ENDIAN}
157 area.X := NtoLE(area.X);
158 area.Y := NtoLE(area.Y);
159 {$ENDIF}
160 CopyMemory(Pointer(PtrUInt(Data)+a*Size), @area, size);
161 end;
162 end;
164 Result := True;
165 end;
167 function TMapWriter_1.AddItems(Items: TItemsRec1Array): Boolean;
168 var
169 a, size: LongWord;
170 item: TItemRec_1;
171 begin
172 if Items = nil then
173 begin
174 Result := True;
175 Exit;
176 end;
178 SetLength(FDataBlocks, Length(FDataBlocks)+1);
180 size := SizeOf(TItemRec_1);
182 with FDataBlocks[High(FDataBlocks)] do
183 begin
184 Block.BlockType := BLOCK_ITEMS;
185 Block.Reserved := $00000000;
186 Block.BlockSize := LongWord(Length(Items))*size;
188 Data := GetMemory(Block.BlockSize);
190 for a := 0 to High(Items) do
191 begin
192 item := Items[a];
193 {$IFDEF FPC_BIG_ENDIAN}
194 item.X := NtoLE(item.X);
195 item.Y := NtoLE(item.Y);
196 {$ENDIF}
197 CopyMemory(Pointer(PtrUInt(Data)+a*size), @item, size);
198 end;
199 end;
201 Result := True;
202 end;
204 function TMapWriter_1.AddMonsters(Monsters: TMonsterRec1Array): Boolean;
205 var
206 a, size: LongWord;
207 mon: TMonsterRec_1;
208 begin
209 if Monsters = nil then
210 begin
211 Result := True;
212 Exit;
213 end;
215 SetLength(FDataBlocks, Length(FDataBlocks)+1);
217 size := SizeOf(TMonsterRec_1);
219 with FDataBlocks[High(FDataBlocks)] do
220 begin
221 Block.BlockType := BLOCK_MONSTERS;
222 Block.Reserved := $00000000;
223 Block.BlockSize := LongWord(Length(Monsters))*size;
225 Data := GetMemory(Block.BlockSize);
227 for a := 0 to High(Monsters) do
228 begin
229 mon := Monsters[a];
230 {$IFDEF FPC_BIG_ENDIAN}
231 mon.X := NtoLE(mon.X);
232 mon.Y := NtoLE(mon.Y);
233 {$ENDIF}
234 CopyMemory(Pointer(PtrUInt(Data)+a*Size), @mon, size);
235 end;
236 end;
238 Result := True;
239 end;
241 function TMapWriter_1.AddPanels(Panels: TPanelsRec1Array): Boolean;
242 var
243 a, size: LongWord;
244 panel: TPanelRec_1;
245 begin
246 if Panels = nil then
247 begin
248 Result := True;
249 Exit;
250 end;
252 SetLength(FDataBlocks, Length(FDataBlocks)+1);
254 size := SizeOf(TPanelRec_1);
256 with FDataBlocks[High(FDataBlocks)] do
257 begin
258 Block.BlockType := BLOCK_PANELS;
259 Block.Reserved := $00000000;
260 Block.BlockSize := LongWord(Length(Panels))*size;
262 Data := GetMemory(Block.BlockSize);
264 for a := 0 to High(Panels) do
265 begin
266 panel := Panels[a];
267 {$IFDEF FPC_BIG_ENDIAN}
268 panel.X := NtoLE(panel.X);
269 panel.Y := NtoLE(panel.Y);
270 panel.Width := NtoLE(panel.Width);
271 panel.Height := NtoLE(panel.Height);
272 panel.TextureNum := NtoLE(panel.TextureNum);
273 panel.PanelType := NtoLE(panel.PanelType);
274 {$ENDIF}
275 CopyMemory(Pointer(PtrUInt(Data)+a*size), @panel, size);
276 end;
277 end;
279 Result := True;
280 end;
282 function TMapWriter_1.AddTextures(Textures: TTexturesRec1Array): Boolean;
283 var
284 a, size: LongWord;
285 begin
286 if Textures = nil then
287 begin
288 Result := True;
289 Exit;
290 end;
292 SetLength(FDataBlocks, Length(FDataBlocks)+1);
294 size := SizeOf(TTextureRec_1);
296 with FDataBlocks[High(FDataBlocks)] do
297 begin
298 Block.BlockType := BLOCK_TEXTURES;
299 Block.Reserved := $00000000;
300 Block.BlockSize := LongWord(Length(Textures))*size;
302 Data := GetMemory(Block.BlockSize);
304 for a := 0 to High(Textures) do
305 CopyMemory(Pointer(PtrUInt(Data)+a*size), @Textures[a], size);
306 end;
308 Result := True;
309 end;
311 function TMapWriter_1.AddTriggers(Triggers: TTriggersRec1Array): Boolean;
312 var
313 a, i, size: LongWord;
314 tr: TTriggerRec_1;
315 data: ^TTriggerData;
316 begin
317 if Triggers = nil then
318 begin
319 Result := True;
320 Exit;
321 end;
323 SetLength(FDataBlocks, Length(FDataBlocks)+1);
325 size := SizeOf(TTriggerRec_1);
327 FDataBlocks[High(FDataBlocks)].Block.BlockType := BLOCK_TRIGGERS;
328 FDataBlocks[High(FDataBlocks)].Block.Reserved := $00000000;
329 FDataBlocks[High(FDataBlocks)].Block.BlockSize := LongWord(Length(Triggers))*size;
331 FDataBlocks[High(FDataBlocks)].Data := GetMemory(FDataBlocks[High(FDataBlocks)].Block.BlockSize);
333 for a := 0 to High(Triggers) do
334 begin
335 tr := Triggers[a];
336 data := @tr.data;
337 // fix broken maps
338 case tr.TriggerType of
339 TRIGGER_MUSIC: data.MusicAction := Min(Max(data.MusicAction, 0), 1);
340 end;
341 // fix endianness
342 {$IFDEF FPC_BIG_ENDIAN}
343 tr.X := NtoLE(tr.X);
344 tr.Y := NtoLE(tr.Y);
345 tr.Width := NtoLE(tr.Width);
346 tr.Height := NtoLE(tr.Height);
347 tr.TexturePanel := NtoLE(tr.TexturePanel);
348 case tr.TriggerType of
349 //TRIGGER_EXIT: ;
350 TRIGGER_TELEPORT:
351 begin
352 data.TargetPoint.X := NtoLE(data.TargetPoint.X);
353 data.TargetPoint.Y := NtoLE(data.TargetPoint.Y);
354 end;
355 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
356 TRIGGER_CLOSETRAP, TRIGGER_TRAP, TRIGGER_LIFTUP, TRIGGER_LIFTDOWN,
357 TRIGGER_LIFT:
358 data.PanelID := NtoLE(data.PanelID);
359 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
360 begin
361 data.tX := NtoLE(data.tX);
362 data.tY := NtoLE(data.tY);
363 data.tWidth := NtoLE(data.tWidth);
364 data.tHeight := NtoLE(data.tHeight);
365 data.Wait := NtoLE(data.Wait);
366 data.Count := NtoLE(data.Count);
367 data.MonsterID := NtoLE(data.MonsterID);
368 end;
369 //TRIGGER_SECRET: ;
370 //TRIGGER_TEXTURE: ;
371 //TRIGGER_SOUND: ;
372 TRIGGER_SPAWNMONSTER:
373 begin
374 data.MonPos.X := NtoLE(data.MonPos.X);
375 data.MonPos.Y := NtoLE(data.MonPos.Y);
376 data.MonHealth := NtoLE(data.MonHealth);
377 data.MonCount := NtoLE(data.MonCount);
378 data.MonMax := NtoLE(data.MonMax);
379 data.MonDelay := NtoLE(data.MonDelay);
380 end;
381 TRIGGER_SPAWNITEM:
382 begin
383 data.ItemPos.X := NtoLE(data.ItemPos.X);
384 data.ItemPos.Y := NtoLE(data.ItemPos.Y);
385 data.ItemCount := NtoLE(data.ItemCount);
386 data.ItemMax := NtoLE(data.ItemMax);
387 data.ItemDelay := NtoLE(data.ItemDelay);
388 end;
389 //TRIGGER_MUSIC:
390 TRIGGER_PUSH:
391 data.PushAngle := NtoLE(data.PushAngle);
392 //TRIGGER_SCORE:
393 TRIGGER_MESSAGE:
394 data.MessageTime := NtoLE(data.MessageTime);
395 TRIGGER_DAMAGE:
396 begin
397 data.DamageValue := NtoLE(data.DamageValue);
398 data.DamageInterval := NtoLE(data.DamageInterval);
399 end;
400 TRIGGER_HEALTH:
401 begin
402 data.HealValue := NtoLE(data.HealValue);
403 data.HealInterval := NtoLE(data.HealInterval);
404 end;
405 TRIGGER_SHOT:
406 begin
407 data.ShotPos.X := NtoLE(data.ShotPos.X);
408 data.ShotPos.Y := NtoLE(data.ShotPos.Y);
409 data.ShotPanelID := NtoLE(data.ShotPanelID);
410 data.ShotIntSight := NtoLE(data.ShotIntSight);
411 data.ShotAngle := NtoLE(data.ShotAngle);
412 data.ShotWait := NtoLE(data.ShotWait);
413 data.ShotAccuracy := NtoLE(data.ShotAccuracy);
414 data.ShotAmmo := NtoLE(data.ShotAmmo);
415 data.ShotIntReload := NtoLE(data.ShotIntReload);
416 end;
417 TRIGGER_EFFECT:
418 begin
419 data.FXWait := NtoLE(data.FXWait);
420 data.FXVelX := NtoLE(data.FXVelX);
421 data.FXVelY := NtoLE(data.FXVelY);
422 end;
423 end;
424 {$ENDIF}
425 CopyMemory(Pointer(PtrUInt(FDataBlocks[High(FDataBlocks)].Data)+a*size), @tr, size);
426 end;
428 Result := True;
429 end;
431 function TMapWriter_1.AddHeader(MapHeader: TMapHeaderRec_1): Boolean;
432 var
433 size: LongWord;
434 hdr: TMapHeaderRec_1;
435 begin
436 SetLength(FDataBlocks, Length(FDataBlocks)+1);
438 size := SizeOf(TMapHeaderRec_1);
440 with FDataBlocks[High(FDataBlocks)] do
441 begin
442 Block.BlockType := BLOCK_HEADER;
443 Block.Reserved := $00000000;
444 Block.BlockSize := size;
446 Data := GetMemory(Block.BlockSize);
448 hdr := MapHeader;
449 {$IFDEF FPC_BIG_ENDIAN}
450 hdr.Width := NtoLE(hdr.Width);
451 hdr.Height := NtoLE(hdr.Height);
452 {$ENDIF}
453 CopyMemory(Pointer(PtrUInt(Data)), @hdr, size);
454 end;
456 Result := True;
457 end;
459 function TMapWriter_1.HandledVersion(): Byte;
460 begin
461 Result := $01;
462 end;
464 end.