Swords of Glass people format

From ModdingWiki
Jump to navigation Jump to search
Swords of Glass people format
Format typeSaved game
Save locationsUnrestricted
Elements savedCharacter stats, items
Games

The character data in Swords of Glass is stored in the People.dat file. The file is fixed-width and stores 20 characters. Only those characters with an Unused flag set to false (0) are active.

Characters

Data type Description
UINT8 X position The X position of the character in the dungeon.
UINT8 Y position The Y position of the character in the dungeon.
UINT8 Z position The Z position (floor) of the character in the dungeon.
UINT8 Strength Character's strength.
UINT8 Dexterity Character's dexterity.
UINT8 IQ Character's IQ.
UINT8 Class 1 - Warrior, 2 - Magician.
1 Byte Unknown ?
UINT8 Level Character's level.
INT16LE Max HP Maximum hit points. Game caps at 255.
INT16LE HP Current hit points. Game caps at 255.
INT16LE Dead flag 0 - Alive, -1 - Dead. When a character dies, this flag is set to true (-1).
4 Bytes Unknown ?
INT16LE Unused flag 0 - Used, -1 - Unused. If this flag is true (-1), this character slot is unused.
Real Experience The character's experience.
Real Gold The character's gold.
1 Byte Unknown ?
12 Items See the Item structure.
UINT8[10] Max MP Maximum magic power for each level. Game caps at 99.
UINT8[10] MP Current magic power for each level. Game caps at 99.
UINT8[30] Spell flag 0 - No, 1 - Yes. Flags for which spells this character knows.
7 Bytes Unknown ?
UINT8 Name length Length of this character's name.
char[7] Name The character's name. Names are always 7 bytes, but you should only display the length of bytes read from the previous value.

Items

Each player has 12 item slots. If the item id is zero, the slot is empty. Both empty and occupied slots are 15 bytes.

Data type Description
UINT8 Item id The id of the item found in the CNames.dat file. If zero, this slot is empty.
UINT8 Bonus The bonus to the item (like Sword +1). The game never goes above +9, but it accepts over-buffed items.
INT16LE Quantity/Durability For items like arrows, this holds the quantity, but for non-stackable items like a sword or armor, this is the durability of the item. It will break at 0. The game never has quantities greater than 9, but accepts them.
UINT8 Name length The length of the item's name. Always 0x0A.
char[10] Name The name of the item. You can create custom names since the game uses id for everything.

Source Code

Exporter

This FreeBASIC program will export each player slot into a text file.

Declare Function RealToDouble(Real48() As UByte) As Double

Dim As Integer PlayerNo, ByteNo, ItemNo, SpellLevel, SpellNo
Dim As UByte PositionX, PositionY, PositionZ, Strength, Dexterity, IQ, ClassId, Unknown1, Level
Dim As UByte Unknown2, Unknown3, Unknown4, Unknown5, Unknown6, Unknown7, Experience(0 To 5)
Dim As UByte Gold(0 To 5), MaxMagicPower(0 To 9), MagicPower(0 To 9)
Dim As UByte SpellFlag(0 To 29), ItemId(0 To 11), Bonus(0 To 11), ItemNameLength(0 To 11), Unknown8
Dim As UByte Unknown9, Unknown10, Unknown11, Unknown12, Unknown13, PlayerNameLength
Dim As String ItemName(0 To 11), PlayerName
Dim As Short MaxHitPoints, CurrentHitPoints, Deceased, Unused, QuantityOrDurability(0 To 11)

Open "People.dat" For Binary As #1
Open "People.txt" For Binary As #2

For PlayerNo = 0 To 19
	Get #1, , PositionX
	Get #1, , PositionY
	Get #1, , PositionZ
	Get #1, , Strength
	Get #1, , Dexterity
	Get #1, , IQ
	Get #1, , ClassId
	Get #1, , Unknown1
	Get #1, , Level
	Get #1, , MaxHitPoints
	Get #1, , CurrentHitPoints
	Get #1, , Deceased
	Get #1, , Unknown2
	Get #1, , Unknown3
	Get #1, , Unknown4
	Get #1, , Unknown5
	Get #1, , Unused
	
	For ByteNo = 0 To 5
		Get #1, , Experience(ByteNo)
	Next ByteNo
	For ByteNo = 0 To 5
		Get #1, , Gold(ByteNo)
	Next ByteNo

	Get #1, , Unknown6
	
	For ItemNo = 0 To 11
		ItemName(ItemNo) = Space(10)
		Get #1, , ItemId(ItemNo)
		Get #1, , Bonus(ItemNo)
		Get #1, , QuantityOrDurability(ItemNo)
		Get #1, , ItemNameLength(ItemNo)
		Get #1, , ItemName(ItemNo)
	Next ItemNo
	
	For SpellLevel = 0 To 9
		Get #1, , MaxMagicPower(SpellLevel)
	Next SpellLevel
	For SpellLevel = 0 To 9
		Get #1, , MagicPower(SpellLevel)
	Next SpellLevel
	For SpellNo = 0 To 29
		Get #1, , SpellFlag(SpellNo)
	Next SpellNo

	Get #1, , Unknown7
	Get #1, , Unknown8
	Get #1, , Unknown9
	Get #1, , Unknown10
	Get #1, , Unknown11
	Get #1, , Unknown12
	Get #1, , Unknown13

	PlayerName = Space(7)
	Get #1, , PlayerNameLength
	Get #1, , PlayerName

	Put #2, , "Player Id: " + Str(PlayerNo) + Chr(13) + Chr(10)
	Put #2, , "Player Is Active?: " + IIf(Unused = True, "No", "Yes") + Chr(13) + Chr(10)
	If Unused = False Then
		Put #2, , "Player Is Alive?: " + IIf(Deceased = True, "No", "Yes") + Chr(13) + Chr(10)
		Put #2, , "Player Name: " + Left(PlayerName, PlayerNameLength) + Chr(13) + Chr(10)
		Put #2, , "Dungeon Coordinates: X(" + Str(PositionX) + "), Y(" + Str(PositionY) + "), Z(" + Str(PositionZ) + ")" + Chr(13) + Chr(10)

		Put #2, , Chr(13) + Chr(10)

		Put #2, , "Class: " + IIf(ClassId = 1, "Warrior", "Magician") + Chr(13) + Chr(10)
		Put #2, , "Level: " + Str(Level) + Chr(13) + Chr(10)
		Put #2, , "Experience: " + Str(RealToDouble(Experience())) + Chr(13) + Chr(10)
		Put #2, , "Stats: Str(" + Str(Strength) + "), Dex(" + Str(Dexterity) + "), IQ(" + Str(IQ) + ")" + Chr(13) + Chr(10)
		Put #2, , "Hit Points: " + Str(MaxHitPoints) + "/" + Str(CurrentHitPoints) + Chr(13) + Chr(10)
		Put #2, , "Gold: " + Str(RealToDouble(Gold())) + Chr(13) + Chr(10)
		
		Put #2, , Chr(13) + Chr(10)
		
		Put #2, , "Magic Power: "
		For SpellLevel = 0 To 9
			Put #2, , Str(MaxMagicPower(SpellLevel)) + "/" + Str(MagicPower(SpellLevel)) + ", "
		Next SpellLevel

		Put #2, , Chr(13) + Chr(10)

		Put #2, , "Spells: "
		For SpellNo = 0 To 29
			Put #2, , Str(SpellNo) + ":" + IIf(SpellFlag(SpellNo) = 1, "Y", "N") + ","
		Next SpellNo

		Put #2, , Chr(13) + Chr(10)
		
		Put #2, , "Items: " + Chr(13) + Chr(10)
		For ItemNo = 0 To 11
			If ItemId(ItemNo) > 0 Then
				Put #2, , "Id: " + Str(ItemId(ItemNo)) + " - " + Left(ItemName(ItemNo), ItemNameLength(ItemNo))
				Put #2, , IIf(Bonus(ItemNo) > 0, " +" + Str(Bonus(ItemNo)), "") + " - "
				Put #2, , "Qty/Durability: " + Str(QuantityOrDurability(ItemNo)) + Chr(13) + Chr(10)
			End If
		Next ItemNo

		Put #2, , Chr(13) + Chr(10)

		Put #2, , "Unknown Bytes: " + Str(Unknown1) + ", " + Str(Unknown2) + ", " + Str(Unknown3) + ", "
		Put #2, , Str(Unknown4) + ", " + Str(Unknown5) + ", " + Str(Unknown6) + ", " + Str(Unknown7) + ", "
		Put #2, , Str(Unknown8) + ", " + Str(Unknown9) + ", " + Str(Unknown10) + ", " + Str(Unknown11) + ", "
		Put #2, , Str(Unknown12) + ", " + Str(Unknown13)
	End If

	Put #2, , Chr(13) + Chr(10)
	Put #2, , Chr(13) + Chr(10)
	Put #2, , Chr(13) + Chr(10)
Next PlayerNo

' Convert a Pascal 48-bit Real into a standard Double.
Function RealToDouble(Real48() As UByte) As Double
    Dim Exponent As Double
    Exponent = Real48(0) - 129.0

    Dim Mantissa As Double
    Dim Value As Double
    
    Value = 1
    Dim ByteNo As Byte
    For ByteNo = 5 To 1 Step -1
        Dim StartBit As Byte
        StartBit = 7
        If ByteNo = 5 Then StartBit = 6
        
        Dim BitNo As Byte
        For BitNo = StartBit To 0 Step -1
            Value = Value / 2
            If ((Real48(ByteNo) ShR BitNo) And 1) = 1 Then
                Mantissa = Mantissa + Value
            End If
        Next BitNo
    Next ByteNo
    
    If Mantissa = 1.0 And Real48(0) = 0 Then
        Return 0.0
    End If
    
    If Real48(5) And &H80 = -1 Then
        Mantissa = -Mantissa
    End If

    Dim Result As Double
    Mantissa = Mantissa + 1
    Result = Mantissa * (2 ^ Exponent)
    
    Return (Result)
End Function

Credits

This save game format was reverse engineered by TheAlmightyGuru. If you find this information helpful in a project you're working on, please give credit where credit is due. (A link back to this wiki would be nice too!)