2012-06-05 14:08:35 -05:00
//
// GameSave.cpp
// The Powder Toy
//
// Created by Simon Robertshaw on 04/06/2012.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
# include <iostream>
2012-07-27 14:06:17 -05:00
# include <sstream>
2012-08-13 09:43:57 -05:00
# include <cmath>
2012-08-19 14:44:50 -05:00
# include <vector>
2012-06-05 14:08:35 -05:00
# include <bzlib.h>
# include "Config.h"
# include "bson/BSON.h"
# include "GameSave.h"
2012-06-07 08:23:26 -05:00
# include "simulation/SimulationData.h"
2012-08-13 09:43:57 -05:00
# include "ElementClasses.h"
2012-07-25 11:12:15 -05:00
extern " C "
{
# include "hmap.h"
}
2012-06-05 14:08:35 -05:00
GameSave : : GameSave ( GameSave & save ) :
waterEEnabled ( save . waterEEnabled ) ,
legacyEnable ( save . legacyEnable ) ,
gravityEnable ( save . gravityEnable ) ,
paused ( save . paused ) ,
gravityMode ( save . gravityMode ) ,
airMode ( save . airMode ) ,
2012-07-27 20:23:21 -05:00
signs ( save . signs ) ,
expanded ( save . expanded ) ,
hasOriginalData ( save . hasOriginalData ) ,
originalData ( save . originalData )
2012-06-05 14:08:35 -05:00
{
2012-07-20 11:43:08 -05:00
blockMap = NULL ;
blockMapPtr = NULL ;
fanVelX = NULL ;
fanVelXPtr = NULL ;
fanVelY = NULL ;
fanVelYPtr = NULL ;
particles = NULL ;
2012-07-27 20:23:21 -05:00
if ( save . expanded )
{
setSize ( save . blockWidth , save . blockHeight ) ;
2012-06-18 09:54:55 -05:00
2012-08-12 16:32:57 -05:00
std : : copy ( save . particles , save . particles + NPART , particles ) ;
std : : copy ( save . blockMapPtr , save . blockMapPtr + ( blockHeight * blockWidth ) , blockMapPtr ) ;
std : : copy ( save . fanVelXPtr , save . fanVelXPtr + ( blockHeight * blockWidth ) , fanVelXPtr ) ;
std : : copy ( save . fanVelYPtr , save . fanVelYPtr + ( blockHeight * blockWidth ) , fanVelYPtr ) ;
2012-07-27 20:23:21 -05:00
}
else
{
blockWidth = save . blockWidth ;
blockHeight = save . blockHeight ;
}
2012-06-07 08:23:26 -05:00
particlesCount = save . particlesCount ;
2012-06-05 14:08:35 -05:00
}
GameSave : : GameSave ( int width , int height )
{
2012-07-20 11:43:08 -05:00
blockMap = NULL ;
blockMapPtr = NULL ;
fanVelX = NULL ;
fanVelXPtr = NULL ;
fanVelY = NULL ;
fanVelYPtr = NULL ;
particles = NULL ;
2012-07-27 20:23:21 -05:00
hasOriginalData = false ;
expanded = true ;
2012-06-05 14:08:35 -05:00
setSize ( width , height ) ;
}
2012-07-27 14:06:17 -05:00
GameSave : : GameSave ( std : : vector < char > data )
{
blockWidth = 0 ;
blockHeight = 0 ;
blockMap = NULL ;
blockMapPtr = NULL ;
fanVelX = NULL ;
fanVelXPtr = NULL ;
fanVelY = NULL ;
fanVelYPtr = NULL ;
particles = NULL ;
2012-07-27 20:23:21 -05:00
expanded = false ;
hasOriginalData = true ;
originalData = data ;
2012-07-28 12:38:34 -05:00
# ifdef DEBUG
std : : cout < < " Creating Collapsed save from data " < < std : : endl ;
# endif
2012-07-27 20:23:21 -05:00
try
{
Expand ( ) ;
}
catch ( ParseException & e )
{
2012-07-27 14:06:17 -05:00
std : : cout < < e . what ( ) < < std : : endl ;
2012-08-19 14:44:50 -05:00
dealloc ( ) ; //Free any allocated memory
2012-07-27 14:06:17 -05:00
throw ;
}
2012-07-27 20:23:21 -05:00
Collapse ( ) ;
2012-07-27 14:06:17 -05:00
}
GameSave : : GameSave ( std : : vector < unsigned char > data )
{
blockWidth = 0 ;
blockHeight = 0 ;
blockMap = NULL ;
blockMapPtr = NULL ;
fanVelX = NULL ;
fanVelXPtr = NULL ;
fanVelY = NULL ;
fanVelYPtr = NULL ;
particles = NULL ;
2012-07-27 20:23:21 -05:00
expanded = false ;
hasOriginalData = true ;
originalData = std : : vector < char > ( data . begin ( ) , data . end ( ) ) ;
2012-07-28 12:38:34 -05:00
# ifdef DEBUG
std : : cout < < " Creating Collapsed save from data " < < std : : endl ;
# endif
2012-07-27 20:23:21 -05:00
try
{
Expand ( ) ;
}
catch ( ParseException & e )
{
2012-07-27 14:06:17 -05:00
std : : cout < < e . what ( ) < < std : : endl ;
2012-08-19 14:44:50 -05:00
dealloc ( ) ; //Free any allocated memory
2012-07-27 14:06:17 -05:00
throw ;
}
2012-07-27 20:23:21 -05:00
Collapse ( ) ;
2012-07-27 14:06:17 -05:00
}
2012-06-05 14:08:35 -05:00
GameSave : : GameSave ( char * data , int dataSize )
{
2012-07-20 11:43:08 -05:00
blockWidth = 0 ;
blockHeight = 0 ;
blockMap = NULL ;
blockMapPtr = NULL ;
fanVelX = NULL ;
fanVelXPtr = NULL ;
fanVelY = NULL ;
fanVelYPtr = NULL ;
particles = NULL ;
2012-07-28 12:38:34 -05:00
expanded = false ;
2012-07-27 20:23:21 -05:00
hasOriginalData = true ;
originalData = std : : vector < char > ( data , data + dataSize ) ;
2012-07-28 12:38:34 -05:00
# ifdef DEBUG
std : : cout < < " Creating Expanded save from data " < < std : : endl ;
# endif
2012-07-27 20:23:21 -05:00
try
{
Expand ( ) ;
}
catch ( ParseException & e )
{
2012-07-27 14:06:17 -05:00
std : : cout < < e . what ( ) < < std : : endl ;
2012-08-19 14:44:50 -05:00
dealloc ( ) ; //Free any allocated memory
2012-07-27 14:06:17 -05:00
throw ;
}
2012-07-27 20:23:21 -05:00
//Collapse();
}
bool GameSave : : Collapsed ( )
{
return ! expanded ;
}
void GameSave : : Expand ( )
{
if ( hasOriginalData & & ! expanded )
{
expanded = true ;
read ( & originalData [ 0 ] , originalData . size ( ) ) ;
}
}
void GameSave : : Collapse ( )
{
if ( expanded & & hasOriginalData )
{
expanded = false ;
if ( particles )
{
delete [ ] particles ;
particles = NULL ;
}
if ( blockMap )
{
delete [ ] blockMap ;
blockMap = NULL ;
}
if ( blockMapPtr )
{
delete [ ] blockMapPtr ;
blockMapPtr = NULL ;
}
if ( fanVelX )
{
delete [ ] fanVelX ;
fanVelX = NULL ;
}
if ( fanVelXPtr )
{
delete [ ] fanVelXPtr ;
fanVelXPtr = NULL ;
}
if ( fanVelY )
{
delete [ ] fanVelY ;
fanVelY = NULL ;
}
if ( fanVelYPtr )
{
delete [ ] fanVelYPtr ;
fanVelYPtr = NULL ;
}
}
2012-07-27 14:06:17 -05:00
}
void GameSave : : read ( char * data , int dataSize )
{
if ( dataSize > 0 )
{
if ( data [ 0 ] = = 0x50 | | data [ 0 ] = = 0x66 )
2012-06-08 16:04:14 -05:00
{
2012-07-28 12:38:34 -05:00
# ifdef DEBUG
std : : cout < < " Reading PSv... " < < std : : endl ;
# endif
2012-07-27 14:06:17 -05:00
readPSv ( data , dataSize ) ;
}
else if ( data [ 0 ] = = ' O ' )
{
2012-07-28 12:38:34 -05:00
# ifdef DEBUG
std : : cout < < " Reading OPS... " < < std : : endl ;
# endif
2012-07-27 14:06:17 -05:00
readOPS ( data , dataSize ) ;
2012-06-08 16:04:14 -05:00
}
else
{
2012-07-27 14:06:17 -05:00
std : : cerr < < " Got Magic number ' " < < data [ 0 ] < < " ' " < < std : : endl ;
throw ParseException ( ParseException : : Corrupt , " Invalid save format " ) ;
2012-06-08 16:04:14 -05:00
}
2012-07-27 14:06:17 -05:00
}
else
{
throw ParseException ( ParseException : : Corrupt , " No data " ) ;
2012-06-05 19:46:13 -05:00
}
2012-06-05 14:08:35 -05:00
}
void GameSave : : setSize ( int newWidth , int newHeight )
{
2012-06-08 16:04:14 -05:00
this - > blockWidth = newWidth ;
this - > blockHeight = newHeight ;
2012-06-05 14:08:35 -05:00
2012-06-07 08:23:26 -05:00
particlesCount = 0 ;
2012-06-05 14:08:35 -05:00
particles = new Particle [ NPART ] ;
2012-06-09 14:16:47 -05:00
2012-06-08 16:04:14 -05:00
blockMapPtr = new unsigned char [ blockHeight * blockWidth ] ;
2012-08-12 16:32:57 -05:00
std : : fill ( blockMapPtr , blockMapPtr + ( blockHeight * blockWidth ) , 0 ) ;
2012-06-08 16:04:14 -05:00
fanVelXPtr = new float [ ( blockHeight ) * ( blockWidth ) ] ;
2012-08-12 16:32:57 -05:00
std : : fill ( fanVelXPtr , fanVelXPtr + ( ( blockHeight ) * ( blockWidth ) ) , 0 ) ;
2012-06-09 14:16:47 -05:00
fanVelYPtr = new float [ ( blockHeight ) * ( blockWidth ) ] ;
2012-08-12 16:32:57 -05:00
std : : fill ( fanVelYPtr , fanVelYPtr + ( ( blockHeight ) * ( blockWidth ) ) , 0 ) ;
2012-06-09 14:16:47 -05:00
blockMap = new unsigned char * [ blockHeight ] ;
for ( int y = 0 ; y < blockHeight ; y + + )
blockMap [ y ] = & blockMapPtr [ y * blockWidth ] ;
2012-06-08 16:04:14 -05:00
fanVelX = new float * [ blockHeight ] ;
for ( int y = 0 ; y < blockHeight ; y + + )
fanVelX [ y ] = & fanVelXPtr [ y * ( blockWidth ) ] ;
fanVelY = new float * [ blockHeight ] ;
for ( int y = 0 ; y < blockHeight ; y + + )
fanVelY [ y ] = & fanVelYPtr [ y * blockWidth ] ;
2012-06-05 14:08:35 -05:00
}
2012-08-01 16:29:22 -05:00
std : : vector < char > GameSave : : Serialise ( )
{
int dataSize ;
char * data = Serialise ( dataSize ) ;
std : : vector < char > dataVect ( data , data + dataSize ) ;
delete data ;
return dataVect ;
}
2012-06-05 14:08:35 -05:00
char * GameSave : : Serialise ( int & dataSize )
{
return serialiseOPS ( dataSize ) ;
}
void GameSave : : Transform ( matrix2d transform , vector2d translate )
{
2012-06-09 14:16:47 -05:00
int i , x , y , nx , ny , width = blockWidth * CELL , height = blockHeight * CELL , newWidth , newHeight , newBlockWidth , newBlockHeight ;
2012-06-09 13:42:07 -05:00
vector2d pos , tmp , ctl , cbr , vel ;
vector2d cornerso [ 4 ] ;
// undo any translation caused by rotation
cornerso [ 0 ] = v2d_new ( 0 , 0 ) ;
2012-06-09 14:16:47 -05:00
cornerso [ 1 ] = v2d_new ( width - 1 , 0 ) ;
cornerso [ 2 ] = v2d_new ( 0 , height - 1 ) ;
cornerso [ 3 ] = v2d_new ( width - 1 , height - 1 ) ;
2012-06-09 13:42:07 -05:00
for ( i = 0 ; i < 4 ; i + + )
{
tmp = m2d_multiply_v2d ( transform , cornerso [ i ] ) ;
if ( i = = 0 ) ctl = cbr = tmp ; // top left, bottom right corner
if ( tmp . x < ctl . x ) ctl . x = tmp . x ;
if ( tmp . y < ctl . y ) ctl . y = tmp . y ;
if ( tmp . x > cbr . x ) cbr . x = tmp . x ;
if ( tmp . y > cbr . y ) cbr . y = tmp . y ;
}
// casting as int doesn't quite do what we want with negative numbers, so use floor()
tmp = v2d_new ( floor ( ctl . x + 0.5f ) , floor ( ctl . y + 0.5f ) ) ;
translate = v2d_sub ( translate , tmp ) ;
2012-06-09 14:16:47 -05:00
newWidth = floor ( cbr . x + 0.5f ) - floor ( ctl . x + 0.5f ) + 1 ;
newHeight = floor ( cbr . y + 0.5f ) - floor ( ctl . y + 0.5f ) + 1 ;
if ( newWidth > XRES ) newWidth = XRES ;
if ( newHeight > YRES ) newHeight = YRES ;
newBlockWidth = newWidth / CELL ;
newBlockHeight = newHeight / CELL ;
unsigned char * * blockMapNew ;
float * * fanVelXNew ;
float * * fanVelYNew ;
float * fanVelXPtrNew ;
float * fanVelYPtrNew ;
unsigned char * blockMapPtrNew ;
blockMapPtrNew = new unsigned char [ newBlockHeight * newBlockWidth ] ;
2012-08-12 16:32:57 -05:00
std : : fill ( blockMapPtrNew , blockMapPtrNew + ( newBlockHeight * newBlockWidth ) , 0 ) ;
2012-06-09 14:16:47 -05:00
fanVelXPtrNew = new float [ newBlockHeight * newBlockWidth ] ;
2012-08-12 16:32:57 -05:00
std : : fill ( fanVelXPtrNew , fanVelXPtrNew + ( newBlockHeight * newBlockWidth ) , 0 ) ;
2012-06-09 14:16:47 -05:00
fanVelYPtrNew = new float [ ( newBlockHeight ) * ( newBlockWidth ) ] ;
2012-08-12 16:32:57 -05:00
std : : fill ( fanVelYPtrNew , fanVelYPtrNew + ( newBlockHeight * newBlockWidth ) , 0 ) ;
2012-06-09 14:16:47 -05:00
blockMapNew = new unsigned char * [ newBlockHeight ] ;
for ( int y = 0 ; y < newBlockHeight ; y + + )
blockMapNew [ y ] = & blockMapPtrNew [ y * newBlockWidth ] ;
fanVelXNew = new float * [ newBlockHeight ] ;
for ( int y = 0 ; y < newBlockHeight ; y + + )
fanVelXNew [ y ] = & fanVelXPtrNew [ y * newBlockWidth ] ;
fanVelYNew = new float * [ newBlockHeight ] ;
for ( int y = 0 ; y < newBlockHeight ; y + + )
fanVelYNew [ y ] = & fanVelYPtrNew [ y * newBlockWidth ] ;
2012-06-09 13:42:07 -05:00
// rotate and translate signs, parts, walls
for ( i = 0 ; i < signs . size ( ) ; i + + )
{
pos = v2d_new ( signs [ i ] . x , signs [ i ] . y ) ;
pos = v2d_add ( m2d_multiply_v2d ( transform , pos ) , translate ) ;
nx = floor ( pos . x + 0.5f ) ;
ny = floor ( pos . y + 0.5f ) ;
2012-06-09 14:16:47 -05:00
if ( nx < 0 | | nx > = newWidth | | ny < 0 | | ny > = newHeight )
2012-06-09 13:42:07 -05:00
{
signs [ i ] . text [ 0 ] = 0 ;
continue ;
}
signs [ i ] . x = nx ;
signs [ i ] . y = ny ;
}
for ( i = 0 ; i < NPART ; i + + )
{
if ( ! particles [ i ] . type ) continue ;
pos = v2d_new ( particles [ i ] . x , particles [ i ] . y ) ;
pos = v2d_add ( m2d_multiply_v2d ( transform , pos ) , translate ) ;
nx = floor ( pos . x + 0.5f ) ;
ny = floor ( pos . y + 0.5f ) ;
2012-06-09 14:16:47 -05:00
if ( nx < 0 | | nx > = newWidth | | ny < 0 | | ny > = newHeight )
2012-06-09 13:42:07 -05:00
{
particles [ i ] . type = PT_NONE ;
continue ;
}
particles [ i ] . x = nx ;
particles [ i ] . y = ny ;
vel = v2d_new ( particles [ i ] . vx , particles [ i ] . vy ) ;
vel = m2d_multiply_v2d ( transform , vel ) ;
particles [ i ] . vx = vel . x ;
particles [ i ] . vy = vel . y ;
}
2012-06-09 14:16:47 -05:00
for ( y = 0 ; y < blockWidth ; y + + )
for ( x = 0 ; x < blockHeight ; x + + )
2012-06-09 13:42:07 -05:00
{
pos = v2d_new ( x * CELL + CELL * 0.4f , y * CELL + CELL * 0.4f ) ;
pos = v2d_add ( m2d_multiply_v2d ( transform , pos ) , translate ) ;
nx = pos . x / CELL ;
ny = pos . y / CELL ;
2012-06-09 14:16:47 -05:00
if ( nx < 0 | | nx > = newBlockWidth | | ny < 0 | | ny > = newBlockHeight )
2012-06-09 13:42:07 -05:00
continue ;
if ( blockMap [ y ] [ x ] )
{
blockMapNew [ ny ] [ nx ] = blockMap [ y ] [ x ] ;
if ( blockMap [ y ] [ x ] = = WL_FAN )
{
vel = v2d_new ( fanVelX [ y ] [ x ] , fanVelY [ y ] [ x ] ) ;
vel = m2d_multiply_v2d ( transform , vel ) ;
fanVelXNew [ ny ] [ nx ] = vel . x ;
fanVelYNew [ ny ] [ nx ] = vel . y ;
}
}
}
//ndata = build_save(size,0,0,nw,nh,blockMapNew,vxn,vyn,pvn,fanVelXNew,fanVelYNew,signst,partst);
2012-06-09 14:16:47 -05:00
blockWidth = newBlockWidth ;
blockHeight = newBlockHeight ;
delete blockMap ;
delete fanVelX ;
delete fanVelY ;
2012-06-09 13:43:35 -05:00
delete blockMapPtr ;
delete fanVelXPtr ;
delete fanVelYPtr ;
2012-06-09 14:16:47 -05:00
blockMap = blockMapNew ;
fanVelX = fanVelXNew ;
fanVelY = fanVelYNew ;
blockMapPtr = ( unsigned char * ) blockMapPtrNew ;
fanVelXPtr = ( float * ) fanVelXPtrNew ;
fanVelYPtr = ( float * ) fanVelYPtrNew ;
2012-06-05 14:08:35 -05:00
}
2012-06-05 19:46:13 -05:00
void GameSave : : readOPS ( char * data , int dataLength )
2012-06-05 14:08:35 -05:00
{
2012-06-12 11:06:38 -05:00
unsigned char * inputData = ( unsigned char * ) data , * bsonData = NULL , * partsData = NULL , * partsPosData = NULL , * fanData = NULL , * wallData = NULL , * soapLinkData = NULL ;
unsigned int inputDataLen = dataLength , bsonDataLen = 0 , partsDataLen , partsPosDataLen , fanDataLen , wallDataLen , soapLinkDataLen ;
unsigned partsCount = 0 , * partsSimIndex = NULL ;
2012-06-05 14:08:35 -05:00
int i , freeIndicesCount , x , y , j ;
int * freeIndices = NULL ;
int blockX , blockY , blockW , blockH , fullX , fullY , fullW , fullH ;
2012-07-25 11:12:15 -05:00
int savedVersion = inputData [ 4 ] ;
2012-06-05 14:08:35 -05:00
bson b ;
bson_iterator iter ;
//Block sizes
blockX = 0 ;
blockY = 0 ;
blockW = inputData [ 6 ] ;
blockH = inputData [ 7 ] ;
//Full size, normalised
fullX = blockX * CELL ;
fullY = blockY * CELL ;
fullW = blockW * CELL ;
fullH = blockH * CELL ;
//From newer version
2012-07-25 11:12:15 -05:00
if ( savedVersion > SAVE_VERSION )
2012-06-05 19:46:13 -05:00
throw ParseException ( ParseException : : WrongVersion , " Save from newer version " ) ;
2012-06-05 14:08:35 -05:00
//Incompatible cell size
if ( inputData [ 5 ] > CELL )
2012-06-05 19:46:13 -05:00
throw ParseException ( ParseException : : InvalidDimensions , " Incorrect CELL size " ) ;
2012-06-05 14:08:35 -05:00
//Too large/off screen
if ( blockX + blockW > XRES / CELL | | blockY + blockH > YRES / CELL )
2012-06-05 19:46:13 -05:00
throw ParseException ( ParseException : : InvalidDimensions , " Save too large " ) ;
2012-06-05 14:08:35 -05:00
2012-06-08 16:04:14 -05:00
setSize ( blockW , blockH ) ;
2012-06-05 14:08:35 -05:00
bsonDataLen = ( ( unsigned ) inputData [ 8 ] ) ;
bsonDataLen | = ( ( unsigned ) inputData [ 9 ] ) < < 8 ;
bsonDataLen | = ( ( unsigned ) inputData [ 10 ] ) < < 16 ;
bsonDataLen | = ( ( unsigned ) inputData [ 11 ] ) < < 24 ;
bsonData = ( unsigned char * ) malloc ( bsonDataLen + 1 ) ;
if ( ! bsonData )
2012-06-05 19:46:13 -05:00
throw ParseException ( ParseException : : InternalError , " Unable to allocate memory " ) ;
2012-06-05 14:08:35 -05:00
//Make sure bsonData is null terminated, since all string functions need null terminated strings
//(bson_iterator_key returns a pointer into bsonData, which is then used with strcmp)
bsonData [ bsonDataLen ] = 0 ;
if ( BZ2_bzBuffToBuffDecompress ( ( char * ) bsonData , & bsonDataLen , ( char * ) ( inputData + 12 ) , inputDataLen - 12 , 0 , 0 ) )
2012-06-05 19:46:13 -05:00
throw ParseException ( ParseException : : Corrupt , " Unable to decompress " ) ;
2012-06-05 14:08:35 -05:00
bson_init_data ( & b , ( char * ) bsonData ) ;
bson_iterator_init ( & iter , & b ) ;
std : : vector < sign > tempSigns ;
while ( bson_iterator_next ( & iter ) )
{
if ( strcmp ( bson_iterator_key ( & iter ) , " signs " ) = = 0 )
{
if ( bson_iterator_type ( & iter ) = = BSON_ARRAY )
{
bson_iterator subiter ;
bson_iterator_subiterator ( & iter , & subiter ) ;
while ( bson_iterator_next ( & subiter ) )
{
if ( strcmp ( bson_iterator_key ( & subiter ) , " sign " ) = = 0 )
{
if ( bson_iterator_type ( & subiter ) = = BSON_OBJECT )
{
bson_iterator signiter ;
bson_iterator_subiterator ( & subiter , & signiter ) ;
sign tempSign ( " " , 0 , 0 , sign : : Left ) ;
while ( bson_iterator_next ( & signiter ) )
{
if ( strcmp ( bson_iterator_key ( & signiter ) , " text " ) = = 0 & & bson_iterator_type ( & signiter ) = = BSON_STRING )
{
2012-06-12 11:13:30 -05:00
char tempString [ 256 ] ;
strncpy ( tempString , bson_iterator_string ( & signiter ) , 255 ) ;
tempString [ 255 ] = 0 ;
2012-06-05 14:08:35 -05:00
clean_text ( ( char * ) tempSign . text . c_str ( ) , 158 - 14 ) ;
2012-06-12 11:13:30 -05:00
tempSign . text = tempString ;
2012-06-05 14:08:35 -05:00
}
else if ( strcmp ( bson_iterator_key ( & signiter ) , " justification " ) = = 0 & & bson_iterator_type ( & signiter ) = = BSON_INT )
{
tempSign . ju = ( sign : : Justification ) bson_iterator_int ( & signiter ) ;
}
else if ( strcmp ( bson_iterator_key ( & signiter ) , " x " ) = = 0 & & bson_iterator_type ( & signiter ) = = BSON_INT )
{
tempSign . x = bson_iterator_int ( & signiter ) + fullX ;
}
else if ( strcmp ( bson_iterator_key ( & signiter ) , " y " ) = = 0 & & bson_iterator_type ( & signiter ) = = BSON_INT )
{
tempSign . y = bson_iterator_int ( & signiter ) + fullY ;
}
else
{
fprintf ( stderr , " Unknown sign property %s \n " , bson_iterator_key ( & signiter ) ) ;
}
}
tempSigns . push_back ( tempSign ) ;
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & subiter ) ) ;
}
}
}
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
else if ( strcmp ( bson_iterator_key ( & iter ) , " parts " ) = = 0 )
{
if ( bson_iterator_type ( & iter ) = = BSON_BINDATA & & ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER & & ( partsDataLen = bson_iterator_bin_len ( & iter ) ) > 0 )
{
partsData = ( unsigned char * ) bson_iterator_bin_data ( & iter ) ;
}
else
{
fprintf ( stderr , " Invalid datatype of particle data: %d[%d] %d[%d] %d[%d] \n " , bson_iterator_type ( & iter ) , bson_iterator_type ( & iter ) = = BSON_BINDATA , ( unsigned char ) bson_iterator_bin_type ( & iter ) , ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER , bson_iterator_bin_len ( & iter ) , bson_iterator_bin_len ( & iter ) > 0 ) ;
}
}
if ( strcmp ( bson_iterator_key ( & iter ) , " partsPos " ) = = 0 )
{
if ( bson_iterator_type ( & iter ) = = BSON_BINDATA & & ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER & & ( partsPosDataLen = bson_iterator_bin_len ( & iter ) ) > 0 )
{
partsPosData = ( unsigned char * ) bson_iterator_bin_data ( & iter ) ;
}
else
{
fprintf ( stderr , " Invalid datatype of particle position data: %d[%d] %d[%d] %d[%d] \n " , bson_iterator_type ( & iter ) , bson_iterator_type ( & iter ) = = BSON_BINDATA , ( unsigned char ) bson_iterator_bin_type ( & iter ) , ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER , bson_iterator_bin_len ( & iter ) , bson_iterator_bin_len ( & iter ) > 0 ) ;
}
}
else if ( strcmp ( bson_iterator_key ( & iter ) , " wallMap " ) = = 0 )
{
if ( bson_iterator_type ( & iter ) = = BSON_BINDATA & & ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER & & ( wallDataLen = bson_iterator_bin_len ( & iter ) ) > 0 )
{
wallData = ( unsigned char * ) bson_iterator_bin_data ( & iter ) ;
}
else
{
fprintf ( stderr , " Invalid datatype of wall data: %d[%d] %d[%d] %d[%d] \n " , bson_iterator_type ( & iter ) , bson_iterator_type ( & iter ) = = BSON_BINDATA , ( unsigned char ) bson_iterator_bin_type ( & iter ) , ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER , bson_iterator_bin_len ( & iter ) , bson_iterator_bin_len ( & iter ) > 0 ) ;
}
}
else if ( strcmp ( bson_iterator_key ( & iter ) , " fanMap " ) = = 0 )
{
if ( bson_iterator_type ( & iter ) = = BSON_BINDATA & & ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER & & ( fanDataLen = bson_iterator_bin_len ( & iter ) ) > 0 )
{
fanData = ( unsigned char * ) bson_iterator_bin_data ( & iter ) ;
}
else
{
fprintf ( stderr , " Invalid datatype of fan data: %d[%d] %d[%d] %d[%d] \n " , bson_iterator_type ( & iter ) , bson_iterator_type ( & iter ) = = BSON_BINDATA , ( unsigned char ) bson_iterator_bin_type ( & iter ) , ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER , bson_iterator_bin_len ( & iter ) , bson_iterator_bin_len ( & iter ) > 0 ) ;
}
}
2012-06-12 11:06:38 -05:00
else if ( strcmp ( bson_iterator_key ( & iter ) , " soapLinks " ) = = 0 )
{
if ( bson_iterator_type ( & iter ) = = BSON_BINDATA & & ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER & & ( soapLinkDataLen = bson_iterator_bin_len ( & iter ) ) > 0 )
{
soapLinkData = ( unsigned char * ) bson_iterator_bin_data ( & iter ) ;
}
else
{
fprintf ( stderr , " Invalid datatype of soap data: %d[%d] %d[%d] %d[%d] \n " , bson_iterator_type ( & iter ) , bson_iterator_type ( & iter ) = = BSON_BINDATA , ( unsigned char ) bson_iterator_bin_type ( & iter ) , ( ( unsigned char ) bson_iterator_bin_type ( & iter ) ) = = BSON_BIN_USER , bson_iterator_bin_len ( & iter ) , bson_iterator_bin_len ( & iter ) > 0 ) ;
}
}
2012-06-05 14:08:35 -05:00
else if ( strcmp ( bson_iterator_key ( & iter ) , " legacyEnable " ) = = 0 )
{
if ( bson_iterator_type ( & iter ) = = BSON_BOOL )
{
legacyEnable = bson_iterator_bool ( & iter ) ;
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
else if ( strcmp ( bson_iterator_key ( & iter ) , " gravityEnable " ) = = 0 )
{
if ( bson_iterator_type ( & iter ) = = BSON_BOOL )
{
gravityEnable = bson_iterator_bool ( & iter ) ;
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
else if ( strcmp ( bson_iterator_key ( & iter ) , " waterEEnabled " ) = = 0 )
{
if ( bson_iterator_type ( & iter ) = = BSON_BOOL )
{
waterEEnabled = bson_iterator_bool ( & iter ) ;
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
else if ( strcmp ( bson_iterator_key ( & iter ) , " paused " ) = = 0 )
{
if ( bson_iterator_type ( & iter ) = = BSON_BOOL )
{
paused = bson_iterator_bool ( & iter ) ;
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
else if ( strcmp ( bson_iterator_key ( & iter ) , " gravityMode " ) = = 0 )
{
if ( bson_iterator_type ( & iter ) = = BSON_INT )
{
gravityMode = bson_iterator_int ( & iter ) ;
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
else if ( strcmp ( bson_iterator_key ( & iter ) , " airMode " ) = = 0 )
{
if ( bson_iterator_type ( & iter ) = = BSON_INT )
{
airMode = bson_iterator_int ( & iter ) ;
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
}
//Read wall and fan data
if ( wallData )
{
j = 0 ;
if ( blockW * blockH > wallDataLen )
{
fprintf ( stderr , " Not enough wall data \n " ) ;
goto fail ;
}
for ( x = 0 ; x < blockW ; x + + )
{
for ( y = 0 ; y < blockH ; y + + )
{
if ( wallData [ y * blockW + x ] )
blockMap [ blockY + y ] [ blockX + x ] = wallData [ y * blockW + x ] ;
2012-07-20 13:39:38 -05:00
if ( blockMap [ y ] [ x ] = = O_WL_WALLELEC )
blockMap [ y ] [ x ] = WL_WALLELEC ;
if ( blockMap [ y ] [ x ] = = O_WL_EWALL )
blockMap [ y ] [ x ] = WL_EWALL ;
if ( blockMap [ y ] [ x ] = = O_WL_DETECT )
blockMap [ y ] [ x ] = WL_DETECT ;
if ( blockMap [ y ] [ x ] = = O_WL_STREAM )
blockMap [ y ] [ x ] = WL_STREAM ;
if ( blockMap [ y ] [ x ] = = O_WL_FAN | | blockMap [ y ] [ x ] = = O_WL_FANHELPER )
blockMap [ y ] [ x ] = WL_FAN ;
if ( blockMap [ y ] [ x ] = = O_WL_ALLOWLIQUID )
blockMap [ y ] [ x ] = WL_ALLOWLIQUID ;
if ( blockMap [ y ] [ x ] = = O_WL_DESTROYALL )
blockMap [ y ] [ x ] = WL_DESTROYALL ;
if ( blockMap [ y ] [ x ] = = O_WL_ERASE )
blockMap [ y ] [ x ] = WL_ERASE ;
if ( blockMap [ y ] [ x ] = = O_WL_WALL )
blockMap [ y ] [ x ] = WL_WALL ;
if ( blockMap [ y ] [ x ] = = O_WL_ALLOWAIR )
blockMap [ y ] [ x ] = WL_ALLOWAIR ;
if ( blockMap [ y ] [ x ] = = O_WL_ALLOWSOLID )
blockMap [ y ] [ x ] = WL_ALLOWSOLID ;
if ( blockMap [ y ] [ x ] = = O_WL_ALLOWALLELEC )
blockMap [ y ] [ x ] = WL_ALLOWALLELEC ;
if ( blockMap [ y ] [ x ] = = O_WL_EHOLE )
blockMap [ y ] [ x ] = WL_EHOLE ;
if ( blockMap [ y ] [ x ] = = O_WL_ALLOWGAS )
blockMap [ y ] [ x ] = WL_ALLOWGAS ;
if ( blockMap [ y ] [ x ] = = O_WL_GRAV )
blockMap [ y ] [ x ] = WL_GRAV ;
if ( blockMap [ y ] [ x ] = = O_WL_ALLOWENERGY )
blockMap [ y ] [ x ] = WL_ALLOWENERGY ;
if ( blockMap [ y ] [ x ] = = WL_FAN & & fanData )
2012-06-05 14:08:35 -05:00
{
if ( j + 1 > = fanDataLen )
{
fprintf ( stderr , " Not enough fan data \n " ) ;
}
fanVelX [ blockY + y ] [ blockX + x ] = ( fanData [ j + + ] - 127.0f ) / 64.0f ;
fanVelY [ blockY + y ] [ blockX + x ] = ( fanData [ j + + ] - 127.0f ) / 64.0f ;
}
}
}
}
//Read particle data
if ( partsData & & partsPosData )
{
int newIndex = 0 , fieldDescriptor , tempTemp ;
int posCount , posTotal , partsPosDataIndex = 0 ;
int saved_x , saved_y ;
if ( fullW * fullH * 3 > partsPosDataLen )
{
fprintf ( stderr , " Not enough particle position data \n " ) ;
goto fail ;
}
2012-06-12 11:06:38 -05:00
partsSimIndex = ( unsigned int * ) calloc ( NPART , sizeof ( unsigned ) ) ;
partsCount = 0 ;
2012-06-05 14:08:35 -05:00
i = 0 ;
newIndex = 0 ;
for ( saved_y = 0 ; saved_y < fullH ; saved_y + + )
{
for ( saved_x = 0 ; saved_x < fullW ; saved_x + + )
{
//Read total number of particles at this position
posTotal = 0 ;
posTotal | = partsPosData [ partsPosDataIndex + + ] < < 16 ;
posTotal | = partsPosData [ partsPosDataIndex + + ] < < 8 ;
posTotal | = partsPosData [ partsPosDataIndex + + ] ;
//Put the next posTotal particles at this position
for ( posCount = 0 ; posCount < posTotal ; posCount + + )
{
particlesCount = newIndex + 1 ;
if ( newIndex > = NPART )
{
goto fail ;
}
//i+3 because we have 4 bytes of required fields (type (1), descriptor (2), temp (1))
if ( i + 3 > = partsDataLen )
goto fail ;
x = saved_x + fullX ;
y = saved_y + fullY ;
fieldDescriptor = partsData [ i + 1 ] ;
fieldDescriptor | = partsData [ i + 2 ] < < 8 ;
2012-06-08 16:04:14 -05:00
if ( x > = fullW | | x < 0 | | y > = fullH | | y < 0 )
2012-06-05 14:08:35 -05:00
{
fprintf ( stderr , " Out of range [%d]: %d %d, [%d, %d], [%d, %d] \n " , i , x , y , ( unsigned ) partsData [ i + 1 ] , ( unsigned ) partsData [ i + 2 ] , ( unsigned ) partsData [ i + 3 ] , ( unsigned ) partsData [ i + 4 ] ) ;
goto fail ;
}
if ( partsData [ i ] > = PT_NUM )
partsData [ i ] = PT_DMND ; //Replace all invalid elements with diamond
if ( newIndex < 0 | | newIndex > = NPART )
goto fail ;
2012-06-12 11:06:38 -05:00
//Store partsptr index+1 for this saved particle index (0 means not loaded)
partsSimIndex [ partsCount + + ] = newIndex + 1 ;
2012-06-05 14:08:35 -05:00
//Clear the particle, ready for our new properties
memset ( & ( particles [ newIndex ] ) , 0 , sizeof ( Particle ) ) ;
//Required fields
particles [ newIndex ] . type = partsData [ i ] ;
particles [ newIndex ] . x = x ;
particles [ newIndex ] . y = y ;
i + = 3 ;
//Read temp
if ( fieldDescriptor & 0x01 )
{
//Full 16bit int
tempTemp = partsData [ i + + ] ;
tempTemp | = ( ( ( unsigned ) partsData [ i + + ] ) < < 8 ) ;
particles [ newIndex ] . temp = tempTemp ;
}
else
{
//1 Byte room temp offset
tempTemp = ( char ) partsData [ i + + ] ;
particles [ newIndex ] . temp = tempTemp + 294.15f ;
}
//Read life
if ( fieldDescriptor & 0x02 )
{
if ( i > = partsDataLen ) goto fail ;
particles [ newIndex ] . life = partsData [ i + + ] ;
//Read 2nd byte
if ( fieldDescriptor & 0x04 )
{
if ( i > = partsDataLen ) goto fail ;
particles [ newIndex ] . life | = ( ( ( unsigned ) partsData [ i + + ] ) < < 8 ) ;
}
}
//Read tmp
if ( fieldDescriptor & 0x08 )
{
if ( i > = partsDataLen ) goto fail ;
particles [ newIndex ] . tmp = partsData [ i + + ] ;
//Read 2nd byte
if ( fieldDescriptor & 0x10 )
{
if ( i > = partsDataLen ) goto fail ;
particles [ newIndex ] . tmp | = ( ( ( unsigned ) partsData [ i + + ] ) < < 8 ) ;
2012-08-20 10:48:03 -05:00
//Read 3rd and 4th bytes
if ( fieldDescriptor & 0x1000 )
{
if ( i + 1 > = partsDataLen ) goto fail ;
particles [ newIndex ] . tmp | = ( ( ( unsigned ) partsData [ i + + ] ) < < 16 ) ;
particles [ newIndex ] . tmp | = ( ( ( unsigned ) partsData [ i + + ] ) < < 24 ) ;
}
2012-06-05 14:08:35 -05:00
}
}
//Read ctype
if ( fieldDescriptor & 0x20 )
{
if ( i > = partsDataLen ) goto fail ;
particles [ newIndex ] . ctype = partsData [ i + + ] ;
//Read additional bytes
if ( fieldDescriptor & 0x200 )
{
if ( i + 2 > = partsDataLen ) goto fail ;
particles [ newIndex ] . ctype | = ( ( ( unsigned ) partsData [ i + + ] ) < < 24 ) ;
particles [ newIndex ] . ctype | = ( ( ( unsigned ) partsData [ i + + ] ) < < 16 ) ;
particles [ newIndex ] . ctype | = ( ( ( unsigned ) partsData [ i + + ] ) < < 8 ) ;
}
}
//Read dcolour
if ( fieldDescriptor & 0x40 )
{
if ( i + 3 > = partsDataLen ) goto fail ;
particles [ newIndex ] . dcolour = ( ( ( unsigned ) partsData [ i + + ] ) < < 24 ) ;
particles [ newIndex ] . dcolour | = ( ( ( unsigned ) partsData [ i + + ] ) < < 16 ) ;
particles [ newIndex ] . dcolour | = ( ( ( unsigned ) partsData [ i + + ] ) < < 8 ) ;
particles [ newIndex ] . dcolour | = ( ( unsigned ) partsData [ i + + ] ) ;
}
//Read vx
if ( fieldDescriptor & 0x80 )
{
if ( i > = partsDataLen ) goto fail ;
particles [ newIndex ] . vx = ( partsData [ i + + ] - 127.0f ) / 16.0f ;
}
//Read vy
if ( fieldDescriptor & 0x100 )
{
if ( i > = partsDataLen ) goto fail ;
particles [ newIndex ] . vy = ( partsData [ i + + ] - 127.0f ) / 16.0f ;
}
//Read tmp2
if ( fieldDescriptor & 0x400 )
{
if ( i > = partsDataLen ) goto fail ;
particles [ newIndex ] . tmp2 = partsData [ i + + ] ;
2012-07-25 11:16:56 -05:00
if ( fieldDescriptor & 0x800 )
{
if ( i > = partsDataLen ) goto fail ;
particles [ newIndex ] . tmp2 | = ( ( ( unsigned ) partsData [ i + + ] ) < < 8 ) ;
}
2012-06-05 14:08:35 -05:00
}
2012-06-12 11:06:38 -05:00
//Particle specific parsing:
switch ( particles [ newIndex ] . type )
{
case PT_SOAP :
//Clear soap links, links will be added back in if soapLinkData is present
particles [ newIndex ] . ctype & = ~ 6 ;
break ;
2012-07-25 11:12:15 -05:00
case PT_BOMB :
if ( particles [ newIndex ] . tmp ! = 0 & & savedVersion < 81 )
{
particles [ newIndex ] . type = PT_EMBR ;
particles [ newIndex ] . ctype = 0 ;
if ( particles [ newIndex ] . tmp = = 1 )
particles [ newIndex ] . tmp = 0 ;
}
break ;
case PT_DUST :
if ( particles [ newIndex ] . life > 0 & & savedVersion < 81 )
{
particles [ newIndex ] . type = PT_EMBR ;
particles [ newIndex ] . ctype = ( particles [ newIndex ] . tmp2 < < 16 ) | ( particles [ newIndex ] . tmp < < 8 ) | particles [ newIndex ] . ctype ;
particles [ newIndex ] . tmp = 1 ;
}
break ;
case PT_FIRW :
if ( particles [ newIndex ] . tmp > = 2 & & savedVersion < 81 )
{
int caddress = restrict_flt ( restrict_flt ( ( float ) ( particles [ newIndex ] . tmp - 4 ) , 0.0f , 200.0f ) * 3 , 0.0f , ( 200.0f * 3 ) - 3 ) ;
particles [ newIndex ] . type = PT_EMBR ;
particles [ newIndex ] . tmp = 1 ;
particles [ newIndex ] . ctype = ( ( ( unsigned char ) ( firw_data [ caddress ] ) ) < < 16 ) | ( ( ( unsigned char ) ( firw_data [ caddress + 1 ] ) ) < < 8 ) | ( ( unsigned char ) ( firw_data [ caddress + 2 ] ) ) ;
}
break ;
2012-06-12 11:06:38 -05:00
}
2012-06-05 14:08:35 -05:00
newIndex + + ;
}
}
}
2012-06-12 11:06:38 -05:00
if ( soapLinkData )
{
int soapLinkDataPos = 0 ;
for ( i = 0 ; i < partsCount ; i + + )
{
if ( partsSimIndex [ i ] & & particles [ partsSimIndex [ i ] - 1 ] . type = = PT_SOAP )
{
// Get the index of the particle forward linked from this one, if present in the save data
int linkedIndex = 0 ;
if ( soapLinkDataPos + 3 > soapLinkDataLen ) break ;
linkedIndex | = soapLinkData [ soapLinkDataPos + + ] < < 16 ;
linkedIndex | = soapLinkData [ soapLinkDataPos + + ] < < 8 ;
linkedIndex | = soapLinkData [ soapLinkDataPos + + ] ;
// All indexes in soapLinkData and partsSimIndex have 1 added to them (0 means not saved/loaded)
if ( ! linkedIndex | | linkedIndex - 1 > = partsCount | | ! partsSimIndex [ linkedIndex - 1 ] )
continue ;
linkedIndex = partsSimIndex [ linkedIndex - 1 ] - 1 ;
newIndex = partsSimIndex [ i ] - 1 ;
//Attach the two particles
particles [ newIndex ] . ctype | = 2 ;
particles [ newIndex ] . tmp = linkedIndex ;
particles [ linkedIndex ] . ctype | = 4 ;
particles [ linkedIndex ] . tmp2 = newIndex ;
}
}
}
2012-06-05 14:08:35 -05:00
}
2012-08-17 11:08:24 -05:00
if ( tempSigns . size ( ) )
{
for ( int i = 0 ; i < tempSigns . size ( ) ; i + + )
{
if ( signs . size ( ) = = MAXSIGNS )
break ;
signs . push_back ( tempSigns [ i ] ) ;
}
}
2012-06-05 14:08:35 -05:00
goto fin ;
fail :
//Clean up everything
2012-06-05 19:46:13 -05:00
bson_destroy ( & b ) ;
if ( freeIndices )
free ( freeIndices ) ;
2012-06-12 11:06:38 -05:00
if ( partsSimIndex )
free ( partsSimIndex ) ;
2012-06-05 19:46:13 -05:00
throw ParseException ( ParseException : : Corrupt , " Save data currupt " ) ;
2012-06-05 14:08:35 -05:00
fin :
bson_destroy ( & b ) ;
if ( freeIndices )
free ( freeIndices ) ;
2012-06-18 09:57:41 -05:00
if ( partsSimIndex )
free ( partsSimIndex ) ;
2012-06-05 14:08:35 -05:00
}
2012-06-05 19:46:13 -05:00
void GameSave : : readPSv ( char * data , int dataLength )
2012-06-05 14:08:35 -05:00
{
unsigned char * d = NULL , * c = ( unsigned char * ) data ;
int q , i , j , k , x , y , p = 0 , * m = NULL , ver , pty , ty , legacy_beta = 0 , tempGrav = 0 ;
int bx0 = 0 , by0 = 0 , bw , bh , w , h , y0 = 0 , x0 = 0 ;
int nf = 0 , new_format = 0 , ttv = 0 ;
int * fp = ( int * ) malloc ( NPART * sizeof ( int ) ) ;
std : : vector < sign > tempSigns ;
char tempSignText [ 255 ] ;
sign tempSign ( " " , 0 , 0 , sign : : Left ) ;
//Gol data used to read older saves
int goltype [ NGOL ] ;
int grule [ NGOL + 1 ] [ 10 ] ;
int golRulesCount ;
int * golRulesT = LoadGOLRules ( golRulesCount ) ;
memcpy ( grule , golRulesT , sizeof ( int ) * ( golRulesCount * 10 ) ) ;
free ( golRulesT ) ;
int golTypesCount ;
int * golTypesT = LoadGOLTypes ( golTypesCount ) ;
memcpy ( goltype , golTypesT , sizeof ( int ) * ( golTypesCount ) ) ;
free ( golTypesT ) ;
2012-08-12 16:32:57 -05:00
std : : vector < Element > elements = GetElements ( ) ;
2012-07-20 13:39:38 -05:00
try
{
2012-06-05 14:08:35 -05:00
//New file header uses PSv, replacing fuC. This is to detect if the client uses a new save format for temperatures
//This creates a problem for old clients, that display and "corrupt" error instead of a "newer version" error
if ( dataLength < 16 )
2012-06-05 19:46:13 -05:00
throw ParseException ( ParseException : : Corrupt , " No save data " ) ;
2012-06-05 14:08:35 -05:00
if ( ! ( c [ 2 ] = = 0x43 & & c [ 1 ] = = 0x75 & & c [ 0 ] = = 0x66 ) & & ! ( c [ 2 ] = = 0x76 & & c [ 1 ] = = 0x53 & & c [ 0 ] = = 0x50 ) )
2012-06-05 19:46:13 -05:00
throw ParseException ( ParseException : : Corrupt , " Unknown format " ) ;
2012-06-05 14:08:35 -05:00
if ( c [ 2 ] = = 0x76 & & c [ 1 ] = = 0x53 & & c [ 0 ] = = 0x50 ) {
new_format = 1 ;
}
if ( c [ 4 ] > SAVE_VERSION )
2012-06-05 19:46:13 -05:00
throw ParseException ( ParseException : : WrongVersion , " Save from newer version " ) ;
2012-06-05 14:08:35 -05:00
ver = c [ 4 ] ;
if ( ver < 34 )
{
legacyEnable = 1 ;
}
else
{
if ( ver > = 44 ) {
legacyEnable = c [ 3 ] & 0x01 ;
paused = ( c [ 3 ] > > 1 ) & 0x01 ;
if ( ver > = 46 ) {
gravityMode = ( ( c [ 3 ] > > 2 ) & 0x03 ) ; // | ((c[3]>>2)&0x01);
airMode = ( ( c [ 3 ] > > 4 ) & 0x07 ) ; // | ((c[3]>>4)&0x02) | ((c[3]>>4)&0x01);
}
if ( ver > = 49 ) {
gravityEnable = ( ( c [ 3 ] > > 7 ) & 0x01 ) ;
}
} else {
if ( c [ 3 ] = = 1 | | c [ 3 ] = = 0 ) {
legacyEnable = c [ 3 ] ;
} else {
legacy_beta = 1 ;
}
}
}
bw = c [ 6 ] ;
bh = c [ 7 ] ;
if ( bx0 + bw > XRES / CELL )
bx0 = XRES / CELL - bw ;
if ( by0 + bh > YRES / CELL )
by0 = YRES / CELL - bh ;
if ( bx0 < 0 )
bx0 = 0 ;
if ( by0 < 0 )
by0 = 0 ;
if ( c [ 5 ] ! = CELL | | bx0 + bw > XRES / CELL | | by0 + bh > YRES / CELL )
2012-06-05 19:46:13 -05:00
throw ParseException ( ParseException : : InvalidDimensions , " Save too large " ) ;
2012-06-05 14:08:35 -05:00
i = ( unsigned ) c [ 8 ] ;
i | = ( ( unsigned ) c [ 9 ] ) < < 8 ;
i | = ( ( unsigned ) c [ 10 ] ) < < 16 ;
i | = ( ( unsigned ) c [ 11 ] ) < < 24 ;
d = ( unsigned char * ) malloc ( i ) ;
if ( ! d )
2012-06-05 19:46:13 -05:00
throw ParseException ( ParseException : : Corrupt , " Cannot allocate memory " ) ;
2012-06-05 14:08:35 -05:00
2012-06-08 16:04:14 -05:00
setSize ( bw , bh ) ;
2012-06-05 14:08:35 -05:00
2012-07-27 14:06:17 -05:00
int bzStatus = 0 ;
if ( bzStatus = BZ2_bzBuffToBuffDecompress ( ( char * ) d , ( unsigned * ) & i , ( char * ) ( c + 12 ) , dataLength - 12 , 0 , 0 ) )
{
std : : stringstream bzStatusStr ;
bzStatusStr < < bzStatus ;
throw ParseException ( ParseException : : Corrupt , " Cannot decompress: " + bzStatusStr . str ( ) ) ;
}
2012-06-05 14:08:35 -05:00
dataLength = i ;
2012-07-20 13:39:38 -05:00
std : : cout < < " Parsing " < < dataLength < < " bytes of data, version " < < ver < < std : : endl ;
2012-06-05 14:08:35 -05:00
if ( dataLength < bw * bh )
2012-06-05 19:46:13 -05:00
throw ParseException ( ParseException : : Corrupt , " Save data corrupt (missing data) " ) ;
2012-06-05 14:08:35 -05:00
// normalize coordinates
x0 = bx0 * CELL ;
y0 = by0 * CELL ;
w = bw * CELL ;
h = bh * CELL ;
if ( ver < 46 ) {
gravityMode = 0 ;
airMode = 0 ;
}
m = ( int * ) calloc ( XRES * YRES , sizeof ( int ) ) ;
// load the required air state
for ( y = by0 ; y < by0 + bh ; y + + )
for ( x = bx0 ; x < bx0 + bw ; x + + )
{
if ( d [ p ] )
{
//In old saves, ignore walls created by sign tool bug
//Not ignoring other invalid walls or invalid walls in new saves, so that any other bugs causing them are easier to notice, find and fix
if ( ver < 71 & & d [ p ] = = O_WL_SIGN )
{
p + + ;
continue ;
}
blockMap [ y ] [ x ] = d [ p ] ;
if ( blockMap [ y ] [ x ] = = 1 )
blockMap [ y ] [ x ] = WL_WALL ;
if ( blockMap [ y ] [ x ] = = 2 )
blockMap [ y ] [ x ] = WL_DESTROYALL ;
if ( blockMap [ y ] [ x ] = = 3 )
blockMap [ y ] [ x ] = WL_ALLOWLIQUID ;
if ( blockMap [ y ] [ x ] = = 4 )
blockMap [ y ] [ x ] = WL_FAN ;
if ( blockMap [ y ] [ x ] = = 5 )
blockMap [ y ] [ x ] = WL_STREAM ;
if ( blockMap [ y ] [ x ] = = 6 )
blockMap [ y ] [ x ] = WL_DETECT ;
if ( blockMap [ y ] [ x ] = = 7 )
blockMap [ y ] [ x ] = WL_EWALL ;
if ( blockMap [ y ] [ x ] = = 8 )
blockMap [ y ] [ x ] = WL_WALLELEC ;
if ( blockMap [ y ] [ x ] = = 9 )
blockMap [ y ] [ x ] = WL_ALLOWAIR ;
if ( blockMap [ y ] [ x ] = = 10 )
blockMap [ y ] [ x ] = WL_ALLOWSOLID ;
if ( blockMap [ y ] [ x ] = = 11 )
blockMap [ y ] [ x ] = WL_ALLOWALLELEC ;
if ( blockMap [ y ] [ x ] = = 12 )
blockMap [ y ] [ x ] = WL_EHOLE ;
if ( blockMap [ y ] [ x ] = = 13 )
blockMap [ y ] [ x ] = WL_ALLOWGAS ;
if ( blockMap [ y ] [ x ] = = O_WL_WALLELEC )
blockMap [ y ] [ x ] = WL_WALLELEC ;
if ( blockMap [ y ] [ x ] = = O_WL_EWALL )
blockMap [ y ] [ x ] = WL_EWALL ;
if ( blockMap [ y ] [ x ] = = O_WL_DETECT )
blockMap [ y ] [ x ] = WL_DETECT ;
if ( blockMap [ y ] [ x ] = = O_WL_STREAM )
blockMap [ y ] [ x ] = WL_STREAM ;
if ( blockMap [ y ] [ x ] = = O_WL_FAN | | blockMap [ y ] [ x ] = = O_WL_FANHELPER )
blockMap [ y ] [ x ] = WL_FAN ;
if ( blockMap [ y ] [ x ] = = O_WL_ALLOWLIQUID )
blockMap [ y ] [ x ] = WL_ALLOWLIQUID ;
if ( blockMap [ y ] [ x ] = = O_WL_DESTROYALL )
blockMap [ y ] [ x ] = WL_DESTROYALL ;
if ( blockMap [ y ] [ x ] = = O_WL_ERASE )
blockMap [ y ] [ x ] = WL_ERASE ;
if ( blockMap [ y ] [ x ] = = O_WL_WALL )
blockMap [ y ] [ x ] = WL_WALL ;
if ( blockMap [ y ] [ x ] = = O_WL_ALLOWAIR )
blockMap [ y ] [ x ] = WL_ALLOWAIR ;
if ( blockMap [ y ] [ x ] = = O_WL_ALLOWSOLID )
blockMap [ y ] [ x ] = WL_ALLOWSOLID ;
if ( blockMap [ y ] [ x ] = = O_WL_ALLOWALLELEC )
blockMap [ y ] [ x ] = WL_ALLOWALLELEC ;
if ( blockMap [ y ] [ x ] = = O_WL_EHOLE )
blockMap [ y ] [ x ] = WL_EHOLE ;
if ( blockMap [ y ] [ x ] = = O_WL_ALLOWGAS )
blockMap [ y ] [ x ] = WL_ALLOWGAS ;
if ( blockMap [ y ] [ x ] = = O_WL_GRAV )
blockMap [ y ] [ x ] = WL_GRAV ;
if ( blockMap [ y ] [ x ] = = O_WL_ALLOWENERGY )
blockMap [ y ] [ x ] = WL_ALLOWENERGY ;
}
p + + ;
}
for ( y = by0 ; y < by0 + bh ; y + + )
for ( x = bx0 ; x < bx0 + bw ; x + + )
2012-07-20 13:39:38 -05:00
if ( d [ ( y - by0 ) * bw + ( x - bx0 ) ] = = 4 | | d [ ( y - by0 ) * bw + ( x - bx0 ) ] = = O_WL_FAN )
2012-06-05 14:08:35 -05:00
{
if ( p > = dataLength )
2012-07-20 13:39:38 -05:00
throw ParseException ( ParseException : : Corrupt , " Not enough data at line " MTOS ( __LINE__ ) " in " MTOS ( __FILE__ ) ) ;
2012-06-05 14:08:35 -05:00
fanVelX [ y ] [ x ] = ( d [ p + + ] - 127.0f ) / 64.0f ;
}
for ( y = by0 ; y < by0 + bh ; y + + )
for ( x = bx0 ; x < bx0 + bw ; x + + )
2012-07-20 13:39:38 -05:00
if ( d [ ( y - by0 ) * bw + ( x - bx0 ) ] = = 4 | | d [ ( y - by0 ) * bw + ( x - bx0 ) ] = = O_WL_FAN )
2012-06-05 14:08:35 -05:00
{
if ( p > = dataLength )
2012-07-20 13:39:38 -05:00
throw ParseException ( ParseException : : Corrupt , " Not enough data at line " MTOS ( __LINE__ ) " in " MTOS ( __FILE__ ) ) ;
2012-06-05 14:08:35 -05:00
fanVelY [ y ] [ x ] = ( d [ p + + ] - 127.0f ) / 64.0f ;
}
// load the particle map
i = 0 ;
k = 0 ;
pty = p ;
for ( y = y0 ; y < y0 + h ; y + + )
for ( x = x0 ; x < x0 + w ; x + + )
{
if ( p > = dataLength )
2012-07-20 13:39:38 -05:00
throw ParseException ( ParseException : : Corrupt , " Not enough data at line " MTOS ( __LINE__ ) " in " MTOS ( __FILE__ ) ) ;
2012-06-05 14:08:35 -05:00
j = d [ p + + ] ;
if ( j > = PT_NUM ) {
//TODO: Possibly some server side translation
2012-07-20 13:39:38 -05:00
j = PT_DUST ; //throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
2012-06-05 14:08:35 -05:00
}
if ( j )
{
memset ( particles + k , 0 , sizeof ( Particle ) ) ;
particles [ k ] . type = j ;
if ( j = = PT_COAL )
particles [ k ] . tmp = 50 ;
if ( j = = PT_FUSE )
particles [ k ] . tmp = 50 ;
if ( j = = PT_PHOT )
particles [ k ] . ctype = 0x3fffffff ;
if ( j = = PT_SOAP )
particles [ k ] . ctype = 0 ;
if ( j = = PT_BIZR | | j = = PT_BIZRG | | j = = PT_BIZRS )
particles [ k ] . ctype = 0x47FFFF ;
particles [ k ] . x = ( float ) x ;
particles [ k ] . y = ( float ) y ;
m [ ( x - x0 ) + ( y - y0 ) * w ] = k + 1 ;
2012-08-20 19:09:22 -05:00
particlesCount = + + k ;
2012-06-05 14:08:35 -05:00
}
}
// load particle properties
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i )
{
i - - ;
if ( p + 1 > = dataLength )
2012-07-20 13:39:38 -05:00
throw ParseException ( ParseException : : Corrupt , " Not enough data at line " MTOS ( __LINE__ ) " in " MTOS ( __FILE__ ) ) ;
2012-06-05 14:08:35 -05:00
if ( i < NPART )
{
particles [ i ] . vx = ( d [ p + + ] - 127.0f ) / 16.0f ;
particles [ i ] . vy = ( d [ p + + ] - 127.0f ) / 16.0f ;
}
else
p + = 2 ;
}
}
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i )
{
if ( ver > = 44 ) {
if ( p > = dataLength ) {
2012-07-20 13:39:38 -05:00
throw ParseException ( ParseException : : Corrupt , " Not enough data at line " MTOS ( __LINE__ ) " in " MTOS ( __FILE__ ) ) ;
2012-06-05 14:08:35 -05:00
}
if ( i < = NPART ) {
ttv = ( d [ p + + ] ) < < 8 ;
ttv | = ( d [ p + + ] ) ;
particles [ i - 1 ] . life = ttv ;
} else {
p + = 2 ;
}
} else {
if ( p > = dataLength )
2012-07-20 13:39:38 -05:00
throw ParseException ( ParseException : : Corrupt , " Not enough data at line " MTOS ( __LINE__ ) " in " MTOS ( __FILE__ ) ) ;
2012-06-05 14:08:35 -05:00
if ( i < = NPART )
particles [ i - 1 ] . life = d [ p + + ] * 4 ;
else
p + + ;
}
}
}
if ( ver > = 44 ) {
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i )
{
if ( p > = dataLength ) {
2012-07-20 13:39:38 -05:00
throw ParseException ( ParseException : : Corrupt , " Not enough data at line " MTOS ( __LINE__ ) " in " MTOS ( __FILE__ ) ) ;
2012-06-05 14:08:35 -05:00
}
if ( i < = NPART ) {
ttv = ( d [ p + + ] ) < < 8 ;
ttv | = ( d [ p + + ] ) ;
particles [ i - 1 ] . tmp = ttv ;
if ( ver < 53 & & ! particles [ i - 1 ] . tmp )
for ( q = 1 ; q < = NGOLALT ; q + + ) {
if ( particles [ i - 1 ] . type = = goltype [ q - 1 ] & & grule [ q ] [ 9 ] = = 2 )
particles [ i - 1 ] . tmp = grule [ q ] [ 9 ] - 1 ;
}
if ( ver > = 51 & & ver < 53 & & particles [ i - 1 ] . type = = PT_PBCN )
{
particles [ i - 1 ] . tmp2 = particles [ i - 1 ] . tmp ;
particles [ i - 1 ] . tmp = 0 ;
}
} else {
p + = 2 ;
}
}
}
}
if ( ver > = 53 ) {
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
ty = d [ pty + j ] ;
2012-06-12 10:11:34 -05:00
if ( i & & ( ty = = PT_PBCN | | ( ty = = PT_TRON & & ver > = 77 ) ) )
2012-06-05 14:08:35 -05:00
{
if ( p > = dataLength )
2012-07-20 13:39:38 -05:00
throw ParseException ( ParseException : : Corrupt , " Not enough data at line " MTOS ( __LINE__ ) " in " MTOS ( __FILE__ ) ) ;
2012-06-05 14:08:35 -05:00
if ( i < = NPART )
particles [ i - 1 ] . tmp2 = d [ p + + ] ;
else
p + + ;
}
}
}
//Read ALPHA component
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i )
{
if ( ver > = 49 ) {
if ( p > = dataLength ) {
2012-07-20 13:39:38 -05:00
throw ParseException ( ParseException : : Corrupt , " Not enough data at line " MTOS ( __LINE__ ) " in " MTOS ( __FILE__ ) ) ;
2012-06-05 14:08:35 -05:00
}
if ( i < = NPART ) {
particles [ i - 1 ] . dcolour = d [ p + + ] < < 24 ;
} else {
p + + ;
}
}
}
}
//Read RED component
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i )
{
if ( ver > = 49 ) {
if ( p > = dataLength ) {
2012-07-20 13:39:38 -05:00
throw ParseException ( ParseException : : Corrupt , " Not enough data at line " MTOS ( __LINE__ ) " in " MTOS ( __FILE__ ) ) ;
2012-06-05 14:08:35 -05:00
}
if ( i < = NPART ) {
particles [ i - 1 ] . dcolour | = d [ p + + ] < < 16 ;
} else {
p + + ;
}
}
}
}
//Read GREEN component
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i )
{
if ( ver > = 49 ) {
if ( p > = dataLength ) {
2012-07-20 13:39:38 -05:00
throw ParseException ( ParseException : : Corrupt , " Not enough data at line " MTOS ( __LINE__ ) " in " MTOS ( __FILE__ ) ) ;
2012-06-05 14:08:35 -05:00
}
if ( i < = NPART ) {
particles [ i - 1 ] . dcolour | = d [ p + + ] < < 8 ;
} else {
p + + ;
}
}
}
}
//Read BLUE component
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i )
{
if ( ver > = 49 ) {
if ( p > = dataLength ) {
2012-07-20 13:39:38 -05:00
throw ParseException ( ParseException : : Corrupt , " Not enough data at line " MTOS ( __LINE__ ) " in " MTOS ( __FILE__ ) ) ;
2012-06-05 14:08:35 -05:00
}
if ( i < = NPART ) {
particles [ i - 1 ] . dcolour | = d [ p + + ] ;
} else {
p + + ;
}
}
}
}
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
ty = d [ pty + j ] ;
if ( i )
{
if ( ver > = 34 & & legacy_beta = = 0 )
{
if ( p > = dataLength )
{
2012-07-20 13:39:38 -05:00
throw ParseException ( ParseException : : Corrupt , " Not enough data at line " MTOS ( __LINE__ ) " in " MTOS ( __FILE__ ) ) ;
2012-06-05 14:08:35 -05:00
}
if ( i < = NPART )
{
if ( ver > = 42 ) {
if ( new_format ) {
ttv = ( d [ p + + ] ) < < 8 ;
ttv | = ( d [ p + + ] ) ;
if ( particles [ i - 1 ] . type = = PT_PUMP ) {
particles [ i - 1 ] . temp = ttv + 0.15 ; //fix PUMP saved at 0, so that it loads at 0.
} else {
particles [ i - 1 ] . temp = ttv ;
}
} else {
particles [ i - 1 ] . temp = ( d [ p + + ] * ( ( MAX_TEMP + ( - MIN_TEMP ) ) / 255 ) ) + MIN_TEMP ;
}
} else {
particles [ i - 1 ] . temp = ( ( d [ p + + ] * ( ( O_MAX_TEMP + ( - O_MIN_TEMP ) ) / 255 ) ) + O_MIN_TEMP ) + 273 ;
}
}
else
{
p + + ;
if ( new_format ) {
p + + ;
}
}
}
else
{
particles [ i - 1 ] . temp = elements [ particles [ i - 1 ] . type ] . Temperature ;
}
}
}
for ( j = 0 ; j < w * h ; j + + )
{
int gnum = 0 ;
i = m [ j ] ;
ty = d [ pty + j ] ;
if ( i & & ( ty = = PT_CLNE | | ( ty = = PT_PCLN & & ver > = 43 ) | | ( ty = = PT_BCLN & & ver > = 44 ) | | ( ty = = PT_SPRK & & ver > = 21 ) | | ( ty = = PT_LAVA & & ver > = 34 ) | | ( ty = = PT_PIPE & & ver > = 43 ) | | ( ty = = PT_LIFE & & ver > = 51 ) | | ( ty = = PT_PBCN & & ver > = 52 ) | | ( ty = = PT_WIRE & & ver > = 55 ) | | ( ty = = PT_STOR & & ver > = 59 ) | | ( ty = = PT_CONV & & ver > = 60 ) ) )
{
if ( p > = dataLength )
2012-07-20 13:39:38 -05:00
throw ParseException ( ParseException : : Corrupt , " Not enough data at line " MTOS ( __LINE__ ) " in " MTOS ( __FILE__ ) ) ;
2012-06-05 14:08:35 -05:00
if ( i < = NPART )
particles [ i - 1 ] . ctype = d [ p + + ] ;
else
p + + ;
}
//TODO: STKM_init_legs
// no more particle properties to load, so we can change type here without messing up loading
if ( i & & i < = NPART )
{
2012-06-12 12:55:44 -05:00
if ( ver < 79 & & particles [ i - 1 ] . type = = PT_SPNG )
2012-06-05 14:08:35 -05:00
{
if ( fabs ( particles [ i - 1 ] . vx ) > 0.0f | | fabs ( particles [ i - 1 ] . vy ) > 0.0f )
particles [ i - 1 ] . flags | = FLAG_MOVABLE ;
}
if ( ver < 48 & & ( ty = = OLD_PT_WIND | | ( ty = = PT_BRAY & & particles [ i - 1 ] . life = = 0 ) ) )
{
// Replace invisible particles with something sensible and add decoration to hide it
x = ( int ) ( particles [ i - 1 ] . x + 0.5f ) ;
y = ( int ) ( particles [ i - 1 ] . y + 0.5f ) ;
particles [ i - 1 ] . dcolour = 0xFF000000 ;
particles [ i - 1 ] . type = PT_DMND ;
}
if ( ver < 51 & & ( ( ty > = 78 & & ty < = 89 ) | | ( ty > = 134 & & ty < = 146 & & ty ! = 141 ) ) ) {
//Replace old GOL
particles [ i - 1 ] . type = PT_LIFE ;
for ( gnum = 0 ; gnum < NGOLALT ; gnum + + ) {
if ( ty = = goltype [ gnum ] )
particles [ i - 1 ] . ctype = gnum ;
}
ty = PT_LIFE ;
}
if ( ver < 52 & & ( ty = = PT_CLNE | | ty = = PT_PCLN | | ty = = PT_BCLN ) ) {
//Replace old GOL ctypes in clone
for ( gnum = 0 ; gnum < NGOLALT ; gnum + + ) {
if ( particles [ i - 1 ] . ctype = = goltype [ gnum ] )
{
particles [ i - 1 ] . ctype = PT_LIFE ;
particles [ i - 1 ] . tmp = gnum ;
}
}
}
if ( ty = = PT_LCRY ) {
if ( ver < 67 )
{
//New LCRY uses TMP not life
if ( particles [ i - 1 ] . life > = 10 )
{
particles [ i - 1 ] . life = 10 ;
particles [ i - 1 ] . tmp2 = 10 ;
particles [ i - 1 ] . tmp = 3 ;
}
else if ( particles [ i - 1 ] . life < = 0 )
{
particles [ i - 1 ] . life = 0 ;
particles [ i - 1 ] . tmp2 = 0 ;
particles [ i - 1 ] . tmp = 0 ;
}
else if ( particles [ i - 1 ] . life < 10 & & particles [ i - 1 ] . life > 0 )
{
particles [ i - 1 ] . tmp = 1 ;
}
}
else
{
particles [ i - 1 ] . tmp2 = particles [ i - 1 ] . life ;
}
}
2012-07-25 11:12:15 -05:00
if ( ver < 81 )
{
if ( particles [ i - 1 ] . type = = PT_BOMB & & particles [ i - 1 ] . tmp ! = 0 )
{
particles [ i - 1 ] . type = PT_EMBR ;
particles [ i - 1 ] . ctype = 0 ;
if ( particles [ i - 1 ] . tmp = = 1 )
particles [ i - 1 ] . tmp = 0 ;
}
if ( particles [ i - 1 ] . type = = PT_DUST & & particles [ i - 1 ] . life > 0 )
{
particles [ i - 1 ] . type = PT_EMBR ;
particles [ i - 1 ] . ctype = ( particles [ i - 1 ] . tmp2 < < 16 ) | ( particles [ i - 1 ] . tmp < < 8 ) | particles [ i - 1 ] . ctype ;
particles [ i - 1 ] . tmp = 1 ;
}
if ( particles [ i - 1 ] . type = = PT_FIRW & & particles [ i - 1 ] . tmp > = 2 )
{
int caddress = restrict_flt ( restrict_flt ( ( float ) ( particles [ i - 1 ] . tmp - 4 ) , 0.0f , 200.0f ) * 3 , 0.0f , ( 200.0f * 3 ) - 3 ) ;
particles [ i - 1 ] . type = PT_EMBR ;
particles [ i - 1 ] . tmp = 1 ;
particles [ i - 1 ] . ctype = ( ( ( unsigned char ) ( firw_data [ caddress ] ) ) < < 16 ) | ( ( ( unsigned char ) ( firw_data [ caddress + 1 ] ) ) < < 8 ) | ( ( unsigned char ) ( firw_data [ caddress + 2 ] ) ) ;
}
}
2012-06-05 14:08:35 -05:00
}
}
if ( p > = dataLength )
goto version1 ;
j = d [ p + + ] ;
for ( i = 0 ; i < j ; i + + )
{
if ( p + 6 > dataLength )
2012-07-20 13:39:38 -05:00
throw ParseException ( ParseException : : Corrupt , " Not enough data at line " MTOS ( __LINE__ ) " in " MTOS ( __FILE__ ) ) ;
2012-06-05 14:08:35 -05:00
x = d [ p + + ] ;
x | = ( ( unsigned ) d [ p + + ] ) < < 8 ;
tempSign . x = x + x0 ;
x = d [ p + + ] ;
x | = ( ( unsigned ) d [ p + + ] ) < < 8 ;
tempSign . y = x + y0 ;
x = d [ p + + ] ;
tempSign . ju = ( sign : : Justification ) x ;
x = d [ p + + ] ;
if ( p + x > dataLength )
2012-07-20 13:39:38 -05:00
throw ParseException ( ParseException : : Corrupt , " Not enough data at line " MTOS ( __LINE__ ) " in " MTOS ( __FILE__ ) ) ;
2012-06-05 14:08:35 -05:00
if ( x > 254 )
x = 254 ;
memcpy ( tempSignText , d + p , x ) ;
tempSignText [ x ] = 0 ;
tempSign . text = tempSignText ;
tempSigns . push_back ( tempSign ) ;
p + = x ;
}
for ( i = 0 ; i < tempSigns . size ( ) ; i + + )
{
2012-08-17 11:08:24 -05:00
if ( signs . size ( ) = = MAXSIGNS )
2012-06-05 14:08:35 -05:00
break ;
signs . push_back ( tempSigns [ i ] ) ;
}
2012-07-20 13:39:38 -05:00
}
catch ( ParseException & e )
{
if ( m )
{
free ( m ) ;
m = 0 ;
}
if ( d )
{
free ( d ) ;
d = 0 ;
}
if ( fp )
{
free ( fp ) ;
fp = 0 ;
}
throw ;
}
2012-06-05 14:08:35 -05:00
2012-07-20 13:39:38 -05:00
version1 :
if ( m )
{
free ( m ) ;
m = 0 ;
}
if ( d )
{
free ( d ) ;
d = 0 ;
}
if ( fp )
{
free ( fp ) ;
fp = 0 ;
}
2012-06-05 14:08:35 -05:00
}
char * GameSave : : serialiseOPS ( int & dataLength )
{
//Particle *particles = sim->parts;
2012-06-12 11:06:38 -05:00
unsigned char * partsData = NULL , * partsPosData = NULL , * fanData = NULL , * wallData = NULL , * finalData = NULL , * outputData = NULL , * soapLinkData = NULL ;
2012-06-05 14:08:35 -05:00
unsigned * partsPosLink = NULL , * partsPosFirstMap = NULL , * partsPosCount = NULL , * partsPosLastMap = NULL ;
2012-06-12 11:06:38 -05:00
unsigned partsCount = 0 , * partsSaveIndex = NULL ;
unsigned * elementCount = new unsigned [ PT_NUM ] ;
unsigned int partsDataLen , partsPosDataLen , fanDataLen , wallDataLen , finalDataLen , outputDataLen , soapLinkDataLen ;
2012-06-05 14:08:35 -05:00
int blockX , blockY , blockW , blockH , fullX , fullY , fullW , fullH ;
int x , y , i , wallDataFound = 0 ;
int posCount , signsCount ;
bson b ;
2012-08-12 16:32:57 -05:00
std : : fill ( elementCount , elementCount + PT_NUM , 0 ) ;
2012-06-12 11:06:38 -05:00
2012-06-05 14:08:35 -05:00
//Get coords in blocks
blockX = 0 ; //orig_x0/CELL;
blockY = 0 ; //orig_y0/CELL;
//Snap full coords to block size
fullX = blockX * CELL ;
fullY = blockY * CELL ;
//Original size + offset of original corner from snapped corner, rounded up by adding CELL-1
2012-06-08 16:04:14 -05:00
blockW = blockWidth ; //(blockWidth-fullX+CELL-1)/CELL;
blockH = blockHeight ; //(blockHeight-fullY+CELL-1)/CELL;
2012-06-05 14:08:35 -05:00
fullW = blockW * CELL ;
fullH = blockH * CELL ;
//Copy fan and wall data
wallData = ( unsigned char * ) malloc ( blockW * blockH ) ;
wallDataLen = blockW * blockH ;
fanData = ( unsigned char * ) malloc ( ( blockW * blockH ) * 2 ) ;
fanDataLen = 0 ;
for ( x = blockX ; x < blockX + blockW ; x + + )
{
for ( y = blockY ; y < blockY + blockH ; y + + )
{
wallData [ ( y - blockY ) * blockW + ( x - blockX ) ] = blockMap [ y ] [ x ] ;
if ( blockMap [ y ] [ x ] & & ! wallDataFound )
wallDataFound = 1 ;
if ( blockMap [ y ] [ x ] = = WL_FAN )
{
i = ( int ) ( fanVelX [ y ] [ x ] * 64.0f + 127.5f ) ;
if ( i < 0 ) i = 0 ;
if ( i > 255 ) i = 255 ;
fanData [ fanDataLen + + ] = i ;
i = ( int ) ( fanVelY [ y ] [ x ] * 64.0f + 127.5f ) ;
if ( i < 0 ) i = 0 ;
if ( i > 255 ) i = 255 ;
fanData [ fanDataLen + + ] = i ;
}
}
}
if ( ! fanDataLen )
{
free ( fanData ) ;
fanData = NULL ;
}
if ( ! wallDataFound )
{
free ( wallData ) ;
wallData = NULL ;
}
//Index positions of all particles, using linked lists
//partsPosFirstMap is pmap for the first particle in each position
//partsPosLastMap is pmap for the last particle in each position
//partsPosCount is the number of particles in each position
//partsPosLink contains, for each particle, (i<<8)|1 of the next particle in the same position
partsPosFirstMap = ( unsigned int * ) calloc ( fullW * fullH , sizeof ( unsigned ) ) ;
partsPosLastMap = ( unsigned int * ) calloc ( fullW * fullH , sizeof ( unsigned ) ) ;
partsPosCount = ( unsigned int * ) calloc ( fullW * fullH , sizeof ( unsigned ) ) ;
partsPosLink = ( unsigned int * ) calloc ( NPART , sizeof ( unsigned ) ) ;
for ( i = 0 ; i < NPART ; i + + )
{
if ( particles [ i ] . type )
{
x = ( int ) ( particles [ i ] . x + 0.5f ) ;
y = ( int ) ( particles [ i ] . y + 0.5f ) ;
//Coordinates relative to top left corner of saved area
x - = fullX ;
y - = fullY ;
if ( ! partsPosFirstMap [ y * fullW + x ] )
{
//First entry in list
partsPosFirstMap [ y * fullW + x ] = ( i < < 8 ) | 1 ;
partsPosLastMap [ y * fullW + x ] = ( i < < 8 ) | 1 ;
}
else
{
//Add to end of list
partsPosLink [ partsPosLastMap [ y * fullW + x ] > > 8 ] = ( i < < 8 ) | 1 ; //link to current end of list
partsPosLastMap [ y * fullW + x ] = ( i < < 8 ) | 1 ; //set as new end of list
}
partsPosCount [ y * fullW + x ] + + ;
}
}
//Store number of particles in each position
partsPosData = ( unsigned char * ) malloc ( fullW * fullH * 3 ) ;
partsPosDataLen = 0 ;
for ( y = 0 ; y < fullH ; y + + )
{
for ( x = 0 ; x < fullW ; x + + )
{
posCount = partsPosCount [ y * fullW + x ] ;
partsPosData [ partsPosDataLen + + ] = ( posCount & 0x00FF0000 ) > > 16 ;
partsPosData [ partsPosDataLen + + ] = ( posCount & 0x0000FF00 ) > > 8 ;
partsPosData [ partsPosDataLen + + ] = ( posCount & 0x000000FF ) ;
}
}
//Copy parts data
/* Field descriptor format:
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2012-07-25 11:16:56 -05:00
| tmp2 [ 2 ] | tmp2 | ctype [ 2 ] | vy | vx | dcololour | ctype [ 1 ] | tmp [ 2 ] | tmp [ 1 ] | life [ 2 ] | life [ 1 ] | temp dbl len |
2012-06-05 14:08:35 -05:00
life [ 2 ] means a second byte ( for a 16 bit field ) if life [ 1 ] is present
*/
partsData = ( unsigned char * ) malloc ( NPART * ( sizeof ( Particle ) + 1 ) ) ;
partsDataLen = 0 ;
2012-06-12 11:06:38 -05:00
partsSaveIndex = ( unsigned int * ) calloc ( NPART , sizeof ( unsigned ) ) ;
partsCount = 0 ;
2012-06-05 14:08:35 -05:00
for ( y = 0 ; y < fullH ; y + + )
{
for ( x = 0 ; x < fullW ; x + + )
{
//Find the first particle in this position
i = partsPosFirstMap [ y * fullW + x ] ;
//Loop while there is a pmap entry
while ( i )
{
unsigned short fieldDesc = 0 ;
int fieldDescLoc = 0 , tempTemp , vTemp ;
//Turn pmap entry into a particles index
i = i > > 8 ;
2012-06-12 11:06:38 -05:00
//Store saved particle index+1 for this partsptr index (0 means not saved)
partsSaveIndex [ i ] = ( partsCount + + ) + 1 ;
2012-06-05 14:08:35 -05:00
//Type (required)
partsData [ partsDataLen + + ] = particles [ i ] . type ;
2012-06-12 11:06:38 -05:00
elementCount [ particles [ i ] . type ] + + ;
2012-06-05 14:08:35 -05:00
//Location of the field descriptor
fieldDescLoc = partsDataLen + + ;
partsDataLen + + ;
//Extra Temperature (2nd byte optional, 1st required), 1 to 2 bytes
//Store temperature as an offset of 21C(294.15K) or go into a 16byte int and store the whole thing
if ( fabs ( particles [ i ] . temp - 294.15f ) < 127 )
{
tempTemp = ( particles [ i ] . temp - 294.15f ) ;
partsData [ partsDataLen + + ] = tempTemp ;
}
else
{
fieldDesc | = 1 ;
tempTemp = particles [ i ] . temp ;
partsData [ partsDataLen + + ] = tempTemp ;
partsData [ partsDataLen + + ] = tempTemp > > 8 ;
}
//Life (optional), 1 to 2 bytes
if ( particles [ i ] . life )
{
fieldDesc | = 1 < < 1 ;
partsData [ partsDataLen + + ] = particles [ i ] . life ;
if ( particles [ i ] . life > 255 )
{
fieldDesc | = 1 < < 2 ;
partsData [ partsDataLen + + ] = particles [ i ] . life > > 8 ;
}
}
//Tmp (optional), 1 to 2 bytes
if ( particles [ i ] . tmp )
{
fieldDesc | = 1 < < 3 ;
partsData [ partsDataLen + + ] = particles [ i ] . tmp ;
if ( particles [ i ] . tmp > 255 )
{
fieldDesc | = 1 < < 4 ;
partsData [ partsDataLen + + ] = particles [ i ] . tmp > > 8 ;
2012-08-20 10:48:03 -05:00
if ( particles [ i ] . tmp > 65535 )
{
fieldDesc | = 1 < < 12 ;
partsData [ partsDataLen + + ] = ( particles [ i ] . tmp & 0xFF000000 ) > > 24 ;
partsData [ partsDataLen + + ] = ( particles [ i ] . tmp & 0x00FF0000 ) > > 16 ;
}
2012-06-05 14:08:35 -05:00
}
}
//Ctype (optional), 1 or 4 bytes
if ( particles [ i ] . ctype )
{
fieldDesc | = 1 < < 5 ;
partsData [ partsDataLen + + ] = particles [ i ] . ctype ;
if ( particles [ i ] . ctype > 255 )
{
fieldDesc | = 1 < < 9 ;
partsData [ partsDataLen + + ] = ( particles [ i ] . ctype & 0xFF000000 ) > > 24 ;
partsData [ partsDataLen + + ] = ( particles [ i ] . ctype & 0x00FF0000 ) > > 16 ;
partsData [ partsDataLen + + ] = ( particles [ i ] . ctype & 0x0000FF00 ) > > 8 ;
}
}
//Dcolour (optional), 4 bytes
if ( particles [ i ] . dcolour & & ( particles [ i ] . dcolour & 0xFF000000 ) )
{
fieldDesc | = 1 < < 6 ;
partsData [ partsDataLen + + ] = ( particles [ i ] . dcolour & 0xFF000000 ) > > 24 ;
partsData [ partsDataLen + + ] = ( particles [ i ] . dcolour & 0x00FF0000 ) > > 16 ;
partsData [ partsDataLen + + ] = ( particles [ i ] . dcolour & 0x0000FF00 ) > > 8 ;
partsData [ partsDataLen + + ] = ( particles [ i ] . dcolour & 0x000000FF ) ;
}
//VX (optional), 1 byte
if ( fabs ( particles [ i ] . vx ) > 0.001f )
{
fieldDesc | = 1 < < 7 ;
vTemp = ( int ) ( particles [ i ] . vx * 16.0f + 127.5f ) ;
if ( vTemp < 0 ) vTemp = 0 ;
if ( vTemp > 255 ) vTemp = 255 ;
partsData [ partsDataLen + + ] = vTemp ;
}
//VY (optional), 1 byte
if ( fabs ( particles [ i ] . vy ) > 0.001f )
{
fieldDesc | = 1 < < 8 ;
vTemp = ( int ) ( particles [ i ] . vy * 16.0f + 127.5f ) ;
if ( vTemp < 0 ) vTemp = 0 ;
if ( vTemp > 255 ) vTemp = 255 ;
partsData [ partsDataLen + + ] = vTemp ;
}
2012-07-25 11:16:56 -05:00
//Tmp2 (optional), 1 or 2 bytes
2012-06-05 14:08:35 -05:00
if ( particles [ i ] . tmp2 )
{
fieldDesc | = 1 < < 10 ;
partsData [ partsDataLen + + ] = particles [ i ] . tmp2 ;
2012-07-25 11:44:29 -05:00
if ( particles [ i ] . tmp2 > 255 )
2012-07-25 11:16:56 -05:00
{
fieldDesc | = 1 < < 11 ;
2012-07-25 11:44:29 -05:00
partsData [ partsDataLen + + ] = particles [ i ] . tmp2 > > 8 ;
2012-07-25 11:16:56 -05:00
}
2012-06-05 14:08:35 -05:00
}
//Write the field descriptor;
partsData [ fieldDescLoc ] = fieldDesc ;
partsData [ fieldDescLoc + 1 ] = fieldDesc > > 8 ;
//Get the pmap entry for the next particle in the same position
i = partsPosLink [ i ] ;
}
}
}
2012-06-12 11:06:38 -05:00
soapLinkData = ( unsigned char * ) malloc ( 3 * elementCount [ PT_SOAP ] ) ;
soapLinkDataLen = 0 ;
//Iterate through particles in the same order that they were saved
for ( y = 0 ; y < fullH ; y + + )
{
for ( x = 0 ; x < fullW ; x + + )
{
//Find the first particle in this position
i = partsPosFirstMap [ y * fullW + x ] ;
//Loop while there is a pmap entry
while ( i )
{
//Turn pmap entry into a partsptr index
i = i > > 8 ;
if ( particles [ i ] . type = = PT_SOAP )
{
//Only save forward link for each particle, back links can be deduced from other forward links
//linkedIndex is index within saved particles + 1, 0 means not saved or no link
unsigned linkedIndex = 0 ;
if ( ( particles [ i ] . ctype & 2 ) & & particles [ i ] . tmp > = 0 & & particles [ i ] . tmp < NPART )
{
linkedIndex = partsSaveIndex [ particles [ i ] . tmp ] ;
}
soapLinkData [ soapLinkDataLen + + ] = ( linkedIndex & 0xFF0000 ) > > 16 ;
soapLinkData [ soapLinkDataLen + + ] = ( linkedIndex & 0x00FF00 ) > > 8 ;
soapLinkData [ soapLinkDataLen + + ] = ( linkedIndex & 0x0000FF ) ;
}
//Get the pmap entry for the next particle in the same position
i = partsPosLink [ i ] ;
}
}
}
if ( ! soapLinkDataLen )
{
free ( soapLinkData ) ;
soapLinkData = NULL ;
}
2012-06-05 14:08:35 -05:00
if ( ! partsDataLen )
{
free ( partsData ) ;
partsData = NULL ;
}
bson_init ( & b ) ;
bson_append_bool ( & b , " waterEEnabled " , waterEEnabled ) ;
bson_append_bool ( & b , " legacyEnable " , legacyEnable ) ;
bson_append_bool ( & b , " gravityEnable " , gravityEnable ) ;
bson_append_bool ( & b , " paused " , paused ) ;
bson_append_int ( & b , " gravityMode " , gravityMode ) ;
bson_append_int ( & b , " airMode " , airMode ) ;
//bson_append_int(&b, "leftSelectedElement", sl);
//bson_append_int(&b, "rightSelectedElement", sr);
//bson_append_int(&b, "activeMenu", active_menu);
if ( partsData )
bson_append_binary ( & b , " parts " , BSON_BIN_USER , ( const char * ) partsData , partsDataLen ) ;
if ( partsPosData )
bson_append_binary ( & b , " partsPos " , BSON_BIN_USER , ( const char * ) partsPosData , partsPosDataLen ) ;
if ( wallData )
bson_append_binary ( & b , " wallMap " , BSON_BIN_USER , ( const char * ) wallData , wallDataLen ) ;
if ( fanData )
bson_append_binary ( & b , " fanMap " , BSON_BIN_USER , ( const char * ) fanData , fanDataLen ) ;
2012-06-12 11:06:38 -05:00
if ( soapLinkData )
bson_append_binary ( & b , " soapLinks " , BSON_BIN_USER , ( const char * ) soapLinkData , soapLinkDataLen ) ;
2012-06-05 14:08:35 -05:00
signsCount = 0 ;
for ( i = 0 ; i < signs . size ( ) ; i + + )
{
if ( signs [ i ] . text . length ( ) & & signs [ i ] . x > = 0 & & signs [ i ] . x < = fullW & & signs [ i ] . y > = 0 & & signs [ i ] . y < = fullH )
{
signsCount + + ;
}
}
if ( signsCount )
{
bson_append_start_array ( & b , " signs " ) ;
for ( i = 0 ; i < signs . size ( ) ; i + + )
{
if ( signs [ i ] . text . length ( ) & & signs [ i ] . x > = 0 & & signs [ i ] . x < = fullW & & signs [ i ] . y > = 0 & & signs [ i ] . y < = fullH )
{
bson_append_start_object ( & b , " sign " ) ;
bson_append_string ( & b , " text " , signs [ i ] . text . c_str ( ) ) ;
bson_append_int ( & b , " justification " , signs [ i ] . ju ) ;
bson_append_int ( & b , " x " , signs [ i ] . x ) ;
bson_append_int ( & b , " y " , signs [ i ] . y ) ;
bson_append_finish_object ( & b ) ;
}
}
2012-07-06 10:08:52 -05:00
bson_append_finish_array ( & b ) ;
2012-06-05 14:08:35 -05:00
}
bson_finish ( & b ) ;
bson_print ( & b ) ;
finalData = ( unsigned char * ) bson_data ( & b ) ;
finalDataLen = bson_size ( & b ) ;
outputDataLen = finalDataLen * 2 + 12 ;
outputData = ( unsigned char * ) malloc ( outputDataLen ) ;
outputData [ 0 ] = ' O ' ;
outputData [ 1 ] = ' P ' ;
outputData [ 2 ] = ' S ' ;
outputData [ 3 ] = ' 1 ' ;
outputData [ 4 ] = SAVE_VERSION ;
outputData [ 5 ] = CELL ;
outputData [ 6 ] = blockW ;
outputData [ 7 ] = blockH ;
outputData [ 8 ] = finalDataLen ;
outputData [ 9 ] = finalDataLen > > 8 ;
outputData [ 10 ] = finalDataLen > > 16 ;
outputData [ 11 ] = finalDataLen > > 24 ;
if ( BZ2_bzBuffToBuffCompress ( ( char * ) ( outputData + 12 ) , & outputDataLen , ( char * ) finalData , bson_size ( & b ) , 9 , 0 , 0 ) ! = BZ_OK )
{
puts ( " Save Error \n " ) ;
free ( outputData ) ;
dataLength = 0 ;
outputData = NULL ;
goto fin ;
}
printf ( " compressed data: %d \n " , outputDataLen ) ;
dataLength = outputDataLen + 12 ;
fin :
bson_destroy ( & b ) ;
if ( partsData )
free ( partsData ) ;
if ( wallData )
free ( wallData ) ;
if ( fanData )
free ( fanData ) ;
2012-06-12 11:06:38 -05:00
if ( elementCount )
delete [ ] elementCount ;
if ( partsSaveIndex )
free ( partsSaveIndex ) ;
if ( soapLinkData )
free ( soapLinkData ) ;
2012-06-05 14:08:35 -05:00
return ( char * ) outputData ;
}
2012-08-19 14:44:50 -05:00
void GameSave : : dealloc ( )
2012-06-05 14:08:35 -05:00
{
2012-06-18 09:54:55 -05:00
if ( particles )
2012-08-19 14:44:50 -05:00
{
2012-06-18 09:54:55 -05:00
delete [ ] particles ;
2012-08-19 14:44:50 -05:00
particles = NULL ;
}
2012-06-18 09:54:55 -05:00
if ( blockMap )
2012-08-19 14:44:50 -05:00
{
2012-06-18 09:54:55 -05:00
delete [ ] blockMap ;
2012-08-19 14:44:50 -05:00
blockMap = NULL ;
}
2012-06-18 09:54:55 -05:00
if ( blockMapPtr )
2012-08-19 14:44:50 -05:00
{
2012-06-18 09:54:55 -05:00
delete [ ] blockMapPtr ;
2012-08-19 14:44:50 -05:00
blockMapPtr = NULL ;
}
2012-06-18 09:54:55 -05:00
if ( fanVelX )
2012-08-19 14:44:50 -05:00
{
2012-06-18 09:54:55 -05:00
delete [ ] fanVelX ;
2012-08-19 14:44:50 -05:00
fanVelX = NULL ;
}
2012-06-18 09:54:55 -05:00
if ( fanVelXPtr )
2012-08-19 14:44:50 -05:00
{
2012-06-18 09:54:55 -05:00
delete [ ] fanVelXPtr ;
2012-08-19 14:44:50 -05:00
fanVelXPtr = NULL ;
}
2012-06-18 09:54:55 -05:00
if ( fanVelY )
2012-08-19 14:44:50 -05:00
{
2012-06-18 09:54:55 -05:00
delete [ ] fanVelY ;
2012-08-19 14:44:50 -05:00
fanVelY = NULL ;
}
2012-06-18 09:54:55 -05:00
if ( fanVelYPtr )
2012-08-19 14:44:50 -05:00
{
2012-06-18 09:54:55 -05:00
delete [ ] fanVelYPtr ;
2012-08-19 14:44:50 -05:00
fanVelYPtr = NULL ;
}
}
GameSave : : ~ GameSave ( )
{
2012-08-19 14:57:14 -05:00
dealloc ( ) ;
2012-06-07 08:23:26 -05:00
}