/*
*Copyright(c)2018, Jeffrey Lee
*Allrightsreserved.
*
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met: 
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
*/

union {int i[222];char c[888];} game;

#define kills game.i[8]
#define level game.i[9]
#define flighttime game.i[10]
#define debt game.i[11]
#define shipstuff1 game.i[135]
#define shipstuff2 game.i[136]
#define life_support_damage game.i[137]
#define engine_damage game.i[138]
#define weapons_damage game.i[139]
#define targeting_damage game.i[140]
#define scanner_damage game.i[141]
#define ecm_damage game.i[142]
#define cloak_damage game.i[143]
#define credits game.i[145]
#define cargo_size game.i[171]
#define cargo_slaves game.c[688]
#define cargo_exotic game.c[689]
#define cargo_nuke game.c[690]
#define cargo_weapons game.c[691]
#define cargo_shields game.c[692]
#define cargo_pods game.c[693]
#define cargo_computers game.c[694]
#define cargo_ammo game.c[695]
#define cargo_vehicles game.c[696]
#define cargo_machinery game.c[697]
#define cargo_drugs game.c[698]
#define cargo_glass game.c[699]
#define cargo_medicine game.c[700]
#define cargo_ore game.c[701]
#define cargo_spice game.c[702]
#define cargo_granite game.c[703]
#define cargo_timber game.c[704]
#define cargo_chocolate game.c[705]
#define cargo_plastic game.c[706]
#define cargo_livestock game.c[707]
#define cargo_chickens game.c[708]
#define cargo_water game.c[709]
#define cargo_cloth game.c[710]
#define ship_x game.i[178]
#define ship_y game.i[179]
#define jump_speed game.i[182]
#define ship_system game.i[183]
#define selected_missile game.i[185]
#define missiles_red game.c[748]
#define missiles_yellow game.c[749]
#define missiles_green game.c[750]
#define missiles_blue game.c[751]
#define ship_name game.i[188]
#define laser_charge game.i[189]
#define ship_type game.i[190]
#define ship_speed game.i[191]
#define ship_angle game.i[192]
#define top_speed game.i[193]
#define sector_x game.i[196]
#define sector_y game.i[197]
#define x_vel game.i[198]
#define y_vel game.i[199]
#define shield_charge game.c[811]

int get_cloaked_ship_detector() {return (shipstuff2 & 0x00200000)>>21;}
void set_cloaked_ship_detector(int s) {shipstuff2 = (shipstuff2 - (shipstuff2 & 0x00200000)) | s<<21;}

int get_cloak() {return (shipstuff2 & 0x00100000)>>20;}
void set_cloak(int s) {shipstuff2 = (shipstuff2 - (shipstuff2 & 0x00100000)) | s<<20;}

int get_auto_tracker() {return (shipstuff2 & 0x00080000)>>19;}
void set_auto_tracker(int s) {shipstuff2 = (shipstuff2 - (shipstuff2 & 0x00080000)) | s<<19;}

int get_sound_monitor() {return (shipstuff2 & 0x00040000)>>18;}
void set_sound_monitor(int s) {shipstuff2 = (shipstuff2 - (shipstuff2 & 0x00040000)) | s<<18;}

int get_windows() {return (shipstuff2 & 0x00010000)>>16;}
void set_windows(int s) {shipstuff2 = (shipstuff2 - (shipstuff2 & 0x00010000)) | s<<16;}

int get_auto_pilot() {return (shipstuff2 & 0x00008000)>>15;}
void set_auto_pilot(int s) {shipstuff2 = (shipstuff2 - (shipstuff2 & 0x00008000)) | s<<15;}

int get_attractor() {return (shipstuff2 & 0x00004000)>>14;}
void set_attractor(int s) {shipstuff2 = (shipstuff2 - (shipstuff2 & 0x00004000)) | s<<14;}

int get_repair_upgrade() {return (shipstuff2 & 0x00002000)>>13;}
void set_repair_upgrade(int s) {shipstuff2 = (shipstuff2 - (shipstuff2 & 0x00002000)) | s<<13;}

int get_ecm()
{
	if (shipstuff1 & 0x40000000)
		return 2; // Destroy foe
	if (shipstuff1 & 0x80000000)
		return 1; // Destroy all
	if (shipstuff2 & 1)
		return 3; // Seduce foe
	if (shipstuff2 & 2)
		return 0; // None
	return 0;
}
void set_ecm(int s)
{
	shipstuff1 = shipstuff1 & 0x3FFFFFFF;
	shipstuff2 = shipstuff2 - (shipstuff2 & 3);
	if (s == 2)
		shipstuff1 = shipstuff1 | 0x40000000;
	else if (s == 1)
		shipstuff1 = shipstuff1 | 0x80000000;
	else if (s == 3)
		shipstuff2 = shipstuff2 | 1;
	else if (s == 0)
		shipstuff2 = shipstuff2 | 2;
}

int bits_down(int i)
{
	if (i == 1)
		return 0;
	if (i == 2)
		return 1;
	if (i == 4)
		return 2;
	if (i == 8)
		return 3;
	return 0; // Stop any broken save games from corrupting the display
}

int get_top_speed() {return bits_down(shipstuff1 & 0xF);}
void set_top_speed(int s) {shipstuff1 = (shipstuff1 - (shipstuff1 & 0xF)) + (1<<s);}

int get_acceleration() {return bits_down((shipstuff1 & 0x1E0)>>5);}
void set_acceleration(int s) {shipstuff1 = (shipstuff1 - (shipstuff1 & 0x1E0)) + (1<<(s+5));}

int get_rotation_speed() {return bits_down((shipstuff1 & 0x3C00)>>10);}
void set_rotation_speed(int s) {shipstuff1 = (shipstuff1 - (shipstuff1 & 0x3C00)) + (1<<(s+10));}

int get_shields() {return bits_down((shipstuff1 & 0x78000)>>15);}
void set_shields(int s) {shipstuff1 = (shipstuff1 - (shipstuff1 & 0x78000)) + (1<<(s+15));}

int get_firing_rate() {return bits_down((shipstuff1 & 0xF00000)>>20);}
void set_firing_rate(int s) {shipstuff1 = (shipstuff1 - (shipstuff1 & 0xF00000)) + (1<<(s+20));}

int get_weapon_power() {return bits_down((shipstuff1 & 0x1E000000)>>25);}
void set_weapon_power(int s) {shipstuff1 = (shipstuff1 - (shipstuff1 & 0x1E000000)) + (1<<(s+25));}

int get_power_generator() {return bits_down((shipstuff2 & 0x78)>>3);}
void set_power_generator(int s) {shipstuff2 = (shipstuff2 - (shipstuff2 & 0x78)) + (1<<(s+3));}

char ship_names[244][16];

void load_shipnames(char *namesfile)
{
	FILE *f;
	int n,p;
	// Just load straight from SunBurst for now...
	f=fopen(namesfile,"rb"); // Use binary mode so fseek can be easily used
	if (f == NULL)
	{
		for(n=0;n<244;n++)
			strcpy(ship_names[n],"No names loaded");
		return;
	}
	fseek(f,982,SEEK_SET); // Have to copy strings manually though :(
	for(n=0;n<244;n++)
	{
		p=-1;
		do
		{
			p++;
			ship_names[n][p] = fgetc(f);
			if (ship_names[n][p] < 32)
				ship_names[n][p] = 0;
		}
		while (ship_names[n][p] != 0);
	}
	fclose(f);
}

#define names_memory 0x87900

int file_open;

void game_loadfile()
{
	FILE *f;
	int a;
	// Load the file from limp.b[11]...
	f=fopen((char *) &limp.b[11],"rb");
	for (a=0;a<888;a++)
		game.c[a] = fgetc(f); // Load char at a time...
	fclose(f);
	// Now acknowledge load
	limp.b[3] = limp.b[2];
	limp.b[4] = 4; // DataLoadAck
	Limp_SendMessage(17,&limp.b,limp.b[1],0);
	file_open = 1;
	// Set the file name...
	Limp_SetIconText(wh_xfer_send,1,(char *) &limp.b[11]);
}

char *decode_ship_class()
{
	if (ship_type == 0)
		return "Shuttle";
	if (ship_type == 1)
		return "Sirius";
	if (ship_type == 2)
		return "Wing";
	if (ship_type == 3)
		return "Nova";
	if (ship_type == 4)
		return "Kosmos";
	if (ship_type == 5)
		return "Magnx";
	return "Unknown or alien?";
}

char *decode_ship_system()
{
	if (ship_system == 0)
		return "Virain";
	if (ship_system == 1)
		return "Imperial";
	if (ship_system == 2)
		return "Poliniss";
	if (ship_system == 3)
		return "Void";
	if (ship_system == 4)
		return "Alien";
	return "Unknown";
}

char *decode_ship_location()
{
	if (ship_system == 0)
	{
		if ((ship_x == 58) && (ship_y == 60))
			return "HyperJump";
		if ((ship_x == 20) && (ship_y == 10))
			return "Homeworld";
		if ((ship_x == 10) && (ship_y == 50))
			return "Nebula";
		return "Not docked";
	}
	if (ship_system == 1)
	{
		if ((ship_x == 8) && (ship_y == 32))
			return "Jumpstation";
		if ((ship_x == 48) && (ship_y == 42))
			return "Imperial HQ";
		if ((ship_x == 40) && (ship_y == 4))
			return "Nimbus";
		return "Not docked";
	}
	if (ship_system == 2)
	{
		if ((ship_x == 5) && (ship_y == 8))
			return "HyperJump";
		if ((ship_x == 50) && (ship_y == 38))
			return "Home Station";
		if ((ship_x == 10) && (ship_y == 48))
			return "Fortress";
		return "Not docked";
	}
	if (ship_system == 3)
	{
		if ((ship_x == 55) && (ship_y == 57))
			return "Hyper Jump";
		if ((ship_x == 48) && (ship_y == 4))
			return "Research1";
		if ((ship_x == 20) && (ship_y == 24))
			return "Oasis";
		if ((ship_x == 8) && (ship_y == 48))
			return "Research2";
		return "Not docked";
	}
	if (ship_system == 4)
	{
		if ((ship_x == 5) && (ship_y == 20))
			return "Alien Lab";
		return "Not docked";
	}
	return "Unknown";
}

char *decode_damage(int d)
{
	if (d == 0)
		return "OK";
	if (d<256)
		return "Repairable";
	if (d<640)
		return "Crippled";
	return "Dead";
}

void save_file(char *name)
{
	_kernel_swi_regs regs;
	// Read the data into the array...
	get_save_data();
	// Save the file...
#ifdef DEBUG
	fprintf(debuglog,"Saving file to %s\n",name);
#endif
	regs.r[0] = 10;
	regs.r[1] = (int) name;
	regs.r[2] = 0x7DB;
	regs.r[4] = (int) &game;
	regs.r[5] = regs.r[4] + 888;
	_kernel_swi(OS_File,&regs,&regs);
}
