Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente |
back2root:reverse-engineering:planet-x3:part2-savegame_dat [2023/01/12 09:16] – frater | back2root:reverse-engineering:planet-x3:part2-savegame_dat [2023/01/17 09:07] (Version actuelle) – frater |
---|
====== Format of "savegame.dat" ====== | ====== Planet X3 - Format of "savegame.dat" ====== |
| |
Ce fichier est un "dump mémoire" du jeu, il n'est pas compressé ni crypté; on y retrouve la meme structure que dans le code source. | Ce fichier est un "dump mémoire" du jeu, il n'est pas compressé ni crypté; on y retrouve la meme structure que dans le code source. |
| |
| Le fichier est composé de 3 "blocs" de données: |
| |
| * 1 [[#blockmap|block]] de 32 Kb (0x8000 bytes) avec la carte en cours |
| * 1 [[#blockunit|block]] de 2560 bytes (0x1010 bytes) contenant les unités/batiments des 2 factions |
| * 1 [[#blocktimer|block]] de 5 bytes (0x0005 bytes) contenant principalement les timers du jeu. |
| |
| une sauvegarde fait donc TOUJOURS 36885 bytes |
| |
| ===== Function de sauvegarde/chargement ===== |
| |
| Dans le code source, la sauvegarde se fait <color #ed1c24>**uniquement**</color> dans le fichier ''SAVEGAME.DAT''. |
| |
| <code asm> |
| Game_WriteSaveGame: |
| MOV AH,0x3c ; bug no mod selected : random ? |
| MOV CX,0x0 |
| MOV DX,fname_SaveGame_DAT ; = "SAVEGAME.DAT" |
| MOV AH,0x3c |
| INT 0x21 ; Create/truncate file |
| JC exitError ; exit function without handling |
| MOV [fhandler_SaveGame],AX ; preserve file handler |
| JMP continue |
| exitError: RET |
| </code> |
| On découvre ici que cette fonction ne gère **aucune** erreur, la sauvegarde est simplement abandonnée en cas d'erreur d'ouverture de fichier. |
| |
| L'usage du **JMP** pour sauter au dessus du **RET** d'erreur ressemble beaucoup à une structure de gestion d'erreurs (qui a été éliminée de la version finale) propre aux processeurs sans caches (8088, 8086, 6502, etc). |
| |
| Personnellement, je n'aurais pas rompu le flux avec un **JMP** j'aurais placé la gestion (ou non) des erreurs à la fin de la fonction, et réservé le saut (rupture de flux) aux erreurs, afin de ne pas forcer un "flush cache" sur des processeurs plus puissant (x386 et suivant). |
| |
| <code asm> |
| continue: MOV BX,word ptr [fhandler_SaveGame] ; fhandler |
| |
| ; save current game map |
| MOV DX,0x0 |
| MOV CX,0x8000 ; 0x8000 = 256*128 |
| MOV AH,0x40 |
| PUSH DS ; switch to map's Segment |
| MOV DS,word ptr [g_Seg_GameMap] |
| INT 0x21 ; write map (32kb) |
| POP DS ; restore DS |
| </code> |
| |
| la carte du jeu est sauvegardée "tel quel" sans aucune encryption ni compression. |
| |
| <code asm> |
| ; save unit/building records |
| MOV BX,word ptr [fhandler_SaveGame] |
| MOV DX,Game_UnitsArr_Type |
| MOV CX,0x1010 ; Write 256 units/buildings (10 attributes) |
| MOV AH,0x40 |
| INT 0x21 |
| </code> |
| |
| Pareil pour la structure des unités/batiments, sauvegardée "tel quel" sans aucune encryption ni compression. |
| |
| <code asm> |
| ; save Ingame timers |
| MOV BX,word ptr [fhandler_SaveGame] |
| MOV DX,Timer_InGame_Counter |
| MOV CX,0x5 ; 1 word (total seconds) + 3 bytes (Hours:minutes:seconds) |
| MOV AH,0x40 |
| INT 0x21 |
| </code> |
| |
| Avant de fermer le fichier, Planet X3 sauvegarde le compteur de temps générale (1 mot) et le temps "en jeu" 3 bytes |
| |
| <code asm> |
| MOV AH,0x3e ; close file |
| MOV BX,word ptr [fhandler_SaveGame] |
| INT 0x21 |
| RET |
| </code> |
| |
| ===== Block Map ===== |
| {{anchor:blockmap}} |
| {{tablelayout?rowsHeaderSource=Auto&colwidth=""}} |
| ^ Offset ^ Size ^ Description ^ |
| | 0x0000 | 0x8000 | Carte | |
| | 0x8000 | 0x1010 | Unités/batiments | |
| | 0x9010 | 0x0005 | timers | |
| |
| ==== Block d'unités/Batiments ===== |
| {{anchor:blockunit}} |
| {{tablelayout?rowsHeaderSource=Auto&colwidth="83px,,413px"}} |
| ^ Offset ^ Size ^ Description ^ |
| | +0x0000 | 0x0100 | Type d'Unités/batiments | |
| | +0x0100 | 0x0100 | Position X | |
| | +0x0200 | 0x0100 | Position Y | |
| | +0x0300 | 0x0100 | Target X | |
| | +0x0400 | 0x0100 | Target Y | |
| | +0x0500 | 0x0100 | OOT Type | |
| | +0x0600 | 0x0100 | Unknow | |
| | +0x0700 | 0x0100 | Points de Vie | |
| | +0x0800 | 0x0100 | Unknow | |
| | +0x0900 | 0x0100 | Generic Parameter A | |
| | +0x0A00 | 0x0100 | Generic Parameter B | |
| | +0x0B00 | 0x0100 | Generic Parameter C | |
| | +0x0C00 | 0x0100 | Generic Parameter D | |
| | +0x0D00 | 0x0100 | AL | |
| | +0x0E00 | 0x0100 | Unknow | |
| | +0x0F00 | 0x0100 | Etat du Silo Missile | |
| | +0x1000 | 0x0010 | Bloc de configuration | |
| |
| |
| Pour n'importe quel sous-block de 0x100 bytes est divisé en 2 sous sections, 1 pour les humains (offset 0x0000), 1 pour l'ordinateur (offset 0x0080). |
| |
| {{tablelayout?rowsHeaderSource=Auto&colwidth="153px"}} |
| ^ Offset ^ Taille ^ Description ^ |
| | +0x0000 | 0x14 | Unités mobiles Humaines | |
| | +0x0014 | 0x6C | Batiments Humains | |
| | +0x0080 | 0x14 | Unités mobiles Ordinateur | |
| | +0x0094 | 0x6C | Batiments Ordinateur | |
| |
| Suivant le code, le nombre maximum d'unités mobiles humaine diffère. |
| |
| * Dans 2 fonctions, PX3 vérifie le status (offset 0x0000) pour les indices de 0 à 20 (0x00-0x14) |
| * Dans 1 fonction, PX3 vérifie le status (offset 0x0000) pour les indices de 20 à 50 (0x14-0x32) |
| * Dans 5 fonctions, PX3 vérifie le status (offset 0x0000) pour les indices de 0 à 64 (0x00-0x40) |
| * Dans 2 fonctions, PX3 vérifie le status (offset 0x0000) pour les indices de 20 à 64 (0x14-0x40) |
| |
| <WRAP round help> |
| meme si le code présente bien des limites pour le joueur, je n'ai pas trouvé trace de limite similaire pour l'ordinateur (logiquement placée aux offset 0x80, 0x94, ...) |
| </WRAP> |
| |
| ==== Block de configuration ==== |
| |
| ^ offset ^ byte ^ Description ^ |
| | +0 | 1 | Décors de la carte ('1','2','3') | |
| | +1 | 1 | Unité sélectionnée | |
| | +2 | 1 | Réserve de minerais | |
| | +3 | 1 | Réserve de Gaz | |
| | +4 | 1 | Réserve d'électricité | |
| | +5 | 0xB | inconnu | |
| ===== Block "Timer" ===== |
| {{anchor:blocktimer}} |
| |
| ^ offset ^ byte ^ description ^ |
| | +0 | 2 | temps global en jeu (en ms) | |
| | +2 | 1 | Temps : Secondes | |
| | +3 | 1 | Temps : minutes | |
| | +4 | 1 | Temps : heures | |
| |
| ===== Information détaillée ===== |
| |
| {{tablelayout?rowsHeaderSource=Auto&colwidth=",,"}} |
| ^ Offset ^ Taille ^ Taille en Bytes ^ Joueur/\\ Ordinateur ^ Type ^ Description ^ |
| | 0000 | 8000 | 32768 | | | 256x128 tableau de case (carte de jeu) 0x0000 = coin haut-gauche | |
| | 8000 | 14 | 20 | Joueur | Unité | type | |
| | 8014 | 6C | 108 | Joueur | Batiment | type | |
| | 8080 | 80 | 128 | Ordinateur | mixte | type | |
| | 8100 | 14 | 20 | Joueur | Unité | position X | |
| | 8114 | 6C | 108 | Joueur | Batiment | position X | |
| | 8180 | 80 | 128 | Ordinateur | mixte | position X | |
| | 8200 | 14 | 20 | Joueur | Unité | position Y | |
| | 8214 | 6C | 108 | Joueur | Batiment | position Y | |
| | 8280 | 480 | 1152 | Ordinateur | mixte | position Y | |
| | 8700 | 14 | 20 | Joueur | Unité | Vie | |
| | 8714 | 6C | 108 | Joueur | Batiment | Vie | |
| | 8780 | 190 | 400 | Ordinateur | Batiment | Vie | |
| | 8910 | 6F0 | 1776 | Joueur | Missile | Silot Vide/Plein | |
| | 9000 | | | | | | |
| |
| ====== Type de Carte/Décors ====== |
| {{anchor:tileset}} |
| ^ Valeur ^ Description ^ |
| | 0x31 | Champs "green valey" | |
| | 0x32 | Monde de glace (ice) | |
| | 0x33 | désert | |
| |
| {{:back2root:reverse-engineering:planet-x3:pasted:20230112-162052.png}} {{:back2root:reverse-engineering:planet-x3:pasted:20230112-162101.png}} {{:back2root:reverse-engineering:planet-x3:pasted:20230112-162037.png}} |
| |
| |
| ====== Type d'Unité mobiles ====== |
| {{anchor:unit}} |
| {{tablelayout?rowsHeaderSource=Auto}} |
| ^ Valeur ^ Description ^ |
| | 0x01 | builder | |
| | 0x02 | tank | |
| | 0x03 | Heavy Tank | |
| | 0x04 | frigate | |
| | 0x1F | Missile ? | |
| |
| ====== Type de Batiments ====== |
| {{anchor:batiment}} |
| {{tablelayout?rowsHeaderSource=Auto&colwidth=""}} |
| ^ Valeur ^ Proriétaire ^ Description ^ |
| | 0x14 | Joueur | Headquarters | |
| | 0x15 | Joueur | Radar | |
| | 0x16 | Joueur | Power Station | |
| | 0x17 | Joueur | Solar Panel | |
| | 0x19 | Joueur | factory | |
| | 0x1A | Joueur | Missile Silo | |
| | 0x1B | Joueur | Smelter | |
| | | Joueur | Refenery | |
| | 0x21 | Ennemi | Headquarters (Pyramids) | |
| | | Ennemi | Academy | |
| | | Ennemi | Clone Facility | |
| | | Ennemi | Research Building | |
| | | Ennemi | Factory | |
| | | Ennemi | Sentry Pod | |
| |
| |
| ====== Tiles ====== |
| |
| {{:back2root:reverse-engineering:planet-x3:pasted:20230114-113015.png}} |