#include "game.h"

extern SG_COL	req_sel_gour2[];  // Outline Gouraud

/**************************************** GLOBAL VARIABLES ****************************************************/

SAVEGAME_INFO savegame;
#ifdef PSX_VERSION
SAVEGAME_INFO savegame_backup;
#endif
/* For dealing with data in save game buffer */
int SGcount;
char *SGpoint;

int number_cameras=0;

#define SAVE_CREATURE (1<<7)

/***************************************** FUNCTION CODE ******************************************************/

int LoadSaveGameInfo(void)
{
#ifdef PSX_VERSION
	int	status;
	/* Try to load a savegame packet. Returns 1 if success, 0 if failure */
/*	SAVEGAME_INFO *temp;

	temp = (SAVEGAME_INFO *)game_malloc(sizeof(SAVEGAME_INFO)+127, TEMP_ALLOC);

	if (!S_LoadGame(temp, sizeof(SAVEGAME_INFO), 0))
	{
		game_free(sizeof(SAVEGAME_INFO)+127, TEMP_ALLOC);
		return (0);
	}
*/
	/* Copy temp packet into genuine packet */
//	S_MemCpy(&savegame, temp, sizeof(SAVEGAME_INFO));
//	game_free(sizeof(SAVEGAME_INFO)+127, TEMP_ALLOC);
	S_MemCpy(&savegame_backup, &savegame, sizeof(SAVEGAME_INFO));	// make a backup of current setting in-case user cancels
	return(S_LoadGame(&savegame, sizeof(SAVEGAME_INFO)-128, 0));
#else
	return (1);
#endif
}


void InitialiseStartInfo(void)
{
	int i;

#if defined(GAMEDEBUG) && defined(PSX_VERSION)
	printf("InitialiseStartInfo()\n");
#endif
	/* Initialise start data for each level */
#ifdef PC_VERSION
	if (savegame.bonus_flag == 0)
	{
#endif
		for ( i=0;i<MAXIMUM_LEVELS;i++ )
		{
			ModifyStartInfo(i);
			savegame.start[i].available = 0;
			savegame.start[i].timer = 0;
			savegame.start[i].ammo_used = 0;
			savegame.start[i].ammo_hit = 0;
			savegame.start[i].distance_travelled = 0;
			savegame.start[i].kills = 0;
			savegame.start[i].secrets_found = 0;
			savegame.start[i].health_used = 0;
		}

		/* Player can start on gym or level1 */
		savegame.start[LV_GYM].available = 1;
		savegame.start[LV_FIRSTLEVEL].available = 1;
		savegame.bonus_flag = 0;
#ifdef PC_VERSION
	}
#endif
}


void ModifyStartInfo(int level_number)
{
	START_INFO *start;

	start = &savegame.start[level_number];

	start->got_pistols = 1;      			// Always got Pistols
	start->gun_type = LG_PISTOLS;           // assume they are readied
	start->pistol_ammo = 1000;              // Inifinite ammo
	switch (level_number)
	{
		case LV_GYM:
			start->available = 1;
			start->pistol_ammo = start->magnum_ammo = start->uzi_ammo = start->shotgun_ammo = start->harpoon_ammo = start->rocket_ammo = start->m16_ammo = start->harpoon_ammo = start->rocket_ammo = 0;
			start->got_pistols = start->got_magnums = start->got_uzis = start->got_shotgun = start->got_harpoon = start->got_rocket = start->got_m16 = start->got_harpoon = start->got_rocket = 0;
			start->num_medis = start->num_big_medis = start->num_flares = 0;
			start->gun_type = LG_UNARMED;
			start->gun_status = LG_ARMLESS;
			break;

// TODO
		case LV_FIRSTLEVEL:
			start->available = 1;
			start->got_shotgun = 1;
			start->shotgun_ammo = 2*SHOTGUN_AMMO_CLIP;
			start->num_flares = 2;
			start->num_medis = 1;
			start->num_big_medis = 1;
			start->got_magnums = start->got_uzis = start->got_m16 = start->got_harpoon = start->got_rocket = 0;
			start->magnum_ammo = start->uzi_ammo = start->m16_ammo = start->harpoon_ammo = start->rocket_ammo = 0;
			start->gun_status = LG_ARMLESS;
			break;

	}
	if ( savegame.bonus_flag && level_number!=LV_GYM )
	{
		start->available = 1;
		start->got_pistols = start->got_magnums = start->got_uzis = start->got_shotgun = start->got_rocket = start->got_m16 = start->got_harpoon = 1;
		start->magnum_ammo = start->uzi_ammo = start->shotgun_ammo = start->rocket_ammo = start->m16_ammo = start->harpoon_ammo = 10000;
		start->gun_type = LG_ROCKET;
		start->num_flares = 255;
	}
}


void CreateStartInfo(int level_number)
{
	/* Create the start info for a level */
	START_INFO *start;

	start = &savegame.start[level_number];
	start->available = 1;

	/* Insert Pistol Stuff */
	if (Inv_RequestItem(GUN_ITEM))
	{
		start->pistol_ammo = 1000;
		start->got_pistols = 1;
	}
	else
	{
		start->pistol_ammo = 1000;
		start->got_pistols = 0;
	}

	/* Insert Magnum Stuff */
	if (Inv_RequestItem(MAGNUM_ITEM))
	{
		start->magnum_ammo = lara.magnums.ammo;
		start->got_magnums = 1;
	}
	else
	{
		start->magnum_ammo = Inv_RequestItem(MAG_AMMO_ITEM)*MAGNUM_AMMO_QTY;
		start->got_magnums = 0;
	}

	/* Insert Uzi Stuff */
	if (Inv_RequestItem(UZI_ITEM))
	{
		start->uzi_ammo = lara.uzis.ammo;
		start->got_uzis = 1;
	}
	else
	{
		start->uzi_ammo = Inv_RequestItem(UZI_AMMO_ITEM)*UZI_AMMO_QTY;
		start->got_uzis = 0;
	}

	/* Insert Shotgun Stuff */
	if (Inv_RequestItem(SHOTGUN_ITEM))
	{
		start->shotgun_ammo = lara.shotgun.ammo;
		start->got_shotgun = 1;
	}
	else
	{
		start->shotgun_ammo = Inv_RequestItem(SG_AMMO_ITEM)*SHOTGUN_AMMO_QTY;
		start->got_shotgun = 0;
	}

	/* Insert Harpoon Stuff */
	if (Inv_RequestItem(HARPOON_ITEM))
	{
		start->harpoon_ammo = lara.harpoon.ammo;
		start->got_harpoon = 1;
	}
	else
	{
		start->harpoon_ammo = Inv_RequestItem(HARPOON_AMMO_ITEM)*HARPOON_AMMO_QTY;
		start->got_harpoon = 0;
	}

	/* Insert M16 Stuff */
	if (Inv_RequestItem(M16_ITEM))
	{
		start->m16_ammo = lara.m16.ammo;
		start->got_m16 = 1;
	}
	else
	{
		start->m16_ammo = Inv_RequestItem(M16_AMMO_ITEM)*M16_AMMO_QTY;
		start->got_m16 = 0;
	}

	/* Insert Rocket Stuff */
	if (Inv_RequestItem(ROCKET_GUN_ITEM))
	{
		start->rocket_ammo = lara.rocket.ammo;
		start->got_rocket = 1;
	}
	else
	{
		start->rocket_ammo = Inv_RequestItem(ROCKET_AMMO_ITEM)*ROCKET_AMMO_QTY;
		start->got_rocket = 0;
	}

	start->num_flares = Inv_RequestItem(FLARE_ITEM);
	start->num_medis = Inv_RequestItem(MEDI_ITEM);
	start->num_big_medis = Inv_RequestItem(BIGMEDI_ITEM);

	if (lara.gun_type == LG_FLARE)
		start->gun_type = (char)lara.last_gun_type;
	else
		start->gun_type = (char)lara.gun_type;
	start->gun_status = LG_ARMLESS;
}


void	CreateSaveGameInfo(void)
{
	int i, number_flares, flare_age;
	OBJECT_INFO *obj;
	ITEM_INFO *item;
	sint16 flags;
	char tflag;
#ifdef FULL_SAVE
	CREATURE_INFO *creature;
#endif

	savegame.current_level = (sint16)CurrentLevel;

#ifdef PSX_VERSION
	if (savegame.mid_level_save)
		CreateStartInfo(0);
	else
#endif
	CreateStartInfo(CurrentLevel);

	/* Store information about Lara's inventory over what she has at start */
	savegame.num_pickup1 = Inv_RequestItem(PICKUP_ITEM1);
	savegame.num_pickup2 = Inv_RequestItem(PICKUP_ITEM2);
	savegame.num_puzzle1 = Inv_RequestItem(PUZZLE_ITEM1);
	savegame.num_puzzle2 = Inv_RequestItem(PUZZLE_ITEM2);
	savegame.num_puzzle3 = Inv_RequestItem(PUZZLE_ITEM3);
	savegame.num_puzzle4 = Inv_RequestItem(PUZZLE_ITEM4);
	savegame.num_key1 = Inv_RequestItem(KEY_ITEM1);
	savegame.num_key2 = Inv_RequestItem(KEY_ITEM2);
	savegame.num_key3 = Inv_RequestItem(KEY_ITEM3);
	savegame.num_key4 = Inv_RequestItem(KEY_ITEM4);

	ResetSG();

	/* Clear out the savegame buffer */
	for ( i=0;i<MAX_SAVEGAME_BUFFER;i++ )
		savegame.buffer[i] = 0;

	/* Save out all the other bits and bobs that are needed per level */
	WriteSG(&flip_status, sizeof(int));

	/* Flipped map flags */
	for (i=0; i<MAX_FLIPMAPS; i++)
	{
		tflag = (flipmap[i] >> 8);
		WriteSG(&tflag, sizeof(char));
	}

	/* Save out CD flags */
	WriteSG(cd_flags, sizeof(sint16)*MAX_CD_TRACKS);

	/* Camera/sink flags */
	for (i=0; i<number_cameras; i++)
		WriteSG(&camera.fixed[i].flags, sizeof(sint16));

	/* Go through all the items in the level and save out the salient features
		(as flagged in objects.h) */
	for (i=0, item=items; i<level_items; i++, item++)
	{
		obj = &objects[item->object_number];
		if (obj->save_position)
		{
			// can pack x,y,z by reducing to sint16 offsets from room pos + 32bit packed rotation - but is it worth the effort?
			WriteSG(&item->pos, sizeof(PHD_3DPOS));
			WriteSG(&item->room_number, sizeof(sint16));
#ifdef FULL_SAVE
			WriteSG(&item->speed, sizeof(sint16));
			WriteSG(&item->fallspeed, sizeof(sint16));
#endif
		}

		if (obj->save_anim)
		{
			WriteSG(&item->current_anim_state, sizeof(sint16));
#ifdef FULL_SAVE
			WriteSG(&item->goal_anim_state, sizeof(sint16));
			WriteSG(&item->required_anim_state, sizeof(sint16));
#endif
			WriteSG(&item->anim_number, sizeof(sint16));
			WriteSG(&item->frame_number, sizeof(sint16));
		}

		if (obj->save_hitpoints)
			WriteSG(&item->hit_points, sizeof(sint16));

		if (obj->save_flags)
		{
			flags = item->flags + item->active + (item->status<<1) + (item->gravity_status<<3) + (item->collidable<<4);
			if (obj->intelligent && item->data)
				flags |= SAVE_CREATURE;
			WriteSG(&flags, sizeof(sint16));

			/* Intelligent baddies can be carrying stuff which they drop on death */
			if (obj->intelligent)
				WriteSG(&item->carried_item, sizeof(sint16));

#ifdef FULL_SAVE
			/* Write out timer + baddie AI stuff for PC */
			WriteSG(&item->timer, sizeof(sint16));
			if (flags & SAVE_CREATURE)
			{
				creature = (CREATURE_INFO *)item->data;
				WriteSG(&creature->head_rotation, sizeof(sint16));
				WriteSG(&creature->neck_rotation, sizeof(sint16));
				WriteSG(&creature->maximum_turn, sizeof(sint16));
				WriteSG(&creature->flags, sizeof(sint16));
				WriteSG(&creature->mood, sizeof(MOOD_TYPE));
			}
#endif
		}

#ifdef FULL_SAVE
		/* Vehicles need more information saved out */
		if (item->object_number == MOTORBOAT)
			WriteSG(item->data, sizeof(BOAT_INFO));
		else if (item->object_number == SKIDOO)
			WriteSG(item->data, sizeof(SKIDOO_INFO));
		else if (item->object_number == LIFT)
			WriteSG(item->data, sizeof(int)*2);
#endif
	}

	for (i=0; i<15; i++)
		lara.mesh_ptrs[i] = (sint16 *)((long)lara.mesh_ptrs[i] - (long)mesh_base);
	lara.left_arm.frame_base = (sint16 *)((long)lara.left_arm.frame_base - (long)frames);
	lara.right_arm.frame_base = (sint16 *)((long)lara.right_arm.frame_base - (long)frames);

	WriteSG(&lara, sizeof(LARA_INFO));

	for (i=0; i<15; i++)
		lara.mesh_ptrs[i] = (sint16 *)((long)lara.mesh_ptrs[i] + (long)mesh_base);
	lara.left_arm.frame_base = (sint16 *)((long)lara.left_arm.frame_base + (long)frames);
	lara.right_arm.frame_base = (sint16 *)((long)lara.right_arm.frame_base + (long)frames);

#ifdef FULL_SAVE
	/* Is Lara using a new weapon (M16, harpoon, etc)? (won't be on PSX, as have to pick up crystal) */
	if (lara.weapon_item != NO_ITEM)
	{
		item = &items[lara.weapon_item];
		WriteSG(&item->object_number, sizeof(sint16));
		WriteSG(&item->anim_number, sizeof(sint16));
		WriteSG(&item->frame_number, sizeof(sint16));
		WriteSG(&item->current_anim_state, sizeof(sint16));
		WriteSG(&item->goal_anim_state, sizeof(sint16));
	}
#endif

	WriteSG(&flipeffect, sizeof(int));
	WriteSG(&fliptimer, sizeof(int));
	WriteSG(&monks_attack_lara, sizeof(int));

#ifdef FULL_SAVE
	/* First count up number of flares, then output their info */
	number_flares = 0;
	for (i=level_items, item=&items[level_items]; i<NUMBER_ITEMS; i++, item++)
		if (item->active && item->object_number == FLARE_ITEM)
			number_flares++;

		WriteSG(&number_flares, sizeof(int));
	for (i=level_items, item=&items[level_items]; i<NUMBER_ITEMS; i++, item++)
		if (item->active && item->object_number == FLARE_ITEM)
		{
			WriteSG(&item->pos, sizeof(PHD_3DPOS));
			WriteSG(&item->room_number, sizeof(sint16));
			WriteSG(&item->speed, sizeof(sint16));
			WriteSG(&item->fallspeed, sizeof(sint16));
			flare_age = (int)item->data;
			WriteSG(&flare_age, sizeof(int));
		}
#endif

#if defined(PSX_VERSION) && defined(GAMEDEBUG)
	printf("SGcount: %d\n", SGcount);
#endif
}


void ExtractSaveGameInfo(void)
{
	int number_flares, flare_age;
	sint16 i, item_number;
	OBJECT_INFO *obj;
	ITEM_INFO *item;
	FLOOR_INFO *floor;
	sint16 room_number;
	char tflag;
	CREATURE_INFO *creature;
#if defined(PSX_VERSION) && defined(GAMEDEBUG)
	printf("ExtractSaveGameInfo()\n");
#endif

#ifdef PSX_VERSION
	InitialiseLaraInventory(0);
#else
	InitialiseLaraInventory(CurrentLevel);
#endif
#if defined(PSX_VERSION) && defined(GAMEDEBUG)
	printf("Adding Keys/Puzzles\n");
#endif

	/* Initialise Local Level items such as Keys/Puzzle Items */
	for (i=savegame.num_pickup1; i>0; i--)
		Inv_AddItem( PICKUP_ITEM1 );

	for (i=savegame.num_pickup2; i>0; i--)
		Inv_AddItem( PICKUP_ITEM2 );

	for (i=savegame.num_puzzle1; i>0; i--)
		Inv_AddItem( PUZZLE_ITEM1 );

	for (i=savegame.num_puzzle2; i>0; i--)
		Inv_AddItem( PUZZLE_ITEM2 );

	for (i=savegame.num_puzzle3; i>0; i--)
		Inv_AddItem( PUZZLE_ITEM3 );

	for (i=savegame.num_puzzle4; i>0; i--)
		Inv_AddItem( PUZZLE_ITEM4 );

	for (i=savegame.num_key1; i>0; i--)
		Inv_AddItem( KEY_ITEM1 );

	for (i=savegame.num_key2; i>0; i--)
		Inv_AddItem( KEY_ITEM2 );

	for (i=savegame.num_key3; i>0; i--)
		Inv_AddItem( KEY_ITEM3 );

	for (i=savegame.num_key4; i>0; i--)
		Inv_AddItem( KEY_ITEM4 );

#if defined(PSX_VERSION) && defined(GAMEDEBUG)
	printf("Reading savegame buffer\n");
#endif
	/* Now load other stuff from savegame buffer */
	ResetSG();

	/* Flip map if need be */
	ReadSG(&i, sizeof(int));
	if (i)
		FlipMap();

	/* Load flipmap flags */
	for (i=0; i<MAX_FLIPMAPS; i++)
	{
		ReadSG(&tflag, sizeof(char));
		flipmap[i] = (sint16)tflag << 8;
	}

	/* CD track flags */
	ReadSG(cd_flags, sizeof(sint16) * MAX_CD_TRACKS);

	/* Load fixed camera/sink flags */
	for (i=0; i<number_cameras; i++)
		ReadSG(&camera.fixed[i].flags, sizeof(sint16));

	/* Go through all the items in the level and load in the salient features */
	for (i=0, item=items; i<level_items; i++, item++)
	{
		obj = &objects[item->object_number];

		/* MOVABLE BLOCK needs a little extra work due to its effect on the ground height */
		if (obj->control == MovableBlock)
			AlterFloorHeight(item, 1024);

		if (obj->save_position)
		{
			ReadSG(&item->pos, sizeof(PHD_3DPOS));
			ReadSG(&room_number, sizeof(sint16));
#ifdef FULL_SAVE
			ReadSG(&item->speed, sizeof(sint16));
			ReadSG(&item->fallspeed, sizeof(sint16));
#endif
			if (item->room_number != room_number)
				ItemNewRoom(i, room_number);

			/* Setup floor height for item's shadow */
			if (obj->shadow_size)
			{
				floor = GetFloor(item->pos.x_pos, item->pos.y_pos, item->pos.z_pos, &room_number);
				item->floor = GetHeight(floor, item->pos.x_pos, item->pos.y_pos, item->pos.z_pos);
			}

		}

		if (obj->save_anim)
		{
			ReadSG(&item->current_anim_state, sizeof(sint16));
#ifdef FULL_SAVE
			ReadSG(&item->goal_anim_state, sizeof(sint16));
			ReadSG(&item->required_anim_state, sizeof(sint16));
#endif
			ReadSG(&item->anim_number, sizeof(sint16));
			ReadSG(&item->frame_number, sizeof(sint16));
		}

		if (obj->save_hitpoints)
			ReadSG(&item->hit_points, sizeof(sint16));

		if (obj->save_flags)
		{
			ReadSG(&item->flags, sizeof(sint16));
			if (obj->intelligent)
				ReadSG(&item->carried_item, sizeof(sint16));

#ifdef FULL_SAVE
			ReadSG(&item->timer, sizeof(sint16));
#endif

			/* Setup item flags, including activating baddies etc */
			if (item->flags & KILLED_ITEM)
			{
				KillItem(i);
				item->status = DEACTIVATED;
			}
			else
			{
				if ((item->flags & 1) && !item->active)
					AddActiveItem(i);

				item->status = (item->flags & 6)>>1;
				if (item->flags & 8)
					item->gravity_status = 1;
				if (!(item->flags & 0x10))
					item->collidable = 0;
			}

#ifdef FULL_SAVE
			/* Load in baddies intelligence stuff */
			if (item->flags & SAVE_CREATURE)
			{
				EnableBaddieAI(i, 1);
				creature = (CREATURE_INFO *)item->data;
				if (creature)
				{
					ReadSG(&creature->head_rotation, sizeof(sint16));
					ReadSG(&creature->neck_rotation, sizeof(sint16));
					ReadSG(&creature->maximum_turn, sizeof(sint16));
					ReadSG(&creature->flags, sizeof(sint16));
					ReadSG(&creature->mood, sizeof(MOOD_TYPE));
				}
				else
					SGpoint += sizeof(sint16)*4 + sizeof(MOOD_TYPE);
			}
			else if (obj->intelligent)
			{
				/* If not saved, but intelligent, means that currently no AI allocated */
				item->data = NULL;
				if (item->clear_body && item->hit_points<=0 && !(item->flags & KILLED_ITEM)) // uncleared body for the body bag
				{
					item->next_active = body_bag;
					body_bag = i;
				}
			}
#endif
			item->flags &= 0xff00;

			/* PUZZLE HOLES that have deactivated have changed to PUZZLE_DONE */
			if (obj->collision == PuzzleHoleCollision && (item->status==DEACTIVATED || item->status==ACTIVE))
				item->object_number += PUZZLE_DONE1 - PUZZLE_HOLE1;

			/* PICKUPs can be DEACTIVATED if used to trigger a pickup trigger, so need to be removed from draw list */
			if (obj->collision == PickUpCollision && item->status == DEACTIVATED)
				RemoveDrawnItem(i);

			/* SMASH_WINDOW and SMASH_ICE will be in broken state if ONESHOT bit is set */
			if ((item->object_number == SMASH_WINDOW || item->object_number == SMASH_ICE) && (item->flags & ONESHOT))
				item->mesh_bits = 0x00100;

			/* MINE is detonated if ONESHOT set */
			if (item->object_number == MINES && (item->flags & ONESHOT))
				item->mesh_bits = 1;
		}

		/* Setup MOVABLE BLOCK in new position */
		if (obj->control == MovableBlock && item->status == NOT_ACTIVE)
			AlterFloorHeight(item, -1024);

#ifdef FULL_SAVE
		/* Load vehicle specific stuff */
		if (item->object_number == MOTORBOAT)
			ReadSG(item->data, sizeof(BOAT_INFO));
		else if (item->object_number == SKIDOO)
			ReadSG(item->data, sizeof(SKIDOO_INFO));
		else if (item->object_number == LIFT)
			ReadSG(item->data, sizeof(int)*2);
#endif
		/* SKIDMAN may be dead; if so, his skidoo (BANDIT3) is now a true SKIDOO
			(and know will be loaded in after SKIDMAN as he created it) */
		if (item->object_number == SKIDMAN && item->status==DEACTIVATED)
		{
			items[(int)item->data].object_number = SKIDOO;
			InitialiseSkidoo((sint16)item->data);
		}
	}

	ReadSG(&lara, sizeof(LARA_INFO));

	lara.creature = NULL;
	lara.spaz_effect = NULL;
	for (i=0; i<15; i++)
		lara.mesh_ptrs[i] = (sint16 *)((long)lara.mesh_ptrs[i] + (long)mesh_base);
	lara.target = NULL;
	lara.left_arm.frame_base = (sint16 *)((long)lara.left_arm.frame_base + (long)frames);
	lara.right_arm.frame_base = (sint16 *)((long)lara.right_arm.frame_base + (long)frames);

#ifdef FULL_SAVE
	/* Is Lara using a new weapon (M16, harpoon, etc)? (won't be on PSX, as have to pick up crystal) */
	if (lara.weapon_item != NO_ITEM)
	{
		lara.weapon_item = CreateItem();
		item = &items[lara.weapon_item];
		ReadSG(&item->object_number, sizeof(sint16));
		ReadSG(&item->anim_number, sizeof(sint16));
		ReadSG(&item->frame_number, sizeof(sint16));
		ReadSG(&item->current_anim_state, sizeof(sint16));
		ReadSG(&item->goal_anim_state, sizeof(sint16));
		item->status = ACTIVE;
		item->room_number = NO_ROOM;
	}
#endif

	if (lara.burn) // user saved whilst on fire!
	{
		lara.burn = 0;
		LaraBurn();
	}

	ReadSG(&flipeffect, sizeof(int));
	ReadSG(&fliptimer, sizeof(int));
	ReadSG(&monks_attack_lara, sizeof(int));

#ifdef FULL_SAVE
	/* First count up number of flares, then output their info */
	ReadSG(&number_flares, sizeof(int));
	//printf("Number of flares=%d", number_flares);
	for (i=0; i<number_flares; i++)
	{
		item_number = CreateItem();
		item = &items[item_number];
		item->object_number = FLARE_ITEM;
		ReadSG(&item->pos, sizeof(PHD_3DPOS));
		ReadSG(&item->room_number, sizeof(sint16));
		ReadSG(&item->speed, sizeof(sint16));
		ReadSG(&item->fallspeed, sizeof(sint16));
		InitialiseItem(item_number);
		AddActiveItem(item_number);
		ReadSG(&flare_age, sizeof(int));
		item->data = (void *)flare_age;
	}
#endif
}


void ResetSG()
{
	SGcount = 0;
	SGpoint = savegame.buffer;
}


void WriteSG(void *pointer, int size)
{
	char *data;

	SGcount += size;
	if (SGcount >= MAX_SAVEGAME_BUFFER)
	{
#if defined(GAMEDEBUG) && defined(PSX_VERSION)
		printf("SGcount=%d (%d MAX)\n", SGcount, MAX_SAVEGAME_BUFFER);
#endif
		S_ExitSystem("FATAL: Savegame is too big to fit in buffer");
	}

	data = pointer;

	for ( ; size>0; size--)
		*(SGpoint++) = *(data++);
}


void ReadSG(void *pointer, int size)
{
	char *data;

	SGcount += size;

	data = pointer;

	for ( ; size>0; size--)
		*(data++) = *(SGpoint++);
}

#ifndef PSX_VERSION
int ConfirmSave(int fade)
{
	int	nframes;
	int status=1;
	TEXTSTRING *text[3]={NULL};

	T_InitPrint();
	if (fade)
	{
		S_FadeInInventory(1);
	}
	text[0] = T_Print(0,0,0,GF_PCStrings[PCSTR_SAVEMESS8]);
	T_CentreH(text[0], 1);
	T_CentreV(text[0], 1);

	text[1] = T_Print(-26,20,0,GF_PCStrings[PCSTR_SAVEMESS3]);
	T_CentreH(text[1], 1);
	T_CentreV(text[1], 1);
	T_AddOutline(text[1], 1, C_ORANGE, req_sel_gour2, 0);

	text[2] = T_Print(30,20,0,GF_PCStrings[PCSTR_SAVEMESS4]);
	T_CentreH(text[2], 1);
	T_CentreV(text[2], 1);

	while (input & IN_SELECT)
		S_UpdateInput();

	do
	{
		S_UpdateInput();
#ifdef PC_VERSION
		S_InitialisePolyList(SIPL_DONT_CLEAR_SCREEN);	// bgnd clears it
#else
		S_InitialisePolyList();
#endif
		S_CopyBufferToScreen();
		if (input&IN_LEFT && status==0)
		{
			T_AddOutline(text[1], 1, C_ORANGE, req_sel_gour2, 0);
			T_RemoveOutline(text[2]);
			status=1;
		}
		if (input&IN_RIGHT && status==1)
		{
			T_RemoveOutline(text[1]);
			T_AddOutline(text[2], 1, C_ORANGE, req_sel_gour2, 0);
			status=0;
		}

		T_DrawText();
		S_OutputPolyList();
		nframes = S_DumpScreen();
	}
	while(!(input&IN_SELECT));

	input = 0;

	while (input & IN_SELECT)
		S_UpdateInput();

	T_RemovePrint(text[0]); text[0] = NULL;
	T_RemovePrint(text[1]); text[1] = NULL;
	T_RemovePrint(text[2]); text[2] = NULL;

	return(status);
}

void CompleteSave(int fade)
{
	if (fade)
	{
		S_FadeOutInventory(1);
	}
}
#endif
/********************************************************************
 *			create the save game checksum
 *******************************************************************/
#ifdef PSX_VERSION
void	CreateCheckSum( SAVEGAME_INFO *sg )
{
	int		i;
	signed char	*ptr,csum;

	if ( sg==NULL )
		return;
	csum = 0;
	sg->checksum = 0;
	ptr = (signed char *)sg;
	for ( i=0; i<sizeof(SAVEGAME_INFO); i++,ptr++ )
		csum += *ptr;
	sg->checksum = -csum;
}
#else
void	CreateCheckSum(void)
{
	int		i;
	signed char	*ptr,csum;

	csum = 0;
	savegame.checksum = 0;
	ptr = (signed char *)&savegame;
	for ( i=0; i<sizeof(SAVEGAME_INFO); i++,ptr++ )
		csum += *ptr;
	savegame.checksum = -csum;
}
#endif

/********************************************************************
 *			Check If the Savegame is Valid
 *******************************************************************/
int		CheckSumValid( SAVEGAME_INFO *buffer )
{
	int		i;
	signed char	*ptr,csum;

	csum = 0;
	ptr = (signed char *)buffer;
	for ( i=0; i<sizeof(SAVEGAME_INFO); i++,ptr++ )
		csum += *ptr;
	if ( !csum )
		return(1);
	return(0);
}
