Skip to content

Commit 3a8b6f6

Browse files
committed
big refactoring
1 parent dcc7da6 commit 3a8b6f6

File tree

6 files changed

+282
-183
lines changed

6 files changed

+282
-183
lines changed

FF4/FF4.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@
4545
</ItemGroup>
4646
<ItemGroup>
4747
<Compile Include="FF4Rom.cs" />
48+
<Compile Include="Map.cs" />
49+
<Compile Include="MapType.cs" />
4850
<Compile Include="Properties\AssemblyInfo.cs" />
51+
<Compile Include="Tileset.cs" />
4952
</ItemGroup>
5053
<ItemGroup>
5154
<None Include="packages.config" />

FF4/FF4Rom.cs

Lines changed: 24 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -53,143 +53,44 @@ public override bool Validate()
5353
return title == "FINAL FANTASY 2 ";
5454
}
5555

56-
public byte[] GetOverworldSubTiles() => Get(OverworldSubTileGraphicsOffset, 32*MapSubTileCount);
57-
public byte[] GetOverworldTileFormations() => Get(OverworldTileFormationsOffset, 4*MapTileCount);
58-
public byte[] GetOverworldSubTilePaletteOffsets() => Get(OverworldSubTilePaletteOffsetsOffset, MapSubTileCount);
56+
public Tileset Tileset { get; private set; }
57+
public Map Map { get; private set; }
5958

60-
public ushort[] GetOverworldPalette()
59+
public void LoadOverworldMap()
6160
{
62-
var paletteBytes = Get(OverworldPaletteOffset, 2*64);
63-
64-
var palette = new ushort[64];
65-
Buffer.BlockCopy(paletteBytes, 0, palette, 0, 2*64);
66-
67-
return palette;
68-
}
69-
70-
public byte[,] GetOverworldMap()
71-
{
72-
var pointerBytes = Get(OverworldRowPointersOffset, 2*OverworldRowCount);
73-
61+
var data = Get(OverworldRowDataOffset, OverworldRowDataMaxLength);
62+
var pointerBytes = Get(OverworldRowPointersOffset, OverworldRowCount * 2);
7463
var pointers = new ushort[OverworldRowCount];
75-
Buffer.BlockCopy(pointerBytes, 0, pointers, 0, 2*OverworldRowCount);
64+
Buffer.BlockCopy(pointerBytes, 0, pointers, 0, pointerBytes.Length);
7665

77-
var rows = new byte[OverworldRowCount, OverworldRowLength];
78-
for (int y = 0; y < OverworldRowCount; y++)
79-
{
80-
var dataOffset = OverworldRowDataOffset + pointers[y];
81-
var rowOffset = 0;
82-
byte tile = Data[dataOffset];
83-
while (tile != 0xFF)
84-
{
85-
if (tile == 0x00)
86-
{
87-
rows[y, rowOffset++] = 0x00;
88-
rows[y, rowOffset++] = 0x70;
89-
rows[y, rowOffset++] = 0x71;
90-
rows[y, rowOffset++] = 0x72;
91-
}
92-
else if (tile == 0x10)
93-
{
94-
rows[y, rowOffset++] = 0x10;
95-
rows[y, rowOffset++] = 0x73;
96-
rows[y, rowOffset++] = 0x74;
97-
rows[y, rowOffset++] = 0x75;
98-
}
99-
else if (tile == 0x20)
100-
{
101-
rows[y, rowOffset++] = 0x20;
102-
rows[y, rowOffset++] = 0x76;
103-
rows[y, rowOffset++] = 0x77;
104-
rows[y, rowOffset++] = 0x78;
105-
}
106-
else if (tile == 0x30)
107-
{
108-
rows[y, rowOffset++] = 0x30;
109-
rows[y, rowOffset++] = 0x79;
110-
rows[y, rowOffset++] = 0x7A;
111-
rows[y, rowOffset++] = 0x7B;
112-
}
113-
else if (tile >= 0x80)
114-
{
115-
tile -= 0x80;
116-
var count = Data[++dataOffset] + 1;
117-
for (int j = 0; j < count; j++)
118-
{
119-
rows[y, rowOffset++] = tile;
120-
}
121-
}
122-
else
123-
{
124-
rows[y, rowOffset++] = tile;
125-
}
66+
Map = new Map(MapType.Overworld, data, pointers);
12667

127-
dataOffset++;
128-
tile = Data[dataOffset];
129-
}
130-
}
68+
var subTiles = Get(OverworldSubTileGraphicsOffset, 32 * MapSubTileCount);
69+
var formations = Get(OverworldTileFormationsOffset, 4 * MapTileCount);
70+
var paletteBytes = Get(OverworldPaletteOffset, 2 * 64);
71+
var palette = new ushort[64];
72+
Buffer.BlockCopy(paletteBytes, 0, palette, 0, 2 * 64);
73+
var paletteOffsets = Get(OverworldSubTilePaletteOffsetsOffset, MapSubTileCount);
13174

132-
return rows;
75+
Tileset = new Tileset(subTiles, formations, palette, paletteOffsets);
13376
}
13477

135-
public void SaveOverworldMap(byte[,] map)
78+
public void SaveOverworldMap()
13679
{
137-
var compressedBytes = new byte[OverworldRowCount*OverworldRowLength];
138-
ushort dataOffset = 0;
139-
var pointers = new ushort[OverworldRowCount];
140-
141-
for (int y = 0; y < OverworldRowCount; y++)
142-
{
143-
pointers[y] = dataOffset;
144-
int x = 0;
145-
while (x < OverworldRowLength)
146-
{
147-
if (map[y, x] == 0x00 || map[y, x] == 0x10 || map[y, x] == 0x20 || map[y, x] == 0x30)
148-
{
149-
compressedBytes[dataOffset++] = map[y, x];
150-
x += 4;
151-
}
152-
else if (x == OverworldRowLength - 1)
153-
{
154-
compressedBytes[dataOffset++] = map[y, x++];
155-
}
156-
else if (map[y, x + 1] == map[y, x])
157-
{
158-
compressedBytes[dataOffset++] = (byte)(map[y, x++] + 0x80);
159-
160-
byte repeatCount = 0;
161-
while (x < OverworldRowLength && map[y, x - 1] == map[y, x])
162-
{
163-
x++;
164-
repeatCount++;
165-
}
166-
compressedBytes[dataOffset++] = repeatCount;
167-
}
168-
else
169-
{
170-
compressedBytes[dataOffset++] = map[y, x++];
171-
}
172-
}
173-
174-
compressedBytes[dataOffset++] = 0xFF;
175-
}
176-
177-
if (dataOffset > OverworldRowDataMaxLength)
80+
var length = Map.Length;
81+
if (length > OverworldRowDataMaxLength)
17882
{
179-
throw new IndexOutOfRangeException($"Overworld map data is too big: {dataOffset} bytes used, {OverworldRowDataMaxLength} bytes allowed");
83+
throw new IndexOutOfRangeException($"Overworld map data is too big: {length} bytes used, {OverworldRowDataMaxLength} bytes allowed");
18084
}
18185

182-
var pointerBytes = new byte[OverworldRowCount*2];
86+
byte[] data;
87+
ushort[] pointers;
88+
byte[] pointerBytes = new byte[OverworldRowCount*2];
89+
Map.GetCompressedData(out data, out pointers);
18390
Buffer.BlockCopy(pointers, 0, pointerBytes, 0, pointerBytes.Length);
184-
Put(OverworldRowPointersOffset, pointerBytes);
18591

186-
var mapDataBytes = new byte[OverworldRowDataMaxLength];
187-
Buffer.BlockCopy(compressedBytes, 0, mapDataBytes, 0, dataOffset);
188-
while (dataOffset < OverworldRowDataMaxLength)
189-
{
190-
mapDataBytes[dataOffset++] = 0xFF;
191-
}
192-
Put(OverworldRowDataOffset, mapDataBytes);
92+
Put(OverworldRowDataOffset, data);
93+
Put(OverworldRowPointersOffset, pointerBytes);
19394
}
19495
}
19596
}

FF4/Map.cs

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Runtime.CompilerServices;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
8+
namespace FF4
9+
{
10+
public class Map
11+
{
12+
private readonly byte[,] _map;
13+
private readonly byte[][] _compressedRows;
14+
private readonly int[] _compressedRowLengths;
15+
16+
public MapType MapType;
17+
18+
public byte this[int y, int x]
19+
{
20+
get { return _map[y, x]; }
21+
set
22+
{
23+
_map[y, x] = value;
24+
CompressRow(y);
25+
}
26+
}
27+
28+
public int Length => _compressedRowLengths.Sum();
29+
30+
public Map(MapType mapType, byte[] data, ushort[] pointers)
31+
{
32+
MapType = mapType;
33+
34+
if (mapType == MapType.Overworld)
35+
{
36+
var rowCount = FF4Rom.OverworldRowCount;
37+
_map = new byte[rowCount, FF4Rom.OverworldRowLength];
38+
_compressedRows = new byte[rowCount][];
39+
_compressedRowLengths = new int[rowCount];
40+
41+
for (int y = 0; y < rowCount; y++)
42+
{
43+
var dataOffset = pointers[y];
44+
var x = 0;
45+
byte tile = data[dataOffset++];
46+
while (tile != 0xFF)
47+
{
48+
if (tile == 0x00)
49+
{
50+
_map[y, x++] = 0x00;
51+
_map[y, x++] = 0x70;
52+
_map[y, x++] = 0x71;
53+
_map[y, x++] = 0x72;
54+
}
55+
else if (tile == 0x10)
56+
{
57+
_map[y, x++] = 0x10;
58+
_map[y, x++] = 0x73;
59+
_map[y, x++] = 0x74;
60+
_map[y, x++] = 0x75;
61+
}
62+
else if (tile == 0x20)
63+
{
64+
_map[y, x++] = 0x20;
65+
_map[y, x++] = 0x76;
66+
_map[y, x++] = 0x77;
67+
_map[y, x++] = 0x78;
68+
}
69+
else if (tile == 0x30)
70+
{
71+
_map[y, x++] = 0x30;
72+
_map[y, x++] = 0x79;
73+
_map[y, x++] = 0x7A;
74+
_map[y, x++] = 0x7B;
75+
}
76+
else if (tile >= 0x80)
77+
{
78+
tile -= 0x80;
79+
var count = data[dataOffset++] + 1;
80+
for (int j = 0; j < count; j++)
81+
{
82+
_map[y, x++] = tile;
83+
}
84+
}
85+
else
86+
{
87+
_map[y, x++] = tile;
88+
}
89+
90+
tile = data[dataOffset++];
91+
}
92+
93+
CompressRow(y);
94+
}
95+
}
96+
}
97+
98+
public void GetCompressedData(out byte[] data, out ushort[] pointers)
99+
{
100+
// Just for now until we cover all execution paths.
101+
data = null;
102+
pointers = null;
103+
104+
if (MapType == MapType.Overworld)
105+
{
106+
data = new byte[FF4Rom.OverworldRowDataMaxLength];
107+
pointers = new ushort[FF4Rom.OverworldRowCount];
108+
int dataOffset = 0;
109+
for (int y = 0; y < FF4Rom.OverworldRowCount; y++)
110+
{
111+
Buffer.BlockCopy(_compressedRows[y], 0, data, dataOffset, _compressedRowLengths[y]);
112+
pointers[y] = (ushort)dataOffset;
113+
114+
dataOffset += _compressedRowLengths[y];
115+
}
116+
117+
while (dataOffset < data.Length)
118+
{
119+
data[dataOffset++] = 0xFF;
120+
}
121+
}
122+
}
123+
124+
private void CompressRow(int y)
125+
{
126+
int rowLength = FF4Rom.OverworldRowLength;
127+
_compressedRows[y] = new byte[rowLength + 1]; // extra 0xFF at the end
128+
129+
int x = 0, dataOffset = 0;
130+
while (x < rowLength)
131+
{
132+
if (_map[y, x] == 0x00 || _map[y, x] == 0x10 || _map[y, x] == 0x20 || _map[y, x] == 0x30)
133+
{
134+
_compressedRows[y][dataOffset++] = _map[y, x];
135+
x += 4;
136+
}
137+
else if (x == rowLength - 1)
138+
{
139+
_compressedRows[y][dataOffset++] = _map[y, x++];
140+
}
141+
else if (_map[y, x + 1] == _map[y, x])
142+
{
143+
_compressedRows[y][dataOffset++] = (byte)(_map[y, x++] + 0x80);
144+
145+
byte repeatCount = 0;
146+
while (x < rowLength && _map[y, x - 1] == _map[y, x])
147+
{
148+
x++;
149+
repeatCount++;
150+
}
151+
_compressedRows[y][dataOffset++] = repeatCount;
152+
}
153+
else
154+
{
155+
_compressedRows[y][dataOffset++] = _map[y, x++];
156+
}
157+
}
158+
159+
_compressedRows[y][dataOffset++] = 0xFF;
160+
_compressedRowLengths[y] = dataOffset;
161+
}
162+
}
163+
}

FF4/MapType.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace FF4
8+
{
9+
public enum MapType
10+
{
11+
Overworld,
12+
Underworld,
13+
Moon,
14+
Area
15+
}
16+
}

0 commit comments

Comments
 (0)