/*

	Noctis galactic guide / TESTS command.
	GOES Net Module.
	
	This module runs some tests on stuff. I can't be more specific because I'll probably change this module a lot. :P
	
	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)
	Note: FindSystems() is a modified version of isthere(): Instead of checking each system or planet to see if its ID matches one we're searching for, FindSystems calls CheckSystem for every system it finds. Note that CheckSystem can tell it to exit (if the user presses escape) - this is because it can be a long time between slices in FindSystems.

	Modified Feb 13 2005 by SL to fix possible bug due to use of align_m and align_e, now uses start_y and start_z instead.
	
	This doesn't actually compile right now. FindSystems should be copied from fndplnt.
*/

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"

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

long int num_error_x=0;
long int num_error_y=0;
long int num_error_z=0;
long int num_nonexistant=0;
long int num_differ_lseed_lid=0;
long int num_differ_lseed_tseed=0;
long int num_differ_lid_tseed=0;
long int num_differ_lid_lid2=0;
long int num_equal=0;
long int num_valid=0;
long int num_valid_third=0;
long int num_nonexistant_third=0;
long int num_differ_lseed_ttseed=0;

double diff_lseed_lid=0;
double diff_lseed_tseed=0;
double diff_lid_tseed=0;
double diff_lid_lid2=0;
double diff_lseed_ttseed=0;

double max_diff_lseed_lid=0;

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   *situation_file  = "..\\DATA\\Current.BIN";

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 prepare_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) {
	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) {
			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;*/
}

long int systemsChecked = 0;
long int outofrangeSystems = 0;
long planetsWithRuins = 0;
long totalPlanets = 0;
	
int CheckSystem ()
{
	fprintf(stderr, "CHECKING %li %li %li\n", (long) foundstar_x, (long) foundstar_y, (long) foundstar_z);
	ap_target_x = foundstar_x;
	ap_target_y = foundstar_y;
	ap_target_z = foundstar_z;
	
	double dxx = sqrt (ap_target_x * ap_target_x + ap_target_z * ap_target_z);
	dxx += fabs(ap_target_y * 30);
	if (dxx > 2E9) {
		outofrangeSystems++;
		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;
	}
	//warn("extract_ap_target_infos", -1);
	extract_ap_target_infos ();
	//warn("prepare_nearstar", -1);
	prepare_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 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;
		/*if (rotation>0 && (rotation<bestrotation || bestrotation==-1 || (rotation==bestrotation && dxx<bestdistance))) {
			bestrotation = rotation;
			beststar_x = nearstar_x;
			beststar_y = nearstar_y;
			beststar_z = nearstar_z;
			bestdistance = dxx;
			p1 = bestrotation; p1 *= 360;
			p2 = p1 / 1000; p2 /= 1000;
			p3 = p1 / 1000; p3 %= 1000;
			p4 = p1 % 1000;
			//sprintf (warnbuffer, "BEST ROTATION TRIADS %03ld:%03ld:%03ld AT DISTANCE OF %lf", p2, p3, p4, dxx);
			sprintf (warnbuffer, "BEST ROTATION TRIADS %03ld:%03ld:%03ld", p2, p3, p4);
										
			memset(warnbuffer+strlen(warnbuffer), 32, 64-strlen(warnbuffer));
			warnbuffer[64]=0;
			warnMsg (warnbuffer, 2);
			sprintf (warnbuffer, "DISTANCE %8.3f", bestdistance);
			warnMsg (warnbuffer, 4);
			
			if (isMoon) {
				bestmoon = nearstar_p_moonid[n];
				bestplanet = nearstar_p_owner[n];
			} else {
				bestplanet=n;
				bestmoon=-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 FindSystems ()
{
	double laststar_id, laststar_seed, laststar_id2, third_seed;
	
	long temp_x, temp_y, temp_z, third_x, third_y, third_z, xz, mixer;
	double temp_seed;
	
	unsigned sx, sy, sz;

	unsigned visible_sectors_x = analyzed_sectors_range;
	unsigned visible_sectors_y = analyzed_sectors_range;
	unsigned visible_sectors_z = analyzed_sectors_range;

	long   	sect_x, sect_y, sect_z;

	sect_x = (dzat_x - visible_sectors_x*50000) / 100000; sect_x *= 100000;
	sect_y = (dzat_y - visible_sectors_y*50000) / 100000; sect_y *= 100000;
	sect_z = (dzat_z - visible_sectors_z*50000) / 100000; sect_z *= 100000;
	
	long start_y = sect_y;
	long start_z = sect_z;
	
	int rarity_factor, differences;
	
	asm {	mov ax, visible_sectors_x
		mov sx, ax }
e_while:asm {	mov ax, visible_sectors_y
		mov sy, ax }
m_while:asm {	mov ax, visible_sectors_z
		mov sz, ax }
i_while:asm {	
		
		//first set:
		db 0x66, 0xBB, 0x50, 0xC3, 0x00, 0x00 // mov ebx, 50000
		db 0x66; mov ax, word ptr sect_x
		db 0x66; mov dx, word ptr sect_z
		db 0x66; add ax, dx
		db 0x66; mov cx, ax
		db 0x66; mov dx, ax
		db 0x66, 0x81, 0xE2, 0xFF, 0xFF, 0x01, 0x00 // and edx, 0x0001FFFF
		db 0x66; add dx, word ptr sect_x
		db 0x66; sub dx, bx
		db 0x66; mov word ptr laststar_x, dx
		db 0x66; imul dx
		db 0x66; add dx, ax
		db 0x66; add cx, dx
		db 0x66, 0x81, 0xE2, 0xFF, 0xFF, 0x01, 0x00 // and edx, 0x0001FFFF
		db 0x66; add dx, word ptr sect_y
		db 0x66; sub dx, bx
		db 0x66; mov word ptr laststar_y, dx
		db 0x66; mov ax, cx
		db 0x66; imul dx
		db 0x66; add dx, ax
		db 0x66, 0x81, 0xE2, 0xFF, 0xFF, 0x01, 0x00 // and edx, 0x0001FFFF
		db 0x66; add dx, word ptr sect_z
		db 0x66; sub dx, bx
		db 0x66; mov word ptr laststar_z, dx
		fild dword ptr laststar_x
		fstp  laststar_x
		fild dword ptr laststar_y
		fstp  laststar_y
		fild dword ptr laststar_z
		fstp  laststar_z
	}
		laststar_id = laststar_x/100000.0*laststar_y/100000.0*laststar_z/100000.0;
		
		//sect_x*sect_x + sect_z*sect_z would overflow the range of a long int.
		double dsect_x = sect_x;
		double dsect_y = sect_y;
		double dsect_z = sect_z;
		double distance_from_home = sqrt (dsect_x*dsect_x + dsect_z*dsect_z);
		distance_from_home += 30 * fabs(dsect_y);
		rarity_factor = distance_from_home * 0.25e-8;
		rarity_factor = 1 << rarity_factor;
		rarity_factor--;
		
	asm {		
		//second set:
		db 0x66, 0xBB, 0x50, 0xC3, 0x00, 0x00 // mov ebx, 50000
		db 0x66; mov ax, word ptr sect_x
		db 0x66; mov cx, word ptr sect_y
		db 0x66; mov dx, word ptr sect_z
		db 0x66, 0x0F, 0xAF, 0xCA // imul ecx, edx
		db 0x66; add ax, dx
		db 0x66; mov cx, ax
		db 0x66; mov dx, cx
		db 0x66, 0x81, 0xE2, 0xFF, 0xFF, 0x01, 0x00 // and edx, 0x0001FFFF
		db 0x66; add dx, word ptr sect_x
		db 0x66; sub dx, bx
		jnz i_cont_x }  // |
		asm jmp error_x;   // | excludes stars with x coordinate = 0
i_cont_x: asm {                 // |
		db 0x66; mov word ptr temp_x, dx
		db 0x66; mov ax, cx
		db 0x66; imul dx
		db 0x66; add dx, ax
		db 0x66; add cx, dx
		db 0x66, 0x81, 0xE2, 0xFF, 0xFF, 0x01, 0x00 // and edx, 0x0001FFFF
		db 0x66; add dx, word ptr sect_y
		db 0x66; sub dx, bx
		jnz i_cont_y }  // |
		asm jmp error_y;   // | excludes stars with y coordinate = 0
i_cont_y: asm {                 // |
		db 0x66; mov word ptr temp_y, dx
		db 0x66; mov ax, cx
		db 0x66; imul dx
		db 0x66; add dx, ax
		db 0x66, 0x81, 0xE2, 0xFF, 0xFF, 0x01, 0x00 // and edx, 0x0001FFFF
		db 0x66; add dx, word ptr sect_z
		db 0x66; sub dx, bx
		jnz i_cont_z }  // |
		asm jmp error_z;   // | excludes stars with z coordinate = 0
i_cont_z: asm {                 // |
		db 0x66; mov word ptr temp_z, dx
		mov ax, word ptr temp_x
		add ax, word ptr temp_y
		add ax, word ptr temp_z
		test ax, rarity_factor
		jz ispresent
		jmp nonexistant}
error_x:
		num_error_x++;
		goto i_next;
error_y:
		num_error_y++;
		goto i_next;
error_z:
		num_error_z++;
		goto i_next;
nonexistant:
		num_nonexistant++;
		goto i_next;
ispresent:
		laststar_seed = laststar_x/100000*laststar_y/100000*laststar_z/100000;
		laststar_id2 = laststar_x/100000.0*laststar_y/100000.0*laststar_z/100000.0;
		temp_seed = ((double)temp_x)/100000*((double)temp_y)/100000*((double)temp_z)/100000;
		
		//third test
		xz = sect_x + sect_z;
		third_x = (xz & 0x1ffff) + sect_x - 50000;
		if (third_x!=0) {
			third_y = ImulAndAdd(third_x, xz);
			mixer = xz + third_y;
			third_y = (third_y & 0x1ffff) + sect_y - 50000;
			if (third_y!=0) {
				third_z = ImulAndAdd(third_y, mixer);
				third_z = (third_z & 0x1ffff) + sect_z - 50000;
				if (third_z!=0) {
					short rarity = (((short)third_x) + ((short)third_y) + ((short)third_z));
					if ((rarity & rarity_factor) == 0) {
						num_valid_third++;
						third_seed = ((double)third_x)/100000*((double)third_y)/100000*((double)third_z)/100000;
						if (laststar_seed != third_seed) {
							num_differ_lseed_ttseed++;
							double diff = laststar_seed-third_seed;
							if (diff<0) diff=-diff;
							diff_lseed_ttseed+=diff;
							differences++;
						}
					} else {
						num_nonexistant_third++;
					}
				}
			}
		}
		differences=0;
		if (laststar_seed != laststar_id) {
			num_differ_lseed_lid++;
			double diff = laststar_seed-laststar_id;
			if (diff<0) diff=-diff;
			diff_lseed_lid+=diff;
			if (diff>max_diff_lseed_lid) max_diff_lseed_lid=diff;
			differences++;
		}
		if (laststar_id != laststar_id2) {
			num_differ_lid_lid2++;
			double diff = laststar_id-laststar_id2;
			if (diff<0) diff=-diff;
			diff_lid_lid2+=diff;
			differences++;
		}
		if (laststar_seed != temp_seed) {
			num_differ_lseed_tseed++;
			double diff = laststar_seed-temp_seed;
			if (diff<0) diff=-diff;
			diff_lseed_tseed+=diff;
			differences++;
		}
		if (laststar_id != temp_seed) {
			num_differ_lid_tseed++;
			double diff = laststar_id-temp_seed;
			if (diff<0) diff=-diff;
			diff_lid_tseed+=diff;
			differences++;
		}
		if ((long)(laststar_seed* 1E5) == 1599551984L) {
			
		}
		num_valid++;
		if (differences==0) {
			num_equal++;
		}
		
		if (CheckSystem()) {
			goto e_end;
		}
i_next:	asm {	db 0x66; mov ax, word ptr advance
		db 0x66; add word ptr sect_z, ax
		dec sz
		jz i_end
		jmp i_while }

i_end:	  asm { mov dx, word ptr start_z
		db 0x66; mov word ptr sect_z, dx
		db 0x66; add word ptr sect_y, ax
		dec sy
		jz m_end
		jmp m_while }
m_end:	  asm { db 0x66; mov dx, word ptr start_y
		db 0x66; mov word ptr sect_y, dx
		db 0x66; add word ptr sect_x, ax
		dec sx
		jz e_end
		db 0x66; pusha }
		if (sts > 1) {
			sprintf (warnbuffer, "SLICE %d OF %d", visible_sectors_x - sx, visible_sectors_x);
			warnMsg (warnbuffer, 1);
			while (kbhit()) {
				if (getch() == 27) {
					asm { db 0x66; popa }
					return;
				}
			}
		}
	  asm { db 0x66; popa
		jmp e_while }
e_end:	  return;
y_end:	  return;
}*/

void main ()
{
	CHECK_SITUATION;
	long p1, p2, p3, p4;
	/*asm {	xor	ax, ax
		mov	es, ax
		cmp	byte ptr es:[0x449], 0x13
		je	startup }

	printf ("\nGalactic Organization of Explorers and Stardrifters (G.O.E.S)\n");
	printf ("-------------------------------------------------------------\n");
	printf ("This is a GOES NET module and must be run from a stardrifter.\n");
	printf ("Please use the onboard computer console to run this module.\n");
	printf ("\n\t- GOES NET onboard microsystem, EPOC 6011 REVISION 2\n");
	return;
*/
	startup:
	msg ("RUNNING TESTS...");
	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;
	//FindSystems ();
	isthere2(0.0, analyzed_sectors_range, 0, 0, 0, False);
	char msgBuff[120];
	
	sprintf (msgBuff, "CHECKED %li SYSTEMS", systemsChecked);
	msg (msgBuff);
	sprintf (msgBuff, "IGNORED %li OUTOFRANGE", outofrangeSystems);
	msg (msgBuff);
	sprintf (msgBuff, "FOUND %li", planetsWithRuins);
	msg (msgBuff);
	sprintf (msgBuff, "PLANETS WITH RUINS");
	msg (msgBuff);
	sprintf (msgBuff, "IN    %li", totalPlanets);
	msg (msgBuff);
	sprintf (msgBuff, "PLANETS 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 ("");
	/*msg("D MEANS DIFFERENCE");
	msg("DIFF MEANS DIFFERENCE TOO");
	msg("LS MEANS LSEED");
	msg("TS MEANS TSEED");
	sprintf(msgBuff, "NUM ERROR X: %li", num_error_x); msg(msgBuff);
	sprintf(msgBuff, "NUM ERROR Y: %li", num_error_y); msg(msgBuff);
	sprintf(msgBuff, "NUM ERROR Z: %li", num_error_z); msg(msgBuff);
	sprintf(msgBuff, "NUM NONEXISTANT: %li", num_nonexistant); msg(msgBuff);
	sprintf(msgBuff, "NUM VALID: %li", num_valid); msg(msgBuff);
	sprintf(msgBuff, "NUM EQUAL: %li", num_equal); msg(msgBuff);
	sprintf(msgBuff, "NUM D LS LID: %li", num_differ_lseed_lid); msg(msgBuff);
	sprintf(msgBuff, "NUM D LID LID2: %li", num_differ_lid_lid2); msg(msgBuff);
	sprintf(msgBuff, "NUM D LS TS: %li", num_differ_lseed_tseed); msg(msgBuff);
	sprintf(msgBuff, "NUM D LID TS: %li", num_differ_lid_tseed); msg(msgBuff);
	sprintf(msgBuff, "NUM D LS 3S: %li", num_differ_lseed_ttseed); msg(msgBuff);
	sprintf(msgBuff, "NUM DIFFERENT: %li", num_valid-num_equal); msg(msgBuff);
	sprintf(msgBuff, "LS LI: %.10f", diff_lseed_lid); msg(msgBuff);
	sprintf(msgBuff, "LI LI2: %.10f", diff_lid_lid2); msg(msgBuff);
	sprintf(msgBuff, "LS TS: %.10f", diff_lseed_tseed); msg(msgBuff);
	sprintf(msgBuff, "LI TS: %.10f", diff_lid_tseed); msg(msgBuff);
	sprintf(msgBuff, "MLSLI: %.15f", max_diff_lseed_lid); msg(msgBuff);
	sprintf(msgBuff, "LS 3S: %.15f", diff_lseed_ttseed); msg(msgBuff);
	*/
	
	_close (fh);
}