/*

	Noctis galactic guide / RSCAN command.
	GOES Net Module.
	
	This scans the current system for ruins.
	
	Module written by SL, with a good part of the code copied from other modules' source. (You can probably tell what's mine (or mostly so), since I use CamelCase for the names of functions I write)
	
*/

const double MAX_OBJECTS_PER_STAR = 80;

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <dos.h>
#include <io.h>
#define ISTHEREACTION CheckSystem();
int CheckSystem ();
#include "modshare.hpp"

//////////////////////////////////////////////////////////////////////////////

char msgBuff[120];
	
long flat_rnd_seed;

void fast_srand (long seed) // selezione tabella pseudo.
			    // 4.294.967.295 tabelle possibili.
			    // (ca. 20000 elementi diversi per tabella)
{
	asm {
		or word ptr seed, 3
		db 0x66; mov ax, word ptr seed
		db 0x66; mov word ptr flat_rnd_seed, ax
	}
}

long fast_random (long mask) // estrazione di un numero: "mask" attiva i bits.
{
	long num;

	asm {
		db 0x66; mov ax, word ptr flat_rnd_seed
		db 0x66; mov dx, word ptr flat_rnd_seed
		db 0x66; mul dx
			 add al, dl
		db 0x66; add word ptr flat_rnd_seed, ax
		db 0x66; and ax, word ptr mask
		db 0x66; mov word ptr num, ax
	}

	return (num);
}

int ranged_fast_random (int range)
{
	if (range<=0) range = 1;
	return (fast_random(0x7FFF) % range);
}

float flandom ()
{ return ((float)random(32767) * 0.000030518); }

float fast_flandom ()
{ return ((float)fast_random(32767) * 0.000030518); }



char   sync               = 1;		// 0
char   anti_rad           = 1;          // 1
char   pl_search          = 0;          // 2
char   field_amplificator = 0;          // 3
char   ilight             = 63;         // 4
char   ilightv            = 1;          // 5
char   charge             = 3;          // 6
char   revcontrols        = 0;          // 7
char   ap_targetting      = 0;          // 8
char   ap_targetted       = 0;          // 9
char   ip_targetting      = 0;          // 10
char   ip_targetted       = -1;		// 11
char   ip_reaching        = 0;          // 12
char   ip_reached         = 0;          // 13
char   ap_target_spin     = 0;          // 14
char   ap_target_r        = 0;          // 15
char   ap_target_g        = 0;          // 16
char   ap_target_b        = 0;          // 17
char   nearstar_spin      = 0;          // 18
char   nearstar_r         = 0;          // 19
char   nearstar_g         = 0;          // 20
char   nearstar_b         = 0;          // 21
char   gburst	          = 0;          // 22
char   menusalwayson      = 1;		// 23
char   depolarize  	  = 0;          // 24
int    sys                = 4;		// 25
int    pwr                = 15000;	// 27
int    dev_page           = 0;		// 29
int    ap_target_class    = 0;		// 31
int    f_ray_elapsed	  = 0;		// 33
int    nearstar_class     = 0;		// 35
int    nearstar_nop       = 0;		// 37
float  pos_x              = 0;		// 39
float  pos_y              = 0;		// 43
float  pos_z              = -500;	// 47
float  user_alfa          = 0;		// 51
float  user_beta          = 0;		// 55
float  navigation_beta    = 0;		// 59
float  ap_target_ray      = 0;		// 63
float  nearstar_ray       = 1000;	// 67
double dzat_x             = +3797120;
double dzat_y             = -4352112;
double dzat_z             = -925018;
double ap_target_x        = 0;
double ap_target_y        = 1E9;
double ap_target_z        = 0;
double nearstar_x         = 0;
double nearstar_y         = 1E9;
double nearstar_z         = 0;
double helptime           = 0;
double ip_target_initial_d= 0;
double requested_approach_coefficient = 1;
double current_approach_coefficient = 1;
double reaction_time      = 0.01;
char   fcs_status[11]     = "STANDBY";
int    fcs_status_delay   = 0;
int    psys               = 4;
double ap_target_initial_d= 0;
double requested_vimana_coefficient = 1;
double current_vimana_coefficient = 1;
double vimana_reaction_time = 0.01;
char   lithium_collector  = 0;
char   autoscreenoff	  = 0;
char   ap_reached         = 0;
int    lifter		  = 0;
double secs		  = 0;

void unfreeze ()
{
	int fh = _open (real_situation_file, 0);
	if (fh>-1) {
		_read (fh, &sync, 244);
		_close (fh);
	}
}

//////////////////////////////////////////////////////////////////////////////


double 	object_id = 12345;
char   	object_label[25];
double 	s_object_id = 12345;
char   	s_object_label[25];

double	subject_id = 12345;
double  idscale = 100000; //0.00001;

int	sts;
char	query;

long	round;
int 	i, fh, gh;
int 	analyzed_sectors_range;
char	*file = "..\\DATA\\STARMAP.BIN";
char    *comm = "..\\DATA\\COMM.BIN";

char	outbuffer[40];
char	textbuffer[40];
char	parbuffer[160];
char	nullbuffer[128];
char	objectname[21];
char	subjectname[21];

//////////////////////////////////////////////////////////////////////////////

const double deg = M_PI / 180;

#define qt_M_PI   4*M_PI/3

#define star_classes    12
#define planet_types    10
#define avgmoons        4
#define log2avgmoons	2
#define maxbodies	20 * avgmoons

char class_rgb[3*star_classes] = {
	63, 58, 40,
	30, 50, 63,
	63, 63, 63,
	63, 30, 20,
	63, 55, 32,
	32, 16, 10,
	32, 28, 24,
	10, 20, 63,
	63, 32, 16,
	48, 32, 63,
	40, 10, 10,
	00, 63, 63
};

int class_ray[star_classes] = { 5000, 15000, 300, 20000, 15000, 1000, 3000,
				2000, 4000, 1500, 30000, 250 };

int class_rayvar[star_classes] = { 2000, 10000, 200, 15000, 5000, 1000, 3000,
				   500, 5000, 10000, 1000, 10 };

int class_act[star_classes] = { 2, 4, 1, 6, 5, 10, 100, 1, 2, 1, 10, 1 };

char class_planets[star_classes] = { 12, 18, 8, 15, 20, 3, 0, 1, 7, 20, 2, 5 };

char   nearstar_p_type       [maxbodies];
int    nearstar_p_owner	     [maxbodies];
char   nearstar_p_moonid     [maxbodies];
double nearstar_p_ring       [maxbodies];
double nearstar_p_tilt       [maxbodies];
double nearstar_p_ray        [maxbodies];
double nearstar_p_orb_ray    [maxbodies];
double nearstar_p_orb_seed   [maxbodies];
double nearstar_p_orb_tilt   [maxbodies];
double nearstar_p_orb_orient [maxbodies];
double nearstar_p_orb_ecc    [maxbodies];

int planet_possiblemoons[] = { 1, 1, 2, 3, 2, 2, 18, 2, 3, 20, 20 };

const double planet_orb_scaling=  5.0;
const double avg_planet_sizing =  2.4;
const double moon_orb_scaling  = 12.8;
const double avg_moon_sizing   =  1.8;

double avg_planet_ray[] = { 0.007, 0.003, 0.010, 0.011, 0.010,
			    0.008, 0.064, 0.009, 0.012, 0.125,
			    2.000 };

double laststar_x, laststar_y, laststar_z, beststar_x, beststar_y, beststar_z;
int bestplanet=-1; int bestmoon=-1; int bestrotation=-1;
double bestdistance=-1;
float  zrandom (int range) { return (random(range) - random(range)); }
double nearstar_identity;
int    nearstar_nob;


void extract_ap_target_infos ()
{
	srand (ap_target_x/100000*ap_target_y/100000*ap_target_z/100000);

	ap_target_class = random (star_classes);
	ap_target_ray = ((float)class_ray[ap_target_class] + (float)random(class_rayvar[ap_target_class])) * 0.001;

	ap_target_r = class_rgb[3*ap_target_class+0];
	ap_target_g = class_rgb[3*ap_target_class+1];
	ap_target_b = class_rgb[3*ap_target_class+2];

	ap_target_spin = 0;
	if (ap_target_class==11) ap_target_spin = random (30) + 1;
	if (ap_target_class==7) ap_target_spin = random (12) + 1;
	if (ap_target_class==2) ap_target_spin = random (4) + 1;
}

void scan_nearstar ()
{
	int    n, c, q, r, s, t;
	double key_radius;

	/*nearstar_class = ap_target_class;
	nearstar_x = ap_target_x;
	nearstar_y = ap_target_y;
	nearstar_z = ap_target_z;
	nearstar_ray = ap_target_ray;
	nearstar_spin = ap_target_spin;
	nearstar_r = ap_target_r;
	nearstar_g = ap_target_g;
	nearstar_b = ap_target_b;*/

	nearstar_identity = nearstar_x/100000*nearstar_y/100000*nearstar_z/100000;

	srand ((long)nearstar_x%10000*(long)nearstar_y%10000*(long)nearstar_z%10000);

	nearstar_nop = random (class_planets[nearstar_class] + 1);

	for (n=0; n<nearstar_nop; n++) {
		nearstar_p_owner[n]	 = -1;
		nearstar_p_orb_orient[n] = (double) deg * (double) random (360);
		nearstar_p_orb_seed[n]   = 3 * (n*n+1) * nearstar_ray + (float) random (300 * nearstar_ray) / 100;
		nearstar_p_tilt[n]       = zrandom (10*nearstar_p_orb_seed[n]) / 500;
		nearstar_p_orb_tilt[n]   = zrandom (10*nearstar_p_orb_seed[n]) / 5000;
		nearstar_p_orb_ecc[n]    = 1 - (double) random (nearstar_p_orb_seed[n] + 10*fabs(nearstar_p_orb_tilt[n])) / 2000;
		nearstar_p_ray[n]        = (double) random (nearstar_p_orb_seed[n]) * 0.001 + 0.01;
		nearstar_p_ring[n]	 = zrandom (nearstar_p_ray[n]) * (1 + (double) random (1000) / 100);
		if (nearstar_class != 8)
			nearstar_p_type[n] = random (planet_types);
		else {
			if (random(2)) {
				nearstar_p_type[n] = 10;
				nearstar_p_orb_tilt[n] *= 100;
			}
			else
				nearstar_p_type[n] = random (planet_types);
		}
		if (nearstar_class==2||nearstar_class==7||nearstar_class==15)
			nearstar_p_orb_seed[n] *= 10;
	}

	if (!nearstar_class) {
		if (random(4)==2) nearstar_p_type[2] = 3;
		if (random(4)==2) nearstar_p_type[3] = 3;
		if (random(4)==2) nearstar_p_type[4] = 3;
	}

	for (n=0; n<nearstar_nop; n++) {
		switch (nearstar_class) {
			case 2: while (nearstar_p_type[n]==3)
					nearstar_p_type[n] = random (10);
				break;
			case 5: while (nearstar_p_type[n]==6||
				       nearstar_p_type[n]==9)
					nearstar_p_type[n] = random (10);
				break;
			case 7:	nearstar_p_type[n] = 9;
				break;
			case 9: while (nearstar_p_type[n]!=0&&
				       nearstar_p_type[n]!=6&&
				       nearstar_p_type[n]!=9)
					nearstar_p_type[n] = random (10);
				break;
			case 11:while (nearstar_p_type[n]!=1&&
				       nearstar_p_type[n]!=7)
					nearstar_p_type[n] = random (10);
		}
	}

	for (n=0; n<nearstar_nop; n++) {
		switch (nearstar_p_type[n]) {
			case 0:
				if (random(8))
					nearstar_p_type[n] ++;
				break;
			case 3:
				if ((n<2)||(n>6)||(nearstar_class&&random(4))) {
					if (random(2))
						nearstar_p_type[n]++;
					else
						nearstar_p_type[n]--;
				}
				break;
			case 7:
				if (n<7) {
					if (random(2))
						nearstar_p_type[n] --;
					else
						nearstar_p_type[n] -= 2;
				}
				break;
		}
	}

	nearstar_nob = nearstar_nop;

	if (nearstar_class==2||nearstar_class==7||nearstar_class==15)
		goto no_moons;

	for (n=0; n<nearstar_nop; n++) {
		// (t=) Numero di satelliti per pianeta.
		s = nearstar_p_type[n];
		if (n < 2) {
			t = 0;
			if (s == 10)
				t = random (3);
		}
		else
			t = random (planet_possiblemoons[s] + 1);
		if (nearstar_nob + t > maxbodies)
			t = maxbodies - nearstar_nob;
		for (c=0; c<t; c++) {
			q 			 = nearstar_nob + c;
			nearstar_p_owner[q]	 = n;
			nearstar_p_moonid[q]	 = c;
			nearstar_p_orb_orient[q] = (double) deg * (double) random (360);
			nearstar_p_orb_seed[q]   = (c*c+4) * nearstar_p_ray[n] + (float) zrandom (300 * nearstar_p_ray[n]) / 100;
			nearstar_p_tilt[q]       = zrandom (10*nearstar_p_orb_seed[q]) / 50;
			nearstar_p_orb_tilt[q]   = zrandom (10*nearstar_p_orb_seed[q]) / 500;
			nearstar_p_orb_ecc[q]    = 1 - (double) random (nearstar_p_orb_seed[q] + 10*fabs(nearstar_p_orb_tilt[q])) / 2000;
			nearstar_p_ray[q]        = (double) random (nearstar_p_orb_seed[n]) * 0.05 + 0.1;
			nearstar_p_ring[q]	 = 0;
			nearstar_p_type[q]       = random (planet_types);
			r = nearstar_p_type[q];
			if (r==9 && s != 10) r = 2;
			if (r==6 && s < 9) r = 5;
			if (n > 7 && random(c)) r = 7;
			if (n > 9 && random(c)) r = 7;
			if (r==2 || r==3 || r==4 || r==8) {
				if (s != 6 && s < 9)
					r = 1;
			}
			if (r==3 && s < 9) {
				if (n > 7)
					r = 7;
				if (nearstar_class && random(4))
					r = 5;
				if (nearstar_class == 2 ||
				    nearstar_class == 7 ||
				    nearstar_class == 11)
					r = 8;
			}
			if (r==7 && n <= 5) r = 1;
			if ((nearstar_class==2||nearstar_class==5||
			     nearstar_class==7||nearstar_class==11)
			     && random(n)) r = 7;
			nearstar_p_type[q] = r;
		}
		nearstar_nob += t;
	}

no_moons:
	key_radius = nearstar_ray * planet_orb_scaling;
	if (nearstar_class == 8) key_radius *= 2;
	if (nearstar_class == 2) key_radius *= 16;
	if (nearstar_class == 7) key_radius *= 18;
	if (nearstar_class == 11) key_radius *= 20;
	for (n=0; n<nearstar_nop; n++) {
		nearstar_p_ray[n] = avg_planet_ray[nearstar_p_type[n]]
				  + avg_planet_ray[nearstar_p_type[n]] * zrandom (100) / 200;
		nearstar_p_ray[n] *= avg_planet_sizing;
		nearstar_p_orb_ray[n] = key_radius + key_radius * zrandom (100) / 500;
		nearstar_p_orb_ray[n] += key_radius * avg_planet_ray[nearstar_p_type[n]];
		if (n < 8)
			key_radius += nearstar_p_orb_ray[n];
		else
			key_radius += 0.22 * nearstar_p_orb_ray[n];
	}

	n = nearstar_nop;
	while (n < nearstar_nob) {
		q = 0;
		c = nearstar_p_owner[n];
		key_radius = nearstar_p_ray[c] * moon_orb_scaling;
		while (n<nearstar_nob && nearstar_p_owner[n] == c) {
			nearstar_p_ray[n] = avg_planet_ray[nearstar_p_type[n]]
					  + avg_planet_ray[nearstar_p_type[n]] * zrandom (100) / 200;
			nearstar_p_ray[n] *= avg_moon_sizing;
			nearstar_p_orb_ray[n] = key_radius + key_radius * zrandom (100) / 250;
			nearstar_p_orb_ray[n] += key_radius * avg_planet_ray[nearstar_p_type[n]];
			if (q < 2) key_radius += nearstar_p_orb_ray[n];
			if (q >= 2 && q < 8) key_radius += 0.12 * nearstar_p_orb_ray[n];
			if (q >= 8) key_radius += 0.025 * nearstar_p_orb_ray[n];
			q++;
			n++;
		}
	}

	for (n = 0; n < nearstar_nop; n++) {
		nearstar_p_ring[n] = 0.75 * nearstar_p_ray[n] * (2 + random(3));
		s = nearstar_p_type[n];
		if (s != 6 && s != 9) {
			if (random(5))
				nearstar_p_ring[n] = 0;
		}
		else {
			if (random(2))
				nearstar_p_ring[n] = 0;
		}
	}
}

//////////////////////////////////////////////////////////////////////////////

int GetRotationPeriod(double seedval) {
	fast_srand (seedval + 4112);

	/* "rtperiod" Š il tempo, in secondi, che il pianeta impiega a
	   ruotare di un grado sul proprio asse. Il tempo impiegato per
	   una rotazione completa Š quindi, in secondi, 360 * rtperiod. */

	int rtperiod = 10 * (ranged_fast_random(50) + 1)
					+ 10 * ranged_fast_random(25)
					+ ranged_fast_random (250)
					+ 41;
	return rtperiod;
}
				   
int CheckPlanet(float nearstar_ray, int n, int type, int is_moon, double orb_seed, double orb_tilt, double orb_ecc, double orb_orient) {
	static char msgBuff[120];
	if ((type>=1 && type<=5) || type==7 || type==8) {
		Dword   global_surface_seed, global_surface_seed_raw;
		global_surface_seed = (nearstar_p_ray[n]
			      + nearstar_p_orb_ray[n]
			      + nearstar_p_orb_orient[n]) * 4112;	//I wonder what the 4112 is for (SL)
		global_surface_seed_raw = global_surface_seed;
		SRAND (global_surface_seed_raw);
		fast_srand (global_surface_seed_raw);
		for (Word temp=0; temp<42; temp++) {
			fast_random(temp+100);
		}
		Dword randomRuins = 0;
		for (Word a=0; a<8; a++) {
			randomRuins+=fast_random(1023)+1;
		}
		//randomRuins=[8, 8192]
		randomRuins-=4192;
		//randomRuins=[-4200, 4000]
		if (randomRuins>0) {
			randomRuins/=364;
		} else {
			randomRuins=0;
		}
		//randomRuins=(-4200:363)=0, (364:4000)=[1, 10]
		randomRuins-=3;
		if (randomRuins<0) {
			randomRuins=0;
		}
		//randomRuins=(-4200:363)=0, (364:1455)=0 (1456:4000)=[1, 7]
		if (randomRuins>0) {
			if (is_moon) {
				int owner = nearstar_p_owner[n];
				int moon = nearstar_p_moonid[n];
				sprintf(msgBuff, "M %li OF P %li", (long)(moon+1), (long)(owner+1));
			} else {
				sprintf(msgBuff, "P %li", (long)(n+1));
			}
			msg (msgBuff);
			//fprintf(stderr, "rscan nearstar_nop(%li) nearstar_x(%li) nearstar_y(%li) nearstar_z(%li) Body number (%li) RGSSR(%li) randomRuins: %li.\n", (long)n, (long)nearstar_nop, (long)nearstar_x, (long)nearstar_y, (long)nearstar_z, (long)global_surface_seed_raw, (long)randomRuins);
			return 1;
		}
	}
	return 0;
	//if ((type>=1 && type<=5) || type==7 || type==8) {
	/*if (type==3) {
		if (is_moon) {
			if (type) {
				return GetRotationPeriod (
					 1000000		*
					 nearstar_ray		*
					 type     *
					 orb_orient);
			}
			else {
				return GetRotationPeriod (
					 2000000 * n		*
					 nearstar_ray		*
					 orb_orient);
			}
		}
		else {
			if (type) {
				return GetRotationPeriod (
					 1000000		*
					 type     *
					 orb_seed *
					 orb_tilt *
					 orb_ecc  *
					 orb_orient);
			}
			else {
				return GetRotationPeriod (
					 2000000 * n		*
					 orb_seed *
					 orb_tilt *
					 orb_ecc  *
					 orb_orient);
			}
		}
	}
	return 0;*/
}

char *planetTypeNames[] = { "INTERNALLY HOT",
			       "DUSTY",
			       "THICK ATMO",
			       "FELISIAN",
			       "CREASED",
			       "THIN ATMO",
			       "NOT CONSISTANT",
			       "ICY",
			       "QUARTZ",
			       "SUBSTELLAR",
			       "STAR" };

long int systemsChecked = 0;
long int outofrangeSystems = 0;
long planetsWithRuins = 0;
long totalPlanets = 0;
	
int CheckSystem ()
{
	
	scan_nearstar ();
	//if (nearstar_nob!=2) {
		//fprintf(stderr, "bodies: %li seed: %li\n", (long)nearstar_nob, (long)nearstar_identity);
	//}
	//warn("continuing", -1);
	
	if (nearstar_nob==0) return 0;
	long p1, p2, p3, p4;
	
	for (int n1=0; n1<nearstar_nop; n1++) {
		sprintf(msgBuff, "%i  %s", n1+1, planetTypeNames[nearstar_p_type[n1]]);
		msg(msgBuff);
		for (int n2=0; n2<nearstar_nob; n2++) {
			if (nearstar_p_owner[n2]==n1) {
				sprintf(msgBuff, "-%i %s", nearstar_p_moonid[n2]+1, planetTypeNames[nearstar_p_type[n2]]);
				msg(msgBuff);
			}
		}
	}
	msg (divider);
	
	sprintf (msgBuff, "FOUND RUINS ON:");
	msg (msgBuff);
	
	for (int n=0; n<nearstar_nob; n++) {
		int isMoon = (nearstar_p_owner[n]!=-1);
		planetsWithRuins += CheckPlanet(nearstar_ray, n, nearstar_p_type[n], isMoon, nearstar_p_orb_seed[n], nearstar_p_orb_tilt[n], nearstar_p_orb_ecc[n], nearstar_p_orb_orient[n]);
		totalPlanets += 1;
	}
	systemsChecked++;
	//sprintf (warnbuffer, "CHECKED %li SYSTEMS, IGNORED %li OUTOFRANGE, FOUND %li RUINS PLANETS OUT OF %li PLANETS TOTAL.", systemsChecked, outofrangeSystems, planetsWithRuins, totalPlanets);
	//warnMsg (warnbuffer, 0);
	//fprintf(stderr, warnbuffer);
	//fprintf(stderr, "\n");
	while (kbhit()) {
		if (getch() == 27) {
			return 1;
		}
	}
	return 0;
}


void main ()
{
	long p1, p2, p3, p4;
	CHECK_SITUATION;
	//FILE * file = fopen("..\\DATA\\GOESFILE.TXT", "wb");
	//if (file!=NULL) {
		//goesfile = file;
	//}
	msg ("SCANNING...");
	msg (divider);
	
	i = 2;
	strcpy (parbuffer, _argv[1]);
	
	/*i = 0;
	while (parbuffer[i]) {
		if (parbuffer[i] == '_')
			parbuffer[i] = 32;
		i++;
	}
	if (i==0) {
		analyzed_sectors_range = 100;
	} else {
		sts = atoi (parbuffer);
		if (sts <= 2 || sts > 10000)
			analyzed_sectors_range = 100;
		else
			analyzed_sectors_range = sts;
	}*/
	unfreeze ();
	//warnMsg ("SCANNING THE GALAXY: ESC TO STOP", -1);
	totalPlanets = 0;
	planetsWithRuins = 0;
	CheckSystem();
	if (planetsWithRuins==0) {
		msg ("NO PLANETS OR MOONS");
	}
	msg (divider);
	
	//FindSystems ();
	//isthere2(0.0, analyzed_sectors_range, 0, 0, 0, False);
	
	sprintf (msgBuff, "FOUND %li", planetsWithRuins);
	msg (msgBuff);
	sprintf (msgBuff, "BODIES WITH RUINS");
	msg (msgBuff);
	sprintf (msgBuff, "IN    %li", totalPlanets);
	msg (msgBuff);
	sprintf (msgBuff, "BODIES TOTAL.");
	msg (msgBuff);
	float percent = 0.0f;
	if (totalPlanets>0) {
		percent = ((float)((1000*planetsWithRuins)/(totalPlanets)))/10.0f;
	}
	sprintf(msgBuff, "%4.4f PERCENT", percent);
	msg (msgBuff);
	msg ("");	
	_close (fh);
	//if (goesfile!=stdout) {
		//fclose(goesfile);
	//}
}