/*

	Noctis star map / EVOLVE Star Map to Noctis Five.

	(this program was originarily used to port the old galaxy map
	to the next version of Noctis, Noctis V; the goal is no longer
	possible because due to some unrecoverable errors in NIV, the
	so-called "suricrasian catnip", there is no way to reproduce
	the planets' surfaces as they were in NIV. Therefore, this is
	now only an utility to find out Parsis coords from NIV's starmap)

	Not part of the Noctis IV package, this utility is freely
	redistributable, modificable, whatever... you're free to
	make out derivative works of it if you find them useful...

	Alessandro Ghignola.

*/

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <dos.h>
#include <io.h>
#include <alloc.h>

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

double  dzat_x = +3797120;
double  dzat_y = -4352112;
double  dzat_z = -925018;

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

double 	object_id = 12345;
char   	object_label[25];
char	newmapentry[44];
double  idscale = 0.00001;

int 	fh, fh2, fh3;
int 	analyzed_sectors_range_x = 100;
int 	analyzed_sectors_range_y = 100;
int 	analyzed_sectors_range_z = 100;
char	*file = "C:\\NOCTIS\\DATA\\STARMAP.BIN";
char	*file2 = "C:\\NOCTIS\\DATA\\STARMAP2.BIN";
char	*file3 = "C:\\NOCTIS\\DATA\\STARMAP.TXT";

double  laststar_x, laststar_y, laststar_z;
long	e_laststar_x, e_laststar_y, e_laststar_z;
long	e_laststar_index;

char isthere (double star_id)
{
	double laststar_id;

	double sidlow = star_id - idscale;
	double sidhigh = star_id + idscale;

	unsigned sx, sy, sz;

	unsigned visible_sectors_x = analyzed_sectors_range_x;
	unsigned visible_sectors_y = analyzed_sectors_range_y;
	unsigned visible_sectors_z = analyzed_sectors_range_z;

	long   	advance = 100000;
	long   	sect_x, sect_y, sect_z;

	long   	align_m = 100000 * visible_sectors_z;
	long   	align_e = 100000 * visible_sectors_y;

	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;

	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 {	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; mov word ptr e_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 word ptr e_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
		db 0x66; mov word ptr e_laststar_z, dx
		fild dword ptr laststar_x
		fst  laststar_x
		fmul idscale
		fild dword ptr laststar_y
		fst  laststar_y
		fmul idscale
		fild dword ptr laststar_z
		fst  laststar_z
		fmul idscale
		fmulp
		fmulp
		fst laststar_id
		fcomp sidlow
		fstsw ax
		sahf
		jb i_next
		fld laststar_id
		fcomp sidhigh
		fstsw ax
		sahf
		jb y_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 { db 0x66; mov dx, word ptr align_m
		db 0x66; sub 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 align_e
		db 0x66; sub word ptr sect_y, dx
		db 0x66; add word ptr sect_x, ax
		dec sx
		jz e_end
		jmp e_while }
e_end:	  return (0);
y_end:	  return (1);
}

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

long inrange, outofrange, mapped, ignored;
char notonlystars;
char filter[24];
char textout[100];

long calc_parsis_for_object_id ()
{
	if (isthere (object_id)) {
		return (0);
	}
	else {
		return (-1);
	}
}

void main ()
{
	CHECK_SITUATION;
	long limit;

	printf ("USAGE:\n");
	printf ("EVOLVESM x_origin y_origin z_origin x_range y_range z_range filter\n");
	printf ("\nwhere:");
	printf ("\n\tx_origin = Parsis X coordinate of the center of the area to scan");
	printf ("\n\ty_origin = Parsis Y coordinate of the center of the area to scan");
	printf ("\n\tz_origin = Parsis Z coordinate of the center of the area to scan");
	printf ("\n\tx_range  = Number of sectors to scan along the X (left-to-right) axis");
	printf ("\n\ty_range  = Number of sectors to scan along the Y (down-to-up) axis");
	printf ("\n\tz_range  = Number of sectors to scan along the Z (south-to-north) axis");
	printf ("\n\tfilter   = optional name filter (beginning of name), default = none\n");
	printf ("\ndefaults:");
	printf ("\n\tEVOLVESM 3797120 4352112 -925018 100 100 100\n");
	printf ("\nexamples:");
	printf ("\n\tEVOLVESM 3500000 4500000 -1000000 400 100 400");
	printf ("\n\tEVOLVESM 0 0 0 200 50 200 Balastrackonastreya");
	printf ("\n\tEVOLVESM 3500000 4500000 -1000000 400 100 400 F\n");
	printf ("\nimplicit source file:      C:\\NOCTIS\\DATA\\STARMAP.BIN");
	printf ("\nimplicit destination file: C:\\NOCTIS\\DATA\\STARMAP2.BIN");
	printf ("\nimplicit text output file: C:\\NOCTIS\\DATA\\STARMAP.TXT\n");
	printf ("\nAny key to start, CTRL+C to quit...");
	getch ();
	printf ("\n");

	fh = _open (file, 0);
	if (fh == -1) {
		printf ("STARMAP.BIN NOT AVAILABLE\n");
		return;
	}

	fh2 = _open (file2, 4);
	if (fh2 == -1) {
		fh2 = _creat (file2, 0);
		if (fh2 == -1) {
			printf ("CANNOT CREATE STARMAP2.BIN\n");
			_close (fh);
			return;
		}
	}
	fh3 = _open (file3, 4);
	if (fh3 == -1) {
		fh3 = _creat (file3, 0);
		if (fh3 == -1) {
			printf ("CANNOT CREATE STARMAP.TXT\n");
			_close (fh2);
			_close (fh);
			remove (file2);
			return;
		}
	}

	if (_argc > 1) dzat_x = (double) atol (_argv[1]);
	if (_argc > 2) dzat_y = (double) - atol (_argv[2]);
	if (_argc > 3) dzat_z = (double) atol (_argv[4]);

	if (_argc > 4) {
		analyzed_sectors_range_x = atoi (_argv[4]);
		if (analyzed_sectors_range_x < 10) analyzed_sectors_range_x = 10;
	}
	if (_argc > 5) {
		analyzed_sectors_range_y = atoi (_argv[5]);
		if (analyzed_sectors_range_y < 10) analyzed_sectors_range_y = 10;
	}
	if (_argc > 6) {
		analyzed_sectors_range_z = atoi (_argv[6]);
		if (analyzed_sectors_range_z < 10) analyzed_sectors_range_z = 10;
	}
	if (_argc > 7) {
		strcpy (filter, _argv[7]);
	}

	inrange = 0;
	outofrange = 0;
	mapped = 0;
	ignored = 0;

	_read (fh, &limit, 4);
	while (tell(fh) < limit && _read (fh, &object_id, 8) && _read (fh, object_label, 24) == 24) {
	    if (object_label[21] == 'S') {
	      if (filter[0] || !memicmp(object_label, filter, strlen(filter))) {
		printf (object_label);
		if (_read (fh2, newmapentry, 44) == 44) {
			if (memcmp (&newmapentry[20], object_label, 24)) {
				printf (" (REPRISE)");
				lseek (fh2, -44L, SEEK_CUR);
				goto remap;
			}
			else {
				lseek (fh3, 62, SEEK_CUR);
				printf (" (ALREADY MAPPED)\n");
				mapped++;
			}
		}
		else {
		    remap:
			e_laststar_index = calc_parsis_for_object_id ();
			if (e_laststar_index > -1) {
				inrange++;
				printf (" (IN RANGE)\n");
				_write (fh2, &e_laststar_x, 4);
				_write (fh2, &e_laststar_y, 4);
				_write (fh2, &e_laststar_z, 4);
				_write (fh2, &e_laststar_index, 4);
				_write (fh2, "\0\0\0\0", 4);
				_write (fh2, object_label, 24);
				memset (textout, 32, 100);
				sprintf (textout, "%s,%ld,%ld,%ld", object_label,
					 e_laststar_x, e_laststar_y, e_laststar_z);
				textout[strlen(textout)] = 32;
				textout[60] = 13;
				textout[61] = 10;
				write (fh3, textout, 62);
			}
			else {
				outofrange++;
				printf (" (OUT OF RANGE)\n");
				goto ignorethis;
			}
		}
	      }
	      else {
		ignored++;
	       ignorethis:
		if (eof(fh2)) {
			memset (newmapentry, 0, 44);
			_write (fh2, newmapentry, 44);
		}
		else {
			lseek (fh2, 44, SEEK_CUR);
		}
		if (eof(fh3)) {
			memset (textout, 32, 100);
			sprintf (textout, "%s", object_label);
			textout[strlen(textout)] = 32;
			textout[60] = 13;
			textout[61] = 10;
			_write (fh3, textout, 62);
		}
		else {
			lseek (fh3, 62, SEEK_CUR);
		}
	      }
	    }
	}

	_close (fh);
	_close (fh2);
	_close (fh3);

	printf ("%ld IN RANGE\n", inrange);
	printf ("%ld OUT OF RANGE\n", outofrange);
	printf ("%ld ALREADY MAPPED\n", mapped);
	printf ("%ld IGNORED\n", ignored);
}