2012-05-05 20:06:34 -05:00
/**
* Powder Toy - saving and loading functions
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2011-12-29 20:06:31 -06:00
# include <bzlib.h>
2012-01-13 15:21:42 -06:00
# include <math.h>
2011-12-29 20:06:31 -06:00
# include "defines.h"
# include "powder.h"
# include "save.h"
# include "gravity.h"
# include "BSON.h"
2011-12-30 13:48:11 -06:00
//Pop
pixel * prerender_save ( void * save , int size , int * width , int * height )
{
unsigned char * saveData = save ;
2012-01-04 07:45:36 -06:00
if ( size < 16 )
{
return NULL ;
}
2011-12-30 13:48:11 -06:00
if ( saveData [ 0 ] = = ' O ' & & saveData [ 1 ] = = ' P ' & & saveData [ 2 ] = = ' S ' )
{
return prerender_save_OPS ( save , size , width , height ) ;
}
else if ( ( saveData [ 0 ] = = 0x66 & & saveData [ 1 ] = = 0x75 & & saveData [ 2 ] = = 0x43 ) | | ( saveData [ 0 ] = = 0x50 & & saveData [ 1 ] = = 0x53 & & saveData [ 2 ] = = 0x76 ) )
{
return prerender_save_PSv ( save , size , width , height ) ;
}
2012-01-14 11:46:38 -06:00
return NULL ;
2011-12-30 13:48:11 -06:00
}
2011-12-29 20:06:31 -06:00
void * build_save ( int * size , int orig_x0 , int orig_y0 , int orig_w , int orig_h , unsigned char bmap [ YRES / CELL ] [ XRES / CELL ] , float vx [ YRES / CELL ] [ XRES / CELL ] , float vy [ YRES / CELL ] [ XRES / CELL ] , float pv [ YRES / CELL ] [ XRES / CELL ] , float fvx [ YRES / CELL ] [ XRES / CELL ] , float fvy [ YRES / CELL ] [ XRES / CELL ] , sign signs [ MAXSIGNS ] , void * partsptr )
{
return build_save_OPS ( size , orig_x0 , orig_y0 , orig_w , orig_h , bmap , vx , vy , pv , fvx , fvy , signs , partsptr ) ;
}
int parse_save ( void * save , int size , int replace , int x0 , int y0 , unsigned char bmap [ YRES / CELL ] [ XRES / CELL ] , float vx [ YRES / CELL ] [ XRES / CELL ] , float vy [ YRES / CELL ] [ XRES / CELL ] , float pv [ YRES / CELL ] [ XRES / CELL ] , float fvx [ YRES / CELL ] [ XRES / CELL ] , float fvy [ YRES / CELL ] [ XRES / CELL ] , sign signs [ MAXSIGNS ] , void * partsptr , unsigned pmap [ YRES ] [ XRES ] )
{
unsigned char * saveData = save ;
2012-01-04 07:45:36 -06:00
if ( size < 16 )
{
return 1 ;
}
2011-12-29 20:06:31 -06:00
if ( saveData [ 0 ] = = ' O ' & & saveData [ 1 ] = = ' P ' & & saveData [ 2 ] = = ' S ' )
{
return parse_save_OPS ( save , size , replace , x0 , y0 , bmap , vx , vy , pv , fvx , fvy , signs , partsptr , pmap ) ;
}
else if ( ( saveData [ 0 ] = = 0x66 & & saveData [ 1 ] = = 0x75 & & saveData [ 2 ] = = 0x43 ) | | ( saveData [ 0 ] = = 0x50 & & saveData [ 1 ] = = 0x53 & & saveData [ 2 ] = = 0x76 ) )
{
return parse_save_PSv ( save , size , replace , x0 , y0 , bmap , fvx , fvy , signs , partsptr , pmap ) ;
}
2012-01-14 11:46:38 -06:00
return 1 ;
2011-12-29 20:06:31 -06:00
}
2012-03-14 19:07:21 -05:00
int change_wall ( int wt )
{
if ( wt = = 1 )
return WL_WALL ;
else if ( wt = = 2 )
return WL_DESTROYALL ;
else if ( wt = = 3 )
return WL_ALLOWLIQUID ;
else if ( wt = = 4 )
return WL_FAN ;
else if ( wt = = 5 )
return WL_STREAM ;
else if ( wt = = 6 )
return WL_DETECT ;
else if ( wt = = 7 )
return WL_EWALL ;
else if ( wt = = 8 )
return WL_WALLELEC ;
else if ( wt = = 9 )
return WL_ALLOWAIR ;
else if ( wt = = 10 )
return WL_ALLOWSOLID ;
else if ( wt = = 11 )
return WL_ALLOWALLELEC ;
else if ( wt = = 12 )
return WL_EHOLE ;
else if ( wt = = 13 )
return WL_ALLOWGAS ;
return wt ;
}
2011-12-30 13:48:11 -06:00
pixel * prerender_save_OPS ( void * save , int size , int * width , int * height )
{
2012-01-01 08:35:37 -06:00
unsigned char * inputData = save , * bsonData = NULL , * partsData = NULL , * partsPosData = NULL , * wallData = NULL ;
int inputDataLen = size , bsonDataLen = 0 , partsDataLen , partsPosDataLen , wallDataLen ;
2012-03-14 19:07:21 -05:00
int i , x , y , j , wt , pc , gc ;
2012-01-01 08:35:37 -06:00
int blockX , blockY , blockW , blockH , fullX , fullY , fullW , fullH ;
2012-01-19 17:55:54 -06:00
int bsonInitialised = 0 ;
2012-01-01 08:35:37 -06:00
pixel * vidBuf = NULL ;
2012-01-13 15:21:42 -06:00
bson b ;
bson_iterator iter ;
2011-12-30 13:48:11 -06:00
//Block sizes
2012-01-01 08:35:37 -06:00
blockX = 0 ;
blockY = 0 ;
2011-12-30 13:48:11 -06:00
blockW = inputData [ 6 ] ;
blockH = inputData [ 7 ] ;
//Full size, normalised
2012-01-01 08:35:37 -06:00
fullX = 0 ;
fullY = 0 ;
2011-12-30 13:48:11 -06:00
fullW = blockW * CELL ;
fullH = blockH * CELL ;
2012-01-01 08:35:37 -06:00
//
* width = fullW ;
* height = fullH ;
2011-12-30 13:48:11 -06:00
//From newer version
if ( inputData [ 4 ] > SAVE_VERSION )
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Save from newer version \n " ) ;
goto fail ;
2011-12-30 13:48:11 -06:00
}
//Incompatible cell size
if ( inputData [ 5 ] > CELL )
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Cell size mismatch \n " ) ;
goto fail ;
2011-12-30 13:48:11 -06:00
}
//Too large/off screen
2012-01-01 08:35:37 -06:00
if ( blockX + blockW > XRES / CELL | | blockY + blockH > YRES / CELL )
2011-12-30 13:48:11 -06:00
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Save too large \n " ) ;
goto fail ;
}
bsonDataLen = ( ( unsigned ) inputData [ 8 ] ) ;
bsonDataLen | = ( ( unsigned ) inputData [ 9 ] ) < < 8 ;
bsonDataLen | = ( ( unsigned ) inputData [ 10 ] ) < < 16 ;
bsonDataLen | = ( ( unsigned ) inputData [ 11 ] ) < < 24 ;
bsonData = malloc ( bsonDataLen + 1 ) ;
if ( ! bsonData )
{
fprintf ( stderr , " Internal error while parsing save: could not allocate buffer \n " ) ;
goto fail ;
}
//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 ( bsonData , & bsonDataLen , inputData + 12 , inputDataLen - 12 , 0 , 0 ) )
{
fprintf ( stderr , " Unable to decompress \n " ) ;
goto fail ;
2011-12-30 13:48:11 -06:00
}
2012-01-01 08:35:37 -06:00
bson_init_data ( & b , bsonData ) ;
2012-01-19 17:55:54 -06:00
bsonInitialised = 1 ;
2012-01-01 08:35:37 -06:00
bson_iterator_init ( & iter , & b ) ;
while ( bson_iterator_next ( & iter ) )
{
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 = 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 = 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 = 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 ) ;
}
}
}
vidBuf = calloc ( fullW * fullH , PIXELSIZE ) ;
//Read wall and fan data
if ( wallData )
{
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 ] )
{
2012-03-14 19:07:21 -05:00
wt = wallData [ y * blockW + x ] ;
pc = wtypes [ wt - UI_ACTUALSTART ] . colour ;
gc = wtypes [ wt - UI_ACTUALSTART ] . eglow ;
if ( wtypes [ wt - UI_ACTUALSTART ] . drawstyle = = 1 )
2012-01-01 08:35:37 -06:00
{
2012-03-14 19:07:21 -05:00
for ( i = 0 ; i < CELL ; i + = 2 )
for ( j = ( i > > 1 ) & 1 ; j < CELL ; j + = 2 )
vidBuf [ ( fullY + i + ( y * CELL ) ) * fullW + ( fullX + j + ( x * CELL ) ) ] = pc ;
}
else if ( wtypes [ wt - UI_ACTUALSTART ] . drawstyle = = 2 )
{
for ( i = 0 ; i < CELL ; i + = 2 )
for ( j = 0 ; j < CELL ; j + = 2 )
vidBuf [ ( fullY + i + ( y * CELL ) ) * fullW + ( fullX + j + ( x * CELL ) ) ] = pc ;
}
else if ( wtypes [ wt - UI_ACTUALSTART ] . drawstyle = = 3 )
{
for ( i = 0 ; i < CELL ; i + + )
for ( j = 0 ; j < CELL ; j + + )
vidBuf [ ( fullY + i + ( y * CELL ) ) * fullW + ( fullX + j + ( x * CELL ) ) ] = pc ;
}
else if ( wtypes [ wt - UI_ACTUALSTART ] . drawstyle = = 4 )
{
for ( i = 0 ; i < CELL ; i + + )
for ( j = 0 ; j < CELL ; j + + )
if ( i = = j )
vidBuf [ ( fullY + i + ( y * CELL ) ) * fullW + ( fullX + j + ( x * CELL ) ) ] = pc ;
else if ( j = = i + 1 | | ( j = = 0 & & i = = CELL - 1 ) )
vidBuf [ ( fullY + i + ( y * CELL ) ) * fullW + ( fullX + j + ( x * CELL ) ) ] = gc ;
else
vidBuf [ ( fullY + i + ( y * CELL ) ) * fullW + ( fullX + j + ( x * CELL ) ) ] = PIXPACK ( 0x202020 ) ;
}
// special rendering for some walls
if ( wt = = WL_EWALL )
{
for ( i = 0 ; i < CELL ; i + + )
for ( j = 0 ; j < CELL ; j + + )
if ( ! ( i & j & 1 ) )
vidBuf [ ( fullY + i + ( y * CELL ) ) * fullW + ( fullX + j + ( x * CELL ) ) ] = pc ;
}
else if ( wt = = WL_WALLELEC )
{
for ( i = 0 ; i < CELL ; i + + )
for ( j = 0 ; j < CELL ; j + + )
{
if ( ! ( ( y * CELL + j ) % 2 ) & & ! ( ( x * CELL + i ) % 2 ) )
vidBuf [ ( fullY + i + ( y * CELL ) ) * fullW + ( fullX + j + ( x * CELL ) ) ] = pc ;
else
vidBuf [ ( fullY + i + ( y * CELL ) ) * fullW + ( fullX + j + ( x * CELL ) ) ] = PIXPACK ( 0x808080 ) ;
}
}
else if ( wt = = WL_EHOLE )
{
for ( i = 0 ; i < CELL ; i + = 2 )
for ( j = 0 ; j < CELL ; j + = 2 )
vidBuf [ ( fullY + i + ( y * CELL ) ) * fullW + ( fullX + j + ( x * CELL ) ) ] = PIXPACK ( 0x242424 ) ;
2012-01-01 08:35:37 -06:00
}
2012-03-14 19:07:21 -05:00
}
2012-01-01 08:35:37 -06:00
}
}
}
2011-12-30 13:48:11 -06:00
2012-01-01 08:35:37 -06:00
//Read particle data
if ( partsData & & partsPosData )
{
int fieldDescriptor ;
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 ;
}
i = 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 + + )
{
//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 ;
if ( x > = XRES | | x < 0 | | y > = YRES | | y < 0 )
{
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 )
2012-01-17 18:20:52 -06:00
partsData [ i ] = PT_DMND ; //Replace all invalid elements with diamond
2012-01-01 08:35:37 -06:00
//Draw type
2012-01-25 14:04:14 -06:00
if ( partsData [ i ] = = PT_STKM | | partsData [ i ] = = PT_STKM2 | | partsData [ i ] = = PT_FIGH )
{
pixel lc , hc = PIXRGB ( 255 , 224 , 178 ) ;
if ( partsData [ i ] = = PT_STKM | | partsData [ i ] = = PT_FIGH ) lc = PIXRGB ( 255 , 255 , 255 ) ;
else lc = PIXRGB ( 100 , 100 , 255 ) ;
//only need to check upper bound of y coord - lower bounds and x<w are checked in draw_line
if ( partsData [ i ] = = PT_STKM | | partsData [ i ] = = PT_STKM2 )
{
draw_line ( vidBuf , x - 2 , y - 2 , x + 2 , y - 2 , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , * width ) ;
if ( y + 2 < * height )
{
draw_line ( vidBuf , x - 2 , y + 2 , x + 2 , y + 2 , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , * width ) ;
draw_line ( vidBuf , x - 2 , y - 2 , x - 2 , y + 2 , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , * width ) ;
draw_line ( vidBuf , x + 2 , y - 2 , x + 2 , y + 2 , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , * width ) ;
}
}
else if ( y + 2 < * height )
{
draw_line ( vidBuf , x - 2 , y , x , y - 2 , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , * width ) ;
draw_line ( vidBuf , x - 2 , y , x , y + 2 , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , * width ) ;
draw_line ( vidBuf , x , y - 2 , x + 2 , y , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , * width ) ;
draw_line ( vidBuf , x , y + 2 , x + 2 , y , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , * width ) ;
}
if ( y + 6 < * height )
{
draw_line ( vidBuf , x , y + 3 , x - 1 , y + 6 , PIXR ( lc ) , PIXG ( lc ) , PIXB ( lc ) , * width ) ;
draw_line ( vidBuf , x , y + 3 , x + 1 , y + 6 , PIXR ( lc ) , PIXG ( lc ) , PIXB ( lc ) , * width ) ;
}
if ( y + 12 < * height )
{
draw_line ( vidBuf , x - 1 , y + 6 , x - 3 , y + 12 , PIXR ( lc ) , PIXG ( lc ) , PIXB ( lc ) , * width ) ;
draw_line ( vidBuf , x + 1 , y + 6 , x + 3 , y + 12 , PIXR ( lc ) , PIXG ( lc ) , PIXB ( lc ) , * width ) ;
}
}
else
vidBuf [ ( fullY + y ) * fullW + ( fullX + x ) ] = ptypes [ partsData [ i ] ] . pcolors ;
i + = 3 ; //Skip Type and Descriptor
2012-01-01 08:35:37 -06:00
//Skip temp
if ( fieldDescriptor & 0x01 )
{
i + = 2 ;
}
else
{
i + + ;
}
//Skip life
if ( fieldDescriptor & 0x02 )
{
if ( i + + > = partsDataLen ) goto fail ;
if ( fieldDescriptor & 0x04 )
{
if ( i + + > = partsDataLen ) goto fail ;
}
}
//Skip tmp
if ( fieldDescriptor & 0x08 )
{
if ( i + + > = partsDataLen ) goto fail ;
if ( fieldDescriptor & 0x10 )
{
if ( i + + > = partsDataLen ) goto fail ;
}
}
//Skip ctype
if ( fieldDescriptor & 0x20 )
{
if ( i + + > = partsDataLen ) goto fail ;
2012-01-04 08:29:22 -06:00
if ( fieldDescriptor & 0x200 )
{
if ( i + 2 > = partsDataLen ) goto fail ;
i + = 3 ;
}
2012-01-01 08:35:37 -06:00
}
2012-01-17 18:20:52 -06:00
//Read dcolour
2012-01-01 08:35:37 -06:00
if ( fieldDescriptor & 0x40 )
{
2012-01-25 13:36:54 -06:00
unsigned char r , g , b ;
2012-01-01 08:35:37 -06:00
if ( i + 3 > = partsDataLen ) goto fail ;
2012-01-25 13:36:54 -06:00
i + + ; //Skip alpha
r = partsData [ i + + ] ;
g = partsData [ i + + ] ;
b = partsData [ i + + ] ;
vidBuf [ ( fullY + y ) * fullW + ( fullX + x ) ] = PIXRGB ( r , g , b ) ;
2012-01-01 08:35:37 -06:00
}
2012-01-17 18:20:52 -06:00
//Skip vx
2012-01-01 08:35:37 -06:00
if ( fieldDescriptor & 0x80 )
{
if ( i + + > = partsDataLen ) goto fail ;
}
2012-01-17 18:20:52 -06:00
//Skip vy
2012-01-01 08:35:37 -06:00
if ( fieldDescriptor & 0x100 )
{
if ( i + + > = partsDataLen ) goto fail ;
}
2012-01-17 18:20:52 -06:00
//Skip tmp2
if ( fieldDescriptor & 0x400 )
{
if ( i + + > = partsDataLen ) goto fail ;
}
2012-01-01 08:35:37 -06:00
}
}
}
}
goto fin ;
fail :
if ( vidBuf )
{
free ( vidBuf ) ;
vidBuf = NULL ;
}
fin :
2012-01-19 17:55:54 -06:00
//Don't call bson_destroy if bson_init wasn't called, or an uninitialised pointer (b.data) will be freed and the game will crash
if ( bsonInitialised )
bson_destroy ( & b ) ;
2012-01-01 08:35:37 -06:00
return vidBuf ;
2011-12-30 13:48:11 -06:00
}
2011-12-29 20:06:31 -06:00
void * build_save_OPS ( int * size , int orig_x0 , int orig_y0 , int orig_w , int orig_h , unsigned char bmap [ YRES / CELL ] [ XRES / CELL ] , float vx [ YRES / CELL ] [ XRES / CELL ] , float vy [ YRES / CELL ] [ XRES / CELL ] , float pv [ YRES / CELL ] [ XRES / CELL ] , float fvx [ YRES / CELL ] [ XRES / CELL ] , float fvy [ YRES / CELL ] [ XRES / CELL ] , sign signs [ MAXSIGNS ] , void * o_partsptr )
{
particle * partsptr = o_partsptr ;
2012-04-29 09:31:18 -05:00
unsigned char * partsData = NULL , * partsPosData = NULL , * fanData = NULL , * wallData = NULL , * finalData = NULL , * outputData = NULL , * soapLinkData = NULL ;
2011-12-31 10:49:18 -06:00
unsigned * partsPosLink = NULL , * partsPosFirstMap = NULL , * partsPosCount = NULL , * partsPosLastMap = NULL ;
2012-04-29 09:31:18 -05:00
unsigned partsCount = 0 , * partsSaveIndex = NULL ;
unsigned * elementCount = calloc ( PT_NUM , sizeof ( unsigned ) ) ;
int partsDataLen , partsPosDataLen , fanDataLen , wallDataLen , finalDataLen , outputDataLen , soapLinkDataLen ;
2011-12-29 20:06:31 -06:00
int blockX , blockY , blockW , blockH , fullX , fullY , fullW , fullH ;
int x , y , i , wallDataFound = 0 ;
2011-12-31 12:57:42 -06:00
int posCount , signsCount ;
2012-01-13 15:21:42 -06:00
bson b ;
2011-12-29 20:06:31 -06:00
//Get coords in blocks
blockX = orig_x0 / CELL ;
blockY = orig_y0 / CELL ;
2011-12-31 10:49:18 -06:00
2011-12-29 20:06:31 -06:00
//Snap full coords to block size
fullX = blockX * CELL ;
fullY = blockY * CELL ;
2011-12-31 10:49:18 -06:00
//Original size + offset of original corner from snapped corner, rounded up by adding CELL-1
blockW = ( orig_w + orig_x0 - fullX + CELL - 1 ) / CELL ;
blockH = ( orig_h + orig_y0 - fullY + CELL - 1 ) / CELL ;
2011-12-29 20:06:31 -06:00
fullW = blockW * CELL ;
fullH = blockH * CELL ;
//Copy fan and wall data
wallData = malloc ( blockW * blockH ) ;
wallDataLen = blockW * blockH ;
2011-12-30 13:48:11 -06:00
fanData = malloc ( ( blockW * blockH ) * 2 ) ;
2011-12-29 20:06:31 -06:00
fanDataLen = 0 ;
for ( x = blockX ; x < blockX + blockW ; x + + )
{
for ( y = blockY ; y < blockY + blockH ; y + + )
{
2011-12-30 13:48:11 -06:00
wallData [ ( y - blockY ) * blockW + ( x - blockX ) ] = bmap [ y ] [ x ] ;
2011-12-29 20:06:31 -06:00
if ( bmap [ y ] [ x ] & & ! wallDataFound )
wallDataFound = 1 ;
2012-03-14 19:07:21 -05:00
if ( bmap [ y ] [ x ] = = WL_FAN )
2011-12-29 20:06:31 -06:00
{
2011-12-30 13:48:11 -06:00
i = ( int ) ( fvx [ y ] [ x ] * 64.0f + 127.5f ) ;
if ( i < 0 ) i = 0 ;
if ( i > 255 ) i = 255 ;
fanData [ fanDataLen + + ] = i ;
2011-12-29 20:06:31 -06:00
i = ( int ) ( fvy [ 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 ;
}
2011-12-31 10:49:18 -06:00
//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 = calloc ( fullW * fullH , sizeof ( unsigned ) ) ;
partsPosLastMap = calloc ( fullW * fullH , sizeof ( unsigned ) ) ;
partsPosCount = calloc ( fullW * fullH , sizeof ( unsigned ) ) ;
partsPosLink = calloc ( NPART , sizeof ( unsigned ) ) ;
for ( i = 0 ; i < NPART ; i + + )
{
if ( partsptr [ i ] . type )
{
x = ( int ) ( partsptr [ i ] . x + 0.5f ) ;
y = ( int ) ( partsptr [ i ] . y + 0.5f ) ;
if ( x > = orig_x0 & & x < orig_x0 + orig_w & & y > = orig_y0 & & y < orig_y0 + orig_h )
{
//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 = 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 ) ;
}
}
2011-12-29 20:06:31 -06:00
//Copy parts data
/* Field descriptor format:
2011-12-31 12:57:42 -06:00
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2012-01-17 18:20:52 -06:00
| tmp2 | ctype [ 2 ] | vy | vx | dcololour | ctype [ 1 ] | tmp [ 2 ] | tmp [ 1 ] | life [ 2 ] | life [ 1 ] | temp dbl len |
2011-12-29 20:06:31 -06:00
life [ 2 ] means a second byte ( for a 16 bit field ) if life [ 1 ] is present
*/
partsData = malloc ( NPART * ( sizeof ( particle ) + 1 ) ) ;
partsDataLen = 0 ;
2012-04-29 09:31:18 -05:00
partsSaveIndex = calloc ( NPART , sizeof ( unsigned ) ) ;
partsCount = 0 ;
2011-12-31 10:49:18 -06:00
for ( y = 0 ; y < fullH ; y + + )
2011-12-29 20:06:31 -06:00
{
2011-12-31 10:49:18 -06:00
for ( x = 0 ; x < fullW ; x + + )
2011-12-29 20:06:31 -06:00
{
2011-12-31 10:49:18 -06:00
//Find the first particle in this position
i = partsPosFirstMap [ y * fullW + x ] ;
//Loop while there is a pmap entry
while ( i )
2011-12-29 20:06:31 -06:00
{
2011-12-31 12:57:42 -06:00
unsigned short fieldDesc = 0 ;
2011-12-29 20:06:31 -06:00
int fieldDescLoc = 0 , tempTemp , vTemp ;
2011-12-31 10:49:18 -06:00
//Turn pmap entry into a partsptr index
i = i > > 8 ;
2012-04-29 09:31:18 -05:00
//Store saved particle index+1 for this partsptr index (0 means not saved)
partsSaveIndex [ i ] = ( partsCount + + ) + 1 ;
2011-12-29 20:06:31 -06:00
//Type (required)
partsData [ partsDataLen + + ] = partsptr [ i ] . type ;
2012-04-29 09:31:18 -05:00
elementCount [ partsptr [ i ] . type ] + + ;
2011-12-29 20:06:31 -06:00
//Location of the field descriptor
fieldDescLoc = partsDataLen + + ;
2011-12-31 12:57:42 -06:00
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 ( partsptr [ i ] . temp - 294.15f ) < 127 )
{
tempTemp = ( partsptr [ i ] . temp - 294.15f ) ;
partsData [ partsDataLen + + ] = tempTemp ;
}
else
{
fieldDesc | = 1 ;
tempTemp = partsptr [ i ] . temp ;
partsData [ partsDataLen + + ] = tempTemp ;
partsData [ partsDataLen + + ] = tempTemp > > 8 ;
}
2011-12-29 20:06:31 -06:00
//Life (optional), 1 to 2 bytes
if ( partsptr [ i ] . life )
{
2011-12-31 12:57:42 -06:00
fieldDesc | = 1 < < 1 ;
2011-12-29 20:06:31 -06:00
partsData [ partsDataLen + + ] = partsptr [ i ] . life ;
if ( partsptr [ i ] . life > 255 )
{
2011-12-31 12:57:42 -06:00
fieldDesc | = 1 < < 2 ;
2011-12-29 20:06:31 -06:00
partsData [ partsDataLen + + ] = partsptr [ i ] . life > > 8 ;
}
}
//Tmp (optional), 1 to 2 bytes
if ( partsptr [ i ] . tmp )
{
2011-12-31 12:57:42 -06:00
fieldDesc | = 1 < < 3 ;
2011-12-29 20:06:31 -06:00
partsData [ partsDataLen + + ] = partsptr [ i ] . tmp ;
if ( partsptr [ i ] . tmp > 255 )
{
2011-12-31 12:57:42 -06:00
fieldDesc | = 1 < < 4 ;
2011-12-29 20:06:31 -06:00
partsData [ partsDataLen + + ] = partsptr [ i ] . tmp > > 8 ;
}
}
2012-01-04 08:29:22 -06:00
//Ctype (optional), 1 or 4 bytes
2011-12-29 20:06:31 -06:00
if ( partsptr [ i ] . ctype )
{
2011-12-31 12:57:42 -06:00
fieldDesc | = 1 < < 5 ;
2011-12-29 20:06:31 -06:00
partsData [ partsDataLen + + ] = partsptr [ i ] . ctype ;
2012-01-04 08:29:22 -06:00
if ( partsptr [ i ] . ctype > 255 )
{
fieldDesc | = 1 < < 9 ;
partsData [ partsDataLen + + ] = ( partsptr [ i ] . ctype & 0xFF000000 ) > > 24 ;
partsData [ partsDataLen + + ] = ( partsptr [ i ] . ctype & 0x00FF0000 ) > > 16 ;
partsData [ partsDataLen + + ] = ( partsptr [ i ] . ctype & 0x0000FF00 ) > > 8 ;
}
2011-12-29 20:06:31 -06:00
}
//Dcolour (optional), 4 bytes
if ( partsptr [ i ] . dcolour & & ( partsptr [ i ] . dcolour & 0xFF000000 ) )
{
2011-12-31 12:57:42 -06:00
fieldDesc | = 1 < < 6 ;
2011-12-29 20:06:31 -06:00
partsData [ partsDataLen + + ] = ( partsptr [ i ] . dcolour & 0xFF000000 ) > > 24 ;
partsData [ partsDataLen + + ] = ( partsptr [ i ] . dcolour & 0x00FF0000 ) > > 16 ;
partsData [ partsDataLen + + ] = ( partsptr [ i ] . dcolour & 0x0000FF00 ) > > 8 ;
partsData [ partsDataLen + + ] = ( partsptr [ i ] . dcolour & 0x000000FF ) ;
}
//VX (optional), 1 byte
if ( fabs ( partsptr [ i ] . vx ) > 0.001f )
{
2011-12-31 12:57:42 -06:00
fieldDesc | = 1 < < 7 ;
2011-12-29 20:06:31 -06:00
vTemp = ( int ) ( partsptr [ 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 ( partsptr [ i ] . vy ) > 0.001f )
{
2011-12-31 12:57:42 -06:00
fieldDesc | = 1 < < 8 ;
2011-12-29 20:06:31 -06:00
vTemp = ( int ) ( partsptr [ i ] . vy * 16.0f + 127.5f ) ;
if ( vTemp < 0 ) vTemp = 0 ;
if ( vTemp > 255 ) vTemp = 255 ;
partsData [ partsDataLen + + ] = vTemp ;
}
2012-01-17 18:20:52 -06:00
//Tmp2 (optional), 1 byte
if ( partsptr [ i ] . tmp2 )
{
fieldDesc | = 1 < < 10 ;
partsData [ partsDataLen + + ] = partsptr [ i ] . tmp2 ;
}
2011-12-29 20:06:31 -06:00
//Write the field descriptor;
partsData [ fieldDescLoc ] = fieldDesc ;
2011-12-31 12:57:42 -06:00
partsData [ fieldDescLoc + 1 ] = fieldDesc > > 8 ;
2011-12-31 10:49:18 -06:00
//Get the pmap entry for the next particle in the same position
i = partsPosLink [ i ] ;
2011-12-29 20:06:31 -06:00
}
}
}
2012-04-29 09:31:18 -05:00
soapLinkData = 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 ( partsptr [ 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 ( ( partsptr [ i ] . ctype & 2 ) & & partsptr [ i ] . tmp > = 0 & & partsptr [ i ] . tmp < NPART )
{
linkedIndex = partsSaveIndex [ partsptr [ 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 ;
}
2011-12-30 13:48:11 -06:00
if ( ! partsDataLen )
{
free ( partsData ) ;
partsData = NULL ;
}
2011-12-29 20:06:31 -06:00
bson_init ( & b ) ;
2012-01-01 12:32:07 -06:00
bson_append_bool ( & b , " waterEEnabled " , water_equal_test ) ;
2011-12-30 13:48:11 -06:00
bson_append_bool ( & b , " legacyEnable " , legacy_enable ) ;
bson_append_bool ( & b , " gravityEnable " , ngrav_enable ) ;
bson_append_bool ( & b , " paused " , sys_pause ) ;
bson_append_int ( & b , " gravityMode " , gravityMode ) ;
bson_append_int ( & b , " airMode " , airMode ) ;
2012-01-02 07:59:28 -06:00
//bson_append_int(&b, "leftSelectedElement", sl);
//bson_append_int(&b, "rightSelectedElement", sr);
bson_append_int ( & b , " activeMenu " , active_menu ) ;
2011-12-29 20:06:31 -06:00
if ( partsData )
bson_append_binary ( & b , " parts " , BSON_BIN_USER , partsData , partsDataLen ) ;
2011-12-31 10:49:18 -06:00
if ( partsPosData )
bson_append_binary ( & b , " partsPos " , BSON_BIN_USER , partsPosData , partsPosDataLen ) ;
2011-12-29 20:06:31 -06:00
if ( wallData )
bson_append_binary ( & b , " wallMap " , BSON_BIN_USER , wallData , wallDataLen ) ;
if ( fanData )
bson_append_binary ( & b , " fanMap " , BSON_BIN_USER , fanData , fanDataLen ) ;
2012-04-29 09:31:18 -05:00
if ( soapLinkData )
bson_append_binary ( & b , " soapLinks " , BSON_BIN_USER , soapLinkData , soapLinkDataLen ) ;
2011-12-31 12:57:42 -06:00
signsCount = 0 ;
for ( i = 0 ; i < MAXSIGNS ; i + + )
{
2012-04-28 18:11:54 -05:00
if ( signs [ i ] . text [ 0 ] & & signs [ i ] . x > = orig_x0 & & signs [ i ] . x < = orig_x0 + orig_w & & signs [ i ] . y > = orig_y0 & & signs [ i ] . y < = orig_y0 + orig_h )
2011-12-31 12:57:42 -06:00
{
signsCount + + ;
}
}
if ( signsCount )
{
bson_append_start_array ( & b , " signs " ) ;
for ( i = 0 ; i < MAXSIGNS ; i + + )
{
2012-04-28 18:11:54 -05:00
if ( signs [ i ] . text [ 0 ] & & signs [ i ] . x > = orig_x0 & & signs [ i ] . x < = orig_x0 + orig_w & & signs [ i ] . y > = orig_y0 & & signs [ i ] . y < = orig_y0 + orig_h )
2011-12-31 12:57:42 -06:00
{
bson_append_start_object ( & b , " sign " ) ;
bson_append_string ( & b , " text " , signs [ i ] . text ) ;
bson_append_int ( & b , " justification " , signs [ i ] . ju ) ;
bson_append_int ( & b , " x " , signs [ i ] . x - fullX ) ;
bson_append_int ( & b , " y " , signs [ i ] . y - fullY ) ;
bson_append_finish_object ( & b ) ;
}
}
}
bson_append_finish_array ( & b ) ;
2011-12-29 20:06:31 -06:00
bson_finish ( & b ) ;
bson_print ( & b ) ;
finalData = bson_data ( & b ) ;
finalDataLen = bson_size ( & b ) ;
outputDataLen = finalDataLen * 2 + 12 ;
outputData = 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 ( outputData + 12 , & outputDataLen , finalData , bson_size ( & b ) , 9 , 0 , 0 ) ! = BZ_OK )
{
puts ( " Save Error \n " ) ;
free ( outputData ) ;
* size = 0 ;
outputData = NULL ;
goto fin ;
}
2011-12-31 10:49:18 -06:00
printf ( " compressed data: %d \n " , outputDataLen ) ;
2011-12-29 20:06:31 -06:00
* size = outputDataLen + 12 ;
fin :
bson_destroy ( & b ) ;
if ( partsData )
free ( partsData ) ;
if ( wallData )
free ( wallData ) ;
if ( fanData )
free ( fanData ) ;
2012-04-29 09:31:18 -05:00
if ( elementCount )
free ( elementCount ) ;
if ( partsSaveIndex )
free ( partsSaveIndex ) ;
if ( soapLinkData )
free ( soapLinkData ) ;
2011-12-29 20:06:31 -06:00
return outputData ;
}
int parse_save_OPS ( void * save , int size , int replace , int x0 , int y0 , unsigned char bmap [ YRES / CELL ] [ XRES / CELL ] , float vx [ YRES / CELL ] [ XRES / CELL ] , float vy [ YRES / CELL ] [ XRES / CELL ] , float pv [ YRES / CELL ] [ XRES / CELL ] , float fvx [ YRES / CELL ] [ XRES / CELL ] , float fvy [ YRES / CELL ] [ XRES / CELL ] , sign signs [ MAXSIGNS ] , void * o_partsptr , unsigned pmap [ YRES ] [ XRES ] )
{
particle * partsptr = o_partsptr ;
2012-04-29 09:31:18 -05:00
unsigned char * inputData = save , * bsonData = NULL , * partsData = NULL , * partsPosData = NULL , * fanData = NULL , * wallData = NULL , * soapLinkData = NULL ;
int inputDataLen = size , bsonDataLen = 0 , partsDataLen , partsPosDataLen , fanDataLen , wallDataLen , soapLinkDataLen ;
unsigned partsCount = 0 , * partsSimIndex = NULL ;
2011-12-30 13:48:11 -06:00
int i , freeIndicesCount , x , y , returnCode = 0 , j ;
2011-12-29 20:06:31 -06:00
int * freeIndices = NULL ;
2011-12-30 13:48:11 -06:00
int blockX , blockY , blockW , blockH , fullX , fullY , fullW , fullH ;
2012-01-13 15:21:42 -06:00
bson b ;
bson_iterator iter ;
2011-12-30 13:48:11 -06:00
//Block sizes
blockX = x0 / CELL ;
blockY = y0 / CELL ;
blockW = inputData [ 6 ] ;
blockH = inputData [ 7 ] ;
//Full size, normalised
fullX = blockX * CELL ;
fullY = blockY * CELL ;
fullW = blockW * CELL ;
fullH = blockH * CELL ;
//From newer version
if ( inputData [ 4 ] > SAVE_VERSION )
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Save from newer version \n " ) ;
2011-12-30 13:48:11 -06:00
return 2 ;
}
//Incompatible cell size
if ( inputData [ 5 ] > CELL )
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Cell size mismatch \n " ) ;
2011-12-30 13:48:11 -06:00
return 1 ;
}
//Too large/off screen
if ( blockX + blockW > XRES / CELL | | blockY + blockH > YRES / CELL )
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Save too large \n " ) ;
2011-12-30 13:48:11 -06:00
return 1 ;
}
2011-12-29 20:06:31 -06:00
bsonDataLen = ( ( unsigned ) inputData [ 8 ] ) ;
bsonDataLen | = ( ( unsigned ) inputData [ 9 ] ) < < 8 ;
bsonDataLen | = ( ( unsigned ) inputData [ 10 ] ) < < 16 ;
bsonDataLen | = ( ( unsigned ) inputData [ 11 ] ) < < 24 ;
2011-12-31 10:49:18 -06:00
bsonData = malloc ( bsonDataLen + 1 ) ;
2011-12-29 20:06:31 -06:00
if ( ! bsonData )
{
fprintf ( stderr , " Internal error while parsing save: could not allocate buffer \n " ) ;
return 3 ;
}
2011-12-31 10:49:18 -06: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 ;
2011-12-29 20:06:31 -06:00
if ( BZ2_bzBuffToBuffDecompress ( bsonData , & bsonDataLen , inputData + 12 , inputDataLen - 12 , 0 , 0 ) )
2011-12-30 13:48:11 -06:00
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Unable to decompress \n " ) ;
2011-12-29 20:06:31 -06:00
return 1 ;
2011-12-30 13:48:11 -06:00
}
2011-12-29 20:06:31 -06:00
2011-12-31 12:57:42 -06:00
if ( replace )
{
//Remove everything
clear_sim ( ) ;
2012-05-31 06:20:41 -05:00
erase_bframe ( ) ;
2011-12-31 12:57:42 -06:00
}
2011-12-29 20:06:31 -06:00
bson_init_data ( & b , bsonData ) ;
bson_iterator_init ( & iter , & b ) ;
2011-12-31 12:57:42 -06:00
while ( bson_iterator_next ( & iter ) )
2011-12-29 20:06:31 -06:00
{
2011-12-31 12:57:42 -06:00
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 ) ;
//Find a free sign ID
for ( i = 0 ; i < MAXSIGNS ; i + + )
if ( ! signs [ i ] . text [ 0 ] )
break ;
//Stop reading signs if we have no free spaces
if ( i > = MAXSIGNS )
break ;
while ( bson_iterator_next ( & signiter ) )
{
if ( strcmp ( bson_iterator_key ( & signiter ) , " text " ) = = 0 & & bson_iterator_type ( & signiter ) = = BSON_STRING )
{
2012-04-30 08:36:45 -05:00
strncpy ( signs [ i ] . text , bson_iterator_string ( & signiter ) , 255 ) ;
2011-12-31 12:57:42 -06:00
clean_text ( signs [ i ] . text , 158 - 14 ) ;
}
else if ( strcmp ( bson_iterator_key ( & signiter ) , " justification " ) = = 0 & & bson_iterator_type ( & signiter ) = = BSON_INT )
{
signs [ i ] . ju = bson_iterator_int ( & signiter ) ;
}
else if ( strcmp ( bson_iterator_key ( & signiter ) , " x " ) = = 0 & & bson_iterator_type ( & signiter ) = = BSON_INT )
{
signs [ i ] . x = bson_iterator_int ( & signiter ) + fullX ;
}
else if ( strcmp ( bson_iterator_key ( & signiter ) , " y " ) = = 0 & & bson_iterator_type ( & signiter ) = = BSON_INT )
{
signs [ i ] . y = bson_iterator_int ( & signiter ) + fullY ;
}
else
{
fprintf ( stderr , " Unknown sign property %s \n " , bson_iterator_key ( & signiter ) ) ;
}
}
}
else
{
2012-01-14 11:46:38 -06:00
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & subiter ) ) ;
2011-12-31 12:57:42 -06:00
}
}
}
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
else if ( strcmp ( bson_iterator_key ( & iter ) , " parts " ) = = 0 )
2011-12-29 20:06:31 -06:00
{
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 = 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 ) ;
}
}
2011-12-31 10:49:18 -06:00
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 = 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 ) ;
}
}
2011-12-30 13:48:11 -06:00
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 = 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 = 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-04-29 09:31:18 -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 = 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 ) ;
}
}
2011-12-30 13:48:11 -06:00
else if ( strcmp ( bson_iterator_key ( & iter ) , " legacyEnable " ) = = 0 & & replace )
{
if ( bson_iterator_type ( & iter ) = = BSON_BOOL )
{
legacy_enable = ( ( int ) bson_iterator_bool ( & iter ) ) ? 1 : 0 ;
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
else if ( strcmp ( bson_iterator_key ( & iter ) , " gravityEnable " ) = = 0 & & replace )
{
if ( bson_iterator_type ( & iter ) = = BSON_BOOL )
{
int tempGrav = ngrav_enable ;
tempGrav = ( ( int ) bson_iterator_bool ( & iter ) ) ? 1 : 0 ;
# ifndef RENDERER
//Change the gravity state
if ( ngrav_enable ! = tempGrav )
{
if ( tempGrav )
start_grav_async ( ) ;
else
stop_grav_async ( ) ;
}
# endif
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
2012-01-01 12:32:07 -06:00
else if ( strcmp ( bson_iterator_key ( & iter ) , " waterEEnabled " ) = = 0 & & replace )
{
if ( bson_iterator_type ( & iter ) = = BSON_BOOL )
{
water_equal_test = ( ( int ) bson_iterator_bool ( & iter ) ) ? 1 : 0 ;
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
2011-12-30 13:48:11 -06:00
else if ( strcmp ( bson_iterator_key ( & iter ) , " paused " ) = = 0 & & ! sys_pause )
{
if ( bson_iterator_type ( & iter ) = = BSON_BOOL )
{
sys_pause = ( ( int ) bson_iterator_bool ( & iter ) ) ? 1 : 0 ;
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
else if ( strcmp ( bson_iterator_key ( & iter ) , " gravityMode " ) = = 0 & & replace )
{
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 & & replace )
{
if ( bson_iterator_type ( & iter ) = = BSON_INT )
{
airMode = bson_iterator_int ( & iter ) ;
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
2012-01-02 07:59:28 -06:00
/*else if((strcmp(bson_iterator_key(&iter), "leftSelectedElement")==0 || strcmp(bson_iterator_key(&iter), "rightSelectedElement")) && replace)
{
if ( bson_iterator_type ( & iter ) = = BSON_INT & & bson_iterator_int ( & iter ) > 0 & & bson_iterator_int ( & iter ) < PT_NUM )
{
if ( bson_iterator_key ( & iter ) [ 0 ] = = ' l ' )
{
sl = bson_iterator_int ( & iter ) ;
}
else
{
sr = bson_iterator_int ( & iter ) ;
}
}
else
{
fprintf ( stderr , " Wrong type for %s \n " , bson_iterator_key ( & iter ) ) ;
}
} */
else if ( strcmp ( bson_iterator_key ( & iter ) , " activeMenu " ) = = 0 & & replace )
{
if ( bson_iterator_type ( & iter ) = = BSON_INT & & bson_iterator_int ( & iter ) > 0 & & bson_iterator_int ( & iter ) < SC_TOTAL & & msections [ bson_iterator_int ( & iter ) ] . doshow )
{
active_menu = bson_iterator_int ( & iter ) ;
}
else
{
fprintf ( stderr , " Wrong value for %s \n " , bson_iterator_key ( & iter ) ) ;
}
}
2011-12-30 13:48:11 -06:00
}
//Read wall and fan data
if ( wallData )
{
j = 0 ;
if ( blockW * blockH > wallDataLen )
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Not enough wall data \n " ) ;
2011-12-30 13:48:11 -06:00
goto fail ;
}
for ( x = 0 ; x < blockW ; x + + )
{
for ( y = 0 ; y < blockH ; y + + )
{
2012-03-14 19:07:21 -05:00
if ( wallData [ y * blockW + x ] )
bmap [ blockY + y ] [ blockX + x ] = wallData [ y * blockW + x ] ;
if ( wallData [ y * blockW + x ] = = WL_FAN & & fanData )
2011-12-30 13:48:11 -06:00
{
if ( j + 1 > = fanDataLen )
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Not enough fan data \n " ) ;
2011-12-30 13:48:11 -06:00
}
fvx [ blockY + y ] [ blockX + x ] = ( fanData [ j + + ] - 127.0f ) / 64.0f ;
fvy [ blockY + y ] [ blockX + x ] = ( fanData [ j + + ] - 127.0f ) / 64.0f ;
}
}
}
2012-05-20 18:15:51 -05:00
gravity_mask ( ) ;
2011-12-29 20:06:31 -06:00
}
//Read particle data
2011-12-31 10:49:18 -06:00
if ( partsData & & partsPosData )
2011-12-29 20:06:31 -06:00
{
int newIndex = 0 , fieldDescriptor , tempTemp ;
2011-12-31 10:49:18 -06:00
int posCount , posTotal , partsPosDataIndex = 0 ;
int saved_x , saved_y ;
2012-01-04 07:45:36 -06:00
int freeIndicesIndex = 0 ;
2011-12-31 10:49:18 -06:00
if ( fullW * fullH * 3 > partsPosDataLen )
{
2012-01-01 08:35:37 -06:00
fprintf ( stderr , " Not enough particle position data \n " ) ;
2011-12-31 10:49:18 -06:00
goto fail ;
}
2011-12-29 20:06:31 -06:00
parts_lastActiveIndex = NPART - 1 ;
freeIndicesCount = 0 ;
freeIndices = calloc ( sizeof ( int ) , NPART ) ;
2012-04-29 09:31:18 -05:00
partsSimIndex = calloc ( NPART , sizeof ( unsigned ) ) ;
partsCount = 0 ;
2011-12-29 20:06:31 -06:00
for ( i = 0 ; i < NPART ; i + + )
{
//Ensure ALL parts (even photons) are in the pmap so we can overwrite, keep a track of indices we can use
if ( partsptr [ i ] . type )
{
x = ( int ) ( partsptr [ i ] . x + 0.5f ) ;
y = ( int ) ( partsptr [ i ] . y + 0.5f ) ;
pmap [ y ] [ x ] = ( i < < 8 ) | 1 ;
}
else
freeIndices [ freeIndicesCount + + ] = i ;
}
i = 0 ;
2011-12-31 10:49:18 -06:00
for ( saved_y = 0 ; saved_y < fullH ; saved_y + + )
2011-12-29 20:06:31 -06:00
{
2011-12-31 10:49:18 -06:00
for ( saved_x = 0 ; saved_x < fullW ; saved_x + + )
2011-12-29 20:06:31 -06:00
{
2011-12-31 10:49:18 -06:00
//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 + + )
2011-12-29 20:06:31 -06:00
{
2011-12-31 12:57:42 -06:00
//i+3 because we have 4 bytes of required fields (type (1), descriptor (2), temp (1))
2011-12-31 10:49:18 -06:00
if ( i + 3 > = partsDataLen )
goto fail ;
x = saved_x + fullX ;
y = saved_y + fullY ;
2011-12-31 12:57:42 -06:00
fieldDescriptor = partsData [ i + 1 ] ;
fieldDescriptor | = partsData [ i + 2 ] < < 8 ;
2011-12-31 10:49:18 -06:00
if ( x > = XRES | | x < 0 | | y > = YRES | | y < 0 )
{
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 ;
}
2012-01-01 08:35:37 -06:00
if ( partsData [ i ] > = PT_NUM )
2012-01-17 18:20:52 -06:00
partsData [ i ] = PT_DMND ; //Replace all invalid elements with diamond
2012-04-27 12:26:37 -05:00
if ( pmap [ y ] [ x ] & & posCount = = 0 ) // Check posCount to make sure an existing particle is not replaced twice if two particles are saved in that position
2011-12-31 10:49:18 -06:00
{
//Replace existing particle or allocated block
newIndex = pmap [ y ] [ x ] > > 8 ;
}
2012-01-04 07:45:36 -06:00
else if ( freeIndicesIndex < freeIndicesCount )
2011-12-31 10:49:18 -06:00
{
//Create new particle
2012-01-04 07:45:36 -06:00
newIndex = freeIndices [ freeIndicesIndex + + ] ;
2011-12-31 10:49:18 -06:00
}
else
{
//Nowhere to put new particle, tpt is sad :(
break ;
}
if ( newIndex < 0 | | newIndex > = NPART )
goto fail ;
2012-04-29 09:31:18 -05:00
//Store partsptr index+1 for this saved particle index (0 means not loaded)
partsSimIndex [ partsCount + + ] = newIndex + 1 ;
2011-12-31 10:49:18 -06:00
//Clear the particle, ready for our new properties
memset ( & ( partsptr [ newIndex ] ) , 0 , sizeof ( particle ) ) ;
//Required fields
partsptr [ newIndex ] . type = partsData [ i ] ;
partsptr [ newIndex ] . x = x ;
partsptr [ newIndex ] . y = y ;
2011-12-31 12:57:42 -06:00
i + = 3 ;
2011-12-31 10:49:18 -06:00
2011-12-31 12:57:42 -06:00
//Read temp
2011-12-31 10:49:18 -06:00
if ( fieldDescriptor & 0x01 )
2011-12-31 12:57:42 -06:00
{
//Full 16bit int
tempTemp = partsData [ i + + ] ;
tempTemp | = ( ( ( unsigned ) partsData [ i + + ] ) < < 8 ) ;
partsptr [ newIndex ] . temp = tempTemp ;
}
else
{
//1 Byte room temp offset
tempTemp = ( char ) partsData [ i + + ] ;
partsptr [ newIndex ] . temp = tempTemp + 294.15f ;
}
//Read life
if ( fieldDescriptor & 0x02 )
2011-12-31 10:49:18 -06:00
{
if ( i > = partsDataLen ) goto fail ;
partsptr [ newIndex ] . life = partsData [ i + + ] ;
//Read 2nd byte
2011-12-31 12:57:42 -06:00
if ( fieldDescriptor & 0x04 )
2011-12-31 10:49:18 -06:00
{
if ( i > = partsDataLen ) goto fail ;
2012-01-02 08:04:42 -06:00
partsptr [ newIndex ] . life | = ( ( ( unsigned ) partsData [ i + + ] ) < < 8 ) ;
2011-12-31 10:49:18 -06:00
}
}
//Read tmp
2011-12-31 12:57:42 -06:00
if ( fieldDescriptor & 0x08 )
2011-12-31 10:49:18 -06:00
{
if ( i > = partsDataLen ) goto fail ;
partsptr [ newIndex ] . tmp = partsData [ i + + ] ;
//Read 2nd byte
2011-12-31 12:57:42 -06:00
if ( fieldDescriptor & 0x10 )
2011-12-31 10:49:18 -06:00
{
if ( i > = partsDataLen ) goto fail ;
2012-01-02 08:04:42 -06:00
partsptr [ newIndex ] . tmp | = ( ( ( unsigned ) partsData [ i + + ] ) < < 8 ) ;
2011-12-31 10:49:18 -06:00
}
}
//Read ctype
2011-12-31 12:57:42 -06:00
if ( fieldDescriptor & 0x20 )
2011-12-31 10:49:18 -06:00
{
if ( i > = partsDataLen ) goto fail ;
partsptr [ newIndex ] . ctype = partsData [ i + + ] ;
2012-01-04 08:29:22 -06:00
//Read additional bytes
if ( fieldDescriptor & 0x200 )
{
if ( i + 2 > = partsDataLen ) goto fail ;
partsptr [ newIndex ] . ctype | = ( ( ( unsigned ) partsData [ i + + ] ) < < 24 ) ;
partsptr [ newIndex ] . ctype | = ( ( ( unsigned ) partsData [ i + + ] ) < < 16 ) ;
partsptr [ newIndex ] . ctype | = ( ( ( unsigned ) partsData [ i + + ] ) < < 8 ) ;
}
2011-12-31 10:49:18 -06:00
}
//Read dcolour
2011-12-31 12:57:42 -06:00
if ( fieldDescriptor & 0x40 )
2011-12-31 10:49:18 -06:00
{
if ( i + 3 > = partsDataLen ) goto fail ;
2012-01-02 08:04:42 -06:00
partsptr [ newIndex ] . dcolour = ( ( ( unsigned ) partsData [ i + + ] ) < < 24 ) ;
partsptr [ newIndex ] . dcolour | = ( ( ( unsigned ) partsData [ i + + ] ) < < 16 ) ;
partsptr [ newIndex ] . dcolour | = ( ( ( unsigned ) partsData [ i + + ] ) < < 8 ) ;
partsptr [ newIndex ] . dcolour | = ( ( unsigned ) partsData [ i + + ] ) ;
2011-12-31 10:49:18 -06:00
}
//Read vx
2011-12-31 12:57:42 -06:00
if ( fieldDescriptor & 0x80 )
2011-12-31 10:49:18 -06:00
{
if ( i > = partsDataLen ) goto fail ;
partsptr [ newIndex ] . vx = ( partsData [ i + + ] - 127.0f ) / 16.0f ;
}
//Read vy
2011-12-31 12:57:42 -06:00
if ( fieldDescriptor & 0x100 )
2011-12-31 10:49:18 -06:00
{
if ( i > = partsDataLen ) goto fail ;
partsptr [ newIndex ] . vy = ( partsData [ i + + ] - 127.0f ) / 16.0f ;
}
2012-01-17 18:20:52 -06:00
//Read tmp2
if ( fieldDescriptor & 0x400 )
{
if ( i > = partsDataLen ) goto fail ;
partsptr [ newIndex ] . tmp2 = partsData [ i + + ] ;
}
2012-05-11 19:35:55 -05:00
2012-05-22 17:11:41 -05:00
# ifdef OGLR
2012-05-11 19:35:55 -05:00
partsptr [ newIndex ] . lastX = partsptr [ newIndex ] . x - partsptr [ newIndex ] . vx ;
partsptr [ newIndex ] . lastY = partsptr [ newIndex ] . y - partsptr [ newIndex ] . vy ;
2012-05-22 17:11:41 -05:00
# endif
2012-01-25 14:04:14 -06:00
if ( ( player . spwn = = 1 & & partsptr [ newIndex ] . type = = PT_STKM ) | | ( player2 . spwn = = 1 & & partsptr [ newIndex ] . type = = PT_STKM2 ) )
{
partsptr [ newIndex ] . type = PT_NONE ;
}
else if ( partsptr [ newIndex ] . type = = PT_STKM )
{
STKM_init_legs ( & player , newIndex ) ;
player . spwn = 1 ;
player . elem = PT_DUST ;
}
else if ( partsptr [ newIndex ] . type = = PT_STKM2 )
{
STKM_init_legs ( & player2 , newIndex ) ;
player2 . spwn = 1 ;
player2 . elem = PT_DUST ;
}
else if ( partsptr [ newIndex ] . type = = PT_FIGH )
{
unsigned char fcount = 0 ;
while ( fcount < 100 & & fcount < ( fighcount + 1 ) & & fighters [ fcount ] . spwn = = 1 ) fcount + + ;
if ( fcount < 100 & & fighters [ fcount ] . spwn = = 0 )
{
partsptr [ newIndex ] . tmp = fcount ;
fighters [ fcount ] . spwn = 1 ;
fighters [ fcount ] . elem = PT_DUST ;
fighcount + + ;
STKM_init_legs ( & ( fighters [ fcount ] ) , newIndex ) ;
}
}
2012-04-27 12:26:37 -05:00
else if ( partsptr [ newIndex ] . type = = PT_SOAP )
{
2012-04-29 09:31:18 -05:00
//Clear soap links, links will be added back in if soapLinkData is present
partsptr [ newIndex ] . ctype & = ~ 6 ;
2012-04-27 12:26:37 -05:00
}
2012-01-25 14:04:14 -06:00
if ( ! ptypes [ partsptr [ newIndex ] . type ] . enabled )
partsptr [ newIndex ] . type = PT_NONE ;
2011-12-29 20:06:31 -06:00
}
}
}
2012-04-29 09:31:18 -05:00
if ( soapLinkData )
{
int soapLinkDataPos = 0 ;
for ( i = 0 ; i < partsCount ; i + + )
{
if ( partsSimIndex [ i ] & & partsptr [ 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
partsptr [ newIndex ] . ctype | = 2 ;
partsptr [ newIndex ] . tmp = linkedIndex ;
partsptr [ linkedIndex ] . ctype | = 4 ;
partsptr [ linkedIndex ] . tmp2 = newIndex ;
}
}
}
2011-12-29 20:06:31 -06:00
}
goto fin ;
fail :
//Clean up everything
returnCode = 1 ;
fin :
bson_destroy ( & b ) ;
if ( freeIndices )
free ( freeIndices ) ;
2012-04-29 09:31:18 -05:00
if ( partsSimIndex )
free ( partsSimIndex ) ;
2011-12-29 20:06:31 -06:00
return returnCode ;
}
2011-12-30 13:48:11 -06:00
//Old saving
pixel * prerender_save_PSv ( void * save , int size , int * width , int * height )
{
unsigned char * d , * c = save ;
2012-03-14 19:07:21 -05:00
int i , j , k , x , y , rx , ry , p = 0 , wt , pc , gc ;
2011-12-30 13:48:11 -06:00
int bw , bh , w , h , new_format = 0 ;
pixel * fb ;
if ( size < 16 )
return NULL ;
if ( ! ( c [ 2 ] = = 0x43 & & c [ 1 ] = = 0x75 & & c [ 0 ] = = 0x66 ) & & ! ( c [ 2 ] = = 0x76 & & c [ 1 ] = = 0x53 & & c [ 0 ] = = 0x50 ) )
return NULL ;
if ( c [ 2 ] = = 0x43 & & c [ 1 ] = = 0x75 & & c [ 0 ] = = 0x66 ) {
new_format = 1 ;
}
if ( c [ 4 ] > SAVE_VERSION )
return NULL ;
bw = c [ 6 ] ;
bh = c [ 7 ] ;
w = bw * CELL ;
h = bh * CELL ;
if ( c [ 5 ] ! = CELL )
return NULL ;
i = ( unsigned ) c [ 8 ] ;
i | = ( ( unsigned ) c [ 9 ] ) < < 8 ;
i | = ( ( unsigned ) c [ 10 ] ) < < 16 ;
i | = ( ( unsigned ) c [ 11 ] ) < < 24 ;
d = malloc ( i ) ;
if ( ! d )
return NULL ;
fb = calloc ( w * h , PIXELSIZE ) ;
if ( ! fb )
{
free ( d ) ;
return NULL ;
}
if ( BZ2_bzBuffToBuffDecompress ( ( char * ) d , ( unsigned * ) & i , ( char * ) ( c + 12 ) , size - 12 , 0 , 0 ) )
goto corrupt ;
size = i ;
if ( size < bw * bh )
goto corrupt ;
k = 0 ;
for ( y = 0 ; y < bh ; y + + )
for ( x = 0 ; x < bw ; x + + )
{
2012-03-14 19:07:21 -05:00
int wt = change_wall ( d [ p ] ) ;
2011-12-30 13:48:11 -06:00
rx = x * CELL ;
ry = y * CELL ;
2012-03-14 19:07:21 -05:00
pc = wtypes [ wt - UI_ACTUALSTART ] . colour ;
gc = wtypes [ wt - UI_ACTUALSTART ] . eglow ;
if ( wtypes [ wt - UI_ACTUALSTART ] . drawstyle = = 1 )
2011-12-30 13:48:11 -06:00
{
2012-03-14 19:07:21 -05:00
for ( i = 0 ; i < CELL ; i + = 2 )
for ( j = ( i > > 1 ) & 1 ; j < CELL ; j + = 2 )
fb [ ( i + ry ) * w + ( j + rx ) ] = pc ;
}
else if ( wtypes [ wt - UI_ACTUALSTART ] . drawstyle = = 2 )
{
for ( i = 0 ; i < CELL ; i + = 2 )
for ( j = 0 ; j < CELL ; j + = 2 )
fb [ ( i + ry ) * w + ( j + rx ) ] = pc ;
}
else if ( wtypes [ wt - UI_ACTUALSTART ] . drawstyle = = 3 )
{
for ( i = 0 ; i < CELL ; i + + )
for ( j = 0 ; j < CELL ; j + + )
fb [ ( i + ry ) * w + ( j + rx ) ] = pc ;
}
else if ( wtypes [ wt - UI_ACTUALSTART ] . drawstyle = = 4 )
{
for ( i = 0 ; i < CELL ; i + + )
for ( j = 0 ; j < CELL ; j + + )
if ( i = = j )
fb [ ( i + ry ) * w + ( j + rx ) ] = pc ;
else if ( j = = i + 1 | | ( j = = 0 & & i = = CELL - 1 ) )
fb [ ( i + ry ) * w + ( j + rx ) ] = gc ;
else
fb [ ( i + ry ) * w + ( j + rx ) ] = PIXPACK ( 0x202020 ) ;
}
// special rendering for some walls
if ( wt = = WL_EWALL )
{
for ( i = 0 ; i < CELL ; i + + )
for ( j = 0 ; j < CELL ; j + + )
2011-12-30 13:48:11 -06:00
if ( ! ( i & j & 1 ) )
2012-03-14 19:07:21 -05:00
fb [ ( i + ry ) * w + ( j + rx ) ] = pc ;
}
else if ( wt = = WL_WALLELEC )
{
for ( i = 0 ; i < CELL ; i + + )
for ( j = 0 ; j < CELL ; j + + )
{
if ( ! ( ( y * CELL + j ) % 2 ) & & ! ( ( x * CELL + i ) % 2 ) )
fb [ ( i + ry ) * w + ( j + rx ) ] = pc ;
2011-12-30 13:48:11 -06:00
else
2012-03-14 19:07:21 -05:00
fb [ ( i + ry ) * w + ( j + rx ) ] = PIXPACK ( 0x808080 ) ;
}
2011-12-30 13:48:11 -06:00
}
2012-03-14 19:07:21 -05:00
else if ( wt = = WL_EHOLE )
{
for ( i = 0 ; i < CELL ; i + = 2 )
for ( j = 0 ; j < CELL ; j + = 2 )
fb [ ( i + ry ) * w + ( j + rx ) ] = PIXPACK ( 0x242424 ) ;
}
else if ( wt = = WL_FAN )
k + + ;
2011-12-30 13:48:11 -06:00
p + + ;
}
p + = 2 * k ;
if ( p > = size )
goto corrupt ;
for ( y = 0 ; y < h ; y + + )
for ( x = 0 ; x < w ; x + + )
{
if ( p > = size )
goto corrupt ;
j = d [ p + + ] ;
if ( j < PT_NUM & & j > 0 )
{
if ( j = = PT_STKM | | j = = PT_STKM2 | | j = = PT_FIGH )
{
pixel lc , hc = PIXRGB ( 255 , 224 , 178 ) ;
if ( j = = PT_STKM | | j = = PT_FIGH ) lc = PIXRGB ( 255 , 255 , 255 ) ;
else lc = PIXRGB ( 100 , 100 , 255 ) ;
//only need to check upper bound of y coord - lower bounds and x<w are checked in draw_line
2012-01-25 14:04:14 -06:00
if ( j = = PT_STKM | | j = = PT_STKM2 )
{
draw_line ( fb , x - 2 , y - 2 , x + 2 , y - 2 , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , w ) ;
if ( y + 2 < h )
{
draw_line ( fb , x - 2 , y + 2 , x + 2 , y + 2 , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , w ) ;
draw_line ( fb , x - 2 , y - 2 , x - 2 , y + 2 , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , w ) ;
draw_line ( fb , x + 2 , y - 2 , x + 2 , y + 2 , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , w ) ;
}
}
else if ( y + 2 < h )
2011-12-30 13:48:11 -06:00
{
2012-01-25 14:04:14 -06:00
draw_line ( fb , x - 2 , y , x , y - 2 , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , w ) ;
draw_line ( fb , x - 2 , y , x , y + 2 , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , w ) ;
draw_line ( fb , x , y - 2 , x + 2 , y , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , w ) ;
draw_line ( fb , x , y + 2 , x + 2 , y , PIXR ( hc ) , PIXG ( hc ) , PIXB ( hc ) , w ) ;
2011-12-30 13:48:11 -06:00
}
if ( y + 6 < h )
{
draw_line ( fb , x , y + 3 , x - 1 , y + 6 , PIXR ( lc ) , PIXG ( lc ) , PIXB ( lc ) , w ) ;
draw_line ( fb , x , y + 3 , x + 1 , y + 6 , PIXR ( lc ) , PIXG ( lc ) , PIXB ( lc ) , w ) ;
}
if ( y + 12 < h )
{
draw_line ( fb , x - 1 , y + 6 , x - 3 , y + 12 , PIXR ( lc ) , PIXG ( lc ) , PIXB ( lc ) , w ) ;
draw_line ( fb , x + 1 , y + 6 , x + 3 , y + 12 , PIXR ( lc ) , PIXG ( lc ) , PIXB ( lc ) , w ) ;
}
}
else
fb [ y * w + x ] = ptypes [ j ] . pcolors ;
}
}
free ( d ) ;
* width = w ;
* height = h ;
return fb ;
corrupt :
free ( d ) ;
free ( fb ) ;
return NULL ;
}
2011-12-29 20:06:31 -06:00
int parse_save_PSv ( void * save , int size , int replace , int x0 , int y0 , unsigned char bmap [ YRES / CELL ] [ XRES / CELL ] , float fvx [ YRES / CELL ] [ XRES / CELL ] , float fvy [ YRES / CELL ] [ XRES / CELL ] , sign signs [ MAXSIGNS ] , void * partsptr , unsigned pmap [ YRES ] [ XRES ] )
{
unsigned char * d = NULL , * c = save ;
int q , i , j , k , x , y , p = 0 , * m = NULL , ver , pty , ty , legacy_beta = 0 , tempGrav = 0 ;
int bx0 = x0 / CELL , by0 = y0 / CELL , bw , bh , w , h ;
int nf = 0 , new_format = 0 , ttv = 0 ;
particle * parts = partsptr ;
int * fp = malloc ( NPART * sizeof ( int ) ) ;
//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 ( size < 16 )
return 1 ;
if ( ! ( c [ 2 ] = = 0x43 & & c [ 1 ] = = 0x75 & & c [ 0 ] = = 0x66 ) & & ! ( c [ 2 ] = = 0x76 & & c [ 1 ] = = 0x53 & & c [ 0 ] = = 0x50 ) )
return 1 ;
if ( c [ 2 ] = = 0x76 & & c [ 1 ] = = 0x53 & & c [ 0 ] = = 0x50 ) {
new_format = 1 ;
}
if ( c [ 4 ] > SAVE_VERSION )
return 2 ;
ver = c [ 4 ] ;
if ( ver < 34 )
{
legacy_enable = 1 ;
}
else
{
if ( ver > = 44 ) {
legacy_enable = c [ 3 ] & 0x01 ;
if ( ! sys_pause ) {
sys_pause = ( c [ 3 ] > > 1 ) & 0x01 ;
}
if ( ver > = 46 & & replace ) {
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 & & replace ) {
tempGrav = ( ( c [ 3 ] > > 7 ) & 0x01 ) ;
}
} else {
if ( c [ 3 ] = = 1 | | c [ 3 ] = = 0 ) {
legacy_enable = 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 )
return 3 ;
i = ( unsigned ) c [ 8 ] ;
i | = ( ( unsigned ) c [ 9 ] ) < < 8 ;
i | = ( ( unsigned ) c [ 10 ] ) < < 16 ;
i | = ( ( unsigned ) c [ 11 ] ) < < 24 ;
d = malloc ( i ) ;
if ( ! d )
return 1 ;
if ( BZ2_bzBuffToBuffDecompress ( ( char * ) d , ( unsigned * ) & i , ( char * ) ( c + 12 ) , size - 12 , 0 , 0 ) )
return 1 ;
size = i ;
if ( size < bw * bh )
return 1 ;
// normalize coordinates
x0 = bx0 * CELL ;
y0 = by0 * CELL ;
w = bw * CELL ;
h = bh * CELL ;
if ( replace )
{
if ( ver < 46 ) {
gravityMode = 0 ;
airMode = 0 ;
}
clear_sim ( ) ;
2012-05-31 06:20:41 -05:00
erase_bframe ( ) ;
2011-12-29 20:06:31 -06:00
}
parts_lastActiveIndex = NPART - 1 ;
m = calloc ( XRES * YRES , sizeof ( int ) ) ;
// make a catalog of free parts
//memset(pmap, 0, sizeof(pmap)); "Using sizeof for array given as function argument returns the size of pointer."
memset ( pmap , 0 , sizeof ( unsigned ) * ( XRES * YRES ) ) ;
for ( i = 0 ; i < NPART ; i + + )
if ( parts [ i ] . type )
{
x = ( int ) ( parts [ i ] . x + 0.5f ) ;
y = ( int ) ( parts [ i ] . y + 0.5f ) ;
pmap [ y ] [ x ] = ( i < < 8 ) | 1 ;
}
else
fp [ nf + + ] = i ;
// load the required air state
for ( y = by0 ; y < by0 + bh ; y + + )
for ( x = bx0 ; x < bx0 + bw ; x + + )
{
if ( d [ p ] )
{
2012-01-04 07:45:36 -06:00
//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 ] = = WL_SIGN )
{
p + + ;
continue ;
}
2012-03-14 19:07:21 -05:00
bmap [ y ] [ x ] = change_wall ( d [ p ] ) ;
2011-12-29 20:06:31 -06:00
}
p + + ;
}
for ( y = by0 ; y < by0 + bh ; y + + )
for ( x = bx0 ; x < bx0 + bw ; x + + )
if ( d [ ( y - by0 ) * bw + ( x - bx0 ) ] = = 4 | | d [ ( y - by0 ) * bw + ( x - bx0 ) ] = = WL_FAN )
{
if ( p > = size )
goto corrupt ;
fvx [ y ] [ x ] = ( d [ p + + ] - 127.0f ) / 64.0f ;
}
for ( y = by0 ; y < by0 + bh ; y + + )
for ( x = bx0 ; x < bx0 + bw ; x + + )
if ( d [ ( y - by0 ) * bw + ( x - bx0 ) ] = = 4 | | d [ ( y - by0 ) * bw + ( x - bx0 ) ] = = WL_FAN )
{
if ( p > = size )
goto corrupt ;
fvy [ y ] [ x ] = ( d [ p + + ] - 127.0f ) / 64.0f ;
}
// load the particle map
i = 0 ;
pty = p ;
for ( y = y0 ; y < y0 + h ; y + + )
for ( x = x0 ; x < x0 + w ; x + + )
{
if ( p > = size )
goto corrupt ;
j = d [ p + + ] ;
if ( j > = PT_NUM ) {
//TODO: Possibly some server side translation
j = PT_DUST ; //goto corrupt;
}
gol [ x ] [ y ] = 0 ;
if ( j )
{
if ( pmap [ y ] [ x ] )
{
k = pmap [ y ] [ x ] > > 8 ;
}
else if ( i < nf )
{
k = fp [ i ] ;
i + + ;
}
else
{
m [ ( x - x0 ) + ( y - y0 ) * w ] = NPART + 1 ;
continue ;
}
memset ( parts + k , 0 , sizeof ( particle ) ) ;
parts [ k ] . type = j ;
if ( j = = PT_COAL )
parts [ k ] . tmp = 50 ;
if ( j = = PT_FUSE )
parts [ k ] . tmp = 50 ;
if ( j = = PT_PHOT )
parts [ k ] . ctype = 0x3fffffff ;
if ( j = = PT_SOAP )
parts [ k ] . ctype = 0 ;
if ( j = = PT_BIZR | | j = = PT_BIZRG | | j = = PT_BIZRS )
parts [ k ] . ctype = 0x47FFFF ;
parts [ k ] . x = ( float ) x ;
parts [ k ] . y = ( float ) y ;
m [ ( x - x0 ) + ( y - y0 ) * w ] = k + 1 ;
}
}
// load particle properties
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i )
{
i - - ;
if ( p + 1 > = size )
goto corrupt ;
if ( i < NPART )
{
parts [ i ] . vx = ( d [ p + + ] - 127.0f ) / 16.0f ;
parts [ i ] . vy = ( d [ p + + ] - 127.0f ) / 16.0f ;
2012-05-22 17:11:41 -05:00
# ifdef OGLR
2012-05-11 19:35:55 -05:00
parts [ i ] . lastX = parts [ i ] . x - parts [ i ] . vx ;
parts [ i ] . lastY = parts [ i ] . y - parts [ i ] . vy ;
2012-05-22 17:11:41 -05:00
# endif
2011-12-29 20:06:31 -06:00
}
else
p + = 2 ;
}
}
for ( j = 0 ; j < w * h ; j + + )
{
i = m [ j ] ;
if ( i )
{
if ( ver > = 44 ) {
if ( p > = size ) {
goto corrupt ;
}
if ( i < = NPART ) {
ttv = ( d [ p + + ] ) < < 8 ;
ttv | = ( d [ p + + ] ) ;
parts [ i - 1 ] . life = ttv ;
} else {
p + = 2 ;
}
} else {
if ( p > = size )
goto corrupt ;
if ( i < = NPART )
parts [ 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 > = size ) {
goto corrupt ;
}
if ( i < = NPART ) {
ttv = ( d [ p + + ] ) < < 8 ;
ttv | = ( d [ p + + ] ) ;
parts [ i - 1 ] . tmp = ttv ;
if ( ver < 53 & & ! parts [ i - 1 ] . tmp )
for ( q = 1 ; q < = NGOLALT ; q + + ) {
if ( parts [ i - 1 ] . type = = goltype [ q - 1 ] & & grule [ q ] [ 9 ] = = 2 )
parts [ i - 1 ] . tmp = grule [ q ] [ 9 ] - 1 ;
}
if ( ver > = 51 & & ver < 53 & & parts [ i - 1 ] . type = = PT_PBCN )
{
parts [ i - 1 ] . tmp2 = parts [ i - 1 ] . tmp ;
parts [ 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-04-27 11:46:40 -05:00
if ( i & & ( ty = = PT_PBCN | | ( ty = = PT_TRON & & ver > = 77 ) ) )
2011-12-29 20:06:31 -06:00
{
if ( p > = size )
goto corrupt ;
if ( i < = NPART )
parts [ 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 > = size ) {
goto corrupt ;
}
if ( i < = NPART ) {
parts [ 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 > = size ) {
goto corrupt ;
}
if ( i < = NPART ) {
parts [ 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 > = size ) {
goto corrupt ;
}
if ( i < = NPART ) {
parts [ 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 > = size ) {
goto corrupt ;
}
if ( i < = NPART ) {
parts [ 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 > = size )
{
goto corrupt ;
}
if ( i < = NPART )
{
if ( ver > = 42 ) {
if ( new_format ) {
ttv = ( d [ p + + ] ) < < 8 ;
ttv | = ( d [ p + + ] ) ;
if ( parts [ i - 1 ] . type = = PT_PUMP ) {
parts [ i - 1 ] . temp = ttv + 0.15 ; //fix PUMP saved at 0, so that it loads at 0.
} else {
parts [ i - 1 ] . temp = ttv ;
}
} else {
parts [ i - 1 ] . temp = ( d [ p + + ] * ( ( MAX_TEMP + ( - MIN_TEMP ) ) / 255 ) ) + MIN_TEMP ;
}
} else {
parts [ i - 1 ] . temp = ( ( d [ p + + ] * ( ( O_MAX_TEMP + ( - O_MIN_TEMP ) ) / 255 ) ) + O_MIN_TEMP ) + 273 ;
}
}
else
{
p + + ;
if ( new_format ) {
p + + ;
}
}
}
else
{
parts [ i - 1 ] . temp = ptypes [ parts [ i - 1 ] . type ] . heat ;
}
}
}
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 > = size )
goto corrupt ;
if ( i < = NPART )
parts [ i - 1 ] . ctype = d [ p + + ] ;
else
p + + ;
}
// no more particle properties to load, so we can change type here without messing up loading
if ( i & & i < = NPART )
{
if ( ( player . spwn = = 1 & & ty = = PT_STKM ) | | ( player2 . spwn = = 1 & & ty = = PT_STKM2 ) )
{
parts [ i - 1 ] . type = PT_NONE ;
}
else if ( parts [ i - 1 ] . type = = PT_STKM )
{
STKM_init_legs ( & player , i - 1 ) ;
player . spwn = 1 ;
player . elem = PT_DUST ;
}
else if ( parts [ i - 1 ] . type = = PT_STKM2 )
{
STKM_init_legs ( & player2 , i - 1 ) ;
player2 . spwn = 1 ;
player2 . elem = PT_DUST ;
}
else if ( parts [ i - 1 ] . type = = PT_FIGH )
{
unsigned char fcount = 0 ;
while ( fcount < 100 & & fcount < ( fighcount + 1 ) & & fighters [ fcount ] . spwn = = 1 ) fcount + + ;
if ( fcount < 100 & & fighters [ fcount ] . spwn = = 0 )
{
parts [ i - 1 ] . tmp = fcount ;
fighters [ fcount ] . spwn = 1 ;
fighters [ fcount ] . elem = PT_DUST ;
fighcount + + ;
STKM_init_legs ( & ( fighters [ fcount ] ) , i - 1 ) ;
}
}
2012-05-23 10:20:14 -05:00
else if ( ver < 79 & & parts [ i - 1 ] . type = = PT_SPNG )
2012-04-19 09:40:28 -05:00
{
if ( fabs ( parts [ i - 1 ] . vx ) > 0.0f | | fabs ( parts [ i - 1 ] . vy ) > 0.0f )
parts [ i - 1 ] . flags | = FLAG_MOVABLE ;
}
2011-12-29 20:06:31 -06:00
if ( ver < 48 & & ( ty = = OLD_PT_WIND | | ( ty = = PT_BRAY & & parts [ i - 1 ] . life = = 0 ) ) )
{
// Replace invisible particles with something sensible and add decoration to hide it
x = ( int ) ( parts [ i - 1 ] . x + 0.5f ) ;
y = ( int ) ( parts [ i - 1 ] . y + 0.5f ) ;
parts [ i - 1 ] . dcolour = 0xFF000000 ;
parts [ i - 1 ] . type = PT_DMND ;
}
if ( ver < 51 & & ( ( ty > = 78 & & ty < = 89 ) | | ( ty > = 134 & & ty < = 146 & & ty ! = 141 ) ) ) {
//Replace old GOL
parts [ i - 1 ] . type = PT_LIFE ;
for ( gnum = 0 ; gnum < NGOLALT ; gnum + + ) {
if ( ty = = goltype [ gnum ] )
parts [ 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 ( parts [ i - 1 ] . ctype = = goltype [ gnum ] )
{
parts [ i - 1 ] . ctype = PT_LIFE ;
parts [ i - 1 ] . tmp = gnum ;
}
}
}
if ( ty = = PT_LCRY ) {
if ( ver < 67 )
{
//New LCRY uses TMP not life
if ( parts [ i - 1 ] . life > = 10 )
{
parts [ i - 1 ] . life = 10 ;
parts [ i - 1 ] . tmp2 = 10 ;
parts [ i - 1 ] . tmp = 3 ;
}
else if ( parts [ i - 1 ] . life < = 0 )
{
parts [ i - 1 ] . life = 0 ;
parts [ i - 1 ] . tmp2 = 0 ;
parts [ i - 1 ] . tmp = 0 ;
}
else if ( parts [ i - 1 ] . life < 10 & & parts [ i - 1 ] . life > 0 )
{
parts [ i - 1 ] . tmp = 1 ;
}
}
else
{
parts [ i - 1 ] . tmp2 = parts [ i - 1 ] . life ;
}
}
if ( ! ptypes [ parts [ i - 1 ] . type ] . enabled )
parts [ i - 1 ] . type = PT_NONE ;
}
}
# ifndef RENDERER
//Change the gravity state
if ( ngrav_enable ! = tempGrav & & replace )
{
if ( tempGrav )
start_grav_async ( ) ;
else
stop_grav_async ( ) ;
}
# endif
gravity_mask ( ) ;
if ( p > = size )
goto version1 ;
j = d [ p + + ] ;
for ( i = 0 ; i < j ; i + + )
{
if ( p + 6 > size )
goto corrupt ;
for ( k = 0 ; k < MAXSIGNS ; k + + )
if ( ! signs [ k ] . text [ 0 ] )
break ;
x = d [ p + + ] ;
x | = ( ( unsigned ) d [ p + + ] ) < < 8 ;
if ( k < MAXSIGNS )
signs [ k ] . x = x + x0 ;
x = d [ p + + ] ;
x | = ( ( unsigned ) d [ p + + ] ) < < 8 ;
if ( k < MAXSIGNS )
signs [ k ] . y = x + y0 ;
x = d [ p + + ] ;
if ( k < MAXSIGNS )
signs [ k ] . ju = x ;
x = d [ p + + ] ;
if ( p + x > size )
goto corrupt ;
if ( k < MAXSIGNS )
{
memcpy ( signs [ k ] . text , d + p , x ) ;
signs [ k ] . text [ x ] = 0 ;
clean_text ( signs [ k ] . text , 158 - 14 /* Current max sign length */ ) ;
}
p + = x ;
}
version1 :
if ( m ) free ( m ) ;
if ( d ) free ( d ) ;
if ( fp ) free ( fp ) ;
return 0 ;
corrupt :
if ( m ) free ( m ) ;
if ( d ) free ( d ) ;
if ( fp ) free ( fp ) ;
if ( replace )
{
legacy_enable = 0 ;
clear_sim ( ) ;
2012-05-31 06:20:41 -05:00
erase_bframe ( ) ;
2011-12-29 20:06:31 -06:00
}
return 1 ;
}
void * build_thumb ( int * size , int bzip2 )
{
unsigned char * d = calloc ( 1 , XRES * YRES ) , * c ;
int i , j , x , y ;
for ( i = 0 ; i < NPART ; i + + )
if ( parts [ i ] . type )
{
x = ( int ) ( parts [ i ] . x + 0.5f ) ;
y = ( int ) ( parts [ i ] . y + 0.5f ) ;
if ( x > = 0 & & x < XRES & & y > = 0 & & y < YRES )
d [ x + y * XRES ] = parts [ i ] . type ;
}
for ( y = 0 ; y < YRES / CELL ; y + + )
for ( x = 0 ; x < XRES / CELL ; x + + )
if ( bmap [ y ] [ x ] )
for ( j = 0 ; j < CELL ; j + + )
for ( i = 0 ; i < CELL ; i + + )
d [ x * CELL + i + ( y * CELL + j ) * XRES ] = 0xFF ;
j = XRES * YRES ;
if ( bzip2 )
{
i = ( j * 101 + 99 ) / 100 + 608 ;
c = malloc ( i ) ;
c [ 0 ] = 0x53 ;
c [ 1 ] = 0x68 ;
c [ 2 ] = 0x49 ;
c [ 3 ] = 0x74 ;
c [ 4 ] = PT_NUM ;
c [ 5 ] = CELL ;
c [ 6 ] = XRES / CELL ;
c [ 7 ] = YRES / CELL ;
i - = 8 ;
if ( BZ2_bzBuffToBuffCompress ( ( char * ) ( c + 8 ) , ( unsigned * ) & i , ( char * ) d , j , 9 , 0 , 0 ) ! = BZ_OK )
{
free ( d ) ;
free ( c ) ;
return NULL ;
}
free ( d ) ;
* size = i + 8 ;
return c ;
}
* size = j ;
return d ;
2011-12-31 10:49:18 -06:00
}
2012-01-14 11:46:38 -06:00
void * transform_save ( void * odata , int * size , matrix2d transform , vector2d translate )
{
void * ndata ;
unsigned char ( * bmapo ) [ XRES / CELL ] = calloc ( ( YRES / CELL ) * ( XRES / CELL ) , sizeof ( unsigned char ) ) ;
unsigned char ( * bmapn ) [ XRES / CELL ] = calloc ( ( YRES / CELL ) * ( XRES / CELL ) , sizeof ( unsigned char ) ) ;
particle * partst = calloc ( sizeof ( particle ) , NPART ) ;
sign * signst = calloc ( MAXSIGNS , sizeof ( sign ) ) ;
unsigned ( * pmapt ) [ XRES ] = calloc ( YRES * XRES , sizeof ( unsigned ) ) ;
float ( * fvxo ) [ XRES / CELL ] = calloc ( ( YRES / CELL ) * ( XRES / CELL ) , sizeof ( float ) ) ;
float ( * fvyo ) [ XRES / CELL ] = calloc ( ( YRES / CELL ) * ( XRES / CELL ) , sizeof ( float ) ) ;
float ( * fvxn ) [ XRES / CELL ] = calloc ( ( YRES / CELL ) * ( XRES / CELL ) , sizeof ( float ) ) ;
float ( * fvyn ) [ XRES / CELL ] = calloc ( ( YRES / CELL ) * ( XRES / CELL ) , sizeof ( float ) ) ;
float ( * vxo ) [ XRES / CELL ] = calloc ( ( YRES / CELL ) * ( XRES / CELL ) , sizeof ( float ) ) ;
float ( * vyo ) [ XRES / CELL ] = calloc ( ( YRES / CELL ) * ( XRES / CELL ) , sizeof ( float ) ) ;
float ( * vxn ) [ XRES / CELL ] = calloc ( ( YRES / CELL ) * ( XRES / CELL ) , sizeof ( float ) ) ;
float ( * vyn ) [ XRES / CELL ] = calloc ( ( YRES / CELL ) * ( XRES / CELL ) , sizeof ( float ) ) ;
float ( * pvo ) [ XRES / CELL ] = calloc ( ( YRES / CELL ) * ( XRES / CELL ) , sizeof ( float ) ) ;
float ( * pvn ) [ XRES / CELL ] = calloc ( ( YRES / CELL ) * ( XRES / CELL ) , sizeof ( float ) ) ;
int i , x , y , nx , ny , w , h , nw , nh ;
vector2d pos , tmp , ctl , cbr ;
2012-02-29 16:25:50 -06:00
vector2d vel ;
2012-01-14 11:46:38 -06:00
vector2d cornerso [ 4 ] ;
unsigned char * odatac = odata ;
if ( parse_save ( odata , * size , 0 , 0 , 0 , bmapo , vxo , vyo , pvo , fvxo , fvyo , signst , partst , pmapt ) )
{
free ( bmapo ) ;
free ( bmapn ) ;
free ( partst ) ;
free ( signst ) ;
free ( pmapt ) ;
free ( fvxo ) ;
free ( fvyo ) ;
free ( fvxn ) ;
free ( fvyn ) ;
free ( vxo ) ;
free ( vyo ) ;
free ( vxn ) ;
free ( vyn ) ;
free ( pvo ) ;
free ( pvn ) ;
return odata ;
}
w = odatac [ 6 ] * CELL ;
h = odatac [ 7 ] * CELL ;
// undo any translation caused by rotation
cornerso [ 0 ] = v2d_new ( 0 , 0 ) ;
cornerso [ 1 ] = v2d_new ( w - 1 , 0 ) ;
cornerso [ 2 ] = v2d_new ( 0 , h - 1 ) ;
cornerso [ 3 ] = v2d_new ( w - 1 , h - 1 ) ;
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 ) ;
nw = floor ( cbr . x + 0.5f ) - floor ( ctl . x + 0.5f ) + 1 ;
nh = floor ( cbr . y + 0.5f ) - floor ( ctl . y + 0.5f ) + 1 ;
if ( nw > XRES ) nw = XRES ;
if ( nh > YRES ) nh = YRES ;
// rotate and translate signs, parts, walls
for ( i = 0 ; i < MAXSIGNS ; i + + )
{
if ( ! signst [ i ] . text [ 0 ] ) continue ;
pos = v2d_new ( signst [ i ] . x , signst [ i ] . y ) ;
pos = v2d_add ( m2d_multiply_v2d ( transform , pos ) , translate ) ;
nx = floor ( pos . x + 0.5f ) ;
ny = floor ( pos . y + 0.5f ) ;
if ( nx < 0 | | nx > = nw | | ny < 0 | | ny > = nh )
{
signst [ i ] . text [ 0 ] = 0 ;
continue ;
}
signst [ i ] . x = nx ;
signst [ i ] . y = ny ;
}
for ( i = 0 ; i < NPART ; i + + )
{
if ( ! partst [ i ] . type ) continue ;
pos = v2d_new ( partst [ i ] . x , partst [ i ] . y ) ;
pos = v2d_add ( m2d_multiply_v2d ( transform , pos ) , translate ) ;
nx = floor ( pos . x + 0.5f ) ;
ny = floor ( pos . y + 0.5f ) ;
if ( nx < 0 | | nx > = nw | | ny < 0 | | ny > = nh )
{
partst [ i ] . type = PT_NONE ;
continue ;
}
partst [ i ] . x = nx ;
partst [ i ] . y = ny ;
2012-02-29 16:25:50 -06:00
vel = v2d_new ( partst [ i ] . vx , partst [ i ] . vy ) ;
vel = m2d_multiply_v2d ( transform , vel ) ;
partst [ i ] . vx = vel . x ;
partst [ i ] . vy = vel . y ;
2012-01-14 11:46:38 -06:00
}
for ( y = 0 ; y < YRES / CELL ; y + + )
for ( x = 0 ; x < XRES / CELL ; x + + )
{
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-01-19 16:00:49 -06:00
if ( nx < 0 | | nx > = nw / CELL | | ny < 0 | | ny > = nh / CELL )
2012-01-14 11:46:38 -06:00
continue ;
if ( bmapo [ y ] [ x ] )
{
bmapn [ ny ] [ nx ] = bmapo [ y ] [ x ] ;
if ( bmapo [ y ] [ x ] = = WL_FAN )
{
2012-02-29 16:25:50 -06:00
vel = v2d_new ( fvxo [ y ] [ x ] , fvyo [ y ] [ x ] ) ;
vel = m2d_multiply_v2d ( transform , vel ) ;
fvxn [ ny ] [ nx ] = vel . x ;
fvyn [ ny ] [ nx ] = vel . y ;
2012-01-14 11:46:38 -06:00
}
}
2012-02-29 16:25:50 -06:00
vel = v2d_new ( vxo [ y ] [ x ] , vyo [ y ] [ x ] ) ;
vel = m2d_multiply_v2d ( transform , vel ) ;
vxn [ ny ] [ nx ] = vel . x ;
vyn [ ny ] [ nx ] = vel . y ;
2012-01-14 11:46:38 -06:00
pvn [ ny ] [ nx ] = pvo [ y ] [ x ] ;
}
ndata = build_save ( size , 0 , 0 , nw , nh , bmapn , vxn , vyn , pvn , fvxn , fvyn , signst , partst ) ;
free ( bmapo ) ;
free ( bmapn ) ;
free ( partst ) ;
free ( signst ) ;
free ( pmapt ) ;
free ( fvxo ) ;
free ( fvyo ) ;
free ( fvxn ) ;
free ( fvyn ) ;
free ( vxo ) ;
free ( vyo ) ;
free ( vxn ) ;
free ( vyn ) ;
free ( pvo ) ;
free ( pvn ) ;
return ndata ;
}