|
You last visited: Today at 08:25
Advertisement
PUL (Puzzle) files
Discussion on PUL (Puzzle) files within the CO2 Private Server forum part of the Conquer Online 2 category.
06/11/2012, 19:31
|
#1
|
elite*gold: 0
Join Date: May 2008
Posts: 1,769
Received Thanks: 1,142
|
PUL (Puzzle) files
Just wondering if anyone has any information on their structure. I wrote a basic DMap reader (took about 30 minutes, DMap/ani structure is quite simple.) and I'm trying to parse the PUL files to get the tiles for the map. It's not hard at all to get it to work if you get the offsets right, but some PUL files are half the size of the arena map (the map I worked with first) and the offsets are not absolute at all. Is there something I'm missing about calculating the offset of the tile amounts (x and y)? Of course the tile information is after them, so there's no need for those offsets to be exact.
Edit: And I know that I can calculate the number of tiles by using the tile size and coordinate width/height of the map (given a simple calculation to convert the size to isometric format), but that would still leave the offset for the tile data unknown. So I'd rather just read the data from the file the right way.
Here's an example:
As you can see, the highlighted byte (4) is the amount of tiles for the x axis, while the 4th byte to the right of it (3) is the amount of tiles for the y axis. So, 4x3 tiles, pretty simple. And the data follows immediately after that. The problem is the garbage before the tile amounts, it doesn't seem to be a consistent size, so skipping over it can be a pain. That's the only thing I need a nudge about.
Edit: Scratch that, it does seem to have some uniformity to it. Tile amount for the X axis has been at 263 for 4 maps now, and the amount for the y axis is at 267. They're both UInt16 (ushort).
|
|
|
06/11/2012, 20:43
|
#2
|
elite*gold: 0
Join Date: Jun 2005
Posts: 692
Received Thanks: 353
|
Taken from the EO client source:
Code:
var version = 0;
var header = reader.ReadCString(8);
if (header == "PUZZLE") version = 1;
else if (header == "PUZZLE2") version = 2;
if (version == 0)
return null;
var aniFile = reader.ReadCString(256);
var size = reader.ReadTqSize(); // two ints (Width and Height)
file.Size = size;
var amount = file.PuzzleAmount; // size.Width * size.Height
for (var i = 0; i < amount; i++)
{
file.PuzzleIndex[i] = reader.ReadInt16();
}
file.RollSpeedX = 0;
file.RollSpeedY = 0;
if (version == 2)
{
file.RollSpeedX = reader.ReadInt32();
file.RollSpeedY = reader.ReadInt32();
}
|
|
|
06/11/2012, 20:51
|
#3
|
elite*gold: 0
Join Date: May 2008
Posts: 1,769
Received Thanks: 1,142
|
Quote:
Originally Posted by nTL3fTy
Taken from the EO client source:
Code:
var version = 0;
var header = reader.ReadCString(8);
if (header == "PUZZLE") version = 1;
else if (header == "PUZZLE2") version = 2;
if (version == 0)
return null;
var aniFile = reader.ReadCString(256);
var size = reader.ReadTqSize(); // two ints (Width and Height)
file.Size = size;
var amount = file.PuzzleAmount; // size.Width * size.Height
for (var i = 0; i < amount; i++)
{
file.PuzzleIndex[i] = reader.ReadInt16();
}
file.RollSpeedX = 0;
file.RollSpeedY = 0;
if (version == 2)
{
file.RollSpeedX = reader.ReadInt32();
file.RollSpeedY = reader.ReadInt32();
}
|
Ah, perfect, I was off by a few bytes. Is there a public download of the EO source (unmodified) still around? I formatted my usb drive by accident.
Also, here's a screenshot of TC (newplain) at .025f scale.
|
|
|
06/11/2012, 21:19
|
#4
|
elite*gold: 0
Join Date: Jun 2005
Posts: 692
Received Thanks: 353
|
Quote:
Originally Posted by Zeroxelli
Ah, perfect, I was off by a few bytes. Is there a public download of the EO source (unmodified) still around? I formatted my usb drive by accident.
|
Quote:
Originally Posted by Zeroxelli
Also, here's a screenshot of TC (newplain) at .025f scale.
|
I notice there's no bridges.
|
|
|
06/11/2012, 22:32
|
#5
|
elite*gold: 21
Join Date: Jul 2005
Posts: 9,193
Received Thanks: 5,376
|
Yahh it's a very simple file as already shown. Now you just need a full dmap structure as well as displaying scene objects and then converting between screen and game space based on zoom/camera location and mouse offset.
Are you planning on turning this into a map editor? Mine is basically just missing scene objects right now as well as the FULL dmap structure (just access info right now).
|
|
|
06/12/2012, 01:09
|
#6
|
elite*gold: 20
Join Date: Jun 2005
Posts: 1,013
Received Thanks: 381
|
Full dmap structure for anyone who wants it.
Code:
internal enum MapObjectType
{
Scene = 0x01,
TerrainObject = 0x04,
Backdrop = 0x08,
Effect = 0x0A,
Sound = 0x0F
}
public static MapData Load(Stream file)
{
MapData dmap = new MapData() {
TerrainObjects = new List<MapTerrainObject>(),
Scenes = new List<MapScene>(),
Sounds = new List<MapSound>(),
Effects = new List<Map3DEffect>()
};
using (BinaryReader br = new BinaryReader(file))
{
string dmapheader = br.ReadASCIIString(8);
dmap.PuzzlePath = br.ReadASCIIString(260);
dmap.Bounds = br.ReadSize();
dmap.Cells = new MapCellCollection(dmap.Bounds) { CollectionSize = dmap.Bounds };
for (int j = 0 ; j < dmap.Bounds.Height ; j++) {
for (int i = 0 ; i < dmap.Bounds.Width ; i++) {
dmap.Cells[i, j] = new MapCell() {
Access = br.ReadInt16(),
Surface = br.ReadInt16(),
Height = br.ReadInt16()
};
}
dmap.Cells.OffsetArray.Add(br.ReadInt32());
}
Int32 portalcount = br.ReadInt32();
dmap.Portals = new List<MapPortal>();
for (int i = 0 ; i < portalcount ; i++) {
dmap.Portals.Add(new MapPortal() {
Location = br.ReadPoint(),
PortalType = br.ReadInt32()
});
}
Int32 objCount = br.ReadInt32();
for (int i = 0 ; i < objCount ; i++) {
MapObjectType type;
try {
type = (MapObjectType)br.ReadInt32();
}
catch (EndOfStreamException ex) {
throw ex;
}
switch (type) {
case MapObjectType.Scene:
dmap.Scenes.Add(new MapScene() {
ScenePath = br.ReadASCIIString(260),
Location = br.ReadPoint()
});
break;
case MapObjectType.TerrainObject:
dmap.TerrainObjects.Add(new MapTerrainObject() {
AniPath = br.ReadASCIIString(260),
AniName = br.ReadASCIIString(128),
Location = br.ReadPoint(),
Size = br.ReadSize(),
ImageOffset = br.ReadPoint(),
Interval = br.ReadInt32()
});
break;
case MapObjectType.Effect:
dmap.Effects.Add(new Map3DEffect() {
Effect = br.ReadASCIIString(64),
Location = br.ReadPoint()
});
break;
case MapObjectType.Sound:
dmap.Sounds.Add(new MapSound() {
SoundPath = br.ReadASCIIString(260),
Location = br.ReadPoint(),
Volume = br.ReadInt32(),
Range = br.ReadInt32()
});
break;
default:
throw new UnknownMapDataException();
}
}
Int32 nLayers = br.ReadInt32();
dmap.Layers = new List<MapLayer>(nLayers);
for (int i = 0 ; i < nLayers ; i++) {
MapLayer layer = new MapLayer() {
Backdrops = new List<MapBackdrop>(),
TerrainObjects = new List<MapTerrainObject>(),
index = br.ReadInt32(),
layertype = br.ReadInt32(),
xInt = br.ReadInt32(),
yInt = br.ReadInt32()
};
Int32 nItems = br.ReadInt32();
for (int j = 0 ; j < nItems ; j++) {
MapObjectType nType = (MapObjectType)br.ReadInt32();
switch (nType)
{
case MapObjectType.Backdrop:
layer.Backdrops.Add(new MapBackdrop() {
PuzzlePath = br.ReadASCIIString(260)
});
break;
case MapObjectType.TerrainObject:
layer.TerrainObjects.Add(new MapTerrainObject() {
AniPath = br.ReadASCIIString(260),
AniName = br.ReadASCIIString(128),
Location = br.ReadPoint(),
Size = br.ReadSize(),
ImageOffset = br.ReadPoint(),
Interval = br.ReadInt32()
});
break;
default:
throw new UnknownMapDataException();
}
}
dmap.Layers.Add(layer);
}
}
return dmap;
}
|
|
|
06/12/2012, 01:26
|
#7
|
elite*gold: 0
Join Date: May 2008
Posts: 1,769
Received Thanks: 1,142
|
Quote:
Originally Posted by nTL3fTy
I notice there's no bridges.
|
Yep, haven't even touched scene files yet. And thanks for the link to the EO source, I missed having it as a reference.
Quote:
Originally Posted by pro4never
Yahh it's a very simple file as already shown. Now you just need a full dmap structure as well as displaying scene objects and then converting between screen and game space based on zoom/camera location and mouse offset.
Are you planning on turning this into a map editor? Mine is basically just missing scene objects right now as well as the FULL dmap structure (just access info right now).
|
Hmm, possibly. I just did it to get the coordinates of certain spots in maps in real-time, but being able to make/edit maps would definitely be a plus...
Quote:
Originally Posted by unknownone
Full dmap structure for anyone who wants it.
Code:
internal enum MapObjectType
{
Scene = 0x01,
TerrainObject = 0x04,
Backdrop = 0x08,
Effect = 0x0A,
Sound = 0x0F
}
public static MapData Load(Stream file)
{
MapData dmap = new MapData() {
TerrainObjects = new List<MapTerrainObject>(),
Scenes = new List<MapScene>(),
Sounds = new List<MapSound>(),
Effects = new List<Map3DEffect>()
};
using (BinaryReader br = new BinaryReader(file))
{
string dmapheader = br.ReadASCIIString(8);
dmap.PuzzlePath = br.ReadASCIIString(260);
dmap.Bounds = br.ReadSize();
dmap.Cells = new MapCellCollection(dmap.Bounds) { CollectionSize = dmap.Bounds };
for (int j = 0 ; j < dmap.Bounds.Height ; j++) {
for (int i = 0 ; i < dmap.Bounds.Width ; i++) {
dmap.Cells[i, j] = new MapCell() {
Access = br.ReadInt16(),
Surface = br.ReadInt16(),
Height = br.ReadInt16()
};
}
dmap.Cells.OffsetArray.Add(br.ReadInt32());
}
Int32 portalcount = br.ReadInt32();
dmap.Portals = new List<MapPortal>();
for (int i = 0 ; i < portalcount ; i++) {
dmap.Portals.Add(new MapPortal() {
Location = br.ReadPoint(),
PortalType = br.ReadInt32()
});
}
Int32 objCount = br.ReadInt32();
for (int i = 0 ; i < objCount ; i++) {
MapObjectType type;
try {
type = (MapObjectType)br.ReadInt32();
}
catch (EndOfStreamException ex) {
throw ex;
}
switch (type) {
case MapObjectType.Scene:
dmap.Scenes.Add(new MapScene() {
ScenePath = br.ReadASCIIString(260),
Location = br.ReadPoint()
});
break;
case MapObjectType.TerrainObject:
dmap.TerrainObjects.Add(new MapTerrainObject() {
AniPath = br.ReadASCIIString(260),
AniName = br.ReadASCIIString(128),
Location = br.ReadPoint(),
Size = br.ReadSize(),
ImageOffset = br.ReadPoint(),
Interval = br.ReadInt32()
});
break;
case MapObjectType.Effect:
dmap.Effects.Add(new Map3DEffect() {
Effect = br.ReadASCIIString(64),
Location = br.ReadPoint()
});
break;
case MapObjectType.Sound:
dmap.Sounds.Add(new MapSound() {
SoundPath = br.ReadASCIIString(260),
Location = br.ReadPoint(),
Volume = br.ReadInt32(),
Range = br.ReadInt32()
});
break;
default:
throw new UnknownMapDataException();
}
}
Int32 nLayers = br.ReadInt32();
dmap.Layers = new List<MapLayer>(nLayers);
for (int i = 0 ; i < nLayers ; i++) {
MapLayer layer = new MapLayer() {
Backdrops = new List<MapBackdrop>(),
TerrainObjects = new List<MapTerrainObject>(),
index = br.ReadInt32(),
layertype = br.ReadInt32(),
xInt = br.ReadInt32(),
yInt = br.ReadInt32()
};
Int32 nItems = br.ReadInt32();
for (int j = 0 ; j < nItems ; j++) {
MapObjectType nType = (MapObjectType)br.ReadInt32();
switch (nType)
{
case MapObjectType.Backdrop:
layer.Backdrops.Add(new MapBackdrop() {
PuzzlePath = br.ReadASCIIString(260)
});
break;
case MapObjectType.TerrainObject:
layer.TerrainObjects.Add(new MapTerrainObject() {
AniPath = br.ReadASCIIString(260),
AniName = br.ReadASCIIString(128),
Location = br.ReadPoint(),
Size = br.ReadSize(),
ImageOffset = br.ReadPoint(),
Interval = br.ReadInt32()
});
break;
default:
throw new UnknownMapDataException();
}
}
dmap.Layers.Add(layer);
}
}
return dmap;
}
|
Ahh thank you, references are always great to have.
|
|
|
06/12/2012, 10:15
|
#8
|
elite*gold: 20
Join Date: Mar 2006
Posts: 6,125
Received Thanks: 2,518
|
Just a few corrections on Sparkie's code for the structure.
The value that Sparkie stores is actually a checksum for that row.
Code:
for (int j = 0 ; j < dmap.Bounds.Height ; j++) {
for (int i = 0 ; i < dmap.Bounds.Width ; i++) {
dmap.Cells[i, j] = new MapCell() {
Access = br.ReadInt16(),
Surface = br.ReadInt16(),
Height = br.ReadInt16()
};
}
[B]dmap.Cells.OffsetArray.Add(br.ReadInt32());[/B]
}
So here is TQ's checksum calculation in C++.
Code:
for (int j = 0 ; j < dmap.Bounds.Height ; j++) {
for (int i = 0 ; i < dmap.Bounds.Width ; i++) {
dmap.Cells[i, j] = new MapCell() {
Access = br.ReadInt16(),
Surface = br.ReadInt16(),
Height = br.ReadInt16()
};
[B]//dwCheckData += pLayerInfo->usMask * (pLayerInfo->usTerrain+j+1) + (pLayerInfo->sAltitude+2)*(i+1+pLayerInfo->usTerrain);
}
int ActualCheckSum = br.ReadInt32();
if (RowCheckSum != ActualCheckSum)
return;[/B]
}
The value labelled PortalType, is actually the PortalsID within that map.
Code:
Int32 portalcount = br.ReadInt32();
dmap.Portals = new List<MapPortal>();
for (int i = 0 ; i < portalcount ; i++) {
dmap.Portals.Add(new MapPortal() {
Location = br.ReadPoint(),
[B]PortalType = br.ReadInt32()[/B]
});
}
This change is necessary if you want to actually use the correct method for linking up portals, so if your using an official database for example, otherwise its possible you will become confused about what values mean what with relation to the database.
Code:
Int32 portalcount = br.ReadInt32();
dmap.Portals = new List<MapPortal>();
for (int i = 0 ; i < portalcount ; i++) {
dmap.Portals.Add(new MapPortal() {
Location = br.ReadPoint(),
[B]PortalID = br.ReadInt32()[/B]
});
}
|
|
|
06/12/2012, 21:32
|
#9
|
elite*gold: 0
Join Date: May 2008
Posts: 1,769
Received Thanks: 1,142
|
Quote:
Originally Posted by Korvacs
Just a few corrections on Sparkie's code for the structure.
The value that Sparkie stores is actually a checksum for that row.
Code:
for (int j = 0 ; j < dmap.Bounds.Height ; j++) {
for (int i = 0 ; i < dmap.Bounds.Width ; i++) {
dmap.Cells[i, j] = new MapCell() {
Access = br.ReadInt16(),
Surface = br.ReadInt16(),
Height = br.ReadInt16()
};
}
[B]dmap.Cells.OffsetArray.Add(br.ReadInt32());[/B]
}
So here is TQ's checksum calculation in C++.
Code:
for (int j = 0 ; j < dmap.Bounds.Height ; j++) {
for (int i = 0 ; i < dmap.Bounds.Width ; i++) {
dmap.Cells[i, j] = new MapCell() {
Access = br.ReadInt16(),
Surface = br.ReadInt16(),
Height = br.ReadInt16()
};
[B]//dwCheckData += pLayerInfo->usMask * (pLayerInfo->usTerrain+j+1) + (pLayerInfo->sAltitude+2)*(i+1+pLayerInfo->usTerrain);
}
int ActualCheckSum = br.ReadInt32();
if (RowCheckSum != ActualCheckSum)
return;[/B]
}
The value labelled PortalType, is actually the PortalsID within that map.
Code:
Int32 portalcount = br.ReadInt32();
dmap.Portals = new List<MapPortal>();
for (int i = 0 ; i < portalcount ; i++) {
dmap.Portals.Add(new MapPortal() {
Location = br.ReadPoint(),
[B]PortalType = br.ReadInt32()[/B]
});
}
This change is necessary if you want to actually use the correct method for linking up portals, so if your using an official database for example, otherwise its possible you will become confused about what values mean what with relation to the database.
Code:
Int32 portalcount = br.ReadInt32();
dmap.Portals = new List<MapPortal>();
for (int i = 0 ; i < portalcount ; i++) {
dmap.Portals.Add(new MapPortal() {
Location = br.ReadPoint(),
[B]PortalID = br.ReadInt32()[/B]
});
}
|
Thanks I kinda figured it had something to do with verification, didn't expect a checksum though.
|
|
|
06/12/2012, 23:46
|
#10
|
elite*gold: 0
Join Date: Jan 2008
Posts: 1,434
Received Thanks: 1,147
|
There is also an implementation in my CO2_CORE_DLL which is entirely based on the one in the EO server source. But with Sparkie's implementation and Korvacs rectification, it's pretty much the full format.
|
|
|
06/13/2012, 03:02
|
#11
|
elite*gold: 0
Join Date: May 2008
Posts: 1,769
Received Thanks: 1,142
|
Quote:
Originally Posted by CptSky
There is also an implementation in my CO2_CORE_DLL which is entirely based on the one in the EO server source. But with Sparkie's implementation and Korvacs rectification, it's pretty much the full format.
|
Yeah, I've been considering using your DLL for some of my projects lately, as it does look to be quite useful.
|
|
|
|
Similar Threads
|
[MAP][PUZZLE] Brainbuster I v1.0 (neue Action / Puzzle Map)
09/09/2011 - Minecraft - 2 Replies
Brainbuster I v1.0
Hey Leute,
Achtung: Die Map ist auf Englisch, wir arbeiten allerdings momentan an einer deutschen Version.
hier mein erster Thread und erste Map, die von mir, Telithanor, und einem Kollegen, FW_Bluti, erstellt wurde. Ich wusste nicht recht, wo ich den Thread posten sollte; falls das hier falsch ist, bitte ich den Thread zu verschieben, danke ;) .
Orginial-Thread(Englisch): click
|
Puzzle Piraten
01/25/2011 - General Gaming Discussion - 16 Replies
Bin Neu hier auf dem Board also erstmal hi an alle!
ich Suche Cheats Für das Online game Puzzle Piraten!
gibts da was?
Grüße
super123
|
Getting valid coordinates on dmaps using scene and puzzle files?
01/16/2011 - CO2 Private Server - 0 Replies
So I've successfully gotten the dmap file to fit a specific format, although the number of invalid coordinates is too great. Apparently I need to add in the object accessibility. Any information at all on objects and their structures would be appreciated.
|
Puzzle Pirates
03/03/2009 - General Gaming Discussion - 3 Replies
Is there a hack for puzzle pirates?
www.puzzlepirates.com
(like a dubloons hack or moneyhack?)
|
All times are GMT +2. The time now is 08:25.
|
|