//#if 0
#ifndef WINDOWS
#include "dnoctis0.cpp"
#else

/*

	Noctis.
	-------
	Primo programma pi— serioso del solito, che rovina la sana (ehm...)
	manifestazione informatica delle mie follie, pur senza tradirla
	del tutto. Oh yes.

	Noctis: il popolo dei gatti.
	----------------------------
	Spazio: ultima frontiera.
	Questi sono i viaggi delle zattere cosmiche del popolo felino.
	La loro missione (missione?) Š quella di esplorare strani, nuovi
	mondi, alla ricerca di un territorio da conquistare, eliminando
	eventuali nuove forme di vita o nuove civilt…, per arrivare l…
	dove nessun gatto Š mai giunto prima.

	Storia.
	-------
	Complicata. Il programma Š complicato: forse un po' troppo,
	comunque pi— del solito. Se non trover• un modo di farlo
	digerire al compilatore (siamo a 6900 righe solo con
	il sorgente principale), dovr• modulizzarlo (mai fatto prima,
	molto laborioso e molto antipatico) oppure trovarmi un altro
	compilatore. Sono attivi: astrozattere, stelle e pianeti,
	gestore di bordo, riflessi dell'utente, superfici dei
	pianeti abitabili, rumori atmosferici principali
	(vento, pioggia, tuoni). E' abbozzato, ma fermo,
	il controllo degli eventi: in lavorazione il
	proiettore fationico. -> 27.1.97
	-------
	Il programma Š stato spezzato in due moduli. -> 28.1.97

	Modulo delle funzioni di base di Noctis.
	----------------------------------------
	Il progetto Š costituito da NOCTIS-0.CPP, NOCTIS.CPP,
	pi— un file includente definizioni comuni ai due moduli.

*/

#include "defs.h"
#include "noctis-d.h"
#include "noctis-2.h"
#ifdef WINDOWS
#include "randalg.h"
#include "win.h"
#include "noctis-ng.h"
#include <assert.h>
#endif

void status (const char *status_description, Word message_delay);
/*

	Dati e funzioni specifiche importate da ASSEMBLY.H

*/

#ifdef WINDOWS
Dword QUADWORDS = 16000;
#else
Word QUADWORDS = 16000;
#endif

#ifdef WINDOWS
//Uchar maybefar * adaptor    = (Uchar maybefar *) 0xA0000000;
Uchar maybefar * adapted    = (Uchar maybefar *) WinGetScreen();

#else
Uchar maybefar * adaptor    = (Uchar maybefar *) 0xA0000000;
Uchar maybefar * adapted    = (Uchar maybefar *) 0xB0000000;
#endif


Uchar	tmppal[768];
Uchar 		return_palette[768];
Uchar		surface_palette[768];
Uchar		old_surface_palette[768];

#define WHITE_COLOR 63, 63, 63
#define GRAY_COLOR 32, 32, 32
#define DARK_GRAY_COLOR 16, 16, 16
#define BLACK_COLOR  0,  0,  0

#define OCEAN_COLOR  0, 16, 48
#define FOREST_COLOR 0, 52, 0
#define PLAINS_COLOR 24, 48, 16
#define SHRUBLAND_COLOR 48, 40, 16
#define DESERT_COLOR 52, 52, 8
#define ICY_COLOR 46, 46, 63
//#define MOUNTAIN_COLOR 48, 48, 48
//#define MOUNTAINTOP_COLOR 63, 63, 63
//#define RAINFOREST_COLOR 0, 63, 48
//#define JUNGLE_COLOR 0, 48, 36
//#define FORESTBORDER_COLOR 24, 48, 24

Word lstri (char *stri)
{
	// misura una stringa e la copia su tmppal.
	// Š una funzione di supporto per "reach_your_dir"

	Word c;

	for (c=0; c<768; c++) {
		if (stri[c])
			tmppal[c] = stri[c];
		else {
			tmppal[c] = '\0';
			return (c);
		}
	}

	return (0);
}


void reach_your_dir ()
{
	// Si posiziona nella vera directory in cui attualmente si trova
	// il programma, al di l… di quale sia quella di lavoro corrente.

	int c;
	char d;

	//_argv[0] is the filename of this EXE.
	#ifdef WINDOWS
	int modulesIdx = 0;
	const char modulesString1[] = "modules";
	const char modulesString2[] = "MODULES";
	#endif
	int len = 0;
	len = lstri(_argv[0]) - 1;	//lstri copies the string into tmppal, and returns the length of it (It's a custom function), which will never be more than 767.
	c=len;
	while (c>=0&&tmppal[c]!='\\') {
		c--;	//This marks c at the point BEFORE the filename after the folder-names in the path. i.e. c:\noctis\modules\blah.exe becomes c:\noctis\modules\ .
	}

	#ifdef WINDOWS
	for (int idx=0; idx<c; idx++) {
		if (modulesIdx<7 && (tmppal[c]==modulesString1[modulesIdx] || tmppal[c]==modulesString2[modulesIdx])) {
			modulesIdx++;
		} else {
			modulesIdx=0;
		}
	}
	if (modulesIdx<7) {
		sprintf((char*)(tmppal+c), "\\modules\\");
		c+=8;
	}
	#endif
		
	if (c>=0) {
		if (tmppal[c-1] != ':') //If what's right before the last \ isn't a :, then erase that \ and term the string there.
			tmppal[c] = 0;
		else
			tmppal[c+1] = 0;//Otherwise, term the string after the \.
	}
	
	
	//This checks the case (capitalization) of the drive name.
	//This assumes that we won't have a path that looks like \\blah\blah, which is, ah...
	//well, Noctis will screw up if run from a network share without being mapped to a virtual drive.
	//Fixed, but untested.
	//If it still doesn't work, it's windows' fault, and we'd have to map the share ourselves to make it work.
	//(We aren't going to do that, at this time.)
	
	if (_argv[0][0]>='a' && _argv[0][0]<='z')	{
		d = _argv[0][0] - 'a';
	} else if (_argv[0][0]>='A' && _argv[0][0]<='Z')	{
		d = _argv[0][0] - 'A';
	} else {
		d = 'C'-'A';	//default to C if it's an invalid drive specifier. (The chdir call might fix it... Or might not.)
	}
	
	//d is now drive #, 0=A, 1=B, 2=C, etc
	

	#ifdef WINDOWS
		printf("Changing folder to [%s].\n", tmppal);
		int retval = _chdir((char const*)tmppal);
		printf("Retval from _chdir: %i\n", retval);
	#else
		asm {
			pusha
			//Set default drive to whatever 'd' is (0=A, 1=B, etc)
			mov dl, d
			mov ah, 0x0e
			int 0x21
			
			//Set current directory to 'tmppal'
			mov ah, 0x3b
			lea dx, tmppal
			int 0x21
			popa
		}
	#endif
}

void _320_200_256 () // inizializza grafica a 320x200x256 colori.
{
	#ifdef WINDOWS
	WinShow();
	#else
	//Change screen mode to ... well, see the comment 2 lines above this one, lol.
	asm {
		push ax
		mov ax, 0x13
		int 0x10
		pop ax
	}
	#endif
}

//This was not necessary to convert. (Or it might be with a fullscreen DX app, though I doubt it...)
//									  I'll have to look into that.)
void _80_25_C () // modo grafico 80x25 testo a colori.
{
	#ifndef WINDOWS
	//Go to the standard text mode
	asm {
		push ax
		mov ax, 3
		int 0x10
		pop ax
	}
	#endif
}

Word attendi_pressione_tasto () // aspetta un tasto e dŤ qual'Š.
{
	Uchar ritorno;
	//Read a character from standard input. 0 if there aren't any.

	#ifdef WINDOWS
	return WinGetKey();
	#else
	asm {
		push ax
		mov ah, 8
		int 0x21
		mov ritorno, al
		pop ax
	}
	
	return (ritorno);
	#endif
}

Word tasto_premuto () // torna 1 se c'Š un tasto premuto da estrarre.
{
	#ifdef WINDOWS
	return WinKeyAvailable();
	#else
	//This interrupt call returns 00 if no keys were pressed, or FFh if some have been.
	asm {
		push ax
		mov ah, 0xb
		int 0x21
		cmp al, 0xff
		pop ax
		jne Stop
	}

	return (1);

	Stop:
	return (0);
	#endif
}

Uchar range8088[64*3] = {
 0,  0,  0,  1,  1,  1,  2,  2,  2,  3,  3,  3,  4,  4,  4,  5,  5,  5,
 6,  6,  6,  7,  7,  7,  8,  8,  8,  9,  9,  9, 10, 10, 10, 11, 11, 11,
12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15, 16, 16, 16, 17, 17, 17,
18, 18, 18, 19, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 22, 23, 23, 23,
24, 24, 24, 25, 25, 25, 26, 26, 26, 27, 27, 27, 28, 28, 28, 29, 29, 29,
30, 30, 30, 31, 31, 31, 32, 32, 32, 33, 33, 33, 34, 34, 34, 35, 35, 35,
36, 36, 36, 37, 37, 37, 38, 38, 38, 39, 39, 39, 40, 40, 40, 41, 41, 41,
42, 42, 42, 43, 43, 43, 44, 44, 44, 45, 45, 45, 46, 46, 46, 47, 47, 47,
48, 48, 48, 49, 49, 49, 50, 50, 50, 51, 51, 51, 52, 52, 52, 53, 53, 53,
54, 54, 54, 55, 55, 55, 56, 56, 56, 57, 57, 57, 58, 58, 58, 59, 59, 59,
60, 60, 60, 61, 61, 61, 62, 62, 62, 63, 63, 63 };

void tavola_colori (Uchar *nuova_tavolozza,
		    Uword firstColor, Uword numColors,
		    char filtro_rosso, char filtro_verde, char filtro_blu)
{
	Word c, cc = 0;
	Uword temp;
	
	//Separated these so the windows version can refer to the original, unchanged, variables (SL)
	Uword tripledNumColors = numColors * 3;
	Uword tripledFirstColor = firstColor * 3;
	
	////We won't do this if it's same palette.
	//if (tmppal!=nuova_tavolozza) {
		c = tripledFirstColor;
		while (cc<tripledNumColors) {
			tmppal[c] = nuova_tavolozza[cc];
			cc++;
			c++;
		}
	
		c = tripledFirstColor;
		while (c<tripledNumColors+tripledFirstColor) {
			temp = tmppal[c];
			temp *= filtro_rosso;
			temp /= 63;
			if (temp > 63) temp = 63;
			tmppal[c] = temp;
			c++;
			temp = tmppal[c];
			temp *= filtro_verde;
			temp /= 63;
			if (temp > 63) temp = 63;
			tmppal[c] = temp;
			c++;
			temp = tmppal[c];
			temp *= filtro_blu;
			temp /= 63;
			if (temp > 63) temp = 63;
			tmppal[c] = temp;
			c++;
		}
	//}
	if (!dontDraw) {
			
		#ifdef WINDOWS
		WinStorePalette(firstColor, numColors, tmppal);
		#else
		asm {
			push si
			push ax
			push cx
			push dx
			mov cx, tripledFirstColor
			add cx, tripledNumColors
			lea si, tmppal
			mov ax, seg tmppal
			mov ds, ax
			mov dx, 0x3c8
			mov al, 0
			out dx, al
			inc dx
		}
	dzap:	asm {
			mov al, [si]
			out dx, al
			inc si
			loop dzap
			pop dx
			pop cx
			pop ax
			pop si
		}
		#endif
	}
}

/* Lettura del mouse e ritorno nelle variabili indicate. */

Word mdltx = 0, mdlty = 0, mx = 0, my = 0, mpul = 0;

void mouse_input ()
{
	#ifdef WINDOWS
	WinGetMouseStats(&mdltx, &mdlty, &mpul);
	mx+=mdltx;
	my+=mdlty;
	
	//mdltx = the distance the mouse moved horizontally since the last time this was called (in mickeys)
	//mdlty = the distance the mouse moved vertically since the last time this was called (in mickeys)
	//mx and my are increased by those amounts as well
	//mpul is set to 1 for LMB, 2 for RMB, 3 for both, and 0 for neither?
	#else
	asm {
		push ax
		push bx
		push cx
		push dx
		mov ax, 0xb
		int 0x33
		push cx
		push dx
		mov ax, 5
		int 0x33
		pop dx
		pop cx
		mov mdltx, cx
		mov mdlty, dx
		add mx, cx
		add my, dx
		cmp ax, 0
		je  non_imp
		mov mpul, ax
	}
non_imp:asm {
		pop dx
		pop cx
		pop bx
		pop ax
	}
	#endif
}

// Verifica della presenza del mouse (o del supporto per esso).
// Ed inizializzazione del driver (svuotamento del buffer dei movimenti).

char test_and_init_mouse ()
{
	//determine if the mouse exists. Always true in Windows. :P
	#ifndef WINDOWS
	asm {
		xor ax, ax
		int 33h
		cmp ax, 0
		jne ok
	}

	return (0);

ok:	asm {
		pusha
		mov ax, 0xb
		int 0x33
		mov ax, 5
		int 0x33
		popa
	}
	#endif
	return (1);
}

// Ultraveloce copia di pagina grafica.

void pcopy (Uchar maybefar *dest, Uchar maybefar *sorg)
{
	#ifdef WINDOWS
	asm {
		push esi
		push edi
		push ecx
		cld
		mov ecx, QUADWORDS
		mov esi, [sorg]
		mov edi, [dest]
		rep movsd
		pop ecx
		pop edi
		pop esi
	}
	#else
	asm {
		push si
		push di
		push ds
		push es
		push cx
		cld
		mov cx, QUADWORDS
		lds si, dword ptr sorg
		les di, dword ptr dest
		db 0xf3 // macro: rep movsd
		db 0x66
		db 0xa5
		pop cx
		pop es
		pop ds
		pop di
		pop si
	}
	#endif
}

// Ultraveloce cancella pagina grafica.

void pclear (Uchar maybefar *target, Uchar pattern)
{
	//unsigned char far *target, unsigned char pattern
	asm {
	#ifdef WINDOWS
		push edi
		push ecx
		push eax
		cld
		mov edi, [target]
		mov ecx, QUADWORDS
		mov al, pattern
		mov ah, pattern
		shl eax, 16
		mov al, pattern
		mov ah, pattern
		rep stosd
		pop eax
		pop ecx
		pop edi
	#else
		push di
		push es
		push cx
		push ax
		cld
		les di, dword ptr target
		mov cx, QUADWORDS
		mov al, pattern
		mov ah, pattern
		SHL_EAX_16
		mov al, pattern
		mov ah, pattern
		REP_STOSD
		pop ax
		pop cx
		pop es
		pop di
	#endif
	}
}

// Copia un'area rettangolare.

//NOTVALID: Relies on display width being 320
void areacopy (Uchar maybefar *dest, Uchar maybefar *sorg,
	       Word x, Word y, Word l, Word h)
{
	#ifdef WINDOWS
	Udword p;
	#else
	Uword p;
	#endif

	p = 320 * y + x;

	#ifdef WINDOWS
	asm {
		pushad
		cld
		mov esi, [sorg]
		mov edi, [dest]
		add esi, p
		add edi, p }
ac_nextl: asm {	push esi
		push edi
		movsx ecx, l
		shr ecx, 2
		jecxz ac_bytes
		rep movsd
		}
ac_bytes: asm { movsx ecx, l
		and ecx, 3
		jecxz ac_endl
		rep movsb }
ac_endl:  asm { pop edi
		pop esi
		add esi, 320
		add edi, 320
		dec h
		jnz ac_nextl
		popad
	}
	#else
	asm {	push ds
		push es
		pusha
		cld
		lds si, dword ptr sorg
		les di, dword ptr dest
		add si, p
		add di, p }
ac_nextl: asm {	push si
		push di
		mov cx, l
		shr cx, 2
		jcxz ac_bytes
		db 0xf3 // rep movsd
		db 0x66
		db 0xa5 }
ac_bytes: asm { mov cx, l
		and cx, 3
		jcxz ac_endl
		rep movsb }
ac_endl:  asm { pop di
		pop si
		add si, 320
		add di, 320
		dec h
		jnz ac_nextl
		popa
		pop es
		pop ds
	}
	#endif
}

// Cancella un'area rettangolare.
// Esegue tutti i clipping necessari per l'MCGA.
// O si specificano X2 ed Y2, o si specificano L ed H:
// in ogni modo, i valori non usati vanno lasciati a zero.

void areaclear (Uchar maybefar *dest, Word x, Word y,
		Word x2, Word y2, Word l, Word h, Uchar pattern)
{
	#ifdef WINDOWS
	Udword p;
	#else
	Uword p;
	#endif

	if (x<0) x = 0;
	if (y<0) y = 0;

	if (x2>=320) x2 = 319;
	if (y2>=200) y2 = 199;

	if (x2>0) l = x2 - x;
	if (y2>0) h = y2 - y;

	if (x+l>=320) l = 320 - x;
	if (y+h>=200) h = 200 - y;

	if (l<1 || h<1) return;

	p = 320 * y + x;

	asm {
		#ifdef WINDOWS
		pushad
		#else
		push es
		pusha
		#endif
		pushf
		cld
		#ifdef WINDOWS
		mov edi, [dest]
		add edi, p
		#else
		les di, dword ptr dest
		add di, p
		#endif
		mov al, pattern
		SHL_EAX_8
		mov al, pattern
		SHL_EAX_8
		mov al, pattern
		SHL_EAX_8
		mov al, pattern }
ac_nextl: asm {
		#ifdef WINDOWS
		push edi
		movzx ecx, l	//l is never below 1 in this function
		shr ecx, 2
		jecxz ac_bytes
		#else
		push di
		mov cx, l
		shr cx, 2
		jcxz ac_bytes
		#endif
		REP_STOSD
		}
ac_bytes: asm {
		#ifdef WINDOWS
		movzx ecx, l	//l is never below 1 in this function
		and ecx, 3
		jecxz ac_endl
		#else
		mov cx, l
		and cx, 3
		jcxz ac_endl
		#endif
		rep stosb }
ac_endl:  asm {
		#ifdef WINDOWS
		pop edi
		add edi, 320
		#else
		pop di
		add di, 320
		#endif
		dec h
		jnz ac_nextl
		popf
		#ifdef WINDOWS
		popad
		#else
		popa
		pop es
		#endif
		}
}

/*

	Altro gioiellino: smussa lo schermo, attenuando il contrasto dei
	bordi con un procedimento di media su 4 x 4 pixels.
	Occhio al trucco: normalmente ci sarebbero 16 addizioni e una
	divisione (per 16) da fare, per ogni punto.
	Col trucco, invece, bastano quattro addizioni a 32 bit,
	altre quattro a 8 bit, pi— un paio di shifts ed un and logico su edx.

	Normale: 16 + 42 = 58 cicli.
	Truccato: 8 + 4 = 12 cicli.

	Piuttosto ovvio: la tavola dei colori dev'essere una sfumatura unica
	e compatta, da far rientrare nei primi 64 registri del video DAC;
	il colore zero Š il pi— tenue, il 63 quello pi— brillante.

	Nota: la procedura pu• essere reiterata per ottenere
	      una maggiore attenuazione.

*/

//NOTVALID: Relies on display size being 320x200
//This appears to not read outside the display buffer already :).
void psmooth_grays (Uchar maybefar *target)
{
	asm {
		#ifdef WINDOWS
		pushad
		mov ecx, QUADWORDS
		shl ecx, 2
		mov eax, 320
		shl eax, 2
		sub ecx, eax
		mov edi, [target]
		add edi, 320
		#else
		pusha
		push ds
		mov cx, QUADWORDS
		shl cx, 2
		mov ax, 320
		shl ax, 2
		sub cx, ax
		lds di, dword ptr target
		add di, 320
		#endif
		}
smooth: asm {
		#ifdef WINDOWS
		mov edx, [edi-320]
		add edx, [edi]
		add edx, [edi+320]
		add edx, [edi+640]
		and edx, 0b11111100111111001111110011111100
		#else
		db 0x66; mov dx, [di-320]
		db 0x66; add dx, [di]
		db 0x66; add dx, [di+320]
		db 0x66; add dx, [di+640]
		/* and edx, 11111100111111001111110011111100b */
		db 0x66, 0x81, 0xE2, 0xFC, 0xFC, 0xFC, 0xFC
		#endif
		SHR_EDX_2
		mov al, dl
		add al, dh
		SHR_EDX_16
		add al, dl
		add al, dh
		shr al, 2
		#ifdef WINDOWS
		mov [edi], al
		}
next:   asm {	add edi,1
		dec ecx
		#else
		mov [di], al
		}
next:   asm {	inc di
		dec cx
		#endif
		jnz smooth
		#ifdef WINDOWS
		popad
		#else
		pop ds
		popa
		#endif
	}
}

/* Produce un effetto di dissolvenza al nero, molto rapido. */

//NOTVALID: Depends on display size being 320x200
void pfade (Uchar maybefar *target, Uword segshift, Uchar speed)
{
	asm {
		#ifdef WINDOWS
		pushad
		#else
		pusha
		push 	ds
		#endif
		//The subtracting from cx/ecx makes it do one less line
		
		#ifdef WINDOWS
		mov 	ecx, QUADWORDS	//180 lines when in space
		sub 	ecx, 80			//179 now
		shl 	ecx, 2
		movzx eax, segshift
		shl eax, 4
		add eax, [target]
		mov esi, eax
		#else
		mov 	cx, QUADWORDS
		sub 	cx, 80
		shl 	cx, 2
		lds 	ax, dword ptr target
		mov 	ax, ds
		add 	ax, segshift
		mov 	ds, ax
	
		#endif
		
		
		mov	ah, speed
		#ifdef WINDOWS
		xor edi, edi
		#else
		xor 	di, di
		#endif
		}
fader:  asm {
		#ifdef WINDOWS
		mov al, [esi+edi]
		#else
		mov	al, [di]
		#endif
		and	al, 0x3F
		sub	al, ah
		jnc	store
		xor	al, al }
store:	asm {
		#ifdef WINDOWS
		mov	[esi+edi], al
		inc	edi
		#else
		mov	[di], al
		inc	di
		#endif
		dec 	cx
		jnz 	fader
		#ifdef WINDOWS
		popad
		#else
		pop 	ds
		popa
		#endif
	}
}

/* Versione a colori: 4 sfumature di 64 intensit… ciascuna. */

/*void psmooth_64 (Uchar maybefar *target, Uword segshift)
{
	asm {   pusha
		push 	ds
		mov 	si, QUADWORDS
		sub 	si, 80
		shl 	si, 2
		lds 	ax, dword ptr target
		mov 	ax, ds
		add 	ax, segshift
		mov 	ds, ax
		xor 	di, di }
smooth: asm {	mov	al, [di+320]
		mov	cl, [di+640]
		mov	ah, [di+960]
		mov	bl, [di+639]
		and	ax, 0x3F3F
		mov	bh, [di+641]
		and	bx, 0x3F3F
		add	ax, bx
		and	cl, 0xC0
		add	al, ah
		shr	al, 2
		inc 	di
		or	al, cl
		dec 	si
		mov 	[di-1], al
		jnz 	smooth
		pop 	ds
		popa }
}*/

//NOTVALID: Depends on display size being 320x200
void psmooth_64 (Uchar maybefar *target, Uword segshift)
{
	asm {
		#ifdef WINDOWS
		pushad
		mov esi, QUADWORDS
		sub esi, 80
		shl esi, 2
		movzx edx, segshift
		shl edx, 4
		add edx, [target]
		mov edi, edx
	}
	smooth: asm {	mov	ax, [edi+320]
		mov	bx, [edi+640]
		and	ax, 0x3F3F
		and	bx, 0x3F3F
		mov	cl, [edi+320]
		add	ax, bx
		and	cl, 0xC0
		add	al, ah
		inc 	di
		shr	al, 2
		or	al, cl
		dec 	esi
		mov 	[edi-1], al
		jnz 	smooth
		popad
		#else
		pusha
		push 	ds
		mov 	si, QUADWORDS
		sub 	si, 80
		shl 	si, 2
		lds 	ax, dword ptr target
		mov 	ax, ds
		add 	ax, segshift
		mov 	ds, ax
		xor 	di, di }
smooth: asm {	mov	ax, [di+320]
		mov	bx, [di+640]
		and	ax, 0x3F3F
		and	bx, 0x3F3F
		mov	cl, [di+320]
		add	ax, bx
		and	cl, 0xC0
		add	al, ah
		inc 	di
		shr	al, 2
		or	al, cl
		dec 	si
		mov 	[di-1], al
		jnz 	smooth
		pop 	ds
		popa
	#endif
		
	}
}


/* Versione circolare del procedimento di smoothing */

//NOTVALID: Depends on display size being 320x200
void smootharound_64 (Uchar maybefar *target, Dword cx, Dword cy, Dword r, char diffuse)
{
	Dword x1 = cx - r, y1 = cy - r;
	Dword x2 = cx + r, y2 = cy + r;
	Dword px, py, rs = r*r;
	#ifdef WINDOWS
	Udword cp;
	#else
	Uword cp;
	#endif

	if (r <= 0) return;

	if (x1 > 318) return;
	if (y1 > 198) return;
	if (y1 < 0) y1 = 0;

	if (x2 < 0) return;
	if (x2 > 318) x2 = 318;
	if (y2 < 0) return;
	if (y2 > 198) y2 = 198;

	py = -r;
	while (y1 <= y2) {
		px = -r;
		x1 = cx - r;
		if (x1 < 0) {
			px -= x1;
			x1 = 0;
		}
		cp = (320 * y1) + x1;
		if (diffuse) {
			while (x1 <= x2) {
				if (px*px + py*py < rs) {
				asm {
					#ifdef WINDOWS
					push edi
					push ecx
					mov edi, [target]
					add edi, cp
					mov ax, [edi]
					mov cx, ax
					mov bx, [edi+320]
					#else
					les 	di, dword ptr target
					add	di, cp
					mov	ax, es:[di]
					mov	cx, ax
					mov	bx, es:[di+320]
					#endif
					
					mov	dx, bx
					and	ax, 0x3F3F
					and	bx, 0x3F3F
					add	ax, bx
					and	cx, 0xC0C0
					add	al, ah
					and	dx, 0xC0C0
					shr	al, 2
					mov 	ah, al
					mov	bx, ax
					or	ax, cx
					or	bx, dx
					#ifdef WINDOWS
					mov 	[edi], ax
					mov 	[edi+320], bx
					pop edi
					pop ecx
					#else
					mov 	es:[di], ax
					mov 	es:[di+320], bx
					#endif
					}
				}
				cp++;
				px++;
				x1++;
			}
		}
		else {
			while (x1 <= x2) {
				if (px*px + py*py < rs) {
				asm {
					#ifdef WINDOWS
					push edi
					push ebx
					mov edi, [target]
					add	edi, cp
					mov	ax, [edi]
					mov	bx, [edi+320]
					#else
					les 	di, dword ptr target
					add	di, cp
					mov	ax, es:[di]
					mov	bx, es:[di+320]
					#endif
					mov	cl, al
					and	ax, 0x3F3F
					and	bx, 0x3F3F
					and	cl, 0xC0
					add	ax, bx
					add	al, ah
					shr	al, 2
					or  	al, cl
					#ifdef WINDOWS
					mov 	[edi], al
					pop edi
					pop ebx
					#else
					mov 	es:[di], al
					#endif
					}
				}
				cp++;
				px++;
				x1++;
			}
		}
		py++;
		y1++;
	}
}

// Usando 64 livelli in 4 sfumature, porta lo schermo ad una sola sfumatura.

void mask_pixels (Uchar maybefar *target, Uchar mask)
{
	asm {
		#ifdef WINDOWS
		pushad
		#else
		pusha
		push ds
		#endif
		mov bl, mask
		mov bh, mask
		SHL_EBX_16
		mov bl, mask
		mov bh, mask
		mov ax, 0x3F3F
		SHL_EAX_16
		mov ax, 0x3F3F
		#ifdef WINDOWS
		mov ecx, QUADWORDS
		mov edi, [target] }
mloop:  asm {	and dword ptr [edi], eax
		add dword ptr [edi], ebx
		add edi, 4
		dec ecx
		jnz mloop
		popad
		#else
		mov cx, QUADWORDS
		lds di, target }
mloop:  asm {	db 0x66; and word ptr [di], ax
		db 0x66; add word ptr [di], bx
		add di, 4
		dec cx
		jnz mloop
		pop ds
		popa
		#endif
		}
	return;
}

/*

	Inclusioni HSP.

*/

#ifdef WINDOWS
#include "tdpolygs.h" // 3d-Engine.
#else
#include "ddpolygs.h" // 3d-Engine.
#endif
/*

	Catalogo files di supporto.

*/

#ifdef WINDOWS
char   *situation_file  = "..\\DATA\\WCurrent.BIN";
#else
char   *situation_file  = "..\\DATA\\Current.BIN";
#endif
//#ifdef OLD_STARMAP
char   *starmap_file    = "..\\DATA\\StarMap.BIN";
//#else
char *starmap3_file = "..\\DATA\\starmap3.map";
//#endif
char   *goesoutputfile	= "..\\DATA\\GOESfile.TXT";
#ifdef WINDOWS
char *starmap3b_file = "..\\DATA\\starmap3b.map";
char *surface_file	= "..\\DATA\\WSurface.BIN";
#else
char *surface_file	= "..\\DATA\\Surface.BIN";
#endif
FILEPTR 	sfh; // handle del file della situazione di superficie.

/*

	Dati globali di continuit… (salvati e ripristinati).

*/

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
Word    sys                = 4;		// 25
Word    pwr                = 20000;	// 27
Word    dev_page           = 0;		// 29
Word    ap_target_class    = 0;		// 31
Word    f_ray_elapsed	  = 0;		// 33
Word    nearstar_class     = 0;		// 35
Word    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      = 1000;	// 63
float  nearstar_ray       = 1000;	// 67
double dzat_x             = +3797120;	// 71
double dzat_y             = -4352112;	// 79
double dzat_z             = -925018;	// 87
double ap_target_x        = 0;		// 95
double ap_target_y        = 1E8;	// 103
double ap_target_z        = 0;		// 111
double nearstar_x         = 0;		// 119
double nearstar_y         = 1E8;	// 127
double nearstar_z         = 0;		// 135
double helptime           = 0;		// 143
double ip_target_initial_d= 1E8;	// 151
double requested_approach_coefficient=1;// 159
double current_approach_coefficient = 1;// 167
double reaction_time      = 0.01;	// 175
char   fcs_status[11]     = "STANDBY";	// 183
Word    fcs_status_delay   = 0;		// 194
Word    psys               = 4;		// 196
double ap_target_initial_d= 1E8;	// 198
double requested_vimana_coefficient = 1;// 206
double current_vimana_coefficient = 1;	// 214
double vimana_reaction_time = 0.01;	// 222
char   lithium_collector  = 0;		// 230
char   autoscreenoff	  = 0;		// 231
char   ap_reached         = 0;		// 232
Word    lifter		  = 0;		// 233
double secs		  = 0;		// 235
char   data		  = 0;		// 243
char   surlight		  = 16;		// 244
Word old_currentbin_length = 245;

//Additional variables: (SL and Mega)
char   option_speedup		=0;			// 0
char   option_temperature = 1;			// 1
double nearstar_mass = -1;				// 2
double nearstar_surfaceTemperature = -1;	// 10
double nearstar_temperatureTransmission =-1;// 18
char   option_temperature_units = 0;			// 26
char   option_flying_lander = 1;				// 27
char option_antialias_in_stardrifter = 1;		// 28
char option_center_outerring_pointer = 0;		// 29
char option_x_axis_pointer = 0;		// 30
char option_y_axis_pointer = 0;		// 31
char option_z_axis_pointer = 0;		// 32
char option_multiplayer = 0;		// 33
char option_invis_sd = 0;			// 34
char option_change_over_time = 1;	//35
Dword lastSnapshot = -1;				//36
char option_mouseLook = 0;			//40
Dword ap_target_sx        = 0x7fffffff;		//41
Dword ap_target_sy        = 0x7fffffff;		//45
Dword ap_target_sz        = 0x7fffffff;		//49
Dword nearstar_sx	  	= 0x7fffffff;		//53
Dword nearstar_sy	  	= 0x7fffffff;		//57
Dword nearstar_sz	  	= 0x7fffffff;		//61
char option_3dbrackets = 0;					//65
char option_controlset = 1;                      //66
char current_galaxy = 0;					//67
Word new_currentbin_length = 68;

char 	fcs_status_extended[42] = "STANDBY";

/*

	Dati di controllo per lo sbarco sulla superficie.

*/

char   land_now		  = 0;
char   landing_point	  = 0;
Word    landing_pt_lon	  = 0;
Word    landing_pt_lat	  = 60;

Word 	crepzone;
Word 	nightzone;
Word	sun_x_factor;

char ip_vimana;

/*

	Dati globali non salvati (deducibili da quelli salvati).

*/

char seconds[3], minutes[3], hours[3], n_day[3], n_month[3], n_year[5];
Word  epoc = 6011;

//char          ctb[512];
char          ctb[640];	//Added another row to the screen (SL)
char	      dec[20];

char	      _delay	     = 12;
char          stspeed        = 0;
char          bright;
char          elight	     = 0;
Uword      gl_start 	     = 0;
#ifdef WINDOWS
Udword vptr;
Udword      point;
#else
Uword      vptr;
Uword      point;
#endif
Word           infoarea       = 0;
Word           s_control      = 1;
Word           s_command      = 0;
Word           isecs, p_isecs;
double	      fsecs;
Word	      gl_fps         = 1;
Word	      fps            = 1;
float         dlt_alfa       = 0;
float	      dlt_beta       = 0;
float	      dlt_nav_beta   = 0;
float	      step           = 0;
float	      shift          = 0;
float slide=0;
double        s_m = 1000;
double	      plx, ply, plz;
double        pxx, pyy;
double        delta_x, delta_y;
double 	      nearstar_identity;
Word	      nearstar_nob = 0, nearstar_labeled;
Word	      npcs, resident_map1, resident_map2;
char   	      ontheroof;
Word	      datasheetscroll = 0;
Word	      datasheetdelta = 0;
char 	cloudFilter = 0;
char	terrainFilter = 0;

/*

	Dati costanti nel segmento globale.

*/

/* Alcuni ordinali (da 0 a 20) per determinate rappresentazioni.
   Il corrispondente "zeresimo" Š infrequente ma si pu• usare: Š corretto. */

char *ord[21] = { "zeroth", "first", "second", "third", "fourth", "fifth",
		  "sixth", "seventh", "eight", "nineth", "tenth", "eleventh",
		  "twelveth", "thirteenth", "fourteenth",
		  "fifteenth", "sixteenth", "seventeenth",
		  "eighteenth", "nineteenth", "twentyth" };

//Commented these with their class #s for quick reference, and what real-world star type
//they might resemble, and then some estimated values for various variables, that I calculated,
//but they may not be entirely correct. They're good for estimates at least... (SL)
char *star_description[star_classes] = {														//correction //(multiplied by .001)	//actual mass	//Surftemp
	"medium size, yellow star, suitable for planets having indigenous lifeforms.",//0 ~G		//m 1.886	//r 5-7			//0.9875 - 2.7097		// 5510.7 - 5999.75
	"very large, blue giant star, high energy radiations around.",				//1	  ~B
		//This is outdated now:	//m 1.50	//r 15-25		//21.205 - 98.175		//10,000 - 30,000	//This is pretty massive actually. Er, apparently fusion produces matter in addition to energy in WTotF. WTF? What happened to conservation of energy?
	"white dwarf star, possible harmful radiations.",							//2	  A?		//m 8000.40	//r .3-.5		//0.9048 - 4.1890		// 7,500 - 10,000
	"very large, ancient, red giant star.",										//3	  M?		//m	0.05	//r 20-35		//1.6755 - 8.9797		// 2,000 -  4,000

																						 //4 Was: m 2.44	//r 15-20		//34.495 - 81.765		// 3,500 -  5,000	//It was way too hot, methinks, but we'll see.
	"large and glowing, orange giant star, high nuclear mass.",					//4	  K?		//m 1.00	//r 15-20		//7.0686 - 16.755
	"small, weak, cold, brown dwarf substellar object.",						//5	  T?		//m 3.10	//r 1-2 		//0.0130 - 0.1039		// 1,000 -  1,750
	"large, very weak, very cold, gray giant dead star.",						//6	  L			//m 9.30	//r 3-6			//1.0518 - 8.4144		// 605   -  1,341	//VCold. Type L stars IRL are a dark red color, but I've left the color alone. I don't think they emit Li+ either, but who knows, and besides, this is based on the Wave Theory of the Field, not real life L type stars... Meh :P
	"very small, blue dwarf star, strong gravity well around.",					//7	  ~O		//m 48.00	//r 2-2.5		//1.6085 - 3.1416		//10,000 - 20,000	//Wicked radioactive, wicked hot. It's not actually very massive, but it's tiny.
	"possible MULTIPLE system - planets spread over wide ranges.",				//8	  **		//m 1.00	//r 4-9			//0.2680 - 3.0536		// 2,680 -  6,106	//The planets are probably going to be frozen solid. :o
	"medium size, surrounded by gas clouds, young star.",						//9	  T-Tauri	//m 1.00	//r 1.5-11.5	//0.0141 - 6.3706		// 1,000 -  6,370	//I'm actually pretty certain about this one, but maybe the temperature is supposed to be higher. Don't remember.
	"very large and ancient runaway star, unsuitable for planets.",				//10  Wolf-rayet? //m 0.07	//r 30-31		//7.9168 - 8.7351		// 1,000 -  2,000	//According to NIV manual "runaway" means "it got knocked off course" instead of "it had a runaway fusion process that caused a supernova." Wolf-rayet stars are supernova remnants, IIRC. But so are neutron stars and black holes? I've forgotten already what wolf-rayet stars are, I guess.
	"tiny pulsar object, unsafe, high radiation, strong gravity." };			//11  Neutron star	//m 15000 //r .25-.26	//0.9817 - 1.1043		//(not calc'd since those're ridiculous masses for neutron stars, the req'd mass to form one is pretty high)
																			//Changed neutron star:	//m 500,000 //r .25-.26 //(not calc'd) - 36.811	//(not calc'd) - 92,028
																		//.001 * 4/3 PI * (radius^3) * correction

	//double tmp_float = 1e-3 * qt_M_PI * starRay * starRay * starRay;
	//Bal's radius is approx 5.0210, Bal's mass is approx 1.
	//orig formula is 1 / (.000038 * 5.0210) = 5241.145 C or 5514.295 K (+ 273.15 to be K)
	//new formula is (mass * stmult[class]) + stadd[class]
#if defined(ALL) || defined(TEMPERATURE)
Word class_surfacetemp_mult[star_classes] = { 	284, 	220.84,	 761.22,  273.815, 81.73, 8250.82, 100,
	6522.73, 1229.89, 844.80, 1222.05,  1908.16 };
Word class_surfacetemp_add[star_classes] = { 	5230.2, 2290.06, 6811.25, 1541.22, 0,     892.74,  500,
	-491.81, 2350.39, 988.09, -8674.69,  21786.80};
#endif

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
};

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

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

Word 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       [ng_maxbodies];
Word    nearstar_p_owner	     [ng_maxbodies];
char   nearstar_p_moonid     [ng_maxbodies];
double nearstar_p_ring       [ng_maxbodies];
double nearstar_p_tilt       [ng_maxbodies];
double nearstar_p_ray        [ng_maxbodies];
double nearstar_p_orb_ray    [ng_maxbodies];
double nearstar_p_orb_seed   [ng_maxbodies];
double nearstar_p_orb_tilt   [ng_maxbodies];
double nearstar_p_orb_orient [ng_maxbodies];
double nearstar_p_orb_ecc    [ng_maxbodies];

Word    nearstar_p_rtperiod   [ng_maxbodies];
Word    nearstar_p_rotation   [ng_maxbodies];
Word    nearstar_p_term_start [ng_maxbodies];
Word    nearstar_p_term_end   [ng_maxbodies];

Word    nearstar_p_qsortindex [ng_maxbodies];
float  nearstar_p_qsortdist  [ng_maxbodies];

char *planet_description[] = { "medium size, internally hot, unstable surface, no atmosphere.",
			       "small, solid, dusty, craterized, no atmosphere.",
			       "medium size, solid, thick atmosphere, fully covered by clouds.",
			       "medium size, felisian, breathable atmosphere, suitable for life.",
			       "medium size, rocky, creased, no atmosphere.",
			       "small, solid, thin atmosphere.",
			       "large, not consistent, covered with dense clouds.",
			       "small, solid, icy surface, no atmosphere.",
			       "medium size, surface is mainly native quartz, oxygen atmosphere.",
			       "very large, substellar object, not consistent.",
			       "companion star - not a planet"
	#ifdef WINDOWS
					, "intergalactic gateway"
	#endif
	};

Uchar planet_rgb_and_var[] = { 60, 30, 15,      20, // RGB, and ammount of color(?) of planets as seen from space.
				       40, 50, 40,	25,
				       32, 32, 32, 	32,
				       16, 32, 48,      40,
				       32, 40, 32,	20,
				       32, 32, 32,      32,
				       32, 32, 32,      32,
				       32, 40, 48,      24,
				       40, 40, 40,      30,
				       50, 25, 10,      20,
				       40, 40, 40,	40
	#ifdef WINDOWS
						, 0, 0, 0, 0
	#endif
	};

Word planet_possiblemoons[] = { 1, 1, 2, 3, 2, 2, 18, 2, 3, 20, 20
	#ifdef WINDOWS
								, 0
	#endif
	};


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
	#ifdef WINDOWS
				, 0.010
	#endif
	};

float mindiff = 0.01;

/*

	Matrici video fisiche e logiche, cartografie,
	ed altri blocchi di memoria...

*/

Uchar maybefar  *s_background;
Uchar maybefar  *p_background;
Uchar maybehuge *p_surfacemap;
quadrant      maybefar  *objectschart;
Uchar maybefar  *ruinschart; // come objectschart, ma dichiarato in bytes
Uchar maybefar  *pvfile;

Uchar maybefar  *n_offsets_map;
char maybefar           *n_globes_map;

Uword	    seg_adapted;

/*

	Dati di regolazione delle superfici planetarie.

*/

char sky_red_filter = 63; // Filtri per il cielo.
char sky_grn_filter = 63;
char sky_blu_filter = 63;
char gnd_red_filter = 63; // Filtri per il suolo.
char gnd_grn_filter = 63;
char gnd_blu_filter = 63;
char wtr_red_filter = 63; // Filtri per il suolo.
char wtr_grn_filter = 63;
char wtr_blu_filter = 63;

float planet_grav  = 150; // corrisponde alla gravit… terrestre.
float rainy         = 0; // 0..5 a seconda dell'albedo delle nubi.
Word   albedo        = 0; // Albedo media della superficie di sbarco:
			 // pu• andare da 0 a 62.
Word raw_albedo = 0;	//The albedo without atmospheric effects. (SL)
Word old_albedo = 0;

Uchar sky_brightness = 32; // Luminosit… del cielo (0-48).
Uchar horiz_brt      = 20; // Luminosit… minima dell'orizzonte (0-48).

Uword m200[200]; // numeri da 0 a 199, moltiplicati per 200 (ottimizzaz.)

float	 rwp = 15; // Potenza richiesta del vento (per regolarlo, in NODI).
float    iwp =  0; // Potenza ideale del vento (da 0 a 1).
float    wp  =  0; // Potenza attuale del vento.
float    wdir=  0; // Direzione di provenienza del vento.
float	 wdirsin=0;// Valore di ottimizzazione.
float	 wdircos=1;// Valore di ottimizzazione.

char landed; // Flag settato al momento dell'atterraggio.
char lifter_homing;
char lifter_vertical;
Dword atl_x, atl_z, atl_x2, atl_z2, atl_y; // Posizione codificata quoziente:resto
float atl_xx, atl_zz;
				   // del bozzolo di sbarco.

double qid = 1.0 / 16384; // Costante per trovare l'id x/z di un quadrante.

/*

	Aree per grafica poligonale (personaggi, navicelle, diciture, etc...)

*/

#define handles	16 // 16 handles in questo caso...

Udword pvfile_datatop = 0; // cima dei dati.

// nota: dataptr Š un puntatore relativo che pu• andare da zero a "pvbytes".
Uword pvfile_dataptr[handles] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
Uword pvfile_datalen[handles] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
Uword pvfile_npolygs[handles] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };

char  maybefar *pv_n_vtx[handles]; // numero vertici per ogni poligono (3 o 4).
float maybefar *pvfile_x[handles]; // coord. X (quattro vertici) di ogni poligono.
float maybefar *pvfile_y[handles]; // coord. Y (quattro vertici) di ogni poligono.
float maybefar *pvfile_z[handles]; // coord. Z (quattro vertici) di ogni poligono.
char  maybefar *pvfile_c[handles]; // intensit… del colore di ogni poligono (0..63).
float maybefar *pv_mid_x[handles]; // coordinate X dei punti medi di ogni poligono.
float maybefar *pv_mid_y[handles]; // coordinate Y dei punti medi di ogni poligono.
float maybefar *pv_mid_z[handles]; // coordinate Z dei punti medi di ogni poligono.
float maybefar *pv_mid_d[handles]; // buffer distanza di punti medi dall'osservatore.
Word   maybefar *pv_dep_i[handles]; // indice distanza (ordinamento poligoni).

/* Procedimenti d'estrazione di numeri pseudo-casuali. */

Dword flat_rnd_seed;

void fast_srand (Dword seed) // selezione tabella pseudo.
			    // 4.294.967.295 tabelle possibili.
			    // (ca. 20000 elementi diversi per tabella)
{
	asm {
		or word ptr seed, 3
		#ifdef WINDOWS
		mov eax, dword ptr seed
		mov dword ptr flat_rnd_seed, eax
		#else
		db 0x66; mov ax, word ptr seed
		db 0x66; mov word ptr flat_rnd_seed, ax
		#endif
	}
}

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

	asm {
		MOV_EAX_DWORD_PTR flat_rnd_seed
		MOV_EDX_DWORD_PTR flat_rnd_seed
		DB_0x66; mul MAYBE_EDX
		add al, dl
		DB_0x66; add MAYBE_DWORD_PTR flat_rnd_seed, MAYBE_EAX
		DB_0x66; and MAYBE_EAX, MAYBE_DWORD_PTR mask
		MOV_DWORD_PTR num, MAYBE_EAX
		/*
		#ifdef WINDOWS
		mov eax, dword ptr flat_rnd_seed
		mov edx, dword ptr flat_rnd_seed
		mul edx
			 add al, dl
		add dword ptr flat_rnd_seed, eax
		and eax, dword ptr mask
		mov dword ptr num, eax
		#else
		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
		#endif*/
	}

	return (num);
}

Word ranged_fast_random (Word 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); }

/* Effettua l'apertura di un file "virtuale", inserito nell'applicazione
   stand-alone NOCTIS.EXE - il nome non deve essere cambiato. */

FILEPTR sa_open (Dword offset_of_virtual_file)
{
	FILEPTR fh;

	fh = OPENFILE (supports_nct, OPEN_RB);
	#ifdef WINDOWS
	if (fh==NOFILE) error("supports.nct is missing!");
	#endif
	if (fh==NOFILE) return (NOFILE);
	Dword ret = FILESEEK (fh, offset_of_virtual_file, SEEK_END);
	if (ret IS_FILESEEK_VALID) {
		return (fh);
	} else {
		CLOSEFILE (fh);
		#ifdef WINDOWS
		error("supports.nct is invalid!\n");
		#endif
		return (NOFILE);
	}
}

/* Definisce una parte della tavola colori in modo che una sfumatura graduale
   vada da una tinta ad un'altra, entro un certo numero di tinte intermedie */

void shade (Uchar maybefar *palette_buffer,
	    Word first_color, Word number_of_colors,
	    float start_r,  float start_g,  float start_b,
	    float finish_r, float finish_g, float finish_b)
{
	Word   count = number_of_colors;

	float k = 1.00 / (float)number_of_colors;
	float delta_r = (finish_r - start_r) * k;
	float delta_g = (finish_g - start_g) * k;
	float delta_b = (finish_b - start_b) * k;

	first_color *= 3;

	while (count) {
		if (start_r >= 0 && start_r < 64)
			palette_buffer[first_color + 0] = start_r;
		else {
			if (start_r > 0)
				palette_buffer[first_color + 0] = 63;
			else
				palette_buffer[first_color + 0] = 00;
		}
		//
		if (start_g >= 0 && start_g < 64)
			palette_buffer[first_color + 1] = start_g;
		else {
			if (start_g > 0)
				palette_buffer[first_color + 1] = 63;
			else
				palette_buffer[first_color + 1] = 00;
		}
		//
		if (start_b >= 0 && start_b < 64)
			palette_buffer[first_color + 2] = start_b;
		else {
			if (start_b > 0)
				palette_buffer[first_color + 2] = 63;
			else
				palette_buffer[first_color + 2] = 00;
		}
		//
		start_r += delta_r;
		start_g += delta_g;
		start_b += delta_b;
		//
		first_color += 3;
		count--;
	}
}

/* Copia aree video pi— grandi di 4 per 1 pixels. */

void copia (Uchar maybefar *dest, Uchar maybefar *sorg, Uword x, Uword y, Word l, Word a)
{
	if (l<4) return;
	if (a<1) return;
	x = 320*y + x;
	
	asm {
		#ifdef WINDOWS
		push eax
		push ebx
		push ecx
		push edx
		push esi
		push edi
		#else
		push ax
		push bx
		push cx
		push dx
		push es
		push ds
		push si
		push di
		#endif
		cld
	}

	#ifdef WINDOWS
	_EBX = x + 320*a;
	_EAX = x; _EDX = l;
	asm {
		mov esi, [sorg]
		mov edi, [dest]
		add ebx, esi
		add esi, eax
		add edi, eax
		mov eax, 320
		sub eax, edx
	}

chiclo:	asm {
		cmp esi, ebx
		jnb fine
		mov ecx, edx
		shr ecx, 2
		REP_MOVSD
		mov ecx, edx
		and ecx, 3
	    rep movsb
		add esi, eax
		add edi, eax
		jmp chiclo
	}

fine:	asm {
		pop edi
		pop esi
		pop edx
		pop ecx
		pop ebx
		pop eax
	}
	#else
	_BX = x + 320*a;
	_AX = x; _DX = l;

	asm {
		lds si, dword ptr sorg
		les di, dword ptr dest
		add bx, si
		add si, ax
		add di, ax
		mov ax, 320
		sub ax, dx
	}

chiclo:	asm {
		cmp si, bx
		jnb fine
		mov cx, dx
		shr cx, 2
		REP_MOVSD
		mov cx, dx
		and cx, 3
	    rep movsb
		add si, ax
		add di, ax
		jmp chiclo
	}

fine:	asm {
		pop di
		pop si
		pop ds
		pop es
		pop dx
		pop cx
		pop bx
		pop ax
	}
	#endif
}

/*

	Controllo visualizzazione.

*/

/* Imposta le proiezioni 3d dal punto di vista dell'astrozattera. */

void from_vehicle ()
{
	cam_x = dzat_x; cam_y = dzat_y; cam_z = dzat_z;
	alfa = user_alfa; beta = user_beta + navigation_beta + 180;
	if (beta>=360) beta -= 360;
	change_angle_of_view ();
}

/* Imposta le proiezioni 3d dal punto di vista del protagonista. */

void from_user ()
{
	cam_x = pos_x; cam_y = pos_y; cam_z = pos_z;
	alfa = user_alfa; beta = user_beta;
	change_angle_of_view ();
}
/* Orienta la videocamera virtuale verso un certo punto dato da see_x;y;z,
   frattalizzando l'angolo giro per fare pi— in fretta. */

void watch (double cam_x, double cam_y, double cam_z,
	    double see_x, double see_y, double see_z)
{
	double rx, ry, rz, w, ww, k, q, f1, f2, f3;
	double sinbeta, cosbeta, cosalfa;

	rx     = cam_x - see_x;
	ry     = cam_y - see_y;
	rz     = cam_z - see_z;
	w      = SQRT (rx*rx+ry*ry+rz*rz);

	see_x -= cam_x;
	see_y -= cam_y;
	see_z -= cam_z;

	f1     = 0;
	f2     = 0;

	f3     = 2 * M_PI;

	while (f3 > 0.02) {

		q       = 1e+111;
		ww      = f3 / 10;

		sinbeta = sin(beta);
		cosbeta = cos(beta);

		for (alfa=f2-f3; alfa<f2+f3; alfa+=ww) {
			rx  = - w * sinbeta * cos(alfa) - see_x;
			ry  = + w * sin(alfa) 	        - see_y;
			rz  = + w * cosbeta * cos(alfa) - see_z;
			k   = rx*rx + ry*ry + rz*rz;
			if (k<q) {
				q = k;
				f2 = alfa;
			}
		}

		alfa    = f2;

		ry      = w * sin(alfa) - see_y;
		ry     *= ry;

		cosalfa = cos(alfa);

		q       = 1e+111;
		ww      = f3 / 10;

		for (beta=f1-f3; beta<f1+f3; beta+=ww) {
			rx  = - w * sin(beta) * cosalfa - see_x;
			rz  = + w * cos(beta) * cosalfa - see_z;
			k   = rx*rx + ry + rz*rz;
			if (k<q) {
				q = k;
				f1 = beta;
			}
		}

		beta = f1;

		f3 /= 5;

	}

	alfa /= deg;
	beta /= deg;
}

/* Calcola lo scostamento x-y dal centro del video di un certo punto
   dato da point_x;y;z. Restituisce i valori in delta_x;y. */

char xy (double cam_x, double cam_y, double cam_z,
	 double point_x, double point_y, double point_z)
{
	double xx, yy, zz, z2, rz;

	xx = point_x - cam_x;
	yy = point_y - cam_y;
	zz = point_z - cam_z;

	delta_x = xx * opt_pcosbeta + zz * opt_psinbeta;
	z2      = zz * opt_tcosbeta - xx * opt_tsinbeta;
	rz      = z2 * opt_tcosalfa + yy * opt_tsinalfa;
	delta_y = yy * opt_pcosalfa - z2 * opt_psinalfa;

	if (rz>0.001) {
		delta_x /= rz;
		delta_y /= rz;
		return (1);
	}

	return (0);
}

/* Sposta il protagonista all'interno dell'astrozattera. */

void p_Forward (float delta)
{
	pos_x -= delta * opt_tsinbeta * opt_tcosalfa;
	pos_z += delta * opt_tcosbeta * opt_tcosalfa;
}

/* Calcola la posizione di un certo pianeta in orbita attorno ad una certa
   stella (quella vicina), sulla base dei parametri orbitali (inclinazione,
   eccentricit…, raggio ed orientamento dell'asse maggiore) e ritorna i
   valori in plx, ply, plz. */

double mox, moy, moz;
void   moonorigin (Word n)
{
	double xx;
	double p_riv, ors;
	double alfa, beta;

	ors = nearstar_p_orb_ray[n] * nearstar_p_orb_ray[n];
	p_riv = SQRT (s_m / ors);

	beta = (secs * p_riv * M_PI) / 180;
	alfa = nearstar_p_orb_tilt[n] * deg;

	xx  = -nearstar_p_orb_ray[n] * sin(beta) * cos(alfa);
	moz =  nearstar_p_orb_ray[n] * cos(beta) * cos(alfa);
	moy =  nearstar_p_orb_ray[n] * sin(alfa);

	moz *= nearstar_p_orb_ecc[n];

	beta = nearstar_p_orb_orient[n];

	mox = xx * cos(beta) + moz * sin(beta);
	moz = moz * cos(beta) - xx * sin(beta);
}

void planet_xyz (Word n)
{
	double xx;
	double alfa, beta;
	double p_m, p_riv, ors;

	ors = nearstar_p_orb_ray[n] * nearstar_p_orb_ray[n];

	if (nearstar_p_owner[n] > -1) {
		xx = nearstar_p_ray[nearstar_p_owner[n]];
		p_m = qt_M_PI * xx * xx * xx * 0.44e-4;
		p_riv = SQRT (p_m / ors);
	}
	else
		p_riv = SQRT (s_m / ors);

	beta = (secs * p_riv * M_PI) / 180;
	alfa = nearstar_p_orb_tilt[n] * deg;

	xx  = -nearstar_p_orb_ray[n] * sin(beta) * cos(alfa);
	plz =  nearstar_p_orb_ray[n] * cos(beta) * cos(alfa);
	ply =  nearstar_p_orb_ray[n] * sin(alfa);

	plz *= nearstar_p_orb_ecc[n];

	beta = nearstar_p_orb_orient[n];

	plx = xx * cos(beta) + plz * sin(beta);
	plz = plz * cos(beta) - xx * sin(beta);

	plx += nearstar_x;
	ply += nearstar_y;
	plz += nearstar_z;

	if (nearstar_p_owner[n] > -1) {
		moonorigin (nearstar_p_owner[n]);
		plx += mox;
		ply += moy;
		plz += moz;
	}
}

/* Calcola il periodo di rivoluzione di un corpo, in secondi:
   per i pianeti, attorno alla stella;
   per le lune, attorno al pianeta...
   0.01e-7 Š l'equivalente, nel cosmo virtuale di Noctis,
   della costante gravitazionale. */

float rtp (Word n)
{
	double p_m, p_riv, ors, xx;

	ors = nearstar_p_orb_ray[n] * nearstar_p_orb_ray[n];

	if (nearstar_p_owner[n] > -1) {
		xx = nearstar_p_ray[nearstar_p_owner[n]];
		p_m = qt_M_PI * xx * xx * xx * 0.44e-4;
		p_riv = SQRT (p_m / ors);
	}
	else
		p_riv = SQRT (s_m / ors);

	return (360 / p_riv);
}

/* Calcola la longitudine d'incidenza dello sguardo sulla superficie
   di un certo pianeta dato da (plx, ply, plz). L'osservatore Š posto
   nel punto (obs_x; obs_z) dato che la sua Y Š ininfluente... */

Word planet_viewpoint (double obs_x, double obs_z)
{
	Uword a;
	Word plwp = 0;

	double xx;
	double zz;

	double min = 1E99;

	for (a=0; a<360; a++) {
		xx = plx + cos(deg*(double)a) - obs_x;
		zz = plz + sin(deg*(double)a) - obs_z;
		xx = xx*xx + zz*zz;
		if (xx<min) {
			plwp = a;
			min = xx;
		}
	}

	return (plwp);
}

Word cplx_planet_viewpoint (Word logical_id)
{
	Word owner;

	double ownerplx;
	double ownerplz;

	if (nearstar_p_owner[logical_id] == -1)
		return (planet_viewpoint (nearstar_x, nearstar_z));

	owner = nearstar_p_owner[logical_id];
	if (nearstar_p_type[owner] == 10) {
		planet_xyz (owner);
		ownerplx = plx;
		ownerplz = plz;
		planet_xyz (logical_id);
		return (planet_viewpoint (ownerplx, ownerplz));
	}
	else
		return (planet_viewpoint (nearstar_x, nearstar_z));
}

/* Selezione effetti tramite variabile di controllo "flares". */

char previous_flares_value = 0;
void setfx (char fx) { previous_flares_value = flares; flares = fx; }
void chgfx (char fx) { flares = fx; }
void resetfx (void)  { flares = previous_flares_value; }

/* Tracciamento bastoncini (parte 2d). */

void Stick (Udword xp, Udword yp,
	    Udword xa, Udword ya)
{
	Dword a, b, L;
	#ifdef WINDOWS
	Udword pi, pf;
	assert(xp>=0);
	assert(xp<WIDTH);
	assert(yp>=0);
	assert(yp<HEIGHT);
	assert(xa>=0);
	assert(xa<WIDTH);
	assert(ya>=0);
	assert(ya<HEIGHT);
	Uchar* minScreen = adapted;
	Uchar* maxScreen = adapted+(HEIGHT*WIDTH);
	Uchar* lineStart;
	Uchar* lineEnd;
	#else
	Uword pi, pf;
	#endif
	if (xp==xa) {
		if (ya>=yp) {
			pi = riga[yp] + xp;
			pf = riga[ya+1];
		}
		else {
			pi = riga[ya] + xp;
			pf = riga[yp+1];
		}
		asm {
			
			#ifdef WINDOWS
			mov esi, [adapted]
			#else
			les si, dword ptr adapted
			#endif
			add pi, MAYBE_ESI
			add pf, MAYBE_ESI
			mov MAYBE_ESI, pi
			#ifdef WINDOWS
			push esi
			#endif
		}
		
		switch (flares) {
			case 0:
				#ifdef WINDOWS
				asm pop esi
				#endif
			clu:	asm {
					cmp MAYBE_ESI, pf
					jnb _ret
					#ifdef WINDOWS
					mov word ptr [esi], 0x3E00
					#else
					mov word ptr es:[si], 0x3E00
					#endif
					add MAYBE_ESI, 320
					jmp clu }
				break;
			case 1:
				#ifdef WINDOWS
				asm pop esi
				#endif
			_clu:	asm {	
					cmp MAYBE_ESI, pf
					jnb _ret
					#ifdef WINDOWS
					mov cl, [esi]
					#else
					mov cl, es:[si]
					#endif
					and cl, 0x3F
					#ifdef WINDOWS
					and byte ptr [esi], 0xC0
					#else
					and byte ptr es:[si], 0xC0
					#endif
					add cl, 0x08
					cmp cl, 0x3E
					jb _cl_ok
					mov cl, 0x3E }
			_cl_ok:	asm {
					#ifdef WINDOWS
					add [esi], cl
					#else
					add es:[si], cl
					#endif
					add MAYBE_ESI, 320
					jmp _clu }
				break;
			case 2:
				#ifdef WINDOWS
				asm pop esi
				#endif
			__clu:	asm {	cmp MAYBE_ESI, pf
					jnb _ret
					#ifdef WINDOWS
					mov cl, [esi]
					#else
					mov cl, es:[si]
					#endif
					and cl, 0x3F
					#ifdef WINDOWS
					and byte ptr [esi], 0xC0
					#else
					and byte ptr es:[si], 0xC0
					#endif
					shr cl, 1
					#ifdef WINDOWS
					add [esi], cl
					#else
					add es:[si], cl
					#endif
					add MAYBE_ESI, 320
					jmp __clu }
				break;
			case 3:
				#ifdef WINDOWS
				asm pop esi
				#endif
			___clu:	asm {	cmp MAYBE_ESI, pf
					jnb _ret
					#ifdef WINDOWS
					mov dword ptr [esi], 0x2E1E130E
					#else
					db 0x66, 0x26, 0xC7, 0x04, 0x0E, 0x13, 0x1E, 0x2E
					#endif
					add MAYBE_ESI, 320
					jmp ___clu }
				break;
			default:
				#ifdef WINDOWS
				asm pop esi
				#endif
				break;
		}
	_ret:	return;
	}

	asm {
		#ifdef WINDOWS
		pushad
		#endif
		
		MOV_ESI_DWORD_PTR xa
		SUB_ESI_DWORD_PTR xp
		jnc a_posit
		MOV_EAX_DWORD_PTR xp
		MOV_EBX_DWORD_PTR xa
		MOV_ECX_DWORD_PTR yp
		MOV_EDX_DWORD_PTR ya
		MOV_DWORD_PTR xa, MAYBE_EAX
		MOV_DWORD_PTR xp, MAYBE_EBX
		MOV_DWORD_PTR ya, MAYBE_ECX
		MOV_DWORD_PTR yp, MAYBE_EDX
		DB_0x66; neg MAYBE_ESI }
a_posit:asm {   MOV_DWORD_PTR a, MAYBE_ESI
		MOV_DWORD_PTR L, MAYBE_ESI
		xor ch, ch
		MOV_EAX_DWORD_PTR ya
		SUB_EAX_DWORD_PTR yp
		jnc b_posit
			 not ch
		DB_0x66; neg MAYBE_EAX }
b_posit:asm {   MOV_DWORD_PTR b, MAYBE_EAX
		CMP_EAX_DWORD_PTR L
		jb b_lower
		MOV_DWORD_PTR L, MAYBE_EAX }
b_lower:asm {	INC_DWORD_PTR L
		SHL_DWORD_PTR xa, 16
		MOV_EAX_DWORD_PTR xp
		MOV_EBX_DWORD_PTR yp
		SHL_EAX_16
		SHL_EBX_16
		MOV_DWORD_PTR global_x, MAYBE_EAX
		MOV_DWORD_PTR global_y, MAYBE_EBX
		SHL_DWORD_PTR a, 16
		SAL_DWORD_PTR b, 16
		
			 mov dx, word ptr a[2]
			 mov ax, word ptr a
			 div word ptr L	    // a /= L, 16bit - unsigned
			 mov word ptr a, ax
			 mov word ptr a[2], 0
			 mov dx, word ptr b[2]
			 mov ax, word ptr b
			 div word ptr L     // b /= L, 16bit - false unsigned
			 mov word ptr b, ax
			 mov word ptr b[2], 0
			 test ch, ch
			 jz trace
		NEG_DWORD_PTR b
		}
trace:
		#ifdef WINDOWS
		//asm mov esi, [adapted];
		asm mov esi, [adapted];
		asm push esi
		#else
		asm mov es, seg_adapted;
		#endif
	switch (flares) {

		case 0: // bastoncini solidi che "riflettono" luce.

		asm {
			#ifdef WINDOWS
			pop esi
			mov eax, dword ptr a    // passa in eax il delta_x (ovvero a).
			mov edx, dword ptr b    // passa in edx il delta_y (ovvero b).
			mov ecx, dword ptr xa } // passa in ecx il limite superiore del ciclo (come coordinata x d'arrivo).
			#else
			db 0x66; mov ax, word ptr a    // passa in eax il delta_x (ovvero a).
			db 0x66; mov dx, word ptr b    // passa in edx il delta_y (ovvero b).
			db 0x66; mov cx, word ptr xa } // passa in ecx il limite superiore del ciclo (come coordinata x d'arrivo).
			#endif
	_do:	asm {
			
			#ifdef WINDOWS
			xor edi, edi
			xor ebx, ebx
			#endif
			mov bx, word ptr global_y[2]
			mov di, word ptr global_x[2]
			add MAYBE_EBX, MAYBE_EBX
		
			ADD_DWORD_PTR global_x, MAYBE_EAX
			#ifdef WINDOWS
			add MAYBE_EDI, MAYBE_DWORD_PTR riga[ebx*2]
			and edi, 0xffff
			#else
			add di, word ptr riga[bx]
			#endif
			ADD_DWORD_PTR global_y, MAYBE_EDX
			CMP_DWORD_PTR global_x, MAYBE_ECX
			#ifdef WINDOWS
			mov dword ptr [esi+edi], 0x3E00
			#else
			mov word ptr es:[di+4], 0x3E00
			#endif
			
			jb  _do }

		break;

		case 1: // bastoncini intrinsecamente luminosi.

		asm {
			#ifdef WINDOWS
			asm pop esi
			#endif
			MOV_EAX_DWORD_PTR a
			MOV_EDX_DWORD_PTR b
			
			SHL_EAX_1	//POSSIBLE_OPTIMIZATION: Change to add eax,eax
			SHL_EDX_1	//POSSIBLE_OPTIMIZATION: Change to add edx,edx

			#ifdef WINDOWS
			push ebp			       // salva bp sullo stack
			mov ebp, dword ptr xa // passa in ebp il limite superiore del ciclo (come coordinata x d'arrivo).
			#else
			push bp			       // salva bp sullo stack
			db 0x66; mov bp, word ptr xa // passa in ebp il limite superiore del ciclo (come coordinata x d'arrivo).
			#endif
		}
			
	__do:	asm {
			#ifdef WINDOWS
			xor ebx, ebx
			xor edi, edi
			mov bx, word ptr global_y[2]
			mov di, word ptr global_x[2]
			add ebx, ebx
	       	add dword ptr global_x, eax
			add edi, dword ptr riga[ebx*2]
	       	and edi, 0xffff
			add dword ptr global_y, edx
			mov cl, byte ptr [esi+edi]	//mov cl, byte ptr [esi+edi+4]	//REMOVED4
			shl cx, 2
			add cl, 32
			jnc cl_ok
			mov cl, 0xFB
			#else
			mov bx, word ptr global_y[2]
			mov di, word ptr global_x[2]
			add bx, bx
	       db 0x66; add word ptr global_x, ax
			add di, word ptr riga[bx]
	       db 0x66; add word ptr global_y, dx
			mov cl, es:[di+4]
			shl cx, 2
			add cl, 32
			jnc cl_ok
			mov cl, 0xFB
			#endif
		}
	cl_ok:	asm {   shr cx, 2
	       	#ifdef WINDOWS
	       	cmp dword ptr global_x, ebp
	       	mov byte ptr [esi+edi], cl		//mov byte ptr [esi+edi+4], cl	//REMOVED4
			#else
	       	db 0x66; cmp word ptr global_x, bp
	       	mov es:[di+4], cl
			#endif
			jb __do }

		#ifdef WINDOWS
		asm	pop ebp				   // riprende bp
		#else
		asm	pop bp				   // riprende bp
		#endif

		break;

		case 2: // bastoncini che assorbono luce ("affumicati").

		asm {
			#ifdef WINDOWS
			asm pop esi
			#endif
			MOV_EAX_DWORD_PTR a
			MOV_EDX_DWORD_PTR b
			#ifdef WINDOWS
			push ebp
			mov ebp, dword ptr xa
			}
	___do:	asm {
			xor ebx, ebx
			xor edi, edi
			mov bx, word ptr global_y[2]
			mov di, word ptr global_x[2]
			add ebx, ebx
			add dword ptr global_x, eax
			add edi, dword ptr riga[ebx*2]
	      	and edi, 0xffff
			add dword ptr global_y, edx
			mov cl, byte ptr [esi+edi]	//mov cl, byte ptr [esi+edi+4]	//REMOVED4
			and cl, 0x3F
			and byte ptr [esi+edi], 0xC0	//aand byte ptr [esi+edi+4], 0xC0	//REMOVED4
			shr cl, 1
			add byte ptr [esi+edi], cl	//add byte ptr [esi+edi+4], cl	//REMOVED4
	       	cmp dword ptr global_x, ebp
			#else
			push bp			       // salva bp sullo stack
			db 0x66; mov bp, word ptr xa } // passa in ebp il limite superiore del ciclo (come coordinata x d'arrivo).

	___do:	asm {
			mov bx, word ptr global_y[2]
			mov di, word ptr global_x[2]
			add bx, bx
	       db 0x66; add word ptr global_x, ax
			add di, word ptr riga[bx]
	       db 0x66; add word ptr global_y, dx
			mov cl, es:[di+4]
			and cl, 0x3F
			and byte ptr es:[di+4], 0xC0
			shr cl, 1
			add es:[di+4], cl
	       db 0x66; cmp word ptr global_x, bp
			#endif
			jb ___do }

		#ifdef WINDOWS
		asm	pop ebp				   // riprende bp
		#else
		asm	pop bp				   // riprende bp
		#endif

		break;

		case 3: // come tipo 0, ma pi— larghi.

		asm {
			#ifdef WINDOWS
			asm pop esi
			#endif
			MOV_EAX_DWORD_PTR a	// passa in eax il delta_x (ovvero a).
			MOV_EDX_DWORD_PTR b    // passa in edx il delta_y (ovvero b).
			MOV_ECX_DWORD_PTR xa // passa in ecx il limite superiore del ciclo (come coordinata x d'arrivo).
		}

	____do:	asm {
			#ifdef WINDOWS
			xor ebx, ebx
			xor edi, edi
			#endif
			mov bx, word ptr global_y[2]
			mov di, word ptr global_x[2]
			#ifdef WINDOWS
			add ebx, ebx
			add dword ptr global_x, eax
			add edi, dword ptr riga[ebx*2]
	       	and edi, 0xffff
			add dword ptr global_y, edx
	       	cmp dword ptr global_x, ecx
	       	mov dword ptr [esi+edi], 0xEEDED3CE	//mov dword ptr adapted[edi+4], 0xEEDED3CE
			#else
	       	add bx, bx
			db 0x66; add word ptr global_x, ax
			add di, word ptr riga[bx]
	       db 0x66; add word ptr global_y, dx
	       db 0x66; cmp word ptr global_x, cx
	       db 0x66, 0x26, 0xC7, 0x45, 0x04 // mov dword ptr es:[di+4],
//	       db 0x0E, 0x13, 0x1E, 0x2E       // 0x2E1E130E
	       db 0xCE, 0xD3, 0xDE, 0xEE       // 0x2E1E130E
	       //It's actually 0xEEDED3CE (SL)
	       #endif
			jb  ____do }
			break;
		default:
			#ifdef WINDOWS
			asm pop esi
			#endif
			break;
	}
	#ifdef WINDOWS
	asm popad
	#endif
}

/* Tracciamento bastoncini (parte 3d). */

Dword fpx = -1; // first-point-x
Dword fpy;      // first-point-y

float p_rx, p_ry, p_rz;
float stick_uneg = 200;

void stick3d (float p_x, float p_y, float p_z,
	      float x, float y, float z)
{
	Dword  lx, ly;

	float p_z2, diff;

	float rx, ry, rz, z2, kk;

	fpx = -1;

//	p_x -= cam_x;
//	p_y -= cam_y;
//	p_z -= cam_z;

//	p_z2 = p_z * opt_tcosbeta - p_x * opt_tsinbeta;
//	p_rz = p_z2 * opt_tcosalfa + p_y * opt_tsinalfa;

	asm {	fld p_x
		fsub cam_x
		fst p_x
		fmul opt_tsinbeta
		fld p_z
		fsub cam_z
		fst p_z
		fmul opt_tcosbeta
		fsubrp
		fst p_z2
		fmul opt_tcosalfa
		fld p_y
		fsub cam_y
		fst p_y
		fmul opt_tsinalfa
		faddp
		fstp p_rz }

//	x -= cam_x;
//	y -= cam_y;
//	z -= cam_z;

//	z2 = z * opt_tcosbeta - x * opt_tsinbeta;
//	rz = z2 * opt_tcosalfa + y * opt_tsinalfa;

	asm {	fld x
		fsub cam_x
		fst x
		fmul opt_tsinbeta
		fld z
		fsub cam_z
		fst z
		fmul opt_tcosbeta
		fsubrp
		fst z2
		fmul opt_tcosalfa
		fld y
		fsub cam_y
		fst y
		fmul opt_tsinalfa
		faddp
		fstp rz }

	if (rz<stick_uneg&&p_rz<stick_uneg) return;

//	p_rx = p_x * opt_pcosbeta + p_z * opt_psinbeta;
//	p_ry = p_y * opt_pcosalfa - p_z2 * opt_psinalfa;

	asm {	fld p_x
		fmul opt_pcosbeta
		fld p_z
		fmul opt_psinbeta
		faddp
		fstp p_rx
		fld p_y
		fmul opt_pcosalfa
		fld p_z2
		fmul opt_psinalfa
		fsubp
		fstp p_ry }

//	rx = x * opt_pcosbeta + z * opt_psinbeta;
//	ry = y * opt_pcosalfa - z2 * opt_psinalfa;

	asm {	fld x
		fmul opt_pcosbeta
		fld z
		fmul opt_psinbeta
		faddp
		fstp rx
		fld y
		fmul opt_pcosalfa
		fld z2
		fmul opt_psinalfa
		fsubp
		fstp ry }

	/* Conversione punti alle spalle dell'osservatore rispetto al piano
	   dello schermo. */

	if (rz<stick_uneg) {
		diff = rz-p_rz;
		if (diff<-mindiff || diff>mindiff) {
			kk = (stick_uneg-p_rz) / diff;
			rx = kk * (rx-p_rx) + p_rx;
			ry = kk * (ry-p_ry) + p_ry;
		}
		rz = stick_uneg;
	}
	else {
		if (p_rz<stick_uneg) {
			diff = p_rz-rz;
			if (diff<-mindiff || diff>mindiff) {
				kk = (stick_uneg-rz) / diff;
				p_rx = kk * (p_rx-rx) + rx;
				p_ry = kk * (p_ry-ry) + ry;
			}
			p_rz = stick_uneg;
		}
	}

	// Prospettiva.

//	lx = rx / rz; ly = ry / rz;
//	fpx = p_rx / p_rz; fpy = p_ry / p_rz;

	asm {	fld uno
		fdiv rz
		fld st(0)
		fmul rx
		fistp lx
		fmul ry
		fistp ly
		fld uno
		fdiv p_rz
		fld st(0)
		fmul p_rx
		fistp fpx
		fmul p_ry
		fistp fpy }

	if (fpy<stk_lby&&ly<stk_lby) return; // Linee del tutto fuori campo.
	if (fpy>stk_uby&&ly>stk_uby) return;
	if (fpx<stk_lbx&&lx<stk_lbx) return;
	if (fpx>stk_ubx&&lx>stk_ubx) return;

	/* Ottimizza il tracciamento del segmento, tagliando via le parti
	   che di sicuro non si vedono. Questa parte non Š efficace se
	   i punti di partenza e di arrivo fanno sŤ che il segmento non
	   intersechi alcun lato dell'area visibile: ma in questo peculiare
	   caso le linee vengono escluse dai controlli precedenti. */

	if (fpx<stk_lbx) {
		diff = fpx-lx;
		if (diff<-mindiff || diff>mindiff) {
			kk = (stk_lbx-lx) / diff;
			fpy = kk * (fpy-ly) + ly;
			fpx = stk_lbx;
		}
	}
	if (lx<stk_lbx) {
		diff = lx-fpx;
		if (diff<-mindiff || diff>mindiff) {
			kk = (stk_lbx-fpx) / diff;
			ly = kk * (ly-fpy) + fpy;
			lx = stk_lbx;
		}
	}
	if (fpy<stk_lby) {
		diff = fpy-ly;
		if (diff<-mindiff || diff>mindiff) {
			kk = (stk_lby-ly) / diff;
			fpx = kk * (fpx-lx) + lx;
			fpy = stk_lby;
		}
	}
	if (ly<stk_lby) {
		diff = ly-fpy;
		if (diff<-mindiff || diff>mindiff) {
			kk = (stk_lby-fpy) / diff;
			lx = kk * (lx-fpx) + fpx;
			ly = stk_lby;
		}
	}
	if (fpx>stk_ubx) {
		diff = fpx-lx;
		if (diff<-mindiff || diff>mindiff) {
			kk = (stk_ubx-lx) / diff;
			fpy = kk * (fpy-ly) + ly;
			fpx = stk_ubx;
		}
	}
	if (lx>stk_ubx) {
		diff = lx-fpx;
		if (diff<-mindiff || diff>mindiff) {
			kk = (stk_ubx-fpx) / diff;
			ly = kk * (ly-fpy) + fpy;
			lx = stk_ubx;
		}
	}
	if (fpy>stk_uby) {
		diff = fpy-ly;
		if (diff<-mindiff || diff>mindiff) {
			kk = (stk_uby-ly) / diff;
			fpx = kk * (fpx-lx) + lx;
			fpy = stk_uby;
		}
	}
	if (ly>stk_uby) {
		diff = ly-fpy;
		if (diff<-mindiff || diff>mindiff) {
			kk = (stk_uby-fpy) / diff;
			lx = kk * (lx-fpx) + fpx;
			ly = stk_uby;
		}
	}

	if (fpx==lx&&fpy==ly) return; // Esclude le linee costituite da un punto solo.

	Stick (fpx+x_centro, fpy+y_centro, lx+x_centro, ly+y_centro);
}

/* Se uno "stick" Š un "bastoncino" tridimensionale delimitato da due
   estremit…, un "link" Š un "ponte" tra il punto iniziale dell'ultimo stick
   tracciato ed il punto passato a questa funzione.
   Sembrerebbe un sistema efficace per velocizzare le proiezioni 3d, ma
   in realt… non si pu• applicare sempre: a parte il fatto che uno dei punti
   Š sempre lo stesso, quando questo non Š risultato visibile in precedenza
   neanche i link saranno visibili.
   Attualmente, Noctis usa "link3d" per mostrare i singoli fili d'erba
   sulla superficie di pianeti abitabili. */

void link3d (float x, float y, float z)
{
	Dword lx, ly;

	float rx, ry, rz, z2;

	if (fpx == -1) return;

	if (fpy<=stk_lby) return;
	if (fpy>=stk_uby) return;

	if (fpx<=stk_lbx) return;
	if (fpx>=stk_ubx) return;

//	x -= cam_x;
//	y -= cam_y;
//	z -= cam_z;

//	z2 = z * opt_tcosbeta - x * opt_tsinbeta;
//	rz = z2 * opt_tcosalfa + y * opt_tsinalfa;

	asm {	fld x
		fsub cam_x
		fst x
		fmul opt_tsinbeta
		fld z
		fsub cam_z
		fst z
		fmul opt_tcosbeta
		fsubrp
		fst z2
		fmul opt_tcosalfa
		fld y
		fsub cam_y
		fst y
		fmul opt_tsinalfa
		faddp
		fstp rz }

	if (rz<stick_uneg) return;

//	rx = x * opt_pcosbeta + z * opt_psinbeta;
//	ry = y * opt_pcosalfa - z2 * opt_psinalfa;

	asm {	fld x
		fmul opt_pcosbeta
		fld z
		fmul opt_psinbeta
		faddp
		fstp rx
		fld y
		fmul opt_pcosalfa
		fld z2
		fmul opt_psinalfa
		fsubp
		fstp ry }

	// Prospettiva.

//	lx = rx / rz;
//	ly = ry / rz;

	asm {	fld uno
		fdiv rz
		fld st(0)
		fmul rx
		fistp lx
		fmul ry
		fistp ly }

	// Chopping.

	if (ly<=stk_lby) return;
	if (ly>=stk_uby) return;

	if (lx<=stk_lbx) return;
	if (lx>=stk_ubx) return;

	if (fpx==lx&&fpy==ly) return;

	Stick (fpx+x_centro, fpy+y_centro, lx+x_centro, ly+y_centro);
}

/* Tracciamento bastoncini luminosi (in 2d, per i bagliori,
   generalmente usata con il flag flares = 1). */

void fline (Dword fx, Dword fy,
	    Dword lx, Dword ly)
{
	float kk, diff;

	/* Ottimizza il tracciamento del "Segmento", tagliando via le parti
	   che di sicuro non si vedono. Questa parte non Š efficace se
	   i punti di partenza e di arrivo fanno sŤ che il segmento non
	   intersechi alcun lato dell'area visibile: ma in questo peculiare
	   caso le linee vengono escluse dai controlli successivi. */

	if (fx<stk_lbx) {
		diff = fx-lx;
		if (diff<-mindiff || diff>mindiff) {
			kk = (stk_lbx-lx) / diff;
			fy = kk * (fy-ly) + ly;
			fx = stk_lbx;
		}
	}
	if (lx<stk_lbx) {
		diff = lx-fx;
		if (diff<-mindiff || diff>mindiff) {
			kk = (stk_lbx-fx) / diff;
			ly = kk * (ly-fy) + fy;
			lx = stk_lbx;
		}
	}
	if (fy<stk_lby) {
		diff = fy-ly;
		if (diff<-mindiff || diff>mindiff) {
			kk = (stk_lby-ly) / diff;
			fx = kk * (fx-lx) + lx;
			fy = stk_lby;
		}
	}
	if (ly<stk_lby) {
		diff = ly-fy;
		if (diff<-mindiff || diff>mindiff) {
			kk = (stk_lby-fy) / diff;
			lx = kk * (lx-fx) + fx;
			ly = stk_lby;
		}
	}
	if (fx>stk_ubx) {
		diff = fx-lx;
		if (diff<-mindiff || diff>mindiff) {
			kk = (stk_ubx-lx) / diff;
			fy = kk * (fy-ly) + ly;
			fx = stk_ubx;
		}
	}
	if (lx>stk_ubx) {
		diff = lx-fx;
		if (diff<-mindiff || diff>mindiff) {
			kk = (stk_ubx-fx) / diff;
			ly = kk * (ly-fy) + fy;
			lx = stk_ubx;
		}
	}
	if (fy>stk_uby) {
		diff = fy-ly;
		if (diff<-mindiff || diff>mindiff) {
			kk = (stk_uby-ly) / diff;
			fx = kk * (fx-lx) + lx;
			fy = stk_uby;
		}
	}
	if (ly>stk_uby) {
		diff = ly-fy;
		if (diff<-mindiff || diff>mindiff) {
			kk = (stk_uby-fy) / diff;
			lx = kk * (lx-fx) + fx;
			ly = stk_uby;
		}
	}

	if (fx==lx&&fy==ly) return; // Esclude le linee costituite da un punto solo.

	if (fy<stk_lby||ly<stk_lby) return; // Esclude le linee che mai e poi mai si vedranno.
	if (fy>stk_uby||ly>stk_uby) return;
	if (fx<stk_lbx||lx<stk_lbx) return;
	if (fx>stk_ubx||lx>stk_ubx) return;

	Stick (fx+x_centro, fy+y_centro, lx+x_centro, ly+y_centro);
}

/* Funzione ricorsiva che suddivide poligoni triangolari in quattro parti
   ugualmente triangolari, casualizzandone leggermente la colorazione. */

Uchar map_color_a = 30;
Uchar map_color_b = 31;
Uchar map_color_c = 32;
Uchar map_color_d = 33;

void randomic_mapper (float x0,
		      float y0,
		      float z0,
		      float x1,
		      float y1,
		      float z1,
		      float x2,
		      float y2,
		      float z2,
		      char divisions)
{
	float vx[3], vy[3], vz[3];

	float e0, f0, g0;
	float e1, f1, g1;
	float e2, f2, g2;

	divisions--;

	if (divisions) {
		e0 = (x0 + x1) * 0.5; f0 = (y0 + y1) * 0.5; g0 = (z0 + z1) * 0.5;
		e1 = (x1 + x2) * 0.5; f1 = (y1 + y2) * 0.5; g1 = (z1 + z2) * 0.5;
		e2 = (x0 + x2) * 0.5; f2 = (y0 + y2) * 0.5; g2 = (z0 + z2) * 0.5;
		if (divisions==1) {
			vx[0] = x0; vy[0] = y0; vz[0] = z0;
			vx[1] = e0; vy[1] = f0; vz[1] = g0;
			vx[2] = e2; vy[2] = f2; vz[2] = g2;
			poly3d (vx, vy, vz, 3, map_color_a);
			randomic_mapper (x0, y0, z0, e0, f0, g0, e2, f2, g2, divisions);
			vx[0] = e1; vy[0] = f1; vz[0] = g1;
			poly3d (vx, vy, vz, 3, map_color_b);
			randomic_mapper (e1, f1, g1, e0, f0, g0, e2, f2, g2, divisions);
			vx[1] = x2; vy[1] = y2; vz[1] = z2;
			poly3d (vx, vy, vz, 3, map_color_c);
			randomic_mapper (e1, f1, g1, x2, y2, z2, e2, f2, g2, divisions);
			vx[2] = x1; vy[2] = y1; vz[2] = z1;
			vx[1] = e0; vy[1] = f0; vz[1] = g0;
			poly3d (vx, vy, vz, 3, map_color_d);
			randomic_mapper (e1, f1, g1, e0, f0, g0, x1, y1, z1, divisions);
		}
		else {
			randomic_mapper (x0, y0, z0, e0, f0, g0, e2, f2, g2, divisions);
			randomic_mapper (e1, f1, g1, e0, f0, g0, e2, f2, g2, divisions);
			randomic_mapper (e1, f1, g1, x2, y2, z2, e2, f2, g2, divisions);
			randomic_mapper (e1, f1, g1, e0, f0, g0, x1, y1, z1, divisions);
		}
	}
}

/* Libera un handle in cui era stato caricato un file di grafica poligonale:
   se l'handle Š gi… libero, non succede nulla. */

void unloadpv (Word handle)
{
	Word      h;
	Uword eod;

	if (handle >= handles) return;
	if (!pvfile_datalen[handle]) return;

	// aggiorna i puntatori di tutti gli handle
	// che sono memorizzati oltre quello specificato.
	// il type cast serve per convincere le cacchio di specifiche ANSI
	// che il puntatore Š spostato byte per byte, e non come penserebbe
	// a seconda del tipo di dati a cui punta. se trovo quello che ha
	// definito l'ANSI cosŤ lo faccio nero.
	for (h = 0; h < handles; h++) {
		if (pvfile_dataptr[h] > pvfile_dataptr[handle]) {
			(char maybefar*)pv_n_vtx[h] -= pvfile_datalen[handle];
			(char maybefar*)pvfile_x[h] -= pvfile_datalen[handle];
			(char maybefar*)pvfile_y[h] -= pvfile_datalen[handle];
			(char maybefar*)pvfile_z[h] -= pvfile_datalen[handle];
			(char maybefar*)pvfile_c[h] -= pvfile_datalen[handle];
			if (pv_mid_x[h]) {
				(char maybefar*)pv_mid_x[h] -= pvfile_datalen[handle];
				(char maybefar*)pv_mid_y[h] -= pvfile_datalen[handle];
				(char maybefar*)pv_mid_z[h] -= pvfile_datalen[handle];
				(char maybefar*)pv_mid_d[h] -= pvfile_datalen[handle];
				(char maybefar*)pv_dep_i[h] -= pvfile_datalen[handle];
			}
			pvfile_dataptr[h] -= pvfile_datalen[handle];
		}
	}
	
	// sposta indietro i dati per liberare memoria nell'area poligonale.
	// (se Š necessario...)
	eod = pvfile_dataptr[handle] + pvfile_datalen[handle];
	if (eod < pvfile_datatop)
		FMEMMOVE(pv_n_vtx[handle], pv_n_vtx[handle] + pvfile_datalen[handle], pvfile_datatop - eod);

	// aggiorna la cima dei dati dell'area poligonale.
	pvfile_datatop -= pvfile_datalen[handle];

	// aggiorna la situazione della memoria per grafica poligonale,
	// in modo che l'handle sia ora considerato libero.
	pvfile_datalen[handle] = 0;
}

/* Libera tutti gli handles.
   (E non guarda in faccia a nessuno). */

void unloadallpv ()
{
	Word h;

	pvfile_datatop = 0;

	for (h = 0; h < handles; h++)
		pvfile_datalen[h] = 0;
}

/* Carica un file di dati per la grafica poligonale.
   Se l'handle specificato era occupato, esso viene liberato e riassegnato.
	handle: numero della banca dati in cui ospitare il file, da 0 a 15;
	viturtual_file_position: offset negativo dalla fine di Noctis.EXE;
	x/y/z_scale: correzione in scala dei poligoni su tutti gli assi;
	x/y/z_move: traslazione dei poligoni su tutti gli assi;
	base_color: colore di base dei poligoni;
	depth_sort: flag che specifica se allocare spazio per il calcolo
		    dei punti medi dei vertici di ogni poligono ed effettuare
		    il depth-sorting quando si deve tracciare l'oggetto.
      * Ritorno: -1 se non Š possibile accedere al file;
		  0 se l'handle non Š assegnabile (non esiste),
		    oppure se non c'Š abbastanza memoria nel buffer
		    della grafica poligonale ("pvfile") per caricare
		    e/o gestire tutti i poligoni che compongono l'oggetto;
		 +1 se tutto Š andato bene. */


char loadpvf (Word   handle, FILEPTR fh,
	     float xscale, float yscale, float zscale,
	     float xmove,  float ymove,  float zmove,
	     Uchar base_color,   char depth_sort)
{
	Word c, p;
	// verifica disponibilit… del file e dell'handle.
	if (fh==NOFILE) return -1;

	// verifica se l'handle Š gi… occupato. se lo Š, lo libera.
	if (pvfile_datalen[handle]) unloadpv (handle);

	// aggiornamento handle interno.
	pvfile_datalen[handle] = 0;
	pvfile_dataptr[handle] = pvfile_datatop;

	// lettura numero poligoni.
	READFILE(fh, &pvfile_npolygs[handle], 2);

	// preparazione puntatori.
	pv_n_vtx[handle] = (char maybefar *)  (pvfile + pvfile_datatop);
	pvfile_datatop  +=  1 * pvfile_npolygs[handle];
	pvfile_x[handle] = (float maybefar *) (pvfile + pvfile_datatop);
	pvfile_datatop  += 16 * pvfile_npolygs[handle];
	pvfile_y[handle] = (float maybefar *) (pvfile + pvfile_datatop);
	pvfile_datatop  += 16 * pvfile_npolygs[handle];
	pvfile_z[handle] = (float maybefar *) (pvfile + pvfile_datatop);
	pvfile_datatop  += 16 * pvfile_npolygs[handle];
	pvfile_c[handle] = (char maybefar *)  (pvfile + pvfile_datatop);
	pvfile_datatop  +=  1 * pvfile_npolygs[handle];

	// azzera il primo puntatore dei dati per il depth sort
	// (sta a significare, se non viene successivamente modificato,
	// che non Š richiesto il depth sorting per l'oggetto in questione).
	pv_mid_x[handle] = 0;

	// verifica disponibilit… memoria prima di leggere i dati.
	if (pvfile_datatop > pv_bytes) {
		DebugPrintf(1, "Not enough pv space available to load model. Need %li more.", (long)pvfile_datatop-(long)pv_bytes);
		pvfile_datatop = pvfile_dataptr[handle];
		CLOSEFILE(fh);
		return (0);
	}

	// lettura di tutti i dati sui poligoni, in un unico blocco.
	READFILE(fh, pvfile + pvfile_dataptr[handle],
	       pvfile_datatop - pvfile_dataptr[handle]);

	// dopodich‚ si pu• anche richiudere il file...
	CLOSEFILE(fh);

	// azzeramento dati sui vertici non usati (per i triangoli)
	for (p=0; p<pvfile_npolygs[handle]; p++) {
		if (pv_n_vtx[handle][p] == 3) {
			pvfile_x[handle][4*p+3] = 0;
			pvfile_y[handle][4*p+3] = 0;
			pvfile_z[handle][4*p+3] = 0;
		}
		
	}

	// preparazione puntatori per la gestione del depth sorting.
	if (depth_sort) {
		pv_mid_x[handle] = (float maybefar *) (pvfile + pvfile_datatop);
		pvfile_datatop  += 4 * pvfile_npolygs[handle];
		pv_mid_y[handle] = (float maybefar *) (pvfile + pvfile_datatop);
		pvfile_datatop  += 4 * pvfile_npolygs[handle];
		pv_mid_z[handle] = (float maybefar *) (pvfile + pvfile_datatop);
		pvfile_datatop  += 4 * pvfile_npolygs[handle];
		pv_mid_d[handle] = (float maybefar *) (pvfile + pvfile_datatop);
		pvfile_datatop  += 4 * pvfile_npolygs[handle];
		pv_dep_i[handle] = (Word maybefar *)   (pvfile + pvfile_datatop);
		pvfile_datatop  += 2 * pvfile_npolygs[handle];
		// verifica disponibilit… memoria per i dati appena aggiunti.
		if (pvfile_datatop > pv_bytes) {
			DebugPrintf(1, "Not enough pv space available for depth-sort data for model. Need %li more.", (long)pvfile_datatop-(long)pv_bytes);
			pvfile_datatop = pvfile_dataptr[handle];
			return (0);
		}
	}

	// adattamento scala, colore e traslazione.
	for (c=0; c<4*pvfile_npolygs[handle]; c++) {
		pvfile_x[handle][c] *= xscale;
		pvfile_x[handle][c] += xmove;
		pvfile_y[handle][c] *= yscale;
		pvfile_y[handle][c] += ymove;
		pvfile_z[handle][c] *= zscale;
		pvfile_z[handle][c] += zmove;
		pvfile_c[handle][c] += base_color;
	}

	// calcolo punti medi e preparazione indici per il depth-sorting.
	if (depth_sort) {
		for (p=0; p<pvfile_npolygs[handle]; p++) {
			pv_dep_i[handle][p] = p;
			pv_mid_d[handle][p] = 0;
			pv_mid_x[handle][p] = 0;
			pv_mid_y[handle][p] = 0;
			pv_mid_z[handle][p] = 0;
			if (pv_n_vtx[handle][p]) {
				for (c=0; c<pv_n_vtx[handle][p]; c++) {
					pv_mid_x[handle][p] += pvfile_x[handle][4*p+c];
					pv_mid_y[handle][p] += pvfile_y[handle][4*p+c];
					pv_mid_z[handle][p] += pvfile_z[handle][4*p+c];
				}
				pv_mid_x[handle][p] /= c;
				pv_mid_y[handle][p] /= c;
				pv_mid_z[handle][p] /= c;
			}
		}
	}

	// tutto fatto: computo memoria utilizzata da questo handle.
	pvfile_datalen[handle] = pvfile_datatop - pvfile_dataptr[handle];
	//DebugPrintf(0, "Model %i takes up %i bytes.\n", handle, pvfile_datalen[handle]);
	return (1);
}

char loadpv (Word   handle, Dword virtual_file_position,
	     float xscale, float yscale, float zscale,
	     float xmove,  float ymove,  float zmove,
	     Uchar base_color,   char depth_sort)
{
	if (handle >= handles) return (0);
	return loadpvf(handle, sa_open (virtual_file_position),
		xscale, yscale, zscale, xmove, ymove, zmove,
		base_color, depth_sort);
}

char loadpvs (Word   handle, const char *filename,
	     float xscale, float yscale, float zscale,
	     float xmove,  float ymove,  float zmove,
	     Uchar base_color,   char depth_sort)
{
	FILEPTR file = OPENFILE(filename, OPEN_RB);
	if (file == NOFILE) {
		DebugPrintf(1, "Missing file %s.", filename);
	}
	return loadpvf(handle,
	file,
		xscale, yscale, zscale, xmove, ymove, zmove,
		base_color, depth_sort);
}


/* Ordinamento a ricorsione. Per mettere in ordine in fretta i poligoni.
   Si occupa anche di altri ordinamenti per distanza... per esempio ordina
   i pianeti e le lune... */

void QuickSort (Word maybefar *index, float maybefar *mdist, Word start, Word end)
{
	Word   tq;

	Word   jq = end;
	Word   iq = start;

	float xq = mdist[index[(start+end)/2]];

	while (iq<=jq) {
		while (mdist[index[iq]] > xq) iq++;
		while (mdist[index[jq]] < xq) jq--;
		if (iq<=jq) {
			tq = index[iq];
			index[iq] = index[jq];
			index[jq] = tq;
			iq++;
			jq--;
		}
	}

	if (start < jq) QuickSort (index, mdist, start, jq);
	if (iq < end)   QuickSort (index, mdist, iq, end);
}

/* Traccia una figura poligonale.
   handle: l'handle (da 0 a 15) che si Š attribuito al file con "loadpv";
   mode: pu• essere -- 0 = tracciamento poligoni in tinta unita;
		       1 = tracciamento con texture mapping;
		       2 = rimappatura randomica ricorsiva dei poligoni.
   rm_iterations: viene usato solo se mode = 2, indica quante suddivisioni
		  devono essere effettuate per ogni poligono rimappato;
   center_x/y/z: coordinate ove piazzare il centro dell'oggetto;
   use_depth_sort: flag per attivare il depth sort, che viene tuttavia
		   effettivamente attivato solo se Š stato incluso come
		   opzione nella chiamata a "loadpv" per quell'handle. */

void drawpv (Word handle, Word mode, Word rm_iterations,
	     float center_x, float center_y, float center_z,
	     char use_depth_sort)
{
	//return;
	float dx, dy, dz;
	Uword p, c, i, k;

	if (handle >= handles) {
		DebugPrintf(1, "drawpv: handle(%i) >= handles(%i)\n", (int) handle, (int) handles);
		return;
	}
	if (!pvfile_datalen[handle]) {
		DebugPrintf(1, "drawpv: pvfile_datalen[%i] is 0 (%i).\n", (int) handle, (int) pvfile_datalen[handle]);
		return;
	}
	// traslazione intero spazio all'origine dell'oggetto.
	cam_x -= center_x;
	cam_y -= center_y;
	cam_z -= center_z;

	if (use_depth_sort && pv_mid_x[handle]) {
		// tracciamento con depth sorting.
		// fase 1: calcolo distanza punti medi.
		for (p=0; p<pvfile_npolygs[handle]; p++) {
			dx                  = pv_mid_x[handle][p] - cam_x;
			dy                  = pv_mid_y[handle][p] - cam_y;
			dz                  = pv_mid_z[handle][p] - cam_z;
			pv_mid_d[handle][p] = dx*dx + dy*dy + dz*dz;
			pv_dep_i[handle][p] = p;
		}
		// fase 2: ordinamento poligoni in base alla distanza.
		QuickSort (pv_dep_i[handle], pv_mid_d[handle],
			   0, pvfile_npolygs[handle] - 1);
		// fase 3: tracciamento, nell'ordine specificato sopra.
		for (p=0; p<pvfile_npolygs[handle]; p++) {
			c = pv_dep_i[handle][p];
			i = c * 4;
			//DebugPrintf(0, "handle=%i c=%i pv_n_vtx[handle][c]=%i", (int)handle, (int)c, (int)pv_n_vtx[handle][c]);
			switch (mode) {
				case 0:	poly3d (pvfile_x[handle] + i,
						pvfile_y[handle] + i,
						pvfile_z[handle] + i,
						pv_n_vtx[handle][c],
						pvfile_c[handle][c]);
					break;
				case 1: k = pvfile_c[handle][c];
					asm {   push	ax
						mov 	ax, k
						and 	ax, 0x3F
						and 	k,  0xC0
						shr 	ax, 1
						or	k,  ax
						pop	ax }
					polymap (pvfile_x[handle] + i,
						 pvfile_y[handle] + i,
						 pvfile_z[handle] + i,
						 pv_n_vtx[handle][c], k);
					break;
				case 2:	map_color_a = pvfile_c[handle][c];
					map_color_b = map_color_a - 2;
					map_color_c = map_color_a - 1;
					map_color_d = map_color_a + 1;
					randomic_mapper (pvfile_x[handle][i+0], pvfile_y[handle][i+0], pvfile_z[handle][i+0],
							 pvfile_x[handle][i+1], pvfile_y[handle][i+1], pvfile_z[handle][i+1],
							 pvfile_x[handle][i+2], pvfile_y[handle][i+2], pvfile_z[handle][i+2], rm_iterations);
					if (pv_n_vtx[handle][p] == 4)
						randomic_mapper (pvfile_x[handle][i+2], pvfile_y[handle][i+2], pvfile_z[handle][i+2],
								 pvfile_x[handle][i+3], pvfile_y[handle][i+3], pvfile_z[handle][i+3],
								 pvfile_x[handle][i+0], pvfile_y[handle][i+0], pvfile_z[handle][i+0], rm_iterations);
			}
		}
	}
	else {
		// tracciamento senza depth sorting.
		// in queso caso traccia i poligoni nell'ordine in cui
		// sono stati salvati nel file di grafica di "PolyVert".
		for (p=0, i=0; p<pvfile_npolygs[handle]; p++, i+=4) {
			//DebugPrintf(0, "handle=%i p=%i pv_n_vtx[handle][c]=%i", (int)handle, (int)p, (int)pv_n_vtx[handle][p]);
			switch (mode) {
				case 0:	poly3d (pvfile_x[handle] + i,
						pvfile_y[handle] + i,
						pvfile_z[handle] + i,
						pv_n_vtx[handle][p],
						pvfile_c[handle][p]);
					break;
				case 1: k = pvfile_c[handle][p];
					asm {   push	ax
						mov 	ax, k
						and 	ax, 0x3F
						and 	k,  0xC0
						shr 	ax, 1
						or	k,  ax
						pop	ax }
					polymap (pvfile_x[handle] + i,
						 pvfile_y[handle] + i,
						 pvfile_z[handle] + i,
						 pv_n_vtx[handle][p], k);
					break;
				case 2:	map_color_a = pvfile_c[handle][p];
					map_color_b = map_color_a - 2;
					map_color_c = map_color_a - 1;
					map_color_d = map_color_a + 1;
					randomic_mapper (pvfile_x[handle][i+0], pvfile_y[handle][i+0], pvfile_z[handle][i+0],
							 pvfile_x[handle][i+1], pvfile_y[handle][i+1], pvfile_z[handle][i+1],
							 pvfile_x[handle][i+2], pvfile_y[handle][i+2], pvfile_z[handle][i+2], rm_iterations);
					if (pv_n_vtx[handle][p] == 4)
						randomic_mapper (pvfile_x[handle][i+2], pvfile_y[handle][i+2], pvfile_z[handle][i+2],
								 pvfile_x[handle][i+3], pvfile_y[handle][i+3], pvfile_z[handle][i+3],
								 pvfile_x[handle][i+0], pvfile_y[handle][i+0], pvfile_z[handle][i+0], rm_iterations);
			}
		}
	}

	// traslazione intero spazio all'origine precedente.
	cam_x += center_x;
	cam_y += center_y;
	cam_z += center_z;
}

/* Replica una forma poligonale, copiandola da un'handle gi… definito
   a uno di uguali dimensioni. In caso d'errore, non succede nulla. */

void copypv (Word dest_handle, Word src_handle)
{
	if (src_handle >= handles) {
		DebugPrintf(1, "copypv: src_handle(%i) >= handles(%i)\n", (int) src_handle, (int) handles);
		return;
	}
	if (dest_handle >= handles) {
		DebugPrintf(1, "copypv: dest_handle(%i) >= handles(%i)\n", (int) dest_handle, (int) handles);
		return;
	}
	if (!pvfile_datalen[src_handle]) {
		DebugPrintf(1, "copypv: pvfile_datalen[%i] is 0 (%i).\n", (int) src_handle, (int) pvfile_datalen[src_handle]);
		return;
	}
	//WORKPVNOTE: Trying to get workpv to work.
	//if (pvfile_datalen[dest_handle] != pvfile_datalen[src_handle]) return;
	if (pvfile_datalen[dest_handle] < pvfile_datalen[src_handle]) {
		DebugPrintf(1, "copypv: Not enough space in dest buffer (%u, space %u) to hold src data (%u, space %u).\n", (unsigned) dest_handle, (unsigned) pvfile_datalen[dest_handle], (unsigned) src_handle, (unsigned) pvfile_datalen[src_handle]);
		return;	//This should allow us to copy smaller models into a larger model buffer. (SL)
	}
	//_fmemmove (pv_n_vtx[dest_handle], pv_n_vtx[src_handle], pvfile_datalen[src_handle]);
	//pvfile_npolygs[dest_handle] = pvfile_npolygs[src_handle];
	
	//Just point these at the source's data, we don't modify them. (SL)
	//if (pvfile_datalen[dest_handle] > pvfile_datalen[src_handle]) {
		//copy other stuff
		pvfile_npolygs[dest_handle] = pvfile_npolygs[src_handle];
		Dword len1 = pvfile_npolygs[src_handle];
		Dword len2 = pvfile_npolygs[src_handle]+pvfile_npolygs[src_handle];
		Dword len4 = pvfile_npolygs[src_handle]<<2;
		Dword len16 = pvfile_npolygs[src_handle]<<4;
		FMEMCPY (pv_n_vtx[dest_handle], pv_n_vtx[src_handle], len1);
		FMEMCPY (pvfile_x[dest_handle], pvfile_x[src_handle], len16);
		FMEMCPY (pvfile_y[dest_handle], pvfile_y[src_handle], len16);
		FMEMCPY (pvfile_z[dest_handle], pvfile_z[src_handle], len16);
		
		FMEMCPY (pv_mid_x[dest_handle], pv_mid_x[src_handle], len4);
		FMEMCPY (pv_mid_y[dest_handle], pv_mid_y[src_handle], len4);
		FMEMCPY (pv_mid_z[dest_handle], pv_mid_z[src_handle], len4);
		
		//pvfile_c is not modified after initialization
		FMEMCPY (pvfile_c[dest_handle], pvfile_c[src_handle], len1); // intensit… del colore di ogni poligono (0..63).
			
		//pv_mid_d and pv_dep_i are only used in drawpv, so we point these at the original buffers.
		//pv_mid_d's contents are set every time drawpv runs with depth sorting, and
		//I've modified it (drawpv) to also reset pv_dep_i before sorting. Before it relied on it being
		//reset when copypv was used, since the original model's pv_dep_i was never modified.
		FMEMCPY (pv_mid_d[dest_handle], pv_mid_d[src_handle], len4); // intensit… del colore di ogni poligono (0..63).
		FMEMCPY (pv_dep_i[dest_handle], pv_dep_i[src_handle], len2); // intensit… del colore di ogni poligono (0..63).
	
	//} else {
	//	_fmemmove (pv_n_vtx[dest_handle], pv_n_vtx[src_handle], pvfile_datalen[src_handle]);
	//}
	
}

//WORKPVNOTE: Trying to get workpv to work.
void workpv (Word dest_handle, Word src_handle)
{
	if (src_handle >= handles) {
		DebugPrintf(1, "workpv: src_handle(%i) >= handles(%i)\n", (int) src_handle, (int) handles);
		return;
	}
	if (dest_handle >= handles) {
		DebugPrintf(1, "workpv: dest_handle(%i) >= handles(%i)\n", (int) dest_handle, (int) handles);
		return;
	}
	pvfile_datalen[dest_handle] = 0;
	pvfile_dataptr[dest_handle] = pvfile_datatop;
	
	pvfile_npolygs[dest_handle] = pvfile_npolygs[src_handle];
	
	
	pv_n_vtx[dest_handle] = (char maybefar *)  (pvfile + pvfile_datatop);
	pvfile_datatop  +=  1 * pvfile_npolygs[dest_handle];
	pvfile_x[dest_handle] = (float maybefar *) (pvfile + pvfile_datatop);
	pvfile_datatop  += 16 * pvfile_npolygs[dest_handle];
	pvfile_y[dest_handle] = (float maybefar *) (pvfile + pvfile_datatop);
	pvfile_datatop  += 16 * pvfile_npolygs[dest_handle];
	pvfile_z[dest_handle] = (float maybefar *) (pvfile + pvfile_datatop);
	pvfile_datatop  += 16 * pvfile_npolygs[dest_handle];
	//pvfile_c[dest_handle] = 0;
	pvfile_c[dest_handle] = (char maybefar *)  (pvfile + pvfile_datatop);
	pvfile_datatop  +=  1 * pvfile_npolygs[dest_handle];
	// azzera il primo puntatore dei dati per il depth sort
	// (sta a significare, se non viene successivamente modificato,
	// che non Š richiesto il depth sorting per l'oggetto in questione).
	pv_mid_x[dest_handle] = 0;
	// verifica disponibilit… memoria prima di leggere i dati.
	if (pvfile_datatop > pv_bytes) {
		DebugPrintf(1, "workpv: Not enough pv space available for model work buffer. Need %li more.", (long)pvfile_datatop-(long)pv_bytes);
		pvfile_datatop = pvfile_dataptr[dest_handle];
		return;
	}
	

	// preparazione puntatori per la gestione del depth sorting.
	pv_mid_x[dest_handle] = (float maybefar *) (pvfile + pvfile_datatop);
	pvfile_datatop  += 4 * pvfile_npolygs[dest_handle];
	pv_mid_y[dest_handle] = (float maybefar *) (pvfile + pvfile_datatop);
	pvfile_datatop  += 4 * pvfile_npolygs[dest_handle];
	pv_mid_z[dest_handle] = (float maybefar *) (pvfile + pvfile_datatop);
	pvfile_datatop  += 4 * pvfile_npolygs[dest_handle];
	//pv_mid_d[dest_handle] = 0;
	//pv_dep_i[dest_handle] = 0;
	pv_mid_d[dest_handle] = (float maybefar *) (pvfile + pvfile_datatop);
	pvfile_datatop  += 4 * pvfile_npolygs[dest_handle];
	pv_dep_i[dest_handle] = (Word maybefar *)   (pvfile + pvfile_datatop);
	pvfile_datatop  += 2 * pvfile_npolygs[dest_handle];
	
	// verifica disponibilit… memoria per i dati appena aggiunti.
	if (pvfile_datatop > pv_bytes) {
		DebugPrintf(1, "workpv: Not enough pv space available for depth-sort data for model work buffer. Need %li more.", (long)pvfile_datatop-(long)pv_bytes);
		pvfile_datatop = pvfile_dataptr[dest_handle];
		return;
	}

	// tutto fatto: computo memoria utilizzata da questo handle.
	pvfile_datalen[dest_handle] = pvfile_datatop - pvfile_dataptr[dest_handle];
	//DebugPrintf(0, "Work buffer (%i) takes up %i bytes.\n", (int)dest_handle, (int)pvfile_datalen[dest_handle]);
}

float getUpmostYFromPV(Word handle) {
	if (handle >= handles) {
		DebugPrintf(1, "getUpmostYFromPV: handle(%i) >= handles(%i)\n", (int) handle, (int) handles);
		return 0.0f;
	}
	if (!pvfile_datalen[handle]) {
		DebugPrintf(1, "getUpmostYFromPV: pvfile_datalen[%i] is 0 (%i).\n", (int) handle, (int) pvfile_datalen[handle]);
		return 0.0f;
	}
	float bestY=pvfile_y[handle][0];
	for (Word p = 0; p < pvfile_npolygs[handle]; p++) {
		for (Word v=0; v< pv_n_vtx[handle][p]; v++) {
			float y = pvfile_y[handle][4 * p + v];
			if (y<bestY) bestY=y;
		}
	}
	return bestY;
}

float getDownmostYFromPV(Word handle) {
	if (handle >= handles) {
		DebugPrintf(1, "getDownmostYFromPV: handle(%i) >= handles(%i)\n", (int) handle, (int) handles);
		return 0.0f;
	}
	if (!pvfile_datalen[handle]) {
		DebugPrintf(1, "getDownmostYFromPV: pvfile_datalen[%i] is 0 (%i).\n", (int) handle, (int) pvfile_datalen[handle]);
		return 0.0f;
	}
	float bestY=pvfile_y[handle][0];
	for (Word p = 0; p < pvfile_npolygs[handle]; p++) {
		for (Word v=0; v< pv_n_vtx[handle][p]; v++) {
			float y = pvfile_y[handle][4 * p + v];
			if (y>bestY) bestY=y;
		}
	}
	return bestY;
}

float getLowXFromPV(Word handle) {
	if (handle >= handles) {
		DebugPrintf(1, "getLowXFromPV: handle(%i) >= handles(%i)\n", (int) handle, (int) handles);
		return 0.0f;
	}
	if (!pvfile_datalen[handle]) {
		DebugPrintf(1, "getLowXFromPV: pvfile_datalen[%i] is 0 (%i).\n", (int) handle, (int) pvfile_datalen[handle]);
		return 0.0f;
	}
	float bestX=pvfile_x[handle][0];
	for (Word p = 0; p < pvfile_npolygs[handle]; p++) {
		for (Word v=0; v< pv_n_vtx[handle][p]; v++) {
			float x = pvfile_x[handle][4 * p + v];
			if (x<bestX) bestX=x;
		}
	}
	return bestX;
}

float getLowZFromPV(Word handle) {
	if (handle >= handles) {
		DebugPrintf(1, "getLowZFromPV: handle(%i) >= handles(%i)\n", (int) handle, (int) handles);
		return 0.0f;
	}
	if (!pvfile_datalen[handle]) {
		DebugPrintf(1, "getLowZFromPV: pvfile_datalen[%i] is 0 (%i).\n", (int) handle, (int) pvfile_datalen[handle]);
		return 0.0f;
	}
	float bestZ=pvfile_z[handle][0];
	for (Word p = 0; p < pvfile_npolygs[handle]; p++) {
		for (Word v=0; v< pv_n_vtx[handle][p]; v++) {
			float z = pvfile_z[handle][4 * p + v];
			if (z<bestZ) bestZ=z;
		}
	}
	return bestZ;
}

float getHighXFromPV(Word handle) {
	if (handle >= handles) {
		DebugPrintf(1, "getHighXFromPV: handle(%i) >= handles(%i)\n", (int) handle, (int) handles);
		return 0.0f;
	}
	if (!pvfile_datalen[handle]) {
		DebugPrintf(1, "getHighXFromPV: pvfile_datalen[%i] is 0 (%i).\n", (int) handle, (int) pvfile_datalen[handle]);
		return 0.0f;
	}
	float bestX=pvfile_x[handle][0];
	for (Word p = 0; p < pvfile_npolygs[handle]; p++) {
		for (Word v=0; v< pv_n_vtx[handle][p]; v++) {
			float x = pvfile_x[handle][4 * p + v];
			if (x>bestX) bestX=x;
		}
	}
	return bestX;
}

float getHighZFromPV(Word handle) {
	if (handle >= handles) {
		DebugPrintf(1, "getHighZFromPV: handle(%i) >= handles(%i)\n", (int) handle, (int) handles);
		return 0.0f;
	}
	if (!pvfile_datalen[handle]) {
		DebugPrintf(1, "getHighZFromPV: pvfile_datalen[%i] is 0 (%i).\n", (int) handle, (int) pvfile_datalen[handle]);
		return 0.0f;
	}
	float bestZ=pvfile_z[handle][0];
	for (Word p = 0; p < pvfile_npolygs[handle]; p++) {
		for (Word v=0; v< pv_n_vtx[handle][p]; v++) {
			float z = pvfile_z[handle][4 * p + v];
			if (z>bestZ) bestZ=z;
		}
	}
	return bestZ;
}
/* Ruota una forma poligonale rispetto a uno dei suoi vertici,
   che viene assunto come centro di rotazione, applicando anche
   un fattore di scalatura (che pu• essere 1 se non Š necessario
   cambiare le dimensioni, come possono essere 0 gli angoli se
   si stanno cambiando le dimensioni senza ruotare).
   "vertexs_to_affect" Š un puntatore a una serie di strutture "pvlist",
   nelle quali sono elencati i vertici che verranno effettivamente modificati:
   se il puntatore "vertexs_to_affect" Š nullo, tutti i vertici lo sono.
   Gli angoli sono espressi in gradi. */

void modpv (Word handle, Word polygon_id, Word vertex_id,
	    float x_scale, float y_scale, float z_scale,
	    float x_angle, float y_angle, float z_angle,
	    pvlist *vertexs_to_affect)
{
	if (handle >= handles) {
		DebugPrintf(1, "modpv: handle(%i) >= handles(%i)\n", (int) handle, (int) handles);
		return;
	}
	if (!pvfile_datalen[handle]) {
		DebugPrintf(1, "modpv: pvfile_datalen[%i] is 0 (%i).\n", (int) handle, (int) pvfile_datalen[handle]);
		return;
	}
	
	float sin_x = sin (deg * x_angle);
	float cos_x = cos (deg * x_angle);
	float sin_y = sin (deg * y_angle);
	float cos_y = cos (deg * y_angle);
	float sin_z = sin (deg * z_angle);
	float cos_z = cos (deg * z_angle);

	Word   c, p, v, i, j;

	float x1, y1, z1;
	float cx, cy, cz;

	if (polygon_id > -1 && vertex_id > -1) {
		i = 4 * polygon_id + vertex_id;
		cx = pvfile_x[handle][i];
		cy = pvfile_y[handle][i];
		cz = pvfile_z[handle][i];
	}
	else {
		cx = 0;
		cy = 0;
		cz = 0;
	}

	if (!vertexs_to_affect) {
		for (p = 0; p < pvfile_npolygs[handle]; p++) {
			i = 4 * p;
			for (v = 0; v < pv_n_vtx[handle][p]; v++) {
				x1 = (pvfile_x[handle][i]-cx) * cos_y + (pvfile_z[handle][i]-cz) * sin_y;
				z1 = (pvfile_z[handle][i]-cz) * cos_y - (pvfile_x[handle][i]-cx) * sin_y;
				pvfile_z[handle][i] = z_scale * (z1 * cos_x + (pvfile_y[handle][i]-cy) * sin_x) + cz;
				y1 = (pvfile_y[handle][i]-cy) * cos_x - z1 * sin_x;
				pvfile_x[handle][i] = x_scale * (x1 * cos_z + y1 * sin_z) + cx;
				pvfile_y[handle][i] = y_scale * (y1 * cos_z - x1 * sin_z) + cy;
				i++;
			}
		}
	}
	else {
		p = 0;
		while (vertexs_to_affect[p].polygon_id != 0xFFF) {
			c = vertexs_to_affect[p].polygon_id;
			i = 4 * c;
			v = 0;
			do {	if (v==0 && vertexs_to_affect[p].vtxflag_0) { j = i;     goto perform; }
				if (v==1 && vertexs_to_affect[p].vtxflag_1) { j = i + 1; goto perform; }
				if (v==2 && vertexs_to_affect[p].vtxflag_2) { j = i + 2; goto perform; }
				if (v==3 && vertexs_to_affect[p].vtxflag_3) { j = i + 3; goto perform; }
				goto next;
		       perform: x1 = (pvfile_x[handle][j]-cx) * cos_y + (pvfile_z[handle][j]-cz) * sin_y;
				z1 = (pvfile_z[handle][j]-cz) * cos_y - (pvfile_x[handle][j]-cx) * sin_y;
				pvfile_z[handle][j] = z_scale * (z1 * cos_x + (pvfile_y[handle][j]-cy) * sin_x) + cz;
				y1 = (pvfile_y[handle][j]-cy) * cos_x - z1 * sin_x;
				pvfile_x[handle][j] = x_scale * (x1 * cos_z + y1 * sin_z) + cx;
				pvfile_y[handle][j] = y_scale * (y1 * cos_z - x1 * sin_z) + cy;
			  next: v ++;
			} while (v < pv_n_vtx[handle][c]);
			p ++;
		}
	}

	if (pv_mid_x[handle]) {
		for (p = 0; p < pvfile_npolygs[handle]; p++) {
			i = 4 * p;
			cx = 0; cy = 0; cz = 0;
			for (v = 0; v < pv_n_vtx[handle][p]; v++) {
				cx += pvfile_x[handle][i];
				cy += pvfile_y[handle][i];
				cz += pvfile_z[handle][i];
				i++;
			}
			pv_mid_x[handle][p] = cx / v;
			pv_mid_y[handle][p] = cy / v;
			pv_mid_z[handle][p] = cz / v;
		}
	}
}

/* Ritorna il corrispondente alfabetico di numeri interi e/o reali. */

char *alphavalue (double value)
{
	gcvt (value, 15, dec);
	int len = strlen(dec);
	if (len>1 && dec[len-1]=='.') {
		dec[len-1]=0;
	}
	return (dec);
}

/* Background, con la mappa offsets.map, in quicktime vr. */

void background (Uword start,
		 Uchar maybefar *target,
		 Uchar maybefar *background,
		 Uchar maybefar *offsetsmap,
		 Uword total_map_bytes,
		 Uword screenshift)
{
	#ifdef WINDOWS
	Word screenshiftW = reinterpret_cast<Word> (screenshift);
	Uword *offsetsmapUW = (Uword *)offsetsmap;
	
	Dword bgpos=start;	//REMOVE4 (maybe)
	Dword numwords=(total_map_bytes>>1);
	for (int a=0; a<64000; a++) {
		target[a]=0;
	}
	for (Dword curpos=0; curpos<numwords; curpos++) {
		if (offsetsmapUW[curpos]<64000) {
			Uchar pixel = 32;
			//if (bgpos>=0) {
				if (bgpos>=st_bytes) bgpos-=st_bytes;
				if (bgpos>=0) {
					pixel = background[bgpos];
				}
				Dword screenpos = (Dword)offsetsmapUW[curpos]+(Dword)screenshiftW;
				for (int ycounter=0; ycounter<5; ycounter++) {
					for (int xcounter=0; xcounter<5; xcounter++) {
						//DebugPrintf(0, "screenpos+xcounter=%i", (int)(screenpos+xcounter));
						if (screenpos+xcounter<0) {
							//Dword s2 = screenpos+xcounter;
							//while (s2<0) s2+=64000;
							//target[s2]=pixel;
							#ifdef WINDOWS
							//char tempbuffer[256];
							//sprintf(tempbuffer, "screenpos=%i ycounter=%i xcounter=%i sum=%i", screenpos, xcounter, ycounter, screenpos+xcounter);
							//MessageBox(NULL, tempbuffer, "[target] buffer overflow, too low.", MB_OK);
							#endif
						} else if (screenpos+xcounter>64000) {
							//Dword s2 = screenpos+xcounter;
							//while (s2>64000) s2-=64000;
							//target[s2]=pixel;
							//char tempbuffer[256];
							//sprintf(tempbuffer, "screenpos=%i offsetsmapUW[curpos]=%i screenshift=%i ycounter=%i xcounter=%i sum=%i", screenpos, offsetsmapUW[curpos], screenshift, xcounter, ycounter, screenpos+xcounter);
							//MessageBox(NULL, tempbuffer, "[target] buffer overflow, too high.", MB_OK);
						} else {
							target[screenpos+xcounter]=pixel;
						}
					}
					screenpos+=WIDTH;
				}
			//}
			bgpos++;
			//curpos++;
		} else {
			//blanket
			//skip pixels
			bgpos+=(offsetsmapUW[curpos]-64000);
		}
	}
	#else
	
	asm {   pusha
		push ds
		les ax, dword ptr target
		add screenshift, ax
		mov dx, screenshift
		mov ax, es
		les bx, dword ptr background
		mov bx, es
		mov cx, total_map_bytes
		shr cx, 1
		lds si, dword ptr offsetsmap
		mov bp, start
		add bp, 4
		db 0x8E, 0xE3 // mov fs, bx
		mov es, ax }
rigiro: asm {   cmp word ptr [si], 64000
		jnb blanket
		mov di, [si]
		add di, dx
		db 0x64, 0x8A, 0x46, 0x00 // mov al, fs:[bp]
		mov ah, al
		db 0x66; shl ax, 8
		mov al, ah
		db 0x66; shl ax, 8
		mov al, ah
		db 0x66; mov es:[di], ax
		mov es:[di+4], al
		db 0x66; mov es:[di+320], ax
		mov es:[di+324], al
		db 0x66; mov es:[di+640], ax
		mov es:[di+644], al
		db 0x66; mov es:[di+960], ax
		mov es:[di+964], al
		db 0x66; mov es:[di+1280], ax
		mov es:[di+1284], al
		add bp, 1
		add si, 2
		dec cx
		jnz rigiro
		jmp fine }
blanket:asm {	mov bx, [si]
		sub bx, 64000
		add bp, bx
		add si, 2
		dec cx
		jnz rigiro }
fine:	asm {	pop ds
		popa }
	#endif
}

/* Cielo stellato, tre-di vero. A campo amplificato, annovera 2744 stelle,
   con magnitudine da 0 a +13 (ho pensato che un gatto, con vista scotopica,
   e nello spazio, ne possa vedere parecchie di pi— del normale...). */

void sky (Uword limits)
{
	#ifdef WINDOWS
	if (NewGalaxy_sky(limits)) {
		return;
	}
	#endif
	Dword min_xy = 1E9;

	char visible_sectors = 9;
	if (field_amplificator) visible_sectors = 14;

	Uchar sx, sy, sz;
	float xx, yy, zz, z2, rz, inv_rz, starneg;

	if (!ap_targetting)
		starneg = 10000;
	else
		starneg = 1;

	Dword sect_x, sect_y, sect_z, rx, ry;
	Dword advance = 100000, k = 100000*visible_sectors;

	Dword temp_x, temp_y, temp_z, temp;
	Word temp_rarity;

	/* 	Il seguente frammento controlla la rarefazione delle stelle
		all'aumentare della distanza dal centro galattico. La scala
		sull'asse Y Š amplificata di 30 volte per matenere credibili
		le proporzioni della galassia che, pur essendo piuttosto
		ellittica (o grassottella), ha la forma di un disco
		schiacciato. Le stelle si rarefanno a seconda del valore
		di "distance_from_home". Questa Š una tabella che fornisce
		il numero di stelle eliminate (ogni settore contiene una
		stella, e il numero di settori visibili a campo amplificato
		Š di 14*14*14 = 2744) man mano che distance_from_home
		aumenta il suo valore:

		0-400.000.000			0 stelle eliminate
		400.000.000-800.000.000		1 su 2 stelle eliminate
		1.200.000.000-1.600.000.000	3 su 4 stelle eliminate
		1.600.000.000-2.000.000.000	7 su 8 stelle eliminate

		Oltre 2 miliardi di unit…, non Š pi— permesso selezionare
		stelle: il rapporto di rarefazione sarebbe comunque di
		1 stella effettiva ogni 16 settori. */

	Word rarity_factor;
	double distance_from_home;

	/*
	distance_from_home = SQRT (dzat_x*dzat_x + dzat_z*dzat_z);
	distance_from_home += 30 * fabs(dzat_y);
	rarity_factor = distance_from_home * 0.25e-8;
	rarity_factor = 1 << rarity_factor;
	rarity_factor--;
	*/
	
	sect_x = (dzat_x - visible_sectors*50000) / 100000; sect_x *= 100000;
	sect_y = (dzat_y - visible_sectors*50000) / 100000; sect_y *= 100000;
	sect_z = (dzat_z - visible_sectors*50000) / 100000; sect_z *= 100000;

	asm {
		PUSHAD
		#ifdef WINDOWS
		mov esi, [adapted]
		#else
		push es
		les ax, dword ptr adapted
		#endif
		mov al, visible_sectors
		mov sx, al }
e_while:asm {	mov al, visible_sectors
		mov sy, al }
m_while:asm {	mov al, visible_sectors
		mov sz, al }
i_while:asm {
		#ifdef WINDOWS
		mov ebx, 50000
		#else
		db 0x66, 0xBB, 0x50, 0xC3, 0x00, 0x00 // mov ebx, 50000
		#endif
		MOV_EAX_DWORD_PTR sect_x
		MOV_ECX_DWORD_PTR sect_y
		MOV_EDX_DWORD_PTR sect_z
		IMUL_ECX_EDX
		DB_0x66; add MAYBE_EAX, MAYBE_EDX
		DB_0x66; mov MAYBE_ECX, MAYBE_EAX
		DB_0x66; mov MAYBE_EDX, MAYBE_ECX
		AND_EDX_0x0001FFFF
		DB_0x66; add MAYBE_EDX, MAYBE_DWORD_PTR sect_x
		DB_0x66; sub MAYBE_EDX, MAYBE_EBX
		
		jnz i_cont_x }  // |
		asm jmp next;   // | excludes stars with x coordinate = 0
i_cont_x: asm {                 // |
		MOV_DWORD_PTR temp_x, MAYBE_EDX
		DB_0x66; mov MAYBE_EAX, MAYBE_ECX
		IMUL_EDX
		DB_0x66; add MAYBE_EDX, MAYBE_EAX
		DB_0x66; add MAYBE_ECX, MAYBE_EDX
		AND_EDX_0x0001FFFF
		DB_0x66; add MAYBE_EDX, MAYBE_DWORD_PTR sect_y
		DB_0x66; sub MAYBE_EDX, MAYBE_EBX
		jnz i_cont_y }  // |
		asm jmp next;   // | excludes stars with y coordinate = 0
i_cont_y: asm {                 // |
		MOV_DWORD_PTR temp_y, MAYBE_EDX
		DB_0x66; mov MAYBE_EAX, MAYBE_ECX
		IMUL_EDX
		DB_0x66; add MAYBE_EDX, MAYBE_EAX
		AND_EDX_0x0001FFFF
		DB_0x66; add MAYBE_EDX, MAYBE_DWORD_PTR sect_z
		DB_0x66; sub MAYBE_EDX, MAYBE_EBX
		jnz i_cont_z }  // |
		asm jmp next;   // | excludes stars with z coordinate = 0
i_cont_z: asm {                 // |
		MOV_DWORD_PTR temp_z, MAYBE_EDX
		#ifndef WINDOWS
		pop es
		#endif
		PUSHAD
		}
		double dsect_x = sect_x; dsect_x*=dsect_x;
		double dsect_y = sect_y; dsect_y=30*fabs(dsect_y);
		double dsect_z = sect_z; dsect_z*=dsect_z;
		distance_from_home = SQRT (dsect_x + dsect_z) + dsect_y;
		
		rarity_factor = (Dword)(distance_from_home * 0.25e-8);
		rarity_factor = 1 << rarity_factor;
		rarity_factor--;
		
		//if (temp_x==-7259888 && temp_y==-1043725 && temp_z==391264926) {
			//fprintf(stderr, "Sky: sect_x(%li) sect_y(%li) sect_z(%li) dsect_x(%li) dsect_y(%li) dsect_z(%li) distance_from_home(%li) rarity_factor(%li) x(%li) y(%li) z(%li)\n", (long)sect_x, (long)sect_y, (long)sect_z, (long)dsect_x, (long)dsect_y, (long)dsect_z, (long)distance_from_home, (long) rarity_factor, (long) temp_x, (long) temp_y, (long) temp_z);
		//}
		
		double tempDxx = SQRT ((double)temp_x * (double)temp_x + (double)temp_z * (double)temp_z);
		tempDxx += fabs((double)temp_y * 30);
		if (tempDxx > 2E9) {
			asm {
				POPAD
				#ifndef WINDOWS
				push es
				les ax, dword ptr adapted
				#endif
				jmp endgame;
			}
		}
		asm {
		POPAD
		#ifndef WINDOWS
		push es
		les ax, dword ptr adapted
		#endif
		mov ax, word ptr temp_x
		add ax, word ptr temp_y
		add ax, word ptr temp_z
		mov word ptr temp_rarity, ax
		
		//test ax, rarity_factor
		test rarity_factor, ax	//This is actually the correct way to do it, the special test ax form is only for immediates (text AX, imm16).
		jz ispresent
		jmp endgame }
ispresent:asm {	fild dword ptr temp_z
		fsub dzat_z
		fst zz
		fmul opt_tcosbeta
		fild dword ptr temp_x
		fsub dzat_x
		fst xx
		fmul opt_tsinbeta
		fsubp
		fst z2
		fmul opt_tcosalfa
		fild dword ptr temp_y
		fsub dzat_y
		fst yy
		fmul opt_tsinalfa
		faddp
		fst rz
		fcomp starneg
		fstsw ax
		sahf
		jnb _123stella
		jmp endgame }
_123stella:asm {fld xx
		fmul opt_pcosbeta
		fld zz
		fmul opt_psinbeta
		faddp
		fld uno
		fdiv rz
		fst inv_rz
		fmulp
		fistp rx
		#ifdef WINDOWS
		movsx edi, word ptr rx
		add edi, x_centro
		cmp edi, 10
		#else
		mov di, word ptr rx
		add di, x_centro
		cmp di, 10
		#endif
		ja _x_low_ok
		jmp endgame }
_x_low_ok:asm {
		#ifdef WINDOWS
		//NOTVALID: Depends on display width being 320.
		cmp edi, 310
		#else
		cmp di, 310
		#endif
		jb _x_high_ok
		jmp endgame }
_x_high_ok:asm{	fld yy
		fmul opt_pcosalfa
		fld z2
		fmul opt_psinalfa
		fsubp
		fmul inv_rz
		fistp ry
		sub word ptr ry, 2
		#ifdef WINDOWS
		movsx ebx, word ptr ry
		add ebx, y_centro
		cmp ebx, 10
		#else
		mov bx, word ptr ry
		add bx, y_centro
		cmp bx, 10
		#endif
		ja _y_low_ok
		jmp endgame }
_y_low_ok:asm {
		#ifdef WINDOWS
		//NOTVALID: Depends on display width being 320.
		cmp ebx, 190
		#else
		cmp bx, 190
		#endif
		jb _y_high_ok
		jmp endgame }
_y_high_ok: asm {
		#ifdef WINDOWS
		shl ebx, 1
		add edi, dword ptr riga[ebx*2]
		#else
		shl bx, 1
		add di, word ptr riga[bx]
		#endif
		cmp ap_targetting, 1
		je newgame
		#ifdef WINDOWS
		cmp byte ptr [esi+edi], 68	//cmp byte ptr [esi+edi+4], 68	//REMOVED4
		#else
		cmp byte ptr es:[di+4], 68
		#endif
		je endgame
		mov ax, limits
		#ifdef WINDOWS
		cmp byte ptr [esi+edi], ah	//cmp byte ptr [esi+edi+4], ah	//REMOVED4
		#else
		cmp byte ptr es:[di+4], ah
		#endif
		jb endgame
		#ifdef WINDOWS
		cmp byte ptr [esi+edi], al	//cmp byte ptr [esi+edi+4], al	//REMOVED4
		#else
		cmp byte ptr es:[di+4], al
		#endif
		ja endgame }
newgame: asm {	fld rz
		fistp temp
		mov cl, 13
		add cl, field_amplificator
		#ifdef WINDOWS
		mov edx, dword ptr temp
		shr edx, cl
		#else
		db 0x66; mov dx, word ptr temp
		db 0x66; shr dx, cl
		#endif
		mov al, 63
		sub al, dl
		jc colorout
		#ifdef WINDOWS
		mov dl, byte ptr [esi+edi]	//mov dl, byte ptr [esi+edi+4]	//REMOVED4
		and byte ptr [esi+edi], 0xC0	//and byte ptr adapted[edi], 0xC0
		#else
		mov dl, es:[di+4]
		and byte ptr es:[di+4], 0xC0
		#endif
		and dl, 0x3F
		add al, dl
		cmp al, 63
		jbe colorin
		mov al, 63 }
colorin: asm {
		#ifdef WINDOWS
		or byte ptr [esi+edi], al	//or byte ptr [esi+edi+4], al	//REMOVED4
		#else
		or es:[di+4], al
		#endif
	}
colorout:asm {	cmp ap_targetting, 1
		je extend }
endgame: asm	jmp next
extend:
/*
		'extend' does this:
			f1=rx*rx
			f2=ry*ry
			f1+=f2
			temp=ft
			temp = ry*ry + rx*rx
			if temp >= min_xy goto next
			(else)
			min_xy = temp
			store ap_target_? coords from temp_? coords
		(SL)
*/
		asm {
		#ifdef WINDOWS
		fild rx
		fild rx
		fmulp
		fild ry
		fild ry
		fmulp
		#else
		fild rx
		fmul st(0), st(0)
		fild ry
		fmul st(0), st(0)
		#endif
		faddp
		fistp temp
		MOV_EAX_DWORD_PTR temp
		#ifdef WINDOWS
		cmp eax, dword ptr min_xy
		#else
		db 0x66; cmp ax, word ptr min_xy
		#endif
		jnb next
		#ifdef WINDOWS
		mov dword ptr min_xy, eax
		#else
		db 0x66; mov word ptr min_xy, ax
		#endif
		fild dword ptr temp_x
		fstp ap_target_x
		fild dword ptr temp_y
		fstp ap_target_y
		fild dword ptr temp_z
		fstp ap_target_z
		#ifdef WINDOWS
		mov eax, dword ptr sect_x
		mov dword ptr ap_target_sx, eax
		mov eax, dword ptr sect_y
		mov dword ptr ap_target_sy, eax
		mov eax, dword ptr sect_z
		mov dword ptr ap_target_sz, eax
		#else
		db 0x66; mov ax, word ptr sect_x
		db 0x66; mov word ptr ap_target_sx, ax
		db 0x66; mov ax, word ptr sect_y
		db 0x66; mov word ptr ap_target_sy, ax
		db 0x66; mov ax, word ptr sect_z
		db 0x66; mov word ptr ap_target_sz, ax
		#endif
		}
next: 	  asm {
		#ifdef WINDOWS
		mov eax, dword ptr advance
		add dword ptr sect_z, eax
		#else
		db 0x66; mov ax, word ptr advance
		db 0x66; add word ptr sect_z, ax
		#endif
		dec sz
		jz i_end
		jmp i_while }
i_end:	  asm {
		#ifdef WINDOWS
		mov edx, dword ptr k
		sub dword ptr sect_z, edx
		add dword ptr sect_y, eax
		#else
		db 0x66; mov dx, word ptr k
		db 0x66; sub word ptr sect_z, dx
		db 0x66; add word ptr sect_y, ax
		#endif
		dec sy
		jz m_end
		jmp m_while }
m_end:	  asm {
		#ifdef WINDOWS
		sub dword ptr sect_y, edx
		add dword ptr sect_x, eax
		#else
		db 0x66; sub word ptr sect_y, dx
		db 0x66; add word ptr sect_x, ax
		#endif
		dec sx
		jz e_end
		jmp e_while }
e_end:	  // No more...
	asm {
		#ifndef WINDOWS
		pop es
		#endif
		POPAD
	}
}

/* Ancora quicktime-vr, purtroppo Š necessaria: una sfera che poi pu• essere
   un pianeta o una stella (non Š il caso di andare per il sottile).
   Usa un'enormit… di registri: salti mortali con le macro in codice macchina
   perch‚ il c++ non mi considera i registri estesi. Meglio ricapitolare:
   DS passa su GS, ES Š la pagina video (solitamente nascosta, non Š
   l'area dell'adattatore) specificata in target, FS ospita la tapestry,
   la tappezzeria da mappare sul globo, e il vecchio DS punta all'area
   della mappa degli offsets, compressa con il sistema di MAPS.EXE nella
   sua sezione X-Y. In effetti non sono offsets video gi… pronti, perch‚
   vanno calcolati (primo byte = Y, secondo byte = X). Quando la Y Š 100
   significa che l'offset originario era 64000 e che quindi non si tratta
   di un punto, ma di una serie di avanzamenti consecutivi lungo il
   segmento della tappezzeria, indicati per la precisione dal byte X. */

Uchar glass_bubble = 1; // Se settato, disegna una specie di bolla
				// trasparente attorno ai globi tracciati con
				// la funzione "globe". Serve per simulare la
				// presenza dell'atmosfera, ma solo per i
				// pianeti che hanno CONSIDEREVOLI quantit…
				// di gas attorno.

/* Cacchio, dei veri e propri fill managers, e funzionano!
   Da non crederci, in C++, e pure dopo aver cambiato ES, FS e GS! */
#ifdef WINDOWS
#define gman1x1 0
#define gman2x2 1
#define gman3x3 2
#define gman4x4 3

#else
void gman1x1 ()
{
	asm	mov es:[di+4], dl
}

void gman2x2 ()
{
	asm {   mov dh, dl
		mov es:[di+4], dx
		mov es:[di+324], dx }
}

void gman3x3 ()
{
	asm {	mov dh, dl
		mov es:[di+4], dx
		mov es:[di+6], dl
		mov es:[di+324], dx
		mov es:[di+326], dl
		mov es:[di+644], dx
		mov es:[di+646], dl }
}

void gman4x4 ()
{
	asm {	mov dh, dl
		mov es:[di+4], dx
		mov es:[di+6], dx
		mov es:[di+324], dx
		mov es:[di+326], dx
		mov es:[di+644], dx
		mov es:[di+646], dx
		mov es:[di+964], dx
		mov es:[di+966], dx }
}
#endif
void globe (Uword start,
	    Uchar maybefar *target,
	    Uchar maybefar *tapestry,
	    Uchar maybefar *offsetsmap,
	    Uword total_map_bytes,
	    double x, double y, double z,
	    float mag_factor, char colormask, char globe_saturation)
{
	#ifdef WINDOWS
	int	gman;
	#else
	void	*gman;
	#endif
	Word	center_x, center_y, temp;
	double	xx, yy, zz, z2, rx, ry, rz;

	xx = x - dzat_x;
	yy = y - dzat_y;
	zz = z - dzat_z;

	rx = xx * (double)opt_pcosbeta + zz * (double)opt_psinbeta;
	z2 = zz * (double)opt_tcosbeta - xx * (double)opt_tsinbeta;
	rz = z2 * (double)opt_tcosalfa + yy * (double)opt_tsinalfa;
	ry = yy * (double)opt_pcosalfa - z2 * (double)opt_psinalfa;

	if (rz<0.001) return;

	mag_factor /= rz;
	gman = gman1x1;
	
	if (mag_factor<0.01) mag_factor = 0.001;
	if (mag_factor>0.33) gman = gman2x2;
	if (mag_factor>0.66) gman = gman3x3;
	if (mag_factor>0.99) gman = gman4x4;
	if (mag_factor>1.32) mag_factor = 1.32;

	rx /= rz; ry /= rz;

	/* 320 = Largh. schermo, 100 = max x/y pixels della mappa,
	   1.32 = massimo fattore d'ingrandimento con punti di 4 pixels. */

	if (rx<-292||rx>292) return; // 292 = (320 / 2) + (100 * 1.32)
	if (ry<-232||ry>232) return; // 232 = (200 / 2) + (100 * 1.32)

	center_x = rx + x_centro_f;
	center_y = ry + y_centro_f;
	
	#ifdef WINDOWS
	//This had been tested in DOS, and works.
	/*
	gs = ds
	cx = total_map_bytes >> 1
	es = seg tapestry
	//In DOS start = start + offset tapestry
	bx = "tapestryPos" = start
	fs = seg tapestry
	es = seg target
	ax = offset target
	ds = seg offsetsmap
	si = "offsetsmapPos" = offset offsetsmap
	*/
	char maybefar* offsetsmapS = (char maybefar*) offsetsmap;
	Uword tapestryPos = start;
	Uword offsetsmapPos = 0;
	Udword screenpos = 0;
	Uword xpos = 0;
	Uword ypos = 0;
	Uchar dl;
	for (Uword cx = total_map_bytes >> 1; cx>0; cx--) {
		rigiro:
		if (offsetsmap[offsetsmapPos] != 100) {
			pixel:
			ypos = (Uword) (((double)offsetsmapS[offsetsmapPos] * mag_factor) + center_y);
			if (ypos>=6 && ypos<191) {
				screenpos = riga[ypos];
				
				xpos = (Uword) (((double)offsetsmapS[offsetsmapPos+1] * mag_factor) + center_x);
				if (xpos>=6 && xpos<311) {
					screenpos += xpos;
					dl = tapestry[tapestryPos];
					if (dl < globe_saturation) {
						dl = globe_saturation;
					}
					dl |= colormask;
					switch (gman) {
						case gman1x1:
							target[screenpos] = dl;
							break;
						case gman2x2:
							target[screenpos] = dl;
							target[screenpos+1] = dl;
							target[screenpos+320] = dl;
							target[screenpos+321] = dl;
							break;
						case gman3x3:
							target[screenpos] = dl;
							target[screenpos+1] = dl;
							target[screenpos+2] = dl;
							target[screenpos+320] = dl;
							target[screenpos+321] = dl;
							target[screenpos+322] = dl;
							target[screenpos+640] = dl;
							target[screenpos+641] = dl;
							target[screenpos+642] = dl;
							break;
						case gman4x4:
							target[screenpos] = dl;
							target[screenpos+1] = dl;
							target[screenpos+2] = dl;
							target[screenpos+3] = dl;
							target[screenpos+320] = dl;
							target[screenpos+321] = dl;
							target[screenpos+322] = dl;
							target[screenpos+323] = dl;
							target[screenpos+640] = dl;
							target[screenpos+641] = dl;
							target[screenpos+642] = dl;
							target[screenpos+643] = dl;
							target[screenpos+960] = dl;
							target[screenpos+961] = dl;
							target[screenpos+962] = dl;
							target[screenpos+963] = dl;
							break;
					}
				}
			}
			clipout:
			tapestryPos++;
			offsetsmapPos+=2;
		} else {
			blanket:
			tapestryPos += offsetsmap[offsetsmapPos+1];
			offsetsmapPos+=2;
		}
		
	}
	fine:
	#else
	asm {   pusha
		push ds
		push ds
		db 0x0F, 0xA9 // pop gs
		mov cx, total_map_bytes
		shr cx, 1
		les ax, dword ptr tapestry
		add start, ax
		mov bx, start
		mov ax, es
		db 0x8E, 0xE0 // mov fs, ax
		les ax, dword ptr target
		lds si, dword ptr offsetsmap }
rigiro: asm {   cmp byte ptr [si], 100
		jne pixel
		jmp blanket }
pixel:  asm {	mov al, [si]
		cbw			//sign-extend al to ax
		mov temp, ax
		fild word ptr temp
		fmul dword ptr mag_factor
		fistp word ptr temp
		mov di, temp
		add di, center_y
		cmp di, 6
		jb clipout
		cmp di, 191
		jnb clipout
		mov al, [si+1]      // istruzione di caricamento x #1
		add di, di	//double di because riga is a word (but note: in WINDOWS it's a dword)
		cbw		    // istruzione di caricamento x #2
		db 0x65, 0x8B, 0xBD /* mov di, gs:riga[di] - prima parte */
		dw offset riga	    /* mov di, gs:riga[di] - 2nda parte */
		mov temp, ax	    // istruzione di caricamento x #3
		fild word ptr temp
		fmul dword ptr mag_factor
		fistp word ptr temp
		mov ax, temp
		add ax, center_x
		cmp ax, 6
		jb clipout
		cmp ax, 311
		jnb clipout
		add di, ax
		db 0x64, 0x8A, 0x17 // mov dl, fs:[bx]
		cmp dl, globe_saturation
		jnb asis
		mov dl, globe_saturation }
asis:	asm {	or dl, colormask
		call [gman] }
clipout:asm {	add bx, 1
		add si, 2
		dec cx
		jz fine
		jmp rigiro }
blanket:asm {	mov al, [si+1]
		xor ah, ah
		add bx, ax
		add si, 2
		dec cx
		jz fine
		jmp rigiro }
fine:	asm {	pop ds
		popa }
	#endif

	if (!glass_bubble) return;

	temp = mag_factor * 7.25;

	if (!temp) return;

	rx = mag_factor * 110;
	ry =(1.2 * deg) / mag_factor;
	rz = 0.5 * ry;
	z2 = 0.833 * rx;
	while (rz < 2*M_PI) {
		smootharound_64 (target,
				 center_x + rx*cos(rz),
				 center_y + z2*sin(rz), temp, 1);
		rz += ry;
	}
}

/* Come precedente, modificata per fare globi luminosi, senza dettagli
   ma con un evidente demarcazione fra emisfero illuminato e buio.
   Viene usata per i pianeti in media distanza. */

void glowinglobe (Word start,
		  Uchar maybefar *target,
		  Uchar maybefar *offsetsmap,
		  Uword total_map_bytes,
		  double x, double y, double z, float mag_factor,
		  Word terminator_start, Word terminator_arc,
		  Uchar color)
{
	#ifdef WINDOWS
	Uword center_x, center_y;
	#else
	Uword center_x, center_y, temp;
	#endif
	double xx, yy, zz, z2, rx, ry, rz;

	xx = x - dzat_x;
	yy = y - dzat_y;
	zz = z - dzat_z;

	rx = xx * (double)opt_pcosbeta + zz * (double)opt_psinbeta;
	z2 = zz * (double)opt_tcosbeta - xx * (double)opt_tsinbeta;
	rz = z2 * (double)opt_tcosalfa + yy * (double)opt_tsinalfa;
	ry = yy * (double)opt_pcosalfa - z2 * (double)opt_psinalfa;

	if (rz<0.001) return;

	mag_factor /= rz;

	if (mag_factor>0.66) mag_factor = 0.66;
	if (mag_factor<0.01) mag_factor = 0.001;

	rx /= rz; ry /= rz;

	/* 320 = Largh. schermo, 100 = max x/y pixels della mappa,
	   0.66 = massimo fattore d'ingrandimento con punti di 4 pixels. */

	if (rx<-226||rx>226) return; // 172 = (320 / 2) + (100 * 0.66)
	if (ry<-166||ry>166) return; // 132 = (200 / 2) + (100 * 0.66)

	center_x = rx + x_centro_f;
	center_y = ry + y_centro_f;

	start -= terminator_start;
	while (start < 0) start += 360;

	#ifdef WINDOWS
	//This has been tested in DOS, and works.
	/*
	gs = ds
	cx = total_map_bytes >> 1
	bl = color&0xc0
	bh = ((color&0x3F) >> 2)
	bh |= bl;
	bl = color;
	dx = "tapestryPos" = start;
	es = seg target
	ax = offset target
	ds = seg offsetsmap
	si = "offsetsmapPos" = offset offsetsmap
	
	*/
	char maybefar* offsetsmapS = (char maybefar*) offsetsmap;
	Uword tapestryPos = start;
	Uword offsetsmapPos = 0;
	Udword screenpos = 0;
	Uword xpos = 0;
	Uword ypos = 0;
	Uchar bl = color&0xc0;
	Uchar bh = ((color&0x3F) >> 2);
	bh |= bl;
	bl = color;
	for (Uword cx = total_map_bytes >> 1; cx>0; cx--) {
		rigiro:
		if (offsetsmap[offsetsmapPos] != 100) {
			pixel:
			if ((tapestryPos&3)>0) {
				ypos = (Uword) (((double)offsetsmapS[offsetsmapPos] * mag_factor) + center_y);
				if (ypos>=10 && ypos<190) {
					screenpos = riga[ypos];
					
					xpos = (Uword) (((double)offsetsmapS[offsetsmapPos+1] * mag_factor) + center_x);
					if (xpos>=9 && xpos<310) {
						screenpos += xpos;
						if (tapestryPos>=terminator_arc) {
							target[screenpos] = bl;
						} else {
							target[screenpos] = bh;
						}
					}
				}
			}
			clipout:
			tapestryPos++;
			if (tapestryPos>=360) {
				tapestryPos=0;
			}
			offsetsmapPos+=2;
		} else {
			blanket:
			tapestryPos += offsetsmap[offsetsmapPos+1];
			while (tapestryPos>=360) {
				tapestryPos-=360;
			}
			offsetsmapPos+=2;
		}
	}
	#else
	asm {   pusha
		push ds
		push ds
		db 0x0F, 0xA9 // pop gs
		mov cx, total_map_bytes
		shr cx, 1
		mov bl, color
		and bl, 0xC0
		mov bh, color
		and bh, 0x3F
		shr bh, 2
		or  bh, bl
		mov bl, color
		mov dx, start
		les ax, dword ptr target
		lds si, dword ptr offsetsmap }
rigiro: asm {   cmp byte ptr [si], 100
		jne pixel
		jmp blanket }
pixel:  asm {	test dx, 3
		jz doit
		jmp clipout }
doit:	asm {	mov al, [si]
		cbw
		mov temp, ax
		fild word ptr temp
		fmul dword ptr mag_factor
		fistp word ptr temp
		mov di, temp
		add di, center_y
		cmp di, 10
		jnb y_ok
		cmp di, 190
		jb y_ok
		jmp clipout }
y_ok:	asm {	mov al, [si+1]
		add di, di
		cbw
		db 0x65, 0x8B, 0xBD /* mov di, gs:riga[di] */
		dw offset riga
		mov temp, ax
		fild word ptr temp
		fmul dword ptr mag_factor
		fistp word ptr temp
		mov ax, temp
		add ax, center_x
		cmp ax, 9
		jb  clipout
		cmp ax, 310
		jnb clipout
		add di, ax
		cmp dx, terminator_arc
		jb darkdot
		mov es:[di+4], bl
		jmp clipout }
darkdot:asm 	mov es:[di+4], bh
clipout:asm {	add dx, 1
		cmp dx, 360
		jb rtn_ok
		xor dx, dx }
rtn_ok: asm {	add si, 2
		dec cx
		jz fine
		jmp rigiro }
blanket:asm {	mov al, [si+1]
		xor ah, ah
		add dx, ax }
rtj_lp: asm {	cmp dx, 360
		jb rtj_ok
		sub dx, 360
		jmp rtj_lp }
rtj_ok: asm {	add si, 2
		dec cx
		jz fine
		jmp rigiro }
fine:	asm {	pop ds
		popa }
	#endif
}

/* Modificata per fare globi bianchi.
   Viene usata per le stelle viste da lontano, e per la corona stellare.
   Non ha bisogno della mappa dei globi. Color compreso fra 0 e 0x3F,
   perch‚ per maggior velocit… funziona sulla prima sfumatura. */

void whiteglobe (Uchar maybefar *target,
		 double x, double y, double z,
		 float mag_factor, float fgm_factor)
{
	double center_x, center_y, mag, fgm, shade_ext, ise;
	double xx, yy, zz, z2, rx, ry, rz, xa, ya, xb, yb;
	double magsq, fgmsq;
	#ifdef WINDOWS
	Udword pixptr;
	#else
	Uword pixptr;
	#endif
	char pix;

	xx = x - dzat_x;
	yy = y - dzat_y;
	zz = z - dzat_z;

	rx = xx * (double)opt_pcosbeta + zz * (double)opt_psinbeta;
	z2 = zz * (double)opt_tcosbeta - xx * (double)opt_tsinbeta;
	rz = z2 * (double)opt_tcosalfa + yy * (double)opt_tsinalfa;
	ry = yy * (double)opt_pcosalfa - z2 * (double)opt_psinalfa;

	if (rz<0.001) return;

	mag_factor /= rz;

	if (mag_factor>2.99) mag_factor = 2.99;
	if (mag_factor<0.01) mag_factor = 0.01;

	rx /= rz; ry /= rz;

	/* 320 = Largh. schermo, 100 = max x/y pixels della mappa,
	   3.00 = massimo fattore d'ingrandimento con dispersione. */

	if (rx<-460||rx>460) return; // 460 = (320 / 2) + (100 * 3.00)
	if (ry<-400||ry>400) return; // 400 = (200 / 2) + (100 * 3.00)

	center_x = rx + x_centro_f + 0.5;
	center_y = ry + y_centro_f + 0.5;

	mag = mag_factor * 100 + 1.5;
	fgm = fgm_factor * mag; // full globe magnitude
	shade_ext = mag - fgm;
	if (shade_ext < 1) shade_ext = 1;
	ise = 0x3F / shade_ext;

	magsq = mag * mag;
	fgmsq = fgm * fgm;

	#ifdef WINDOWS
	//We don't need any of this :P
	#else
	asm les dx, dword ptr target
	asm mov ax, es
	asm shr dx, 4
	asm add ax, dx
	asm db 0x8e, 0xe0 // mov fs, ax
	#endif
	
	ya = - mag * 1.2;
	yb = center_y + mag;
	yy = center_y - mag;
	while (yy < yb) {
		xa = - mag;
		xb = center_x + mag;
		xx = center_x - mag;
		while (xx < xb) {
			if (xx > 9 && xx < 313 && yy > 9 && yy < 190) {
				zz = xa*xa + ya*ya;
				if (zz < magsq) {
					if (zz > fgmsq)
						pix = 0x3F - (SQRT(zz) - fgm) * ise;
					else
						pix = 0x3F;
					pixptr = riga[(int)yy] + (int)xx;
					pix += target[pixptr];
					if (pix > 0x3F) {
						#ifdef WINDOWS
						target[pixptr]= 0x3f;
						target[pixptr+1]= 0x3f;
						target[pixptr+320]= 0x3f;
						target[pixptr+321]= 0x3f;
						#else
						
						asm {
							mov di, pixptr
							db 0x64, 0xC7, 0x45, 0x04, 0x3F, 0x3F
							db 0x64, 0xC7, 0x85, 0x44, 0x01, 0x3F, 0x3F
						}
						//target[pixptr] = 0x3F;
						/*
						0x64 0xc7: mov fs:r/m16, imm16
						0x45: 01000101: mod:01  opcode/reg:0  r/m:101: [DI]+disp8
						0x85: 10000101: mod:10  opcode/reg:0  r/m:101: [DI]+disp16
						disp:
							0x04: 		4
							0x44 0x01: 	324
						Then 0x3f3f for the immediate value.
						So:
						
						asm {
							mov di, pixptr
							mov fs:[di+4], 0x3f3f
							mov fs:[di+324], 0x3f3f
						}
						(SL)
						*/
						#endif
					}
					else {
						#ifdef WINDOWS
						target[pixptr]= pix;
						target[pixptr+1]= pix;
						target[pixptr+320]= pix;
						target[pixptr+321]= pix;
						#else
						
						asm {
							mov al, pix
							mov di, pixptr
							mov ah, al
							db 0x64, 0x89, 0x45, 0x04
							db 0x64, 0x89, 0x85, 0x44, 0x01
						}
						
						//target[pixptr] = pix;
						/*
						0x64 0x89: mov fs:r/m16, r16
						
						0x45: 01000101: mod:01  opcode/reg:0(ax)  r/m:101: [DI]+disp8
						0x85: 10000101: mod:10  opcode/reg:0(ax)  r/m:101: [DI]+disp16
						disp:
							0x04: 		4
							0x44 0x01: 	324
						So:
						
						asm {
							mov al, pix
							mov di, pixptr
							mov ah, al
							mov fs:[di+4], ax
							mov fs:[di+324], ax
						}
						(SL)
						*/
						#endif
					}
				}
			}
			xa += 2;
			xx += 2;
		}
		ya += 2.4;
		yy += 2;
	}
}

/* Come sopra, ma mentre quella di sopra traccia in 4x4 pixels,
   dimezzando la risoluzione per essere pi— veloce nel tracciamento
   di globi che possono coprire tutto lo schermo, questa traccia in 1x1,
   Š pi— precisa ma applicabile solo alla visualizzazione delle stelle
   viste dai pianeti. */

double xsun_onscreen;

void whitesun (Uchar maybefar *target,
	       double x, double y, double z,
	       float mag_factor, float fgm_factor)
{
	double center_x, center_y, mag, fgm, shade_ext, ise;
	double xx, yy, zz, z2, rx, ry, rz, xa, ya, xb, yb;
	double magsq, fgmsq;

	#ifdef WINDOWS
	Udword pixptr;
	#else
	Uword pixptr;
	#endif
	char pix;

	xx = x - dzat_x;
	yy = y - dzat_y;
	zz = z - dzat_z;

	rx = xx * (double)opt_pcosbeta + zz * (double)opt_psinbeta;
	z2 = zz * (double)opt_tcosbeta - xx * (double)opt_tsinbeta;
	rz = z2 * (double)opt_tcosalfa + yy * (double)opt_tsinalfa;
	ry = yy * (double)opt_pcosalfa - z2 * (double)opt_psinalfa;

	if (rz<0.001) return;

	mag_factor /= rz;

	if (mag_factor>2.99) mag_factor = 2.99;
	if (mag_factor<0.01) mag_factor = 0.01;

	rx /= rz; ry /= rz;
	xsun_onscreen = rx + x_centro_f;

	/* 320 = Largh. schermo, 100 = max x/y pixels della mappa,
	   3.00 = massimo fattore d'ingrandimento con dispersione. */

	if (rx<-460||rx>460) return; // 460 = (320 / 2) + (100 * 3.00)
	if (ry<-400||ry>400) return; // 400 = (200 / 2) + (100 * 3.00)

	center_x = rx + x_centro_f + 0.5;
	center_y = ry + y_centro_f + 0.5;

	mag = mag_factor * 100 + 1.5;
	fgm = fgm_factor * mag; // full globe magnitude
	shade_ext = mag - fgm;
	if (shade_ext < 1) shade_ext = 1;
	ise = 0x3F / shade_ext;

	magsq = mag * mag;
	fgmsq = fgm * fgm;

	ya = - mag * 1.2;
	yb = center_y + mag;
	yy = center_y - mag;
	while (yy < yb) {
		xa = - mag;
		xb = center_x + mag;
		xx = center_x - mag;
		while (xx < xb) {
			if (xx > 9 && xx < 313 && yy > 9 && yy < 190) {
				zz = xa*xa + ya*ya;
				if (zz < magsq) {
					if (zz > fgmsq)
						pix = 0x3F - (SQRT(zz) - fgm) * ise;
					else
						pix = 0x3F;
					pixptr = riga[(Word)yy] + (Word)xx;
					pix += target[pixptr];
					if (pix > 0x3F)
						target[pixptr] = 0x3F;
					else
						target[pixptr] = pix;
				}
			}
			xa ++;
			xx ++;
		}
		ya += 1.2;
		yy ++;
	}
}

/* Bagliori attorno alle luci pi— intense. */

/*float maybefar *lft_sin = (float maybefar *) farmalloc (361*4);
float maybefar *lft_cos = (float maybefar *) farmalloc (361*4);*/

float maybefar lft_sin[361];
float maybefar lft_cos[361];

char lens_flares_init ()
{
	Word c;

	double a = 0, step = M_PI / 180.0;

	if (!lft_sin||!lft_cos) return (0);

	for (c = 0; c <= 360; c++) {
		lft_cos[c] = cos (a);
		lft_sin[c] = sin (a);
		//The following line was used to test to make sure these were being initialized the same in windows and in DOS, by comparing the output from each in NIVDEBUG.LOG
		//DebugPrintf(0, "lft_cos[%i]=%f\nlft_sin[%i]=%f\n", (int) c, lft_cos[c], (int) c, lft_sin[c]);
		a += step;
	}

	return (1);
}

void lens_flares_for (double cam_x, double cam_y, double cam_z,
		      double xlight, double ylight, double zlight,
		      double step, Word added, char on_hud, char condition,
		      Word xshift, Word yshift)
{
	double k = 10.0 / step, l = 1, u = 1.5;

	double xx, yy, zz, z2, rx, ry, rz;

	Dword xs, ys, dx, dy;
	float xr, yr;

	Uchar temp;

	Word c, r;

	setfx (1);

	xx = xlight - cam_x;
	yy = ylight - cam_y;
	zz = zlight - cam_z;

	rx = xx * (double)opt_pcosbeta + zz * (double)opt_psinbeta;
	z2 = zz * (double)opt_tcosbeta - xx * (double)opt_tsinbeta;
	rz = z2 * (double)opt_tcosalfa + yy * (double)opt_tsinalfa;
	ry = yy * (double)opt_pcosalfa - z2 * (double)opt_psinalfa;

	if (rz>1) {
		if (step<0)
			k = -step / rz;
		else
			k = 10 / step;
		xs = rx / rz + xshift;
		ys = ry / rz + yshift;
		if (xs>-150&&ys>-90&&xs<160&&ys<90) {
			switch (condition) {
				case 1: temp = adapted[xs+x_centro+riga[ys+y_centro]];
					if (temp<64) goto exit_local;
					break;
				case 2: temp = adapted[xs+x_centro+riga[ys+y_centro]];
					if (temp<64||temp>127) goto exit_local;
					break;
			}
			for (c=0; c<180; c+=added) {
				dx = lft_cos[c] * k * l;
				dy = lft_sin[c] * k * l;
				fline (xs-dx, ys-dy, xs+dx, ys+dy);
				if (on_hud && !(c%8)) {
					dx /= 10; dy /= 10;
					xr = (float)xs * -0.1;
					yr = (float)ys * -0.1;
					for (r = 0; r < 3; r++)  {
						fline (xr-dx, yr-dy, xr+dx, yr+dy);
						dx *= 4; dy *= 4;
						xr *= 3; yr *= 3;
					}
				}
				l *= u;
				if (l>3||l<1) u = 1 / u;
			}
		}
	}

	exit_local:
	resetfx ();
}

/* Puntini lontani, per esempio pianeti e lune.
   Le due funzioni si integrano: viene disegnato un puntino se la distanza
   Š grande. Man mano che ci si avvicina, il puntino diventa un dischetto,
   del diametro massimo di 5 pixels. Ovviamente, per fare dischi pi— grandi,
   bisogna passare il controllo a un'altra funzione (sul tipo di globe). */

const double  pix_dst_scale = 0.384;
const double  pix_rad_scale = 1228.8;
#define	      LIGHT_EMITTING	0
#define	      LIGHT_ABSORBING	1
#define	      MULTICOLOUR	2
char 	      pixilating_effect = LIGHT_EMITTING;
char	      pixel_spreads = 1;
Uchar multicolourmask = 0xC0;

void single_pixel_at_ptr (Uword ptr, Uchar pixel_color)
{
	#ifdef WINDOWS
	//This code was tested in DOS and appears to work.
	/*
	dx = ptr;
	cl = pixel_color;
	*/
	Uchar al, ah;
	Udword offsetPos;
	
	switch (pixilating_effect) {
		case LIGHT_EMITTING:
			/*
			es = seg adapted
			di = ptr + offset adapted
			*/
			offsetPos = ptr;
			if (adapted[offsetPos]>=64) {
				al = (adapted[offsetPos] & 0x3F) + pixel_color;
				ah = adapted[offsetPos] & 0xC0;
				if (al>0x3E) {
					al=0x3E;
				}
				al |= ah;
				adapted[offsetPos] = al;
			}
			break;
		case LIGHT_ABSORBING:
			/*
			es = seg adapted
			di = ptr + offset adapted
			*/
			offsetPos = ptr;
			if (adapted[offsetPos]>=64) {
				al = ((adapted[offsetPos] & 0x3F) + pixel_color)>>1;
				ah = adapted[offsetPos] & 0xC0;
				al |= ah;
				adapted[offsetPos] = al;
			}
			break;
		case MULTICOLOUR:
			/*
			es = seg adapted
			di = ptr + offset adapted
			*/
			offsetPos = ptr;
			if (adapted[offsetPos]>=64) {
				al = ((adapted[offsetPos] & 0x3F) + pixel_color)>>1;
				ah = multicolourmask & 0xC0;
				al |= ah;
				adapted[offsetPos] = al;
			}
			break;
	}
	#else
	_DX = ptr;
	_CL = pixel_color;

	switch (pixilating_effect) {
		case LIGHT_EMITTING:
		asm {	les di, dword ptr adapted
			add di, dx
			cmp byte ptr es:[di], 64
			jb c0vered
			mov al, es:[di]
			mov ah, es:[di]
			and al, 0x3F
			and ah, 0xC0
			add al, cl
			cmp al, 0x3E
			jbe grd_ok
			mov al, 0x3E }
	grd_ok: asm {	or  al, ah
			mov es:[di], al }
	       c0vered: break;
		case LIGHT_ABSORBING:
		asm {	les di, dword ptr adapted
			add di, dx
			cmp byte ptr es:[di], 64
			jb c1vered
			mov al, es:[di]
			mov ah, es:[di]
			and al, 0x3F
			and ah, 0xC0
			add al, cl
			shr al, 1
			or  al, ah
			mov es:[di], al }
	       c1vered: break;
		case MULTICOLOUR:
		asm {	les di, dword ptr adapted
			add di, dx
			cmp byte ptr es:[di], 64
			jb c2vered
			mov al, es:[di]
			mov ah, multicolourmask
			and al, 0x3F
			and ah, 0xC0
			add al, cl
			shr al, 1
			or  al, ah
			mov es:[di], al }
	       c2vered: break;
	}
	#endif
}

char far_pixel_at (double xlight, double ylight, double zlight,
		   double radii, Uchar unconditioned_color)
{
	double	xx, yy, zz, z2, rz;
	Dword	pixel_color;

	Uchar edge_color_1;
	Uchar edge_color_2;
	Uchar edge_color_3;
	Uchar edge_color_4;

	xx = xlight - dzat_x;
	yy = ylight - dzat_y;
	zz = zlight - dzat_z;

	pxx = xx * opt_pcosbeta + zz * opt_psinbeta;
	z2  = zz * opt_tcosbeta - xx * opt_tsinbeta;
	rz  = z2 * opt_tcosalfa + yy * opt_tsinalfa;
	pyy = yy * opt_pcosalfa - z2 * opt_psinalfa;

	if (rz>0.001) {
		if (!unconditioned_color) {
			pixel_color = 64 - (rz * pix_dst_scale) + (radii * pix_rad_scale);
			if (pixel_color > 63) pixel_color = 63;
			if (pixel_color < 0) pixel_color = 0;
		}
		else
			pixel_color = unconditioned_color;
		pxx /= rz; pxx += x_centro;
		pyy /= rz; pyy += y_centro;
		//NOTVALID: Depends on screen size being 320x200.
		if (pxx>10&&pyy>10&&pxx<310&&pyy<190) {
			vptr = 320*(Word)pyy + pxx;
			if (pixel_spreads) {
				edge_color_1 = pixel_color >> 1;
				edge_color_2 = pixel_color >> 2;
				edge_color_3 = pixel_color >> 3;
				edge_color_4 = pixel_color >> 4;
				if (edge_color_1 > 7) {
					single_pixel_at_ptr (vptr - 320, edge_color_1);
					single_pixel_at_ptr (vptr + 320, edge_color_1);
					single_pixel_at_ptr (vptr -   1, edge_color_1);
					single_pixel_at_ptr (vptr +   1, edge_color_1);
				}
				if (edge_color_2 > 7) {
					single_pixel_at_ptr (vptr - 321, edge_color_2);
					single_pixel_at_ptr (vptr - 319, edge_color_2);
					single_pixel_at_ptr (vptr + 321, edge_color_2);
					single_pixel_at_ptr (vptr + 319, edge_color_2);
				}
				if (edge_color_3 > 7) {
					single_pixel_at_ptr (vptr - 640, edge_color_3);
					single_pixel_at_ptr (vptr + 640, edge_color_3);
					single_pixel_at_ptr (vptr -   2, edge_color_3);
					single_pixel_at_ptr (vptr +   2, edge_color_3);
				}
				if (edge_color_4 > 7) {
					single_pixel_at_ptr (vptr - 641, edge_color_4);
					single_pixel_at_ptr (vptr - 639, edge_color_4);
					single_pixel_at_ptr (vptr + 641, edge_color_4);
					single_pixel_at_ptr (vptr + 639, edge_color_4);
					single_pixel_at_ptr (vptr - 322, edge_color_4);
					single_pixel_at_ptr (vptr - 318, edge_color_4);
					single_pixel_at_ptr (vptr + 322, edge_color_4);
					single_pixel_at_ptr (vptr + 318, edge_color_4);
				}
				if (pixel_color > 7)
					single_pixel_at_ptr (vptr, pixel_color);
			}
			else {
				if (pixel_color)
					single_pixel_at_ptr (vptr, pixel_color);
			}
			return (1);
		}
	}

	return (0);
}

/*

	Resto delle funzioni che operano su dati locali.
	Funzioni per: regolazione del timer cosmico di NOCTIS,
		      costruzione dei dintorni delle stelle e dei pianeti,
		      visualizzazione dei pianeti dall'orbita.

*/

/* Misura il tempo trascorso dal 1-1-1984 ad oggi, con la precisione di
   un fotogramma (in media, 1/25 di secondo). */
char dfm[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };


void getsecs ()
{
	Word m;

	#ifndef WINDOWS
	asm {	mov ah, 4
		int 0x1a
		lea bx, n_year
		mov ah, ch
		shr ah, 4
		mov al, ch
		and al, 0xF
		add ax, '00'
				xchg al, ah
		mov [bx], ax
		mov ah, cl
		shr ah, 4
		mov al, cl
		and al, 0xF
		add ax, '00'
		xchg al, ah
		mov [bx+2], ax
		lea bx, n_month
		mov ah, dh
		shr ah, 4
		mov al, dh
		and al, 0xF
		add ax, '00'
		xchg al, ah
		mov [bx], ax
		lea bx, n_day
		mov ah, dl
		shr ah, 4
		mov al, dl
		and al, 0xF
		add ax, '00'
		xchg al, ah
		mov [bx], ax
		mov ah, 2
		int 0x1a
		lea bx, hours
		mov ah, ch
		shr ah, 4
		mov al, ch
		and al, 0xF
		add ax, '00'
		xchg al, ah
		mov [bx], ax
		lea bx, minutes
		mov ah, cl
		shr ah, 4
		mov al, cl
		and al, 0xF
		add ax, '00'
		xchg al, ah
		mov [bx], ax
		lea bx, seconds
		mov ah, dh
		shr ah, 4
		mov al, dh
		and al, 0xF
		add ax, '00'
		xchg al, ah
		mov [bx], ax
	}
	#else
	SYSTEMTIME systime;
	GetSystemTime(&systime);
	itoa(systime.wYear, n_year, 10);
	itoa(systime.wMonth, n_month, 10);
	itoa(systime.wDay, n_day, 10);
	itoa(systime.wHour, hours, 10);
	itoa(systime.wMinute, minutes, 10);
	itoa(systime.wSecond, seconds, 10);
	#endif
	
	//if (!useUTC) {
	noutc:
	secs = atol (n_year) - 1984;		      // anni dal 1984
	secs = secs * 365 + (Dword)(secs / 4);	      // anni * 365 + anni / 4

	for (m=1; m<atoi(n_month); m++)
		secs += dfm[m];			      // giorni per mese

	if (atoi(n_month)>2 && !(atol(n_year)%4)) secs++; // se l'anno Š bisestile

	secs += atoi(n_day) - 1;			      // + giorni mese attuale
	secs *= 86400;                                // secondi in un giorno

	secs += 3600 * atol(hours);		      // ora corrente in sec.
	secs += 60 * atoi(minutes);		      // minuti corr. in sec.

	isecs = atoi(seconds);			      // secondi correnti.
	secs += isecs;
	//DebugPrintf("Y%s M%s D%s h%s m%s s%s secs %f", n_year, n_month, n_day, hours, minutes, seconds, secs);
	//DebugPrintf("secs is %f.",secs);
		
	/*
		//Commented out because the UTC time code wasn't working, and we'll be using IRC-server time
		//through hacirc when multiplayer is enabled.
		
	} else {
		unsigned int date=0, time=0;
		//DebugPrintf("year is %s, month %s, day %s, hours %s, minutes %s, seconds %s.",n_year,n_month,n_day,hours,minutes,seconds);
		date = (((atoi(year)-1980)<<9) + (atoi(n_month)<<5) + atoi(n_day));
		time = ((atoi(hours)<<1) + (atoi(minutes)<<5) + (atoi(seconds)>>1));	//It's seconds/2...
		_CX = time;
		_DX = date;
		asm {
			//dx now holds the packed date
			//cx now holds the packed time
			xor bh, bh
			mov bl, 1
			mov ax, 0x71a7
			push es
			les di, dword ptr timebuffLow
			int 0x21
			pop es
			
			//64-bit divide by 100
			//[timebuff] is the low bytes, [timebuff+4] the high bytes
		}
		//unsigned long tb0 = timebuff[0];
		//unsigned long tb1 = timebuff[1];
		//unsigned long rem0 = 0;
		//unsigned long rem4 = 0;
		_EDX = 0;
		_EAX = timebuff[1];
		_EBX = 10000000;
		asm { db 0x66; div bx }
		//rem4 = _EDX;
		timebuff[1]=_EAX;
		_EAX=timebuff[0];
		_EBX = 10000000;
		asm { db 0x66; div bx }
		//rem0 = _EDX;
		timebuff[0]=_EAX;
		//unsigned long ta0 = timebuff[0];
		//unsigned long ta1 = timebuff[1];
		
		//subtract jan 1 1984 from it
		_EAX = timebuff[0];
		_EBX = secs1984[0];
		_ECX = timebuff[1];
		_EDX = secs1984[1];
		asm {
			db 0x66; sub ax, bx
			jnc nocarry
			db 0x66; sub cx, 1
		} nocarry:
		asm {
			db 0x66; sub cx, dx
		}
		timebuff[0]=_EAX;
		timebuff[1]=_ECX;
		
		//DebugPrintf("Numbers are (Low, High). Date/Time: (%x, %x). Before divide, timebuff is (%lx,%lx). After divide it is (%lx,%lx). We subtract (%lx,%lx). After subtraction it is (%lx,%lx). Remainders:(%lx,%lx)", date, time, tb0, tb1, ta0, ta1, secs1984[0], secs1984[1], timebuff[0], timebuff[1], rem0, rem4);
		isecs = timebuff[0]%60;
		asm {
			fild qword ptr timebuff
			fstp secs
		}
		//secs = timebuff[0];
		//DebugPrintf("secs is %f.",secs);
		//goto noutc;
	}*/
	
	//timeAdjustment = ((secs-665329490)*10-(secs-665329490));	//Speed time up by 10x. I added this at 665:329:490, and wanted it to start at the same time and only be 10x after. Sort of. This was for testing the movement of the sun in the sky, etc. (SL)
	
	if (timeAdjustment!=0) {
		secs += timeAdjustment;
		isecs = ((int)secs)%60;
	}
	
	//DebugPrintf("secs = %ul", secs);
	if (p_isecs != isecs) {			      // timing dei fotogrammi
		if (_delay>=10) _delay--;
		p_isecs = isecs;
		gl_fps = fps;
		fps = 1;
	}
	else {					      // frazioni di secondo
		if (gl_fps) secs += (double)fps / (double)gl_fps;
		fsecs = (double)fps / (double)gl_fps;
		fps++;
	}

	epoc = 6011 + secs / 1e9;
}

/* Estrae dalla tabella pseudo, da 74000 miliardi di elementi diversi, le
   informazioni sulla stella che si Š scelta. */

#include "randalg.h"

void extract_ap_target_infos ()
{
	SRAND (ap_target_x/100000*ap_target_y/100000*ap_target_z/100000);
	
	ap_target_class = RANDOM (star_classes);
	//if (ap_target_class!=my_ap_target_class) {
	//	DebugPrintf(1, "Error: ap_target_class = %i, my_ap_target_class = %i", (int)ap_target_class, (int)my_ap_target_class);
	//}
	ap_target_ray = ((float)class_ray[ap_target_class] + (float)RANDOM(class_rayvar[ap_target_class])) * 0.001;
	fprintf(stderr, "ap_target_x(%f) ap_target_y(%f) ap_target_z(%f) class_ray[%i](%i) class_rayvar[%i](%i) ap_target_ray(%f)\n", ap_target_x, ap_target_y, ap_target_z, (int)ap_target_class, (int)class_ray[ap_target_class], (int)ap_target_class, (int)class_rayvar[ap_target_class], (double)ap_target_ray);
	
	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;
}

/* Estrae un numero pseudo-casuale di tipo intero convertendolo a f-p. */

float zrandom (Word range) { return (RANDOM(range) - RANDOM(range)); }

/* Parte della gestione della cartografia.
   E' stata spostata qui perch‚ possa essere chiamata da "prepare_nearstar".
   -------------------------------------------------------------------------
   Cerca un codice d'identificazione (per un pianeta o per una stella)
   nel file di cartografia stellare, e riporta la posizione del record.
   Se il risultato Š -1, il codice non esiste, ovvero non c'Š un nome
   per la stella o per il pianeta che corrisponde a quel codice.
   Type pu• essere: P = Pianeta, S = Stella.
   * usa come buffer di lettura "p_surfacemap". */

FILEPTR	smh;
double	idscale = 0.00001;

#ifdef OLD_STARMAP
Dword search_id_code (double id_code, char type)
{
	Dword     	pos = 4;
	char     	found = 0;
	Uword 	n, ptr, index;

	char maybefar 	*buffer_ascii = (char maybefar *)p_surfacemap;
	double maybefar 	*buffer_double = (double maybefar *)p_surfacemap;

	double		id_low = id_code - idscale;
	double		id_high = id_code + idscale;

	smh = OPENFILE (starmap_file, OPEN_RB);
	if (smh ISFILEVALID) {
		FILESEEK (smh, 4, SEEK_SET);
		while ((n = READFILE (smh, buffer_ascii, ps_bytes)) > 0) {
			ptr = 0;
			index = 0;
			while (ptr < n) {
				if (buffer_ascii[ptr + 29] == type) {
					if (buffer_double[index] > id_low &&
					    buffer_double[index] < id_high) {
						found = 1;
						goto stop;
					}
				}
				pos   += 32;
				ptr   += 32;
				index += 4;
			}
		}
		stop:
		CLOSEFILE (smh);
	}

	if (found)
		return (pos);
	else
		return (-1);
}
#else

Dword fb_real_pos = 0;
Dword fb_pos = 0;
Dword fb_bytes = 0;
Bool fb_endOfFile = 0;
FILE * fb_file = NULL;

//Call this to read from the file into the cache, in preparation for
FastBool fbcache() {
	Uchar * buffer = (Uchar*) p_surfacemap;
	Dword startPos = 0;
	if (fb_pos<fb_bytes) {
		startPos=(fb_bytes-fb_pos);
		//fb_real_pos+=startPos;
		memmove(buffer, &(buffer[fb_pos]), startPos);
	}
	Dword result = fread(&(buffer[startPos]), 1, ps_bytes-startPos, fb_file);
	fb_bytes = result+startPos;
	fb_pos = 0;
	if (result > 0) {
		fb_endOfFile=0;
	} else {
		fb_endOfFile=1;
	}
	return (FastBool) fb_endOfFile;
}

//Call this after opening a file.
void fbopen(FILE * file) {
	fb_pos = 0;
	fb_bytes = 0;
	fb_real_pos = 0;
	fb_file = file;
	fbcache();
}

void fbclose() {
	fclose(fb_file);
	fb_pos = 0;
	fb_bytes = 0;
	fb_real_pos = 0;
	fb_file = NULL;
}
//Returns true if we've reached the end of the file.
FastBool fbeof() {
	return fb_endOfFile;
}

//Returns true if we've reached the end of the cache.
FastBool fbeoc() {
	return (fb_pos >= fb_bytes);
}

//Returns the actual file position corresponding to the current cache position.
Dword fbtell() {
	return fb_real_pos;
}

void fbseek(Dword len, Dword mode) {
	if (mode==SEEK_SET) {
		//discard the buffer, fseek to the proper real pos, and re-cache.
		fseek(fb_file, len, SEEK_SET);
		fb_real_pos=len;
		fb_pos=0;
		fb_bytes=0;
		fbcache();
	} else if (mode==SEEK_END) {
		//discard the buffer, fseek to the proper real pos, and re-cache.
		fseek(fb_file, len, SEEK_END);
		fb_real_pos=ftell(fb_file);
		fb_pos=0;
		fb_bytes=0;
		fbcache();
	} else if (mode==SEEK_CUR) {
		if (len>=0 && len<(fb_bytes-fb_pos)) {
			fb_pos+=len;
			fb_real_pos+=len;
			return;
		} else {
			//discard the buffer, fseek to the proper real pos, and re-cache.
			fb_real_pos+=len;
			fseek(fb_file, fb_real_pos, SEEK_SET);
			fb_pos=0;
			fb_bytes=0;
			fbcache();
		}
	}
}

//Reads from the cache to a variable, like fread.
int fbread(void * var, int size, int amount) {
	Uchar * buffer = (Uchar*) p_surfacemap;
	if (size==0 || amount==0) {
		return 0;
	}
	if (fb_pos>=fb_bytes) {
		if (!fbeof()) {
			fbcache();
		}
		if (fb_pos>=fb_bytes && fbeof()) {
			return 0;
		}
	}
	for (int a=0; a<amount; a++) {
		if (fb_pos+size>fb_bytes) {
			if (!fbeof()) {
				fbcache();
			}
			if (fb_pos+size>fb_bytes && fbeof()) {
				return a+1;
			}
		}
		memcpy(var, &(buffer[fb_pos]), size);
		fb_pos+=size;
		fb_real_pos+=size;
	}
	return amount;
}

Dword find_something_in_starmap (char *tgt_name, Udword tgt_nextAlternateFP, Udword tgt_starFP, FastBool checkCoords, Dword tgt_sx, Dword tgt_sy, Dword tgt_sz, FastBool tgt_deleted, Udword systemNumber, Udword galaxy) {
	FILE * starmap3File;
	if (galaxy==0) {
		starmap3File = fopen(starmap3_file, "rb");
	} else {
		starmap3File = fopen(starmap3b_file, "rb");
	}
	if (starmap3File!=NULL) {
		fbopen(starmap3File);
		Uword fileFormatVersion;
		Udword halfStarmap3Version;
		fbread(&fileFormatVersion, 2, 1);
		fbread(&halfStarmap3Version, 4, 1);
		fbread(&halfStarmap3Version, 4, 1);
		Udword curFPos;
		if (fileFormatVersion>2) {
			printf("starmap3.map is a newer format (%u) than we can understand. You need a new version of NICE.\n", fileFormatVersion);
			printf("Press any key to continue.\n");
			fbclose();
			Pause();
			return -1;
		} else {
			Uchar flags;
			Udword discoverer;
			char name[20];
			Dword sx, sy, sz;
			Uword data;
			Udword nextAlternateFP;
			Udword starFP;
			Udword sysNum = 0;
			//int stillZero=1;
			while (!fbeof()) {
				curFPos = fbtell();
				fbread(&flags, 1, 1);
				fbread(&discoverer, 4, 1);
				fbread(&name, 20, 1);
				FastBool validDeleted = (flags&0x20)==0x20;
				if (tgt_deleted==False) {
					validDeleted = 1-validDeleted;
				}
				
				/*if (curFPos>=0x34a3c && curFPos<0x34a7c) {
					//DebugPrintf(0, "For curFPos=%lx, flags=%i, discoverer=%lx, name=%.20s", curFPos, flags, discoverer, name);
				}*/
				
				if (validDeleted && tgt_name!=NULL && memcmp(tgt_name, name, 20)==0) {
					fbclose();
					return curFPos;
				}
				
				if (flags&0x8) {	//star
					fbread(&sx, 4, 1);
					fbread(&sy, 4, 1);
					fbread(&sz, 4, 1);
					fbread(&data, 2, 1);
					fbread(&nextAlternateFP, 4, 1);
					if (systemNumber>0) {
						sysNum++;
						if (sysNum==systemNumber) {
							fbclose();
							return curFPos;
						}
					}
					if (validDeleted) {
						if (tgt_nextAlternateFP!=0) {
							if (nextAlternateFP==tgt_nextAlternateFP) {
								fbclose();
								return curFPos;
							}
						} else if (checkCoords && sx==tgt_sx && sy==tgt_sy && sz==tgt_sz) {
							fbclose();
							return curFPos;
						}
					}
				} else {
					fbread(&starFP, 4, 1);
					fbread(&data, 2, 1);
					fbread(&nextAlternateFP, 4, 1);
					if (validDeleted) {
						if (tgt_nextAlternateFP!=0) {
							if (nextAlternateFP==tgt_nextAlternateFP) {
								fbclose();
								return curFPos;
							}
						}
						if (tgt_starFP!=0) {
							if (starFP==tgt_starFP) {
								fbclose();
								return curFPos;
							}
						}
					}
				}
			}
		}
	}
	fbclose();
	return -1;
}
//Check to see if the system is labelled.
Dword system_labelled (Dword tgt_sx, Dword tgt_sy, Dword tgt_sz, Udword galaxy) {
	return find_something_in_starmap(NULL, 0, 0, True, tgt_sx, tgt_sy, tgt_sz, False, 0, galaxy);
}
Dword deleted_system_labelled (Dword tgt_sx, Dword tgt_sy, Dword tgt_sz, Udword galaxy) {
	return find_something_in_starmap(NULL, 0, 0, True, tgt_sx, tgt_sy, tgt_sz, True, 0, galaxy);
}
Dword something_labelled (char *tgt_name, Udword galaxy) {
	return find_something_in_starmap(tgt_name, 0, 0, False, 0, 0, 0, False, 0, galaxy);
}
Dword something_pointing_alt_to (Udword tgt_nextAlternateFP, Udword galaxy) {
	return find_something_in_starmap(NULL, tgt_nextAlternateFP, 0, False, 0, 0, 0, False, 0, galaxy);
}
Dword something_pointing_star_to (Udword tgt_starFP, Udword galaxy) {
	return find_something_in_starmap(NULL, 0, tgt_starFP, False, 0, 0, 0, False, 0, galaxy);
}
Dword labelled_system_number (Udword num, Udword galaxy) {
	return find_something_in_starmap(NULL, 0, 0, False, 0, 0, 0, False, num, galaxy);
}
//Check to see if the planet/moon is labelled.

Dword planets_labelled (Udword tgt_starFP, Udword galaxy) {
	if (tgt_starFP==-1) {
		return 0;
	}
	Dword retval = 0;
	
	FILE * starmap3File;
	if (galaxy==0) {
		starmap3File = fopen(starmap3_file, "rb");
	} else {
		starmap3File = fopen(starmap3b_file, "rb");
	}
	if (starmap3File!=NULL) {
		fbopen(starmap3File);
		Uword fileFormatVersion;
		Udword halfStarmap3Version;
		fbread(&fileFormatVersion, 2, 1);
		fbread(&halfStarmap3Version, 4, 1);
		fbread(&halfStarmap3Version, 4, 1);
		if (fileFormatVersion>2) {
			printf("starmap3.map is a newer format (%u) than we can understand. You need a new version of NICE.\n", fileFormatVersion);
			printf("Press any key to continue.\n");
			Pause();
			fbclose();
			return -1;
		} else {
			Uchar flags;
			Udword discoverer;
			char name[20];
			Uword data;
			Udword nextAlternateFP;
			Udword starFP;
			//int stillZero=1;
			while (!fbeof()) {
				fbread(&flags, 1, 1);
				if (flags&0x8) {	//star
					fbseek(42, SEEK_CUR);
					//We don't do anything with star entries.
				} else {
					fbread(&discoverer, 4, 1);
					fbread(&name, 20, 1);
					fbread(&starFP, 4, 1);
					fbread(&data, 2, 1);
					fbread(&nextAlternateFP, 4, 1);
					if (!(flags&0x20) && starFP==tgt_starFP) {
						retval++;
					}
				}
			}
			fbclose();
		}
	}
	return retval;
}
Dword planet_labelled (Udword tgt_starFP, Dword bodyNum, Dword owner, Dword moonId, Dword pType, FastBool tgt_deleted, Udword galaxy) {
	if (tgt_starFP==-1) {
		return -1;
	}
	Uword tgt_data;
	//Dword wantedPlanet;
	//Dword wantedMoon;
	if (owner==-1) {	//planet, not moon
		//wantedPlanet=bodyNum;
		//wantedMoon=0x1F;
		tgt_data = (pType) + (bodyNum<<4) + 0x3E00;//(0x1F<<9);
	} else {
		//wantedPlanet=owner;
		//wantedMoon=moonId;
		tgt_data = (pType) + (owner<<4) + (moonId<<9);
	}
	
	
	FILE * starmap3File;
	if (galaxy==0) {
		starmap3File = fopen(starmap3_file, "rb");
	} else {
		starmap3File = fopen(starmap3b_file, "rb");
	}
	if (starmap3File!=NULL) {
		fbopen(starmap3File);
		Uword fileFormatVersion;
		Udword halfStarmap3Version;
		fbread(&fileFormatVersion, 2, 1);
		fbread(&halfStarmap3Version, 4, 1);
		fbread(&halfStarmap3Version, 4, 1);
		if (fileFormatVersion>2) {
			printf("starmap3.map is a newer format (%u) than we can understand. You need a new version of NICE.\n", fileFormatVersion);
			printf("Press any key to continue.\n");
			Pause();
			fbclose();
			return -1;
		} else {
			Uchar flags;
			Udword discoverer;
			char name[20];
			Uword data;
			Udword nextAlternateFP;
			Udword starFP;
			//int stillZero=1;
			while (!fbeof()) {
				fbread(&flags, 1, 1);
				if (flags&0x8) {	//star
					fbseek(42, SEEK_CUR);
					//We don't do anything with star entries.
				} else {
					fbread(&discoverer, 4, 1);
					fbread(&name, 20, 1);
					fbread(&starFP, 4, 1);
					fbread(&data, 2, 1);
					fbread(&nextAlternateFP, 4, 1);
					FastBool validDeleted = flags&0x20;
					if (!tgt_deleted) validDeleted = !validDeleted;
					if (validDeleted && data==tgt_data && starFP==tgt_starFP) {
						Udword pos = fbtell()-35;
						fbclose();
						//DebugPrintf(0,"Found it: pos=%llu",pos);
						return pos;
					}
				}
			}
			fbclose();
		}
	}
	return -1;
}
#endif

/* Prepara le informazioni sulla stella vicina, quella attorno alla quale
   ci si trover…: tra l'altro, prepara i pianeti estraendoli dalla
   tabella pseudo. */

Word starnop (double star_x, double star_y, double star_z)
// stima il numero di pianeti maggiori associato alle coord. di una stella
{
	Word r;
	#ifdef WINDOWS
	r = NewGalaxy_ap_target_starnop();
	if (r!=-1) {
		r += RANDOM (2);
		r -= RANDOM (2);
		if (r < 0) r = 0;
		return r;
	}
	#endif
	SRAND ((Dword)star_x%10000*(Dword)star_y%10000*(Dword)star_z%10000);
	r = RANDOM (class_planets[ap_target_class] + 1);
	//Apparently this is supposed to make the estimate not-always-accurate.
	//I've disabled the inaccuracy for the star whose system you're in. (SL)
	//Well, the disabling didn't really work, so I'll leave this alone for now. (SL)
	//if (!ap_reached || star_x != nearstar_x || star_y == nearstar_y || star_z != nearstar_z) {
		r += RANDOM (2);
		r -= RANDOM (2);
		if (r < 0) r = 0;
	//}
	return (r);
}

void prepare_nearstar (FastBool option)
{
	//DebugPrintf(0, "Beginning of prepare_nearstar. Clock: %li.", clock());
	#ifdef WINDOWS
	if (NewGalaxy_prepare_nearstar(option)) {
		CheckForAndPlaceGates();
		return;
	}
	#endif
	
	Word    n, c, q, r, s, t;
	double key_radius;
	
	//For new temperature stuff (SL)
	nearstar_mass = -1;
	nearstar_surfaceTemperature = -1;
	nearstar_temperatureTransmission =-1;
	
	//Commenting this out might or might not cause problems - not sure yet. (SL)
	//if (!_delay) {
	//DebugPrintf(0, "A Clock: %li.", clock());
	#ifndef OLD_STARMAP
	if (ap_target_sx==0x7FFFFFFF && ap_target_sy==0x7FFFFFFF && ap_target_sz==0x7FFFFFFF) {
		//DebugPrintf(0, "SecCoords Unknown #1 in prepare_nearstar!");
		//Sector coords unknown; find them!
		Dword retval = getSectorCoords(ap_target_x, ap_target_y, ap_target_z, &ap_target_sx, &ap_target_sy, &ap_target_sz);
		if (retval==-1) {
			if (charge!=0) status ("ACK! CAN'T FIND SYSTEM", 200);
			disableR9aBugMessage();
		} else if (retval==-2) {
			enableR9aBugMessage();
		} else {
			disableR9aBugMessage();
		}
	} else {
		disableR9aBugMessage();
	}
	//DebugPrintf(0, "B Clock: %li.", clock());
	#endif
	if (option==COPY_NEARSTAR_FROM_AP_TARGET) {
		nearstar_class = ap_target_class;
		nearstar_x = ap_target_x;
		nearstar_y = ap_target_y;
		nearstar_z = ap_target_z;
		nearstar_sx = ap_target_sx;
		nearstar_sy = ap_target_sy;
		nearstar_sz = ap_target_sz;
		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;
	//}
	}
	//DebugPrintf(0, "C Clock: %li.", clock());
	#ifndef OLD_STARMAP
	if (ap_reached && nearstar_sx==0x7FFFFFFF && nearstar_sy==0x7FFFFFFF && nearstar_sz==0x7FFFFFFF) {
		//Sector coords unknown; find them!
		//DebugPrintf(0, "SecCoords Unknown #2 in prepare_nearstar!");
		Dword retval = getSectorCoords(nearstar_x, nearstar_y, nearstar_z, &nearstar_sx, &nearstar_sy, &nearstar_sz);
		if (retval==-1) {
			if (charge!=0) status ("ACK! CAN'T FIND SYSTEM", 200);
		} else if (retval==-2) {
			enableR9aBugMessage();
		}
	}
	#endif
	//DebugPrintf(0, "D Clock: %li.", clock());
	
	s_m = qt_M_PI * nearstar_ray * nearstar_ray * nearstar_ray * 0.01e-7;

	nearstar_identity = nearstar_x/100000*nearstar_y/100000*nearstar_z/100000;
	//DebugPrintf(0, "E Clock: %li.", clock());
	
	SRAND ((Dword)nearstar_x%10000*(Dword)nearstar_y%10000*(Dword)nearstar_z%10000);

	nearstar_nop = RANDOM (class_planets[nearstar_class] + 1);
	//DebugPrintf(0, "F Clock: %li.", clock());
	
	/* Prima estrazione (pressoch‚ casuale, non realistica). */

	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;
	}
	//DebugPrintf(0, "G Clock: %li.", clock());
	
	/* Aumento delle probabilit… di pianeti abitabili su classe zero. */

	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;
	}
	//DebugPrintf(0, "H Clock: %li.", clock());
	
	/* Eliminazione di pianeti impossibili attorno a certe stelle.
	   Fase 1: solo quelli impossibili per tipo di stella. */

	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);
		}
	}
	//DebugPrintf(0, "I Clock: %li.", clock());
	
	/* Eliminazione di pianeti impossibili attorno a certe stelle.
	   Fase 2: solo quelli impossibili per distanza dalla stella. */

	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;
		}
	}
	//DebugPrintf(0, "J Clock: %li.", clock());
	
	/* Estrazione dei satelliti naturali (lune). */
	
	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 > fg_maxbodies)
			t = fg_maxbodies - nearstar_nob;
		// Caratteristiche dei satelliti.
		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);
			// Estrazione tipologia di satellite:
			r = nearstar_p_type[q];
			// Un oggetto substellare come luna?
			// Ce lo pu• avere solo una stella compagna.
			if (r==9 && s != 10) r = 2;
			// Un gigante gassoso come luna?
			// Ce lo pu• avere solo un oggetto substellare,
			// o una stella compagna in un sistema multiplo.
			if (r==6 && s < 9) r = 5;
			// "Raffreddamento" satelliti esterni, lontani sia
			// dal pianeta che dalla stella, in genere congelati.
			if (n > 7 && RANDOM(c)) r = 7;
			if (n > 9 && RANDOM(c)) r = 7;
			// Lune relativamente grandi possono esistere solo
			// attorno a pianeti gassosi ed oggetti substellari.
			// Invece, i simil-lunari(1), i simil-marziani(5),
			// le lune come Io(0), e quelle come Europa(7),
			// possono esistere anche attorno ad altri tipi di
			// pianeti, ma di certo in scala piuttosto ridotta.
			if (r==2 || r==3 || r==4 || r==8) {
				if (s != 6 && s < 9)
					r = 1;
			}
			// Attorno ai giganti gassosi, se il test precedente
			// Š passato (s = 6/9/10, gassoso/substellare/stella),
			// bŠ, possono anche esserci, a certe condizioni,
			// delle lune abitabili. Per queste, per•, la stella
			// dev'essere in genere di classe zero ed il pianeta
			// gigante non dev'essere troppo lontano dalla stella.
			// C'Š invece uguale probabilit… di trovare mondi
			// abitabili attorno agli oggetti substellari: al di
			// l… della distanza dalla stella, tali lune possono
			// essere scaldate abbastanza da una stella mancata.
			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;
			}
			// Una luna ghiacciata Š esclusa, prima di arrivare
			// almeno alla sesta orbita planetaria, perch‚ fa
			// comunque troppo caldo.
			if (r==7 && n <= 5) r = 1;
			// Ma lune ghiacciate sono comunque molto pi—
			// frequenti se la stella Š molto piccola e fredda:
			// un pianeta in genere pu• avere meccanismi interni
			// che lo scaldano. Una luna no.
			if ((nearstar_class==2||nearstar_class==5||
			     nearstar_class==7||nearstar_class==11)
			     && RANDOM(n)) r = 7;
			// Fine estrazione tipologia di satellite.
			nearstar_p_type[q] = r;
		}
		nearstar_nob += t;
	}

	/* Ri-Normalizzazione delle dimensioni dei pianeti,
	   normalizzazione delle orbite in base al principio di Keplero.
	   Il principio di Keplero stabilisce che il raggio dell'orbita di
	   un pianeta tende ad essere simile alla sommatoria dei raggi delle
	   orbite di tutti i pianeti interni ad esso. Per•, per un numero di
	   pianeti maggiore di 8, il principio non Š pi— valido. Noctis
	   rinormalizza le orbite oltre l'ottava, aggiungendo a tali orbite
	   il 22% circa della sommatoria delle precedenti. Ovvero:

	   SE si applica il principio di Keplero
	   per (ad esempio) 12 pianeti, e per Raggio Prima Orbita = 1,
	   allora i raggi delle altre orbite sarebbero:
	   *	1  2  3  6  12  24  48  96  192  384  768  1536

	   SE si applica l'organizzazione di Noctis, il tutto diventerebbe:
	   *	1  2  3  6  12  24  48  96  117  143  174  212

	   Il 22% non Š un valore a caso: rappresenta all'incirca il rapporto
	   fra i raggi delle orbite di Plutone e di Urano. Plutone Š circa del
	   22% pi— lontano dal Sole di Urano, cioŠ l'ottava orbita. Ovvio che
	   non significa che un sistema planetario pi— vasto debba per forza
	   avere orbite organizzate in questo modo, anche perch‚ Plutone non
	   Š certo un pianeta "naturalmente" formatosi assieme agli altri, ma
	   pi— probabilmente un satellite sfuggito o un corpo della nube di
	   Oort catturato dal Sole. Per• bisogna dire che le influenze delle
	   orbite dei pianeti interni, col proseguire della successione di
	   Keplero, diventano sempre meno significative. Penso che tale
	   successione, semplicemente, debba essere in qualche modo limitata,
	   a un certo punto: Š improbabile che ci siano pianeti in orbita
	   stabile a distanze come quelle risultanti per le orbite oltre
	   l'ottava. Noctis annovera anche stelle con ben 20 pianeti!

	   Come ultima annotazione, il raggio delle orbite Š influenzato
	   anche dalla massa dei pianeti. Pianeti che hanno all'interno delle
	   loro orbite giganti gassosi saranno un po' pi— lontani della media
	   perch‚ altrimenti le loro orbite potrebbero essere troppo
	   destabilizzate dalla massa dei giganti. */

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];
	}

	/* Ri-Normalizzazione delle dimensioni delle lune,
	   normalizzazione orbite lunari in base al principio di Keplero,
	   a sua volta rielaborato come nelle precedenti annotazioni,
	   solo che la limitazione avviene per orbite oltre la terza al 12%,
	   ed Š molto pi— effettiva oltre l'ottava orbita (al 2.5%). */
	//DebugPrintf(0, "K Clock: %li.", clock());
	
	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++;
		}
	}
	//DebugPrintf(0, "L Clock: %li.", clock());
	
	/* Eliminazione di anelli improbabili. */

	for (n = 0; n < nearstar_nop; n++) {
		// A meno di un raggio e mezzo dal centro del pianeta,
		// sar… un po' difficile trovarci un anello stabile.
		nearstar_p_ring[n] = 0.75 * nearstar_p_ray[n] * (2 + RANDOM(3));
		// I pianeti piccoli raramente hanno degli anelli.
		// Non hanno abbastanza massa per frantumare
		// una luna che arrivi troppo vicina.
		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;
		}
	}
	//DebugPrintf(0, "M Clock: %li.", clock());
	
	/* Conteggio degli oggetti che hanno un nome (suggerimento di Ryan) */

	nearstar_labeled = 0;
	#ifdef OLD_STARMAP
	for (n = 1; n <= nearstar_nob; n++) {
		if (search_id_code (nearstar_identity + n, 'P') != -1)
			nearstar_labeled++;
	}
	#else
	#ifdef WINDOWS
	Udword tgt_starFP = system_labelled(nearstar_sx, nearstar_sy, nearstar_sz, current_galaxy);
	#else
	Udword tgt_starFP = system_labelled(nearstar_sx, nearstar_sy, nearstar_sz);
	#endif
	/*for (n=0; n<nearstar_nob; n++) {
		//DebugPrintf(0, "N[%i] Clock: %li.", (int)n, clock());
		if (planet_labelled (tgt_starFP, n, nearstar_p_owner[n], nearstar_p_moonid[n], nearstar_p_type[n], False) != -1)
			nearstar_labeled++;
	}*/
	#ifdef WINDOWS
	nearstar_labeled=planets_labelled(tgt_starFP, current_galaxy);
	#else
	nearstar_labeled=planets_labelled(tgt_starFP);
	#endif
	#endif
	//DebugPrintf(0, "O Clock: %li.", clock());
	/* Reset dei periodi di rotazione
	   (vengono calcolati con la superficie) */

	for (n = 0; n < nearstar_nob; n++) {
		nearstar_p_rtperiod[n] = 0;
	}
	//DebugPrintf(0, "P Clock: %li.", clock());
	#ifdef WINDOWS
	CheckForAndPlaceGates();
	#endif
}

/* Smussa la superficie di un pianeta: media 4x4 rapida. */

void ssmooth (Uchar maybefar *target)
{
	asm {
		#ifdef WINDOWS
		pushad
		#else
		pusha
		push es
		#endif
		mov MAYBE_ECX, QUADWORDS
		shl MAYBE_ECX, 2
		#ifdef WINDOWS
		and ecx, 0xffff
		#endif
		mov MAYBE_EAX, 360
		shl MAYBE_EAX, 2
		#ifdef WINDOWS
		and eax, 0xffff
		#endif
		sub MAYBE_ECX, MAYBE_EAX
		#ifdef WINDOWS
		and ecx, 0xffff
		#endif
		#ifdef WINDOWS
		mov edi, [target]
		#else
		les di, dword ptr target
		#endif
		add di, 360
	}
smooth: asm {
		#ifdef WINDOWS
		mov edx, [edi-360]
		add edx, [edi]
		add edx, [edi+360]
		add edx, [edi+720]
		and edx, 0xFCFCFCFC //0b11111100111111001111110011111100
		shr edx, 2
		#else
		db 0x66; mov dx, es:[di-360]
		db 0x66; add dx, es:[di]
		db 0x66; add dx, es:[di+360]
		db 0x66; add dx, es:[di+720]
		/* and edx, 11111100111111001111110011111100b */
		db 0x66, 0x81, 0xE2, 0xFC, 0xFC, 0xFC, 0xFC
		db 0x66; shr dx, 2
		
		#endif
		mov al, dl
		add al, dh
		SHR_EDX_16
		add al, dl
		add al, dh
		shr al, 2
		#ifdef WINDOWS
		mov [edi], al
		inc edi
		#else
		mov es:[di], al
		inc di
		#endif
		dec MAYBE_ECX
		jnz smooth
		#ifndef WINDOWS
		pop es
		#endif
		#ifdef WINDOWS
		popad
		#else
		popa
		#endif
		}
}

/* Smussa leggermente la superficie di un pianeta: media 2x2. */

void lssmooth (Uchar maybefar *target)
{
	asm {
		pushad
		//push es
		mov ecx, QUADWORDS
		sub ecx, 90
		shl ecx, 2
		and ecx, 0xffff
		mov edi, [target] }
smooth: asm {	mov dx, [edi]
		mov al, dl
		and dx, 0b0011111100111111
		mov bx, [edi+360]
		add dl, dh
		and bx, 0b0011111100111111
		add dl, bl
		and al, 0b11000000
		add dl, bh
		shr dl, 2
		or al, dl
		mov [edi], al
		inc edi
		dec cx
		jnz smooth
		//pop es
		popad
	}		
	
	/*asm {
		#ifdef WINDOWS
		pushad
		#else
		pusha
		push es
		#endif
		mov MAYBE_ECX, QUADWORDS
		sub MAYBE_ECX, 90	//80	//Fixed buffer overflow (SL)
		shl MAYBE_ECX, 2
		#ifdef WINDOWS
		mov edi, [target]
		#else
		les di, dword ptr target
		#endif
		}
smooth: asm {
		#ifdef WINDOWS
		mov dx, [edi]
		#else
		mov dx, es:[di]
		#endif
		mov al, dl
		#ifdef WINDOWS
		and dx, 0x3F3F
		mov bx, [edi+360]
		#else
		and dx, 0011111100111111b
		mov bx, es:[di+360]
		#endif
		add dl, dh
		#ifdef WINDOWS
		and dx, 0x3F3F
		#else
		and bx, 0011111100111111b
		#endif
		
		add dl, bl
		#ifdef WINDOWS
		and al, 0xC0
		#else
		and al, 11000000b
		#endif
		add dl, bh
		shr dl, 2
		or al, dl
		#ifdef WINDOWS
		mov [edi], al
		inc edi
		#else
		mov es:[di], al
		inc di
		#endif
		dec MAYBE_ECX
		jnz smooth
		#ifndef WINDOWS
		pop es
		#endif
		#ifdef WINDOWS
		popad
		#else
		popa
		#endif
		}*/
}


Word     c, gr, r, g, b, Acr, Acx, Acy;
float    a, kfract = 2;
char     lave, crays;
#ifdef WINDOWS
Udword    px, py;
#else
Uword    px, py;
#endif

/*

	Funzioni modulari per particolareggiare le superfici.
	Chiamate solo da surface. I parametri vengono passati nelle
	variabili all'uopo adibite: c, gr, r, g, b, cr, cx, cy, lave,
	crays, px, py, ed a.

	kfract Š la densit… delle fratture sui pianeti.
	viene posta a 1 per fare i fulmini nel cielo.

	Alcune ne chiamano altre, dello stesso gruppo, per risparmiare sui
	ritornelli di codice ripetuto. I pianeti particolarissimi non le
	usano, o comunque non usano solo queste.

	Lavorano tutte su p_background anche se, al momento della definizione
	della superficie di una luna, p_background verr… scambiato con
	s_background, che inizialmente Š la mappa della superficie stellare.
	Il fatto Š che da una luna Š probabile vedere il pianeta attorno al
	quale quella data luna sta girando, quindi bisogna mantenere separate
	la mappa planetaria e quella lunare. Non ci si preoccupa, invece, di
	avere pi— di due corpi visibili, perch‚:

		- il primo e il secondo pianeta di qualsiasi stella non
		  possono, per convenzione, avere lune; d'altra parte, dal
		  terzo pianeta in poi la superficie stellare non Š visibile
		  nei dettagli, e pu• essere approssimata da un "whiteglobe",
		  un globo bianco in tinta unita.
		- le lune visibili da un'altra luna appaiono sempre piuttosto
		  piccole, per cui non Š possibile scorgere i dettagli della
		  superficie di una luna dal punto di vista di un'altra.

	Infine, le stesse considerazioni sulle mappe delle superfici,
	valgono per le mappe dei colori: la mappa dei colori della stella
	viene usata per conservare quella delle lune.

*/

void spot () // una piccola macchia chiara sulla superficie.
{
	asm {
		#ifdef WINDOWS
		push edi
		mov edi, [p_background]
		add edi, py
		add edi, px
		mov al, [edi]
		#else
		les di, dword ptr p_background
		add di, py
		add di, px
		mov al, es:[di]
		#endif
		add al, byte ptr gr
		cmp al, 0x3E
		jb minA
		mov al, 0x3E }
   minA: 
   		#ifdef WINDOWS
   		asm		mov [edi], al
		asm pop edi
   		#else
   		asm 	mov es:[di], al
   		#endif
}

void permanent_storm () // tempesta permanente (una macchia colossale).
{
	for (g=1; g<Acr; g++) {
		for (a=0; a<2*M_PI; a+=4*deg) {
			px = Acx + g * cos (a);
			py = Acy + g * sin (a);
			py *= 360;
			spot ();
		}
	}
}

void crater () // un cratere.
{
	for (a=0; a<2*M_PI; a+=4*deg) {
		for (gr=0; gr<Acr; gr++) {
			px = Acx + cos (a) * gr;
			py = Acy + sin (a) * gr;
			vptr = px + 360*py;
			asm {
				#ifdef WINDOWS
				push edi
				mov edi, [p_background]
				add edi, vptr
				mov al, [edi]
				#else
				les di, dword ptr p_background
				add di, vptr
				mov al, es:[di]
				#endif
				mov ah, byte ptr gr
				mov cl, lave
				shr ah, cl
				sub al, ah
				jnc entro
				xor al, al }
		entro:
				#ifdef WINDOWS
				asm  	mov [edi], al
				asm pop edi
				#else
				asm  	mov es:[di], al
				#endif
		}
		asm {
			#ifdef WINDOWS
			push edi
			mov edi, [p_background]
			add edi, vptr
			#else
			les di, dword ptr p_background
			add di, vptr
			#endif
			mov ax, 0x013E
			#ifdef WINDOWS
			mov [edi], ax
			pop edi
			#else
			mov es:[di], ax
			#endif
		}
		if (crays&&!RANDOM(crays)) {
			b = (2+RANDOM(2)) * Acr;
			if (Acy-b>0&&Acy+b<179) {
				for (gr=Acr+1; gr<b; gr++) {
					px = Acx + cos (a) * gr;
					py = Acy + sin (a) * gr;
					vptr = px + 360*py;
					asm {
						#ifdef WINDOWS
						push edi
						mov edi, [p_background]
						add edi, vptr
						mov al, [edi]
						#else
						les di, dword ptr p_background
						add di, vptr
						mov al, es:[di]
						#endif
						mov ah, byte ptr Acr
						add al, ah
						cmp al, 0x3E
						jb entro2
						mov al, 0x3E }
				entro2:
						#ifdef WINDOWS
						asm		mov [edi], al
						asm pop edi
						#else
						asm 	mov es:[di], al
						#endif
				}
			}
		}
	}
}

void band () /* banda scura orizzontale: pu• essere portata al chiaro
		negando la superficie sulla base del fondo scala 0x3E */
{
	asm {
		#ifdef WINDOWS
		push edi
		mov edi, [p_background]
		add edi, py
		#else
		les di, dword ptr p_background
		add di, py
		#endif
		mov cx, Acr
		mov ah, byte ptr g }
nvrain: asm {
		#ifdef WINDOWS
		mov al, [edi]
		#else
		mov al, es:[di]
		#endif
		sub al, ah
		jnc minA
		xor al, al }
   minA: asm {
   		#ifdef WINDOWS
		mov [edi], al
		add edi, 1
		#else
		mov es:[di], al
		inc di
		#endif
		dec cx
		jnz nvrain
		#ifdef WINDOWS
		pop edi
		#endif
	   }
}

void wave () // Una banda come sopra, per• ondulata.
{
	asm {
		#ifdef WINDOWS
		pushad
		mov edi, [p_background]
		#else
		les di, dword ptr p_background
		#endif
		mov px, 360
		MOVSX_MAYBE_EBX, Acy }
nvrain: asm {	fild px
		fmul a
		#ifdef WINDOWS
		fsin
		#else
		db 0xd9, 0xfe // fsin
		#endif
		fild Acr
		fmulp
		fistp py
		add py, MAYBE_EBX
		mov MAYBE_EAX, py
		mov MAYBE_EDX, 360
		mul MAYBE_EDX
		add MAYBE_EAX, 4
		#ifdef WINDOWS
		mov esi, eax
		add esi, px
		mov byte ptr [edi+esi], 0
		#else
		mov di, ax
		add di, px
		mov byte ptr es:[di], 0
		#endif
		dec px
		jnz nvrain
		#ifdef WINDOWS
		popad
		#endif
		}
}

void fracture (Uchar maybefar *target, float max_latitude)
{ // solco scuro: tipo le linee su Europa.
  // ha dei parametri perch‚ viene usata anche per simulare i fulmini
  // quando piove sulla superficie dei pianeti abitabili.
	a = RANDOM (360) * deg;
	gr ++;

	float px = Acx;
	float py = Acy;

	do {
		a += (RANDOM (g) - RANDOM (g)) * deg;
		px += kfract * cos(a);
		if (px>359) px -= 360;
		if (px<0) px += 360;
		py += kfract * sin(a);
		if (py>max_latitude-1) py -= max_latitude;
		if (py<0) py += max_latitude;
		vptr = px + 360 * (Uword)py;
		target[vptr] >>= (Uchar) b;
	gr--; } while (gr);
}

void volcano () // un krakatoa volcano con Gedeone il gigante coglione.
{
	for (a=0; a<2*M_PI; a+=4*deg) {
		b = gr;
		for (g=Acr/2; g<Acr; g++) {
			px = Acx + cos (a) * g;
			py = Acy + sin (a) * g;
			py *= 360;
			spot ();
			gr--;
			if (gr<0) gr = 0;
		}
		gr = b;
	}
}

void contrast (float kt, float kq, float thrshld)
{
	Uword c;

	for (c=0; c<64800; c++) {
		a = p_background[c];
		a -= thrshld;
		if (a>0)
			a *= kt;
		else
			a *= kq;
		a += thrshld;
		if (a<0) a = 0;
		if (a>63) a = 63;
		p_background[c] = a;
	}
}

void randoface (Word range, Word upon)
{
	Uword c;

	for (c=0; c<64800; c++) {
		gr = p_background[c];
		if ((upon>0&&gr>=upon)||(upon<0&&gr<=-upon)) {
			gr += RANDOM (range);
			gr -= RANDOM (range);
			if (gr>63) gr = 63;
			if (gr<0) gr = 0;
			p_background[c] = gr;
		}
	}
}

void negate ()
{
	asm {
		#ifdef WINDOWS
		push edi
		mov edi, p_background
		#else
		les di, p_background
		#endif
		mov cx, 64800 }
negat:	asm {	mov al, 0x3E
		#ifdef WINDOWS
		sub al, [edi]
		mov [edi], al
		add edi, 1
		#else
		sub al, es:[di]
		mov es:[di], al
		inc di
		#endif
		dec cx
		jnz negat }
		#ifdef WINDOWS
		asm pop edi
		#endif
}

void crater_juice ()
{
	lave = RANDOM (3);
	crays = RANDOM (3) * 2;
	for (c=0; c<r; c++) {
		Acx = RANDOM (360);
		Acr = 2 + RANDOM (1+r-c);
		while (Acr>20) Acr -= 10;
		Acy = RANDOM (178 - 2*Acr) + Acr;
		crater ();
		if (Acr>15) lssmooth (p_background);
	}
}

/* Funzioni di mappatura dell'atmosfera.
   Lavorano come le precedenti, ma lavorano su "objectschart"
   piuttosto che su "p_background", e a risoluzione dimezzata.
   Inoltre, MOLTO IMPORTANTE, il campo d'esistenza dell'albedo
   delle nubi non va da 0 a 0x3E ovvero da 0 a 62, MA da 0 a 0x1F,
   ovvero da 0 a 31. Questo perch‚, al momento della discesa sulla
   superficie, l'albedo media di p_background viene usata per
   determinare, sui pianeti abitabili, qualora lo scenario Š
   oceanico o no (se si scende in mare, si deve sempre trovare
   il mare). Dato che l'albedo di p_background Š alterata da
   quella delle nubi contenuta in objectschart, essa viene
   ripristinata al momento della scelta del luogo di sbarco,
   dalla funzione "planets", SOTTRAENDO l'albedo delle nubi
   a quella della superficie di sbarco di p_background.
   Se per•, si lascia l'alterazione dovuta alle nubi, alterare
   l'albedo del territorio sottostante di oltre la met… del campo
   d'esistenza 0..62, si rischia di sottrarre un valore troppo alto
   e di ricondurre l'albedo che viene calcolata sotto al limite che
   determina quando lo scenario Š oceanico (i mari hanno l'albedo pi—
   bassa in assoluto). Il risultato sarebbe che una zona normalmente
   coperta di terra, al passaggio di una grossa nube diventerebbe mare. */

void cirrus () // una piccola macchia chiara (nube brillante).
{
	asm {
		#ifdef WINDOWS
   		push edi
		push ebx
		mov edi, dword ptr objectschart
   		mov ebx, py
		add ebx, px
		shr ebx, 1
		mov al, [ebx+edi]
   		#else
   		les di, dword ptr objectschart
		mov bx, py
		add bx, px
		shr bx, 1
		mov al, es:[bx+di]
		#endif
		add al, byte ptr gr
		cmp al, 0x1F
		jb minA
		mov al, 0x1F }
   minA:
   		#ifdef WINDOWS
   		asm		mov [ebx+edi], al
   		asm pop ebx
		asm pop edi
		#else
   		asm 	mov es:[bx+di], al
   		#endif
}

void atm_cyclon () // ciclone atmosferico: un'ammasso di nubi a spirale.
{
	b = 0;
	while (Acr>0) {
		px = Acx + Acr * cos (a);
		py = Acy + Acr * sin (a);
		py *= 360; cirrus ();
		px += RANDOM(4); cirrus ();
		py += 359; cirrus ();
		px -= RANDOM(4); cirrus ();
		py += 361; cirrus ();
		px += RANDOM(4); cirrus ();
		b++; b %= g;
		if (!b) Acr--;
		a += 6 * deg;
	}
}

void storm () // tempesta (una grande macchia chiara sull'atmosfera).
{
	for (g=1; g<Acr; g++) {
		for (a=0; a<2*M_PI; a+=4*deg) {
			px = Acx + g * cos (a);
			py = Acy + g * sin (a);
			py *= 360;
			cirrus ();
		}
	}
}

/* Calcola la superficie estrapolandola dai dati sul pianeta e dalla
   tabella pseudo-casuale assegnatagli.
   Include il terminatore giorno-notte scurendo l'emisfero notturno
   per un angolo di 130ř, non di 180ř per via della luce diffusa e del
   campo ridotto ai bordi dei globi.
   "colorbase" viene assegnato a 192 per i pianeti, a 128 per le lune. */

   extern char nightisoff;

void surface (Word logical_id, Word type,
	      double seedval, Uchar colorbase)
{
	#ifdef WINDOWS
	Dword			plwp;
	Dword 			QW = QUADWORDS;
	#else
	Word			plwp;
	Word 			QW = QUADWORDS;
	#endif
	Uword 		seed;
	char 			knot1 = 0, brt;
	float 			r1, r2, r3, g1, g2, g3, b1, b2, b3;
	Uchar maybefar 	*overlay = (Uchar maybefar *)objectschart;

	if (type == 10) return; // stella compagna: ha superficie stellare...

	/* impostazione del periodo di rotazione
	   "rotation" marca un punto ideale che rappresenta
	   l'attuale rotazione del pianeta, in gradi, fra 0 e 359.
	   il periodo di rotazione Š estratto in un range molto ampio,
	   con risoluzione di 1 secondo. */

	//fprintf(stderr, "seedval for planet %i is %f\n", (int)logical_id, (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. */

	nearstar_p_rtperiod[logical_id] = 10 * (ranged_fast_random(50) + 1)
					+ 10 * ranged_fast_random(25)
					+ ranged_fast_random (250)
					+ 41;
	//fprintf(stderr, "nearstar_p_rtperiod[%i] is %f\n", (int)logical_id, (double)nearstar_p_rtperiod[logical_id]);
	nearstar_p_rotation[logical_id] = secs / nearstar_p_rtperiod[logical_id];
	nearstar_p_rotation[logical_id] %= 360;

	/* calcolo dell'orientamento del pianeta per il successivo
	   oscuramento del lato buio (rispetto alla posizione della stella) */

	plwp = 89 - cplx_planet_viewpoint (logical_id);
	plwp += nearstar_p_rotation[logical_id];
	plwp %= 360; if (plwp<0) plwp += 360;

	/* selezione della tabella pseudo relativa a questo pianeta
	   la tabella pseudo della funzione "random" propria al C++ ha
	   una discreta probabilit… di ricorrenza, ma essendo integrata
	   con la "ranged_fast_random", la ricorrenza viene annullata
	   ("ranged_fast_random" ha un'enormit… in pi— di tabelle). */

	fast_srand (seedval * 10);
	seed = fast_random (0xFFFF);
	//fprintf(stderr, "NEW SEED: %u\n", seed);
	/* preparazione di una superficie standard (random pattern 0..62):
	   viene elaborata in seguito a seconda del tipo di pianeta. */

	SRAND (seed);
	#define NEWSURFACES
	#ifdef NEWSURFACES
	Uchar * pbc = (Uchar*) p_background;
	Dword pos=0;
	Udword value = seed;	//value=ax
	Uchar valueShift = (Uchar) (RANDOM(8));
	//This is a a rewritten and tweaked version of the asm code below. There're two
	//changes to it, and also it's not exactly the same as the other code, either.
	//The changes are that this includes the seed in every cycle, and also the valueShift
	//for good measure. (SL)
	//Udword crc = 0;
	for (Udword cx=64800; cx>0; cx--) {
		value+=cx;
		value*=value;
		value-=seed;
		value=(value&0xffff)+((value>>16)&0xffff);
		Uchar setVal = (value>>valueShift)&0x3E;
		pbc[pos]=setVal;
		//crc+=setVal;
		pos++;
	}
	//fprintf(stderr, "CRC1 for %i is %lu.\n", (int) logical_id, crc);
	#else

	asm {
		#ifdef WINDOWS
		push edi
		push ebx
		mov edi, [p_background]
		#else
		les di, dword ptr p_background
		#endif
		mov cx, 64800
		mov ax, seed }
rndpat:	asm {   add ax, cx
		xor dx, dx
		imul ax
		add ax, dx
		mov bl, al
		and bl, 0x3E
		#ifdef WINDOWS
		mov [edi], bl
		add di, 1
		#else
		mov es:[di], bl
		inc di
		#endif
		dec cx
		jnz rndpat
		#ifdef WINDOWS
		pop ebx
		pop edi
		#endif
		}
	#endif

	/* preparazione dell'overlay per la mappatura delle evoluzioni
	   dell'atmosfera: viene inizialmente azzerato, in quanto deve
	   essere successivamente rielaborato a seconda del tipo di
	   pianeta. ovviamente non viene rielaborato se il pianeta
	   non ha un atmosfera. */

	FMEMSET (overlay, 0, 32400);

	/* elaborazione della superficie specifica.
	   l'elaborazione dell'overlay per l'atmosfera,
	   nel caso ce ne sia bisogno, Š contemporanea. */

	SRAND (seed);
	QUADWORDS = 16200;

	switch (type) {
		case 0: r = ranged_fast_random (3) + 5;
			/*crc = 0;
			for (int ipx = 0; ipx < 64800; ipx++) {
				crc += p_background[ipx];
			}
			fprintf(stderr, "CRC2 for %i is %lu.\n", (int) logical_id, crc);*/
			for (c=0; c<r; c++) ssmooth (p_background);
			/*crc = 0;
			for (int ipx = 0; ipx < 64800; ipx++) {
				crc += p_background[ipx];
			}
			fprintf(stderr, "CRC3 for %i is %lu.\n", (int) logical_id, crc);*/
			#ifdef WINDOWS
			asm push edi
			#endif
			asm {
				L_DWORD_PTR(es, MAYBE_EDI, p_background)
				mov MAYBE_ECX, 64800 }
		   sep: asm {	
				cmp byte ptr SEGVAR(es, MAYBE_EDI), 28
			   //cmp byte ptr es:[di], 28
				jb low
				//mov byte ptr es:[di], 62
			   mov byte ptr SEGVAR(es, MAYBE_EDI), 62
			   }
		   low:	asm {	inc MAYBE_EDI
				dec MAYBE_ECX
				jnz sep }
			#ifdef WINDOWS
			asm pop edi
			#endif
			/*crc = 0;
			for (int ipx = 0; ipx < 64800; ipx++) {
				crc += p_background[ipx];
			}
			fprintf(stderr, "CRC4 for %i is %lu.\n", (int) logical_id, crc);*/
			
			r = ranged_fast_random (5) + 5;
			for (c=0; c<r; c++) ssmooth (p_background);
			r = 5 + ranged_fast_random (26);
			for (c=0; c<r; c++) {
				Acr = 5 + ranged_fast_random (20);
				Acx = ranged_fast_random (360);
				Acy = ranged_fast_random (130) + 25;
				gr = ranged_fast_random (Acr/2) + Acr/2 + 2;
				volcano ();
			}
			/*crc = 0;
			for (int ipx = 0; ipx < 64800; ipx++) {
				crc += p_background[ipx];
			}
			fprintf(stderr, "CRC5 for %i is %lu.\n", (int) logical_id, crc);*/
			
			r = 100 + ranged_fast_random (100);
			b = ranged_fast_random (3) + 1;
			g = 360;
			for (c=0; c<r; c++) {
				Acx = ranged_fast_random (360);
				Acy = ranged_fast_random (180);
				gr = ranged_fast_random (100);
				fracture (p_background, 180);
			}
			/*crc = 0;
			for (int ipx = 0; ipx < 64800; ipx++) {
				crc += p_background[ipx];
			}
			fprintf(stderr, "CRC6 for %i is %lu.\n", (int) logical_id, crc);*/
			
			lssmooth (p_background);
			/*crc = 0;
			for (int ipx = 0; ipx < 64800; ipx++) {
				crc += p_background[ipx];
			}
			fprintf(stderr, "CRC7 for %i is %lu.\n", (int) logical_id, crc);*/
			
			break;
		case 1: if (ranged_fast_random(2)) ssmooth (p_background);
			r = 10 + ranged_fast_random (41);
			crater_juice ();
			lssmooth (p_background);
			if (!ranged_fast_random(5)) negate ();
			break;
		case 2:	r = 5 + ranged_fast_random (25);
			for (c=0; c<r; c++) {
				Acr = ranged_fast_random (20) + 1;
				Acy = ranged_fast_random (178 - 2*Acr) + Acr;
				switch (RANDOM(2)) {
					case 0: Acx = ((Dword)(10 * secs) / (ranged_fast_random (3600) + 180)) % 360;
						gr = ranged_fast_random (12) + 2;
						storm ();
						break;
					case 1:	gr = ranged_fast_random (15) + 3;
						py = Acy * 360; Acr *= 360;
						g = 1 + ranged_fast_random (gr);
						band ();
				}
			}
			if (!ranged_fast_random(3)) negate ();
			break;
		case 3: r = ranged_fast_random(3) + 4;
			g = 26 + ranged_fast_random(3) - ranged_fast_random(5);
			for (c=0; c<r; c++) ssmooth (p_background);
			#ifdef WINDOWS
			asm push edi
			#endif
			asm {	
				L_DWORD_PTR(es, MAYBE_EDI, p_background)
				mov cx, 64000
				mov ax, seed }
		   sda: asm {   mov dl, byte ptr g
				cmp SEGVAR(es, MAYBE_EDI), dl
				jnb terra
				mov byte ptr SEGVAR(es, MAYBE_EDI), 16
				jmp mare }
		 terra: asm {   add ax, cx
				imul ax
				add ax, dx
				mov bl, al
				and bl, 0x3E
				add SEGVAR(es, MAYBE_EDI), bl
				cmp byte ptr SEGVAR(es, MAYBE_EDI), 0x3E
				jb mare
				mov word ptr SEGVAR(es, MAYBE_EDI), 0x3E }
		  mare: asm {   inc MAYBE_EDI
				dec cx
				jnz sda }
			#ifdef WINDOWS
			asm pop edi
			#endif
			r = 20 + ranged_fast_random (40);
			for (c=0; c<r; c++) {
				gr = ranged_fast_random (5) + 1;
				Acr = ranged_fast_random (10) + 10;
				if (ranged_fast_random(3))
					Acy = ranged_fast_random (172 - 2*Acr) + Acr + 2;
				else
					Acy = 60 + ranged_fast_random (10) - ranged_fast_random (10);
				Acx = ((Dword)(secs) / (ranged_fast_random (360) + 180)) % 360;
				g  = ranged_fast_random (5) + 7;
				a  = ranged_fast_random (360) * deg;
				atm_cyclon ();
			}
			break;
		case 4: ssmooth (p_background);
			if (ranged_fast_random(2)) ssmooth (p_background);
			#ifdef WINDOWS
			asm push edi
			#endif
			asm {
				L_DWORD_PTR(es, MAYBE_EDI, p_background);
				mov cx, 64000 }
		 lmrip: asm {
		 		cmp byte ptr SEGVAR(es, MAYBE_EDI), 32
				jne proxy
				mov word ptr SEGVAR(es, MAYBE_EDI), 0x3E01
				mov byte ptr SEGVAR(es, MAYBE_EDI+360), 0x01 }
		 proxy: asm {	inc MAYBE_EDI
				dec cx
				jnz lmrip
			 }
			#ifdef WINDOWS
			asm pop edi
			#endif
			r = ranged_fast_random (30);
			if (r>20) r *= 10;
			b = ranged_fast_random (3) + 1;
			g = 200 + ranged_fast_random (300);
			for (c=0; c<r; c++) {
				Acx = ranged_fast_random (360);
				Acy = ranged_fast_random (180);
				gr = 50 + ranged_fast_random (100);
				fracture (p_background, 180);
			}
			r = ranged_fast_random (25) + 1; crater_juice ();
			lssmooth (p_background);
			if (ranged_fast_random(2)) lssmooth (p_background);
			break;
		case 5: r = ranged_fast_random (3) + 4;
			for (c=0; c<r; c++) ssmooth (p_background);
			contrast ((float)ranged_fast_random(200) / 900 + 0.6,
				  (float)ranged_fast_random(350) / 100 + 4.0,
				  25 + ranged_fast_random(3));
			randoface (5 + ranged_fast_random(3), -20 * (ranged_fast_random(3) + 1));
			r = 5 + ranged_fast_random (5);
			for (c=0; c<r; c++) {
				Acr = 5 + ranged_fast_random (10);
				Acx = ranged_fast_random (360);
				Acy = ranged_fast_random (145) + 15;
				gr = ranged_fast_random (Acr/2) + 2;
				volcano ();
			}
			r = 5 + ranged_fast_random (5);
			for (c=0; c<r; c++) {
				Acr = ranged_fast_random (30) + 1;
				Acy = ranged_fast_random (178 - 2*Acr) + Acr;
				Acx = ((Dword)(60*secs) / (ranged_fast_random (3600) + 360)) % 360;
				gr = ranged_fast_random (2) + 1;
				permanent_storm ();
			}
			for (c=0; c<10000; c++) {
				gr = ranged_fast_random (10) + 10;
				px = ranged_fast_random (360);
				py = ranged_fast_random (10);
				py *= 360; spot ();
				px = ranged_fast_random (360);
				py = 125 - ranged_fast_random (10);
				py *= 360; spot ();
			}
			if (ranged_fast_random(2))
				ssmooth (p_background);
			else
				lssmooth (p_background);
			break;
		case 6:	r = 3 + ranged_fast_random (5);
			for (c=0; c<r; c++) ssmooth (p_background);
			r = 50 + ranged_fast_random (100);
			for (c=0; c<r; c++) {
				Acr = ranged_fast_random (10) + 1;
				Acy = ranged_fast_random (178 - 2*Acr) + Acr;
				if (ranged_fast_random(8)) {
					gr = ranged_fast_random (5) + 2;
					g = 1 + ranged_fast_random (gr);
					py = Acy * 360;
					Acr *= 360;
					band ();
				}
				else {
					a = (float) (5 + ranged_fast_random(10)) / 30;
					Acr = Acr / 4 + 1;
					wave ();
				}
			}
			r = 50 + ranged_fast_random (100);
			for (c=0; c<r; c++) {
				Acr = ranged_fast_random (15) + 1;
				Acy = ranged_fast_random (178 - 2*Acr) + Acr;
				Acx = ((Dword)(60*secs) / (ranged_fast_random (8000) + 360)) % 360;
				gr = ranged_fast_random (2) + 1;
				if (ranged_fast_random(10))
					Acr = Acr / 2 + 1;
				else
					gr *= 3;
				storm ();
			}
			lssmooth (p_background);
			if (!ranged_fast_random(3)) negate ();
			break;
		case 7: r = 5 + ranged_fast_random (5);
			for (c=0; c<r; c++) ssmooth (p_background);
			r = 10 + ranged_fast_random (50);
			g = 5 + ranged_fast_random (20);
			b = ranged_fast_random (2) + 1;
			for (c=0; c<r; c++) {
				Acx = ranged_fast_random (360);
				Acy = ranged_fast_random (180);
				gr = ranged_fast_random (300);
				fracture (p_background, 180);
			}
			if (ranged_fast_random(2)) lssmooth (p_background);
			randoface (1 + ranged_fast_random(10), 1);
			if (ranged_fast_random(2)) negate ();
			break;
		case 8:	r = ranged_fast_random (10) + 1;
			for (c=0; c<r; c++) lssmooth (p_background);
			r = 100 + ranged_fast_random (50);
			for (c=0; c<r; c++) {
				Acr = ranged_fast_random (5) + 1;
				gr = ranged_fast_random (5) + 1;
				Acx = ranged_fast_random (360);
				Acy = ranged_fast_random (178 - 2*Acr) + Acr;
				permanent_storm ();
			}
			if (ranged_fast_random(2)) negate ();
			break;
		case 9: pclear (p_background, 0x1F);
			for (px = 0; px < 32400; px++) overlay[px] = 0x1F;
	}

	/* rinormalizzazione superficie a intervallo 00-1F:
	   solo se l'atmosfera del pianeta non deve influire
	   sull'aspetto della superficie sottostante, quindi
	   per pianeti felisiani e per quelli simili a marte. */

	if (type==3||type==5) {
		for (px = 0; px < 64800; px++)
			p_background[px] >>= 1;
	}
	
	/* ritocchi specifici finali alla superficie - pianeti felisiani */

	if (type==3) {
		if (ranged_fast_random(2))
			lssmooth (p_background);
		else
			ssmooth (p_background);
	}
	
	//raw_albedo is the surface albedo only, it doesn't include the atmosphere's effects. (SL)
	if (logical_id == ip_targetted && landing_point) {
		ptr = 360 * landing_pt_lat + landing_pt_lon;
		raw_albedo = p_background[ptr]<<1;
	}
	
	if ((type == 3 && terrainFilter==1)) {
		//Put the background, which is currently used for albedo only (if the above condition is true), back to normal. (SL)
		for (px = 0; px < 64800; px++)
			p_background[px] += p_background[px];
	}
	
	if (!(terrainFilter==1 && type==3) && (cloudFilter!=1 || type==2 || type==6 || type==9)) {	//Filter doesn't affect thick-atmo, large non-consitant planets covered in dense clouds, or substellar objects.
		/* fusione mappa terreno + overlay atmosfera,
		   e rinormalizzazione della mappa del terreno
		   in modo che si adatti al range da 0 a 1Fh. */
		for (px = 0, py = 0; px < 32400; py += 2, px++) {
			p_background[py] += overlay[px];
			if (p_background[py] > 0x3E) p_background[py] = 0x3E;
			p_background[py+1] += overlay[px];
			if (p_background[py+1] > 0x3E) p_background[py+1] = 0x3E;
		}
	}

	//Terrain filter, part 1 (SL)
	if (type == 3 && terrainFilter==1) {
		CalculateTerrainTypes(1, logical_id, p_background);
	}
	
	/* ritocchi specifici finali alla superficie - pianeti venusiani */

	if (type==2) {
		if (!RANDOM(3)) {
			psmooth_grays (p_background);
			knot1 = 1;
		}
	}

	/* applicazione terminatore giorno-notte */

	nearstar_p_term_start[logical_id] = plwp + 35;
	if (nearstar_p_term_start[logical_id] >= 360) nearstar_p_term_start[logical_id] -= 360;
	nearstar_p_term_end[logical_id] = nearstar_p_term_start[logical_id] + 130;
	if (nearstar_p_term_end[logical_id] >= 360) nearstar_p_term_end[logical_id] -= 360;
	
	if ((type != 3 && terrainFilter!=1) || terrainFilter==0) {	//Terrain filter doesn't want this either (SL)
		asm {
			#ifdef WINDOWS
			push edi
			mov edi, [p_background]
			mov eax, plwp
			add eax, 35
			//add edi, plwp
			//add edi, 35
			#else
			les di, dword ptr p_background
			add di, plwp
			add di, 35
			#endif
			mov cx, 179 }
	  darkside:
          if (!nightisoff)
          asm {   push cx
			mov cx, 130 }
	  darkline:
          if (!nightisoff)
          asm {
	  		#ifdef WINDOWS
	  		shr byte ptr [edi+eax], 2
		  	add eax, 1
			#else
	  		shr byte ptr es:[di], 2
	  		inc di
			#endif
			dec cx
			jnz darkline
			pop cx
			#ifdef WINDOWS
			add eax, 230
			#else
			add di, 230
			#endif
			dec cx
			jnz darkside
			#ifdef WINDOWS
			pop edi
			#endif
	  		}
		
	}
	
	/* ritocchi specifici finali alla superficie - altri pianeti */
	
	if (type==2) {
		if (knot1)
			ssmooth (p_background);
		else {
			r = 3 + ranged_fast_random (5);
			for (c=0; c<r; c++)
				ssmooth (p_background);
		}
	}

	if (type==6) {
		for (c=0; c<3; c++)
			if (ranged_fast_random(2))
				ssmooth (p_background);
	}

	if (type==9) for (c=0; c<6; c++) ssmooth (p_background);
	
	/* Elaborazione tabella dei colori (ridefinisce da 192 a 255). */

	if (colorbase == 255) {
		QUADWORDS = QW;
		return;
	}

	
	//Terrain filter, part 3 (SL)
	if (type == 3 && terrainFilter==1) {
		shade(tmppal, colorbase+0, 8, BLACK_COLOR, GRAY_COLOR);
		shade(tmppal, colorbase+8, 1, GRAY_COLOR, OCEAN_COLOR);
		shade(tmppal, colorbase+9, 1, OCEAN_COLOR, FOREST_COLOR);
		shade(tmppal, colorbase+10, 1, FOREST_COLOR, PLAINS_COLOR);
		shade(tmppal, colorbase+11, 1, PLAINS_COLOR, SHRUBLAND_COLOR);
		shade(tmppal, colorbase+12, 1, SHRUBLAND_COLOR, DESERT_COLOR);
		shade(tmppal, colorbase+13, 1, DESERT_COLOR, GRAY_COLOR);
		shade(tmppal, colorbase+14, 50, GRAY_COLOR, WHITE_COLOR);
		
		/*
		shade (tmppal, colorbase +  0,  4, BLACK_COLOR, DARK_ICY_COLOR);
		shade (tmppal, colorbase +  4,  8, DARK_ICY_COLOR, DARK_OCEAN_COLOR);
		shade (tmppal, colorbase + 12,  8, DARK_OCEAN_COLOR, DARK_PLAINS_COLOR);
		shade (tmppal, colorbase + 20,  8, DARK_PLAINS_COLOR, DARK_DESERT_COLOR);
		shade (tmppal, colorbase + 28,  4, DARK_DESERT_COLOR, GRAY_COLOR);
		shade (tmppal, colorbase + 32,  4, GRAY_COLOR, ICY_COLOR);
		shade (tmppal, colorbase + 36,  8, ICY_COLOR, OCEAN_COLOR);
		shade (tmppal, colorbase + 44,  8, OCEAN_COLOR, PLAINS_COLOR);
		shade (tmppal, colorbase + 52,  8, PLAINS_COLOR, DESERT_COLOR);
		shade (tmppal, colorbase + 60,  4, DESERT_COLOR, WHITE_COLOR);
		*/
		//ShadeMatrix (tmppal, colorbase, 8, 1, 64, terrain_color_feed);	//8 elements, 1 transition each, 64 colors (the number of colors)
		
	} else {
		type <<= 2;
		r = planet_rgb_and_var[type+0];
		g = planet_rgb_and_var[type+1];
		b = planet_rgb_and_var[type+2];
		c = planet_rgb_and_var[type+3];
	
		r <<= 1; r += nearstar_r; r >>= 1;
		g <<= 1; g += nearstar_g; g >>= 1;
		b <<= 1; b += nearstar_b; b >>= 1;
	
		
		
		//Testing (SL)
		
		/*long global_surface_seed = (nearstar_p_ray[logical_id]
					  + nearstar_p_orb_ray[logical_id]
					  + nearstar_p_orb_orient[logical_id]) * 4112;	//I wonder what the 4112 is for (SL)
		fast_srand (global_surface_seed);
		
		flandom(); flandom(); flandom();
		r1 = (0.65 + 0.5 * flandom())*63;
		g1 = (0.45 + 0.4 * flandom())*63;
		b1 = (0.25 + 0.3 * flandom())*63;
		if (g1 < 0.6) g1 *= 2;
		if (r1<0) r1=0;
		if (g1<0) g1=0;
		if (b1<0) b1=0;
		*/
		r1 = r + RANDOM(c) - RANDOM(c);
		g1 = g + RANDOM(c) - RANDOM(c);
		b1 = b + RANDOM(c) - RANDOM(c);
		r2 = r + RANDOM(c) - RANDOM(c);
		g2 = g + RANDOM(c) - RANDOM(c);
		b2 = b + RANDOM(c) - RANDOM(c);
		r3 = r + RANDOM(c) - RANDOM(c);
		g3 = g + RANDOM(c) - RANDOM(c);
		b3 = b + RANDOM(c) - RANDOM(c);
	
		/*
		r1 = 0; g1 = 0; b1 = 63;
		r2 = 0; g2 = 63; b2 = 0;
		r3 = 63; g3 = 0; b3 = 0;
		*/
		r1 *= 0.25; g1 *= 0.25; b1 *= 0.25;
		r2 *= 0.75; g2 *= 0.75; b2 *= 0.75;
		r3 *= 1.25; g3 *= 1.25; b3 *= 1.25;
		
		type >>= 2;
	
		shade (tmppal, colorbase + 00, 16, 00, 00, 00, r1, g1, b1);
		shade (tmppal, colorbase + 16, 16, r1, g1, b1, r2, g2, b2);
		shade (tmppal, colorbase + 32, 16, r2, g2, b2, r3, g3, b3);
		shade (tmppal, colorbase + 48, 16, r3, g3, b3, 64, 64, 64);
	}
	brt = nearstar_p_owner[logical_id];
	if (brt == -1) brt = logical_id;

	if (brt <= 4)
		brt = 64;
	else
		brt = 64 - (4 * (brt - 4));

	tavola_colori (tmppal + 3*colorbase, colorbase, 64, brt, brt, brt);
		
	QUADWORDS = QW;
	/*crc = 0;
	for (px = 0; px < 64800; px++) {
		crc += p_background[px];
	}
	fprintf(stderr, "CRC for %i is %lu.\n", (int) logical_id, crc);*/
}

/* Tracciamento degli anelli (eventuali). */

void ring (Word planet_id, double ox, double oy, double oz, Word start, Word layers)
{
	Word 	a, b, c, n, m, partn, partcls;
	double	sx, sy, sz;

	double 	ringray = nearstar_p_ring[planet_id];
	double	ringtilt = 0.1 * ringray * nearstar_p_tilt[planet_id];
	double 	step = 0.0075 * ringray;

	fast_srand (10000 * ringray + planet_id);
	b = 1 + fast_random (0x1F) - layers;
	partcls = 1 + fast_random (3);
	while (b > 0) {
		if (!fast_random(7)) {
			c = 1 + fast_random (3);
			pixel_spreads = 0;
		}
		else {
			c = 1 + fast_random (7);
			pixel_spreads = 1;
		}
		a = start - (start % c);
		pixilating_effect = fast_random(1) + fast_random(1);
		if (a < 0) a += 360;
		n = c; while (n + c < 180) {
			m = c + fast_random (1);
			n += m; a += m; if (a > 360) a -= 360;
			sy = oy - ringtilt * lft_sin[a];
			sx = ox + ringray  * lft_sin[a];
			sz = oz + ringray  * lft_cos[a];
			partn = partcls;
			while (partn) {
				sz += step - (fast_flandom() * step);
				sx += step - (fast_flandom() * step);
				far_pixel_at (sx, sy, sz, -0.042, 0);
				partn--;
			}
		}
		ringray += step;
		if (!fast_random(7)) ringray += 5 * step;
		ringtilt = 0.1 * ringray * nearstar_p_tilt[planet_id];
		b--;
	}

	pixilating_effect = LIGHT_EMITTING;
	pixel_spreads = 1;
}

/* Visualizza appopriatamente i pianeti, come punti, barlumi di luce
   o globi ben visibili, a seconda di distanza e raggio. C'Š un terzo
   modo in cui un corpo planetario pu• rendersi visibile: con una falce.
   L'effetto falce viene realizzato da "glowinglobe". */

/*
planets () overwrites:
	objectschart
	p_background
	s_background
*/

void planets ()
{
	char maybefar *atmosphere = (char maybefar *) objectschart;
	Uchar maybefar *surface_backup = (Uchar maybefar*)p_background;

	char is_moon;
	Dword poffs;
	Dword test;

	Word  i1, i2, n1, n2, c1, c2, pnpcs;
	Word  c, n, t, ts, te, ll, plwp, riwp;

	Word  te_ll_distance, te_ll_distance_1, te_ll_distance_2;
	Word  ts_ll_distance, ts_ll_distance_1, ts_ll_distance_2;

	double xx, yy, zz;
	double d3, d2, md2 = 1E9;

	Uchar colorbase, showdisc, showrings, surfacemap;
	Word ringlayers;

	if (ip_targetting) ip_targetted = -1;
	if (!nearstar_nop) return;

	for (n=0; n<nearstar_nob; n++) {
		planet_xyz (n);
		xx = plx - dzat_x;
		yy = ply - dzat_y;
		zz = plz - dzat_z;
		nearstar_p_qsortindex[n] = n;
		nearstar_p_qsortdist[n]  = SQRT (xx*xx+yy*yy+zz*zz);
	}

	QuickSort (nearstar_p_qsortindex,
		   nearstar_p_qsortdist,
		   0, nearstar_nob - 1);

	if (nearstar_nob == 1) {
		pnpcs = npcs;
		npcs  = 0;
		if (npcs != pnpcs) {
			resident_map1 = 0;
			resident_map2 = -1;
		}
	}
	else {
		pnpcs = npcs;
		n1 = nearstar_nob - 1;
		i1 = nearstar_p_qsortindex[n1];
		c1 = nearstar_p_owner[i1];
		n2 = nearstar_nob - 2;
		i2 = nearstar_p_qsortindex[n2];
		c2 = nearstar_p_owner[i2];
		if (c1 > -1) {
			while (c2 > -1) {
				n2 --;
				i2 = nearstar_p_qsortindex[n2];
				c2 = nearstar_p_owner[i2];
			}
		}
		if (current_galaxy==0) {
			npcs = i1 * fg_maxbodies - i2;
		} else {
			npcs = i1 * ng_maxbodies - i2;
		}
		if (npcs != pnpcs) {
			resident_map1 = i1;
			resident_map2 = i2;
		}
	}

	for (c=0; c<nearstar_nob; c++) {
		n  = nearstar_p_qsortindex[c];
		//
		d3 = nearstar_p_qsortdist[n];
		planet_xyz (n);
		if (nearstar_p_owner[n] > -1) {
			p_background = s_background;
			colorbase = 128;
			is_moon = 1;
		}
		else {
			p_background = surface_backup;
			colorbase = 192;
			is_moon = 0;
		}
		showdisc = 0;
		showrings = 0;
		surfacemap = 0;
		if (d3 < 250*nearstar_p_ray[n]) {
			showrings = 1;
			ringlayers = 0.05 * (d3 / nearstar_p_ray[n]);
			if (d3 < 100*nearstar_p_ray[n]) {
				showdisc = 1;
				if (d3 < 25*nearstar_p_ray[n])
					surfacemap = 1;
			}
		}
		//
		if (ip_targetting || !showdisc) {
			if (!dontDraw) {
				far_pixel_at (plx, ply, plz, nearstar_p_ray[n], 0);
			}
			if (ip_targetting) {
				pxx -= x_centro;
				pyy -= y_centro;
				d2 = pxx*pxx + pyy*pyy;
				if (d2<md2) {
					md2 = d2;
					ip_targetted = n;
				}
			}
		}
		//
		if (nearstar_p_type[n] == 10) goto notaplanet;
		//
		if (showrings) {
			if (surfacemap)
				multicolourmask = 0xC0;
			else
				multicolourmask = 0x40;
			plwp = 359 - planet_viewpoint (dzat_x, dzat_z);
			if (nearstar_p_ring[n]) {
				riwp = plwp + 180;
				if (riwp > 359) riwp -= 360;
				if (!dontDraw) {
					ring (n, plx, ply, plz, riwp, ringlayers);
				}
			}
		}
		if (showdisc) {
		    if (surfacemap) {
			if (n==resident_map1 || n==resident_map2) {
				/*
				TEMPORARY Test code:
				static int ipos = 0;
				ipos++;
				if (ipos==10) {
					ipos=0;
					valueMix+=1;
					if (valueMix>64000) valueMix=0;
					char mbuff[30];
					sprintf(mbuff, "VALUEMIX IS %i", (int)valueMix);
					status(mbuff, 50);
				
				*/
				if (is_moon) {
					if (nearstar_p_type[n]) {
						surface (n, nearstar_p_type[n],
							 1000000		*
							 nearstar_ray		*
							 nearstar_p_type[n]     *
							 nearstar_p_orb_orient[n],
							 128);
					}
					else {
						//fprintf(stderr, "M1 n %i, ray %f, orient %f\n", (int)n, nearstar_ray, nearstar_p_orb_orient[n]);
						surface (n, nearstar_p_type[n],
							 2000000 * n		*
							 nearstar_ray		*
							 nearstar_p_orb_orient[n],
							 128);
					}
				}
				else {
					if (nearstar_p_type[n]) {
						/*
						double seedval = 1000000		*
							 nearstar_p_type[n]     *
							 nearstar_p_orb_seed[n] *
							 nearstar_p_orb_tilt[n] *
							 nearstar_p_orb_ecc[n]  *
							 nearstar_p_orb_orient[n];
						//DebugPrintf(0, "seedval=%f type=%i orb_seed=%f orb_tilt=%f orb_ecc=%f orb_orient=%f", seedval, nearstar_p_type[n], nearstar_p_orb_seed[n], nearstar_p_orb_tilt[n], nearstar_p_orb_ecc[n], nearstar_p_orb_orient[n]);
						*/
						surface (n, nearstar_p_type[n],
							 1000000		*
							 nearstar_p_type[n]     *
							 nearstar_p_orb_seed[n] *
							 nearstar_p_orb_tilt[n] *
							 nearstar_p_orb_ecc[n]  *
							 nearstar_p_orb_orient[n],
							 192);
					}
					else {
						surface (n, nearstar_p_type[n],
							 2000000 * n		*
							 nearstar_p_orb_seed[n] *
							 nearstar_p_orb_tilt[n] *
							 nearstar_p_orb_ecc[n]  *
							 nearstar_p_orb_orient[n],
							 192);
					}
				}
				if (n==resident_map1) resident_map1 = -1;
				if (n==resident_map2) resident_map2 = -1;
			}
			if (n == ip_targetted && landing_point) {
				nightzone = 0;
				//
				ts = nearstar_p_term_start[n];
				te = nearstar_p_term_end[n];
				ll = landing_pt_lon;
				//
				if (ts > te) {
					if (ll >= ts
						|| ll < te)
							nightzone = 1;
				}
				else {
					if (ll >= ts
						&& ll < te)
							nightzone = 1;
				}
				//
				te_ll_distance_1 = 0;
				ll = landing_pt_lon;
				while (ll != te) {
					te_ll_distance_1++;
					ll++; if (ll >= 360) ll = 0;
				}
				te_ll_distance_2 = 0;
				ll = landing_pt_lon;
				while (ll != te) {
					te_ll_distance_2++;
					ll--; if (ll <= -1) ll = 359;
				}
				if (te_ll_distance_1 < te_ll_distance_2)
					te_ll_distance = te_ll_distance_1;
				else
					te_ll_distance = te_ll_distance_2;
				ts_ll_distance_1 = 0;
				ll = landing_pt_lon;
				while (ll != ts) {
					ts_ll_distance_1++;
					ll++; if (ll >= 360) ll = 0;
				}
				ts_ll_distance_2 = 0;
				ll = landing_pt_lon;
				while (ll != ts) {
					ts_ll_distance_2++;
					ll--; if (ll <= -1) ll = 359;
				}
				if (ts_ll_distance_1 < ts_ll_distance_2)
					ts_ll_distance = ts_ll_distance_1;
				else
					ts_ll_distance = ts_ll_distance_2;
				if (ts_ll_distance <= te_ll_distance) {
					sun_x_factor = +1;
					crepzone = ts_ll_distance;
				}
				else {
					sun_x_factor = -1;
					crepzone = te_ll_distance;
				}
				//
				fast_srand (nearstar_p_orb_seed[n] * nearstar_p_orb_ecc[n] * 12345);
				
				ptr = 360 * landing_pt_lat + landing_pt_lon;
				
				sky_red_filter = fast_random (31) + 32;
				sky_grn_filter = fast_random (15) + 48;
				sky_blu_filter = fast_random (15) + 48;
				if (is_moon) {
					gnd_red_filter = tmppal[(3 * p_background[ptr]) + 128*3 + 0];
					gnd_grn_filter = tmppal[(3 * p_background[ptr]) + 128*3 + 1];
					gnd_blu_filter = tmppal[(3 * p_background[ptr]) + 128*3 + 2];
				}
				else {
					gnd_red_filter = tmppal[(3 * p_background[ptr]) + 192*3 + 0];
					gnd_grn_filter = tmppal[(3 * p_background[ptr]) + 192*3 + 1];
					gnd_blu_filter = tmppal[(3 * p_background[ptr]) + 192*3 + 2];
				}
				gnd_red_filter += fast_random (15);
				gnd_grn_filter += fast_random (15);
				gnd_blu_filter += fast_random (15);
				test = nearstar_p_type[n];
				albedo = p_background[ptr];		//Albedo now includes atmosphere too - raw_albedo is surface only, and it's set in surface(). (SL)
				if (nightzone) {
					old_albedo = p_background[ptr];
					old_albedo <<= 2;
					if (test==3||test==5)
						old_albedo -= atmosphere[ptr>>1];
					old_albedo >>= 2;
					old_albedo <<= 2;
				}
				else {
					old_albedo = p_background[ptr];
					if (test==3||test==5)
						old_albedo -= atmosphere[ptr>>1];
					old_albedo >>= 2;
					old_albedo <<= 2;
				}
				if (test==3||test==5) old_albedo *= 2; // da 0 a 1F --> da 0 a 3F
				
				rainy = (float)atmosphere[ptr>>1] * 0.25;
				if (rainy > 5) rainy = 5;
				if (nightzone) {
					sky_grn_filter /= 2;
					sky_blu_filter /= 2;
					//if (crepzone > 5) {			//original
					if (crepzone > 2) {				//new, adapted for better night colours.
						sky_red_filter /= 2;
						sky_brightness = 8;
						horiz_brt = 10;
					}
					else {
						//sky_brightness = 32;		//original
						//horiz_brt = 10;			//original
						sky_brightness = 10 + ((2 - crepzone) * 5);		//new, adapted for better night colours.
						horiz_brt = 10 + ((2 - crepzone) * 6);			//new, adapted for better night colours (although pretty much no effect! :P).
						
					}
				}
				else {
					//if (crepzone > 5) {				//original
					if (crepzone > 2) {					//makes sunsets go "faster" and prettier
						sky_brightness = 48;
						horiz_brt = 20;
					}
					else {
						//sky_grn_filter /= 2;			//original
						//sky_blu_filter /= 3;			//original
						//sky_brightness = 40;			//original
						//horiz_brt = 13;				//original
						sky_grn_filter /= 2.0 - ((crepzone - 1) * 0.5);	//new
						sky_blu_filter /= 2.0 - ((crepzone - 1) * 0.5); //new
						sky_brightness = 40 + ((crepzone - 1) * 6); //new
						horiz_brt = 13 + ((crepzone - 1) * 3); //new
					}
				}
				for (poffs = -180; poffs < 180; poffs++) {
					test = poffs + ptr;
					if (test > 0 && test < 64800) {
						_AL = p_background[test];
						asm xor al, 0x1E;
						p_background[test] = _AL;
					}
				}
				for (poffs = -60; poffs < 60; poffs++) {
					if (poffs) {
						test = 360 * poffs + ptr;
						if (test > 0 && test < 64800) {
							_AL = p_background[test];
							asm xor al, 0x1E;
							p_background[test] = _AL;
						}
					}
				}
			}
			t = nearstar_p_type[n];
			if (t == 2 || t == 3 || t == 6 || t == 8 || t == 9)
				glass_bubble = 1;
			else
				glass_bubble = 0;
			if (!dontDraw) {
				globe (plwp + nearstar_p_rotation[n],
			       adapted, p_background, (Uchar maybefar*) n_globes_map, gl_bytes,
			       plx, ply, plz, nearstar_p_ray[n], colorbase, 0);
				
			}
			
			if (n == ip_targetted && landing_point) {
				for (poffs = -180; poffs < 180; poffs++) {
					test = poffs + ptr;
					if (test > 0 && test < 64800) {
						_AL = p_background[test];
						asm xor al, 0x1E;
						p_background[test] = _AL;
					}
				}
				for (poffs = -60; poffs < 60; poffs++) {
					if (poffs) {
						test = 360 * poffs + ptr;
						if (test > 0 && test < 64800) {
							_AL = p_background[test];
							asm xor al, 0x1E;
							p_background[test] = _AL;
						}
					}
				}
			}
		    }
		    else {
			    ts = (89+35) - cplx_planet_viewpoint (n);
			    if (ts < 0) ts += 360;
			    if (ts > 359) ts -= 360;
			    if (!dontDraw) {
					glowinglobe (plwp, adapted, (Uchar*) n_globes_map, gl_bytes, plx,
					 ply, plz, nearstar_p_ray[n], ts, 130, 127);
				}
		    }
		}
		if (showrings) {
			if (nearstar_p_ring[n]) {
				if (!dontDraw) {
					ring (n, plx, ply, plz, plwp, ringlayers);
					if (!showdisc) far_pixel_at (plx, ply, plz, nearstar_p_ray[n], 0);
				}
			}
		}
		notaplanet:
		#ifdef WINDOWS
		0;
		#endif
	}

	p_background = surface_backup;
}

// Necessaria all'inizializzazione (ottimizzazione caricamento segmenti).

void init_FP_segments ()
{
	#ifndef WINDOWS
	asm {   les ax, dword ptr adapted
		mov seg_adapted, es }
	#endif
}

/*

	Gestione cartografia galattica.

	Ad ogni stella Š assegnato un codice d'identificazione univoco,
	derivante dalle sue coordinate. A tale codice si fa riferimento
	per l'associazione dei nomi delle stelle. I codici identificativi
	dei pianeti vengono calcolati a partire da quello della loro stella,
	pi— il numero (progressivo) del pianeta in ordine di distanza.

*/

double 	laststar_x, laststar_y, laststar_z;
Dword laststar_sx, laststar_sy, laststar_sz;

/* Determina se una certa stella, di cui si specifica il codice
   d'identificazione univoco, Š attualmente nel range dei sensori.
   Ritorna 1 quando Š visibile, 0 se non lo Š.
   Quando Š visibile, le coordinate della stella sono riportate
   nelle variabili "laststar_x", "laststar_y" e "laststar_z". */

char isthere (double star_id)
{
	char 		visible_sectors = 9;

	Dword   		sect_x, sect_y, sect_z;
	Dword   		k, advance = 100000;

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

	Uchar 	sx, sy, sz;
	double 		laststar_id;

	sect_x = (dzat_x - visible_sectors*50000) / 100000; sect_x *= 100000;
	sect_y = (dzat_y - visible_sectors*50000) / 100000; sect_y *= 100000;
	sect_z = (dzat_z - visible_sectors*50000) / 100000; sect_z *= 100000;

	if (field_amplificator) visible_sectors = 14;
	k = 100000 * visible_sectors;

	asm {
		#ifdef WINDOWS
		pushad
		#else
		les ax, dword ptr adapted
		#endif
		mov al, visible_sectors
		mov sx, al }
e_while:asm {	mov al, visible_sectors
		mov sy, al }
m_while:asm {	mov al, visible_sectors
		mov sz, al }
i_while:asm {
		#ifdef WINDOWS
		mov ebx, 50000
		mov eax, dword ptr sect_x
		mov edx, dword ptr sect_z
		add eax, edx
		mov ecx, eax
		mov edx, eax
		and edx, 0x0001FFFF
		add edx, dword ptr sect_x
		sub edx, ebx
		mov dword ptr laststar_x, edx
		imul edx
		add edx, eax
		add ecx, edx
		and edx, 0x0001FFFF
		add edx, dword ptr sect_y
		sub edx, ebx
		mov dword ptr laststar_y, edx
		mov eax, ecx
		imul edx
		add edx, eax
		and edx, 0x0001FFFF
		add edx, dword ptr sect_z
		sub edx, ebx
		mov dword ptr laststar_z, edx
		#else
		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
		#endif
		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
		#ifdef WINDOWS
		mov eax, dword ptr sect_x
		mov dword ptr laststar_sx, eax
		mov eax, dword ptr sect_y
		mov dword ptr laststar_sy, eax
		mov eax, dword ptr sect_z
		mov dword ptr laststar_sz, eax
		#else
		db 0x66; mov ax, word ptr sect_x
		db 0x66; mov word ptr laststar_sx, ax
		db 0x66; mov ax, word ptr sect_y
		db 0x66; mov word ptr laststar_sy, ax
		db 0x66; mov ax, word ptr sect_z
		db 0x66; mov word ptr laststar_sz, ax
		#endif
		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 {
		#ifdef WINDOWS
		mov eax, dword ptr advance
		add dword ptr sect_z, eax
		#else
		db 0x66; mov ax, word ptr advance
		db 0x66; add word ptr sect_z, ax
		#endif
		dec sz
		jz i_end
		jmp i_while }
i_end:	  asm {
		#ifdef WINDOWS
		mov edx, dword ptr k
		sub dword ptr sect_z, edx
		add dword ptr sect_y, eax
		#else
		db 0x66; mov dx, word ptr k
		db 0x66; sub word ptr sect_z, dx
		db 0x66; add word ptr sect_y, ax
		#endif
		dec sy
		jz m_end
		jmp m_while }
m_end:	  asm {
		#ifdef WINDOWS
		sub dword ptr sect_y, edx
		add dword ptr sect_x, eax
		#else
		db 0x66; sub word ptr sect_y, dx
		db 0x66; add word ptr sect_x, ax
		#endif
		dec sx
		jz e_end
		jmp e_while }

e_end:
		#ifdef WINDOWS
		asm popad
		#endif
		return (0);
y_end:
		#ifdef WINDOWS
		asm popad
		#endif
		return (1);
}

/* Ricerca tutte le stelle note visibili, fino a 50 contemporaneamente.
   Compila una tabella contenente l'ID di ogni stella e la sua
   posizione in coordinate Parsis. */

const Word 	tgt_bytes_per_scan = 5 * 32;
Dword 		tgt_collect_lastpos = 0;

Word    		targets = 0;
Word    		topmost_target = 0;
Word    		target_line = 0;
char   		update_targets = 0;
char   		collecting_targets = 0;

#ifdef OLD_STARMAP
double 		targets_table_id[50];
#else
Dword targets_table_sx[50];
Dword targets_table_sy[50];
Dword targets_table_sz[50];
#endif
double 		targets_table_px[50];
double 		targets_table_py[50];
double 		targets_table_pz[50];

void collect_targets ()
{
	
	#ifdef OLD_STARMAP
	Uword 	n, ptr, index, toread;
	FILEPTR		local_smh;
	char maybefar 	*buffer_ascii = (char maybefar *)p_surfacemap;
	double maybefar 	*buffer_double = (double maybefar *)p_surfacemap;

	local_smh = OPENFILE (starmap_file, OPEN_RB);
	if (local_smh ISFILEVALID) {
		toread = tgt_bytes_per_scan;
		while (toread) {
			FILESEEK (local_smh, tgt_collect_lastpos, SEEK_SET);
			n = READFILE (local_smh, buffer_ascii, toread);
			if (!n) {
				collecting_targets = 0;
				goto stop;
			}
			ptr = 0;
			index = 0;
			toread = 0;
			while (ptr < n) {
				if (buffer_ascii[ptr + 29] == 'S') {
					if (isthere (buffer_double[index])) {
						targets_table_id[targets] = buffer_double[index];
						targets_table_px[targets] = laststar_x;
						targets_table_py[targets] = laststar_y;
						targets_table_pz[targets] = laststar_z;
						if (targets < 3)
							target_line = targets;
						else
							target_line = 2;
						if (targets > 2)
							topmost_target = targets - 2;
						update_targets = 1;
						targets++;
						if (targets == 50) {
							collecting_targets = 0;
							goto stop;
						}
					}
				}
				else
					toread += 32;
				ptr += 32;
				index += 4;
				tgt_collect_lastpos += 32;
			}
		}
	  stop: CLOSEFILE (local_smh);
	}
	#else
	FILE * starmap3File;
	if (current_galaxy==0) {
		starmap3File = fopen(starmap3_file, "rb");
	} else {
		starmap3File = fopen(starmap3b_file, "rb");
	}
	if (starmap3File!=NULL) {
		Uword fileFormatVersion;
		Udword halfStarmap3Version;
		fread(&fileFormatVersion, 2, 1, starmap3File);
		fread(&halfStarmap3Version, 4, 1, starmap3File);
		fread(&halfStarmap3Version, 4, 1, starmap3File);
		if (fileFormatVersion>2) {
			printf("starmap3.map is a newer format (%u) than we can understand. You need a new version of NICE.\n", fileFormatVersion);
			printf("Press any key to continue.\n");
			Pause();
			return;
		} else {
			Uchar flags;
			Udword discoverer;
			char maybefar 	*name = (char maybefar *)p_surfacemap;
			//char name[20];
			Dword sx, sy, sz;
			Uword data;
			Udword nextAlternateFP;
			Udword starFP;
			//int stillZero=1;
			while (!feof(starmap3File)) {
				fread(&flags, 1, 1, starmap3File);
				fread(&discoverer, 4, 1, starmap3File);
				fread(&name, 20, 1, starmap3File);
				if (flags&0x8) {	//star
					fread(&sx, 4, 1, starmap3File);
					fread(&sy, 4, 1, starmap3File);
					fread(&sz, 4, 1, starmap3File);
					fread(&data, 2, 1, starmap3File);
					fread(&nextAlternateFP, 4, 1, starmap3File);
					if (isthere3(sx, sy, sz)) {
						if (abs(laststar_x-dzat_x)<900000 && abs(laststar_y-dzat_y)<900000 && abs(laststar_z-dzat_z)<900000) {
							targets_table_sx[targets] = sx;
							targets_table_sy[targets] = sy;
							targets_table_sz[targets] = sz;
							targets_table_px[targets] = laststar_x;
							targets_table_py[targets] = laststar_y;
							targets_table_pz[targets] = laststar_z;
							if (targets < 3)
								target_line = targets;
							else
								target_line = 2;
							if (targets > 2)
								topmost_target = targets - 2;
							update_targets = 1;
							targets++;
							if (targets == 50) {
								collecting_targets = 0;
								break;
							}
						}
					}
				} else {
					fread(&starFP, 4, 1, starmap3File);
					fread(&data, 2, 1, starmap3File);
					fread(&nextAlternateFP, 4, 1, starmap3File);
					//We don't do anything with planet entries.
				}
			}
			collecting_targets=0;
		}
	}
	#endif
	
}

/* Cambia lo stato visualizzato dall'FCS sull'Head-Up-Display. */

void status (const char *status_description, Word message_delay)
{
	if (message_delay >= fcs_status_delay) {
		//Sadly, strcpy doesn't do length-checking, so I've had to implement this to handle that: (SL)
		int len = strlen(status_description);
		if (len<10) {
			memcpy(fcs_status, status_description, len);
			fcs_status[len]=0;
			memcpy(fcs_status_extended, fcs_status, len+1);
		} else if (len<41) {
			memcpy(fcs_status, status_description, 10);
			fcs_status[10]=0;
			memcpy(fcs_status_extended, status_description, len);
			fcs_status_extended[len]=0;
		} else {
			memcpy(fcs_status, status_description, 10);
			fcs_status[10]=0;
			memcpy(fcs_status_extended, status_description, 41);
			fcs_status_extended[41]=0;
		}
		fcs_status_delay = message_delay;
	}
}

/* Mappa caratteri per l'HUD:
   font iper-compatto (3 x 5 pixels). */

char digimap[66*5] = {
	 0, 0, 0, 0, 0, // 32. spazio vuoto
	 2, 2, 2, 0, 2, // 33. punto esclamativo
	 5, 0, 0, 0, 0, // 34. virgolette
	 0, 0, 3, 5, 5, // 35. cancelletto (rappresentato da una piccola n.)
	 2, 2, 6, 2, 2, // 36. sistro
	 1, 4, 2, 1, 4, // 37. percento
	 0, 0, 2, 0, 0, // 38. e commericale (non Š possibile visualizzarla)
	 0, 2, 2, 0, 0, // 39. apice
	 4, 2, 2, 2, 4, // 40. parentesi tonda aperta
	 1, 2, 2, 2, 1, // 41. parentesi tonda chiusa
	 0, 0, 7, 2, 2, // 42. asterisco
	 0, 2, 7, 2, 0, // 43. segno pi—
	 0, 0, 0, 2, 1, // 44. virgola
	 0, 0, 7, 0, 0, // 45. segno meno
	 0, 0, 0, 0, 2, // 46. punto
	 0, 4, 2, 1, 0, // 47. barra destrorsa
	 7, 5, 5, 5, 7, // 48. 0
	 3, 2, 2, 2, 7, // 49. 1
	 7, 4, 7, 1, 7, // 50. 2
	 7, 4, 6, 4, 7, // 51. 3
	 4, 6, 5, 7, 4, // 52. 4
	 7, 1, 7, 4, 7, // 53. 5
	 7, 1, 7, 5, 7, // 54. 6
	 7, 4, 4, 4, 4, // 55. 7
	 7, 5, 7, 5, 7, // 56. 8
	 7, 5, 7, 4, 4, // 57. 9
	 0, 2, 0, 2, 0, // 58. duepunti
	 0, 2, 0, 2, 1, // 59. punto e virgola
	 4, 2, 1, 2, 4, // 60. minore
	 0, 7, 0, 7, 0, // 61. uguale
	 1, 2, 4, 2, 1, // 62. maggiore
	 7, 4, 6, 0, 2, // 63. punto interrogativo
	 0, 2, 0, 0, 0, // 64. a commerciale (non visualizzabile)
	 7, 5, 7, 5, 5, // 65. A
	 7, 5, 3, 5, 7, // 66. B
	 7, 1, 1, 1, 7, // 67. C
	 3, 5, 5, 5, 3, // 68. D
	 7, 1, 3, 1, 7, // 69. E
	 7, 1, 3, 1, 1, // 70. F
	 7, 1, 5, 5, 7, // 71. G
	 5, 5, 7, 5, 5, // 72. H
	 2, 2, 2, 2, 2, // 73. I
	 4, 4, 4, 5, 7, // 74. J
	 5, 5, 3, 5, 5, // 75. K
	 1, 1, 1, 1, 7, // 76. L
	 7, 7, 5, 5, 5, // 77. M
	 5, 7, 7, 5, 5, // 78. N
	 7, 5, 5, 5, 7, // 79. O
	 7, 5, 7, 1, 1, // 80. P
	 7, 5, 5, 1, 5, // 81. Q
	 7, 5, 3, 5, 5, // 82. R
	 7, 1, 7, 4, 7, // 83. S
	 7, 2, 2, 2, 2, // 84. T
	 5, 5, 5, 5, 7, // 85. U
	 5, 5, 5, 5, 2, // 86. V
	 5, 5, 7, 7, 5, // 87. W
	 5, 5, 2, 5, 5, // 88. X
	 5, 5, 7, 2, 2, // 89. Y
	 7, 4, 2, 1, 7, // 90. Z
	 0, 0, 6, 2, 2, // 91. parentesi quadra aperta
	 1, 3, 7, 3, 1, // 92. barra sinistrorsa
	 2, 2, 6, 0, 0, // 93. parentesi quadra chiusa
	 2, 2, 2, 2, 2, // 94. ordinale femminile
	 0, 0, 0, 0, 7, // 95. sottolinea
	 1, 2, 0, 0, 0, // 96. accento
	 0, 0, 0, 2, 2  // 97, a (2 vertical dots)
};

/* Mappa caratteri per il computer ed il sistema operativo:
   font a pi— alta risoluzione (32 x 36 pixels).
   Viene caricato in n_globes_map + gl_bytes ed occupa 10800 bytes.
   Questi 10182 bytes (gl_brest) sono praticamente una minuscola estensione
   dell'area n_globes_map che di per s‚, contenendo una semi-texture
   di 32Kb per la superficie dei mari, Š stata estesa da 22586 a 32768. */

Udword maybefar *digimap2; // verr… assegnato a n_globes_map + gl_bytes

/* Cupola panoramica. */

const float cupsize = 1800;
const float cupheight = 1667;

void cupola (float y_or, float brk)
{
	float xx, yy, zz;
	float lat, lon, dlat, dlon, dlon_2, k, clon, slon, ck, sk;

	dlat = M_PI / 20;
	dlon = M_PI / 10;

	dlon_2 = dlon / 2;

	for (lon = 0; lon < 2*M_PI - dlon_2; lon += dlon) {
		k = lon + dlon;
		ck = cos (k); sk = sin (k);
		clon = cos (lon); slon = sin (lon);
		for (lat = dlat; lat < brk * dlat; lat += dlat) {
			xx = cupsize * sin(lat+dlat);
			yy = - cupheight * cos(lat) * y_or;
			zz = cupsize * sin(lat);
			stick3d (zz*clon, yy, zz*slon,
				 xx*clon, -cupheight*cos(lat+dlat)*y_or, xx*slon);
			stick3d (zz*clon, yy, zz*slon,
				 zz*ck, yy, zz*sk);
		}
		if (gburst > 1) {
			lat = (M_PI / 20) * 8 * ((float)gburst / 63);
			lens_flares_for (cam_x, cam_y, cam_z,
					 +cupsize * clon * sin(lat),
					 -cupheight * 	   cos(lat),
					 +cupsize * slon * sin(lat),
					 -50000, 10, 1, 0, 1, 1);
			flares = 0;
		}
	}
}

void polycupola (float y_or, char textured)
{
	float d1, d2, d3, dd;
	float x[4], y[4], z[4];
	float lat, lon, dlat, dlon, dlon_2, k, clon, slon, ck, sk;

	dlat = M_PI / 20;
	dlon = M_PI / 10;

	dlon_2 = dlon / 2;

	if (textured)
		setfx (4);
	else
		setfx (2);

	for (lon = 0; lon < 2*M_PI - dlon_2; lon += dlon) {
		k = lon + dlon;
		ck = cos (k); sk = sin (k);
		clon = cos (lon); slon = sin (lon);
		for (lat = dlat; lat < 8 * dlat; lat += dlat) {
			xx = cupsize * sin(lat+dlat);
			yy = - cupheight * cos(lat) * y_or;
			zz = cupsize * sin(lat);
			x[0] = zz * clon;
			y[0] = yy;
			z[0] = zz * slon;
			x[1] = zz * ck;
			y[1] = yy;
			z[1] = zz * sk;
			x[2] = xx * ck;
			y[2] = - cupheight * cos(lat+dlat) * y_or;
			z[2] = xx * sk;
			x[3] = xx * clon;
			y[3] = - cupheight * cos(lat+dlat) * y_or;
			z[3] = xx * slon;
			if (ontheroof && y_or == 1) {
				d1 = 0.5 * (x[0] + x[1]) - cam_x;
				d2 = 0.5 * (z[0] + z[1]) - cam_z;
				dd = 1000 - SQRT (d1*d1 + d2*d2);
				if (dd > 600) dd = 600;
				if (dd < 0) dd = 0;
				cam_y += dd;
				poly3d (x, y, z, 4, 64);
				cam_y -= dd;
			}
			else {
				if (textured) {
					d1 = 0.5 * (x[0] + x[1]) - cam_x;
					d2 = 0.5 * (y[0] + y[2]) - cam_y;
					d3 = 0.5 * (z[0] + z[1]) - cam_z;
					dd = 500 - SQRT (d1*d1 + d2*d2 + d3*d3);
					if (dd > 500) dd = 500;
					if (dd < 0) dd = 0;
					cam_y += 4 * dd * y_or;
					xx = x[3]; yy = y[3]; zz = z[3];
					x[3] = x[2]; y[3] = y[2]; z[3] = z[2];
					x[2] = x[1]; y[2] = y[1]; z[2] = z[1];
					x[1] = x[0]; y[1] = y[0]; z[1] = z[0];
					x[0] = xx; y[0] = yy; z[0] = zz;
					polymap (x, y, z, 4, 5); // Temporarily fixes the landing cupola's graphical glitches
					//was polymap (x, y, z, 4, 0);
					cam_y -= 4 * dd * y_or;
				}
				else
					poly3d (x, y, z, 4, 64);
			}
		}
	}

	resetfx ();
}

/* Sincronizzatore: su qualsiasi PC un massimo di 18 fotogrammi al secondo. */

clock_t gtime;

void sync_start ()
{ gtime = CLOCK(); }

void sync_stop ()
{
	#ifdef WINDOWS
	//WinCycle();
	#endif
	while (CLOCK() == gtime) {
		#ifdef WINDOWS
		Sleep(1);
		#endif
	}
}

Dword   global_surface_seed, local_surface_seed, global_surface_seed_raw;
float  ppos_x, ppos_y, ppos_z;
double dsd, dsdSq;			// per misurare distanze

/* Carica la bitmap per la superficie stellare. */

void load_starface ()
{
	Uword seed = nearstar_identity * 12345;
	asm {	
		#ifdef WINDOWS
		push edi
		push ebx
		mov edi, [s_background]
		#else
		les di, dword ptr s_background
		#endif
		mov cx, 64800
		mov ax, seed }
rndpat:	asm {   add ax, cx
		xor dx, dx
		imul ax
		add ax, dx
		mov bl, al
		and bl, 0x3E
		#ifdef WINDOWS
		mov [edi], bl
		add edi, 1
		#else
		mov es:[di], bl
		inc di
		#endif
		dec cx
		jnz rndpat
		#ifdef WINDOWS
		pop ebx
		pop edi
		#endif
	}

	Word smoothcount;

	fast_srand (seed);
	smoothcount = fast_random(3);

	if (nearstar_class == 11 || nearstar_class == 7 || nearstar_class == 2)
		smoothcount += fast_random(3) + 2;

	while (smoothcount) {
		ssmooth (s_background);
		smoothcount--;
	}
}

void load_QVRmaps ()
{
	FILEPTR fh;

	fh = sa_open (offsets_map);
	if (fh ISFILEVALID) {
		READFILE (fh, n_offsets_map, om_bytes);
		CLOSEFILE (fh);
	} else {
		#ifdef WINDOWS
		error("Can't load offsets map, file is invalid!");
		#endif
	}

	fh = sa_open (globes_map);
	if (fh ISFILEVALID) {
		READFILE (fh, n_globes_map, gl_bytes);
		CLOSEFILE (fh);
	} else {
		#ifdef WINDOWS
		error("Can't load QVRmaps, file is invalid!");
		#endif
	}
}

void load_digimap2 ()
{
	FILEPTR fh;

	fh = sa_open (off_digimap2);
	if (fh ISFILEVALID) {
		READFILE (fh, digimap2, dm2_bytes);
		/*Uchar maybefar* dm2 = (Uchar maybefar*) digimap2;
		char temp[180];
		Dword b=0;
		Dword a=0;
		for (a=0; a<dm2_bytes; a++) {
			sprintf(temp+b, "%02x", (int) dm2[a]);
			//DebugPrintf(0, "a=%li, b=%li", a, b);
			if (b>=128) {
				b=0;
				//DebugPrintf(0, "%s", temp);
			} else {
				b+=2;
			}
		}
		//if (b!=0) DebugPrintf(0, "%s", temp);
		*/
		CLOSEFILE (fh);
	} else {
		#ifdef WINDOWS
		error("Can't load digimap2, file is invalid or missing!");
		#endif
	}
}

char	outhudbuffer[81];
//char	*compass = "N.........E.........S.........W.........N.........E.........S.......";
//char	*compass = "N.........W.........S.........E.........N.........W.........S.......";
char    *compass = "N....a....W....a....S....a....E....a....N....a....W....a....S....a.."; // "a" translates to a two-dotted period. Indicates NW/NE/SW/SE...


float	tp_gravity = 1, pp_gravity = 1;
float	tp_temp = 22, pp_temp = 22;
float	tp_pressure = 1, pp_pressure = 1;
float	tp_pulse = 118, pp_pulse = 118;

void wrouthud (Uword x, Uword y, Uword l, char *text, Word color = 191)
{
	Word j, i, n;
	Uword spot;

	n = 0; if (!l) l = 32767;
	spot = y * 320 + x;

	while (text[n] && n < l) {
		j = (text[n] - 32) * 5;
		for (i = 0; i < 5; i++) {
			if (digimap[j + i] & 1) adapted[spot+0] = color - adapted[spot+0];
			if (digimap[j + i] & 2) adapted[spot+1] = color - adapted[spot+1];
			if (digimap[j + i] & 4) adapted[spot+2] = color - adapted[spot+2];
			spot += 320;
		}
		spot -= 320 * 5;
		spot += 4;
		n++;
	}
}

extern char showmapz;
extern char showdebug;
extern char showplanet;
extern char showplanetmode;
extern int showplanetadd;
extern char showmaptype;
extern char nohud;
extern char movie;
extern float moviefps;
char blinkhudlights;
char blinkhudlights_stay;
char blinkhudlights_flash;
int  blnr;

void surrounding (char compass_on, Word openhudcount)
{
	Word cpos, crem;
	Dword	lsecs, lptr;
	float	pp_delta, ccom;

	for (lptr=0; lptr<04; lptr++) areaclear (adapted, 10, openhudcount + 9 - lptr, 0, 0, 300, 1, 54 + surlight + 3*lptr);
	for (lptr=0; lptr<10; lptr++) areaclear (adapted, 0, 9 - lptr, 0, 0, 320, 1, 64 + surlight - lptr);
	for (lptr=0; lptr<10; lptr++) areaclear (adapted, 0, 190 + lptr, 0, 0, 320, 1, 64 + surlight - lptr);
	for (lptr=0; lptr<10; lptr++) areaclear (adapted, 9 - lptr, 10, 0, 0, 1, 180, 64 + surlight - lptr);
	for (lptr=0; lptr<10; lptr++) areaclear (adapted, 310 + lptr, 10, 0, 0, 1, 180, 64 + surlight - lptr);

	lptr = 64 + 3 * surlight;
	if (lptr > 127) lptr = 127;

//Turn on (and make a bit larger) those lights. Blinkhudlights turns them on, and Blinkhudlights_stay
//makes them either turn off again, or stay on until Blinkhudlights is set to 0 again.
	if (blinkhudlights == 1) {
		if (lptr <= 111)
		lptr = 127;
		else lptr = 96;
		if (blinkhudlights_stay == 0) blinkhudlights = 0;
			
		blnr = blnr + 1;
		if (blnr >= 10) {
			if (blinkhudlights_flash == 1) {blinkhudlights_flash = 0; goto bla;}
			if (blinkhudlights_flash == 0) blinkhudlights_flash = 1;
				
			bla:
			blnr = 0;
		}			
		
		if ((blinkhudlights_stay == 1 && blinkhudlights_flash == 1) || blinkhudlights_stay == 0) {
			areaclear (adapted, 9, 9, 0, 0, 5, 5, lptr);
			smootharound_64 (adapted, 9, 9, 5, 1);
			areaclear (adapted, 307, 9, 0, 0, 5, 5, lptr);
			smootharound_64 (adapted, 308, 9, 5, 1);
			areaclear (adapted, 9, 187, 0, 0, 5, 5, lptr);
			smootharound_64 (adapted, 9, 188, 5, 1);
			areaclear (adapted, 307, 187, 0, 0, 5, 5, lptr);
			smootharound_64 (adapted, 308, 188, 5, 1);
		} else goto bla2;
	} else {
		bla2:
		areaclear (adapted, 9, 9, 0, 0, 4, 4, lptr);
		smootharound_64 (adapted, 9, 9, 5, 1);
		areaclear (adapted, 308, 9, 0, 0, 4, 4, lptr);
		smootharound_64 (adapted, 308, 9, 5, 1);
		areaclear (adapted, 9, 188, 0, 0, 4, 4, lptr);
		smootharound_64 (adapted, 9, 188, 5, 1);
		areaclear (adapted, 308, 188, 0, 0, 4, 4, lptr);
		smootharound_64 (adapted, 308, 188, 5, 1);
	}

	sprintf (outhudbuffer, "EPOC %d & ", epoc);
	lsecs = secs; lsecs -= lsecs % 1000000L; lsecs /= 1000000L;
	strcat (outhudbuffer, alphavalue(lsecs)); strcat (outhudbuffer, ".");
	lsecs = secs; lsecs %= 1000000L; lsecs -= lsecs % 1000; lsecs /= 1000;
	strcat (outhudbuffer, alphavalue(lsecs)); strcat (outhudbuffer, ".");
	lsecs = secs; lsecs %= 1000;
	strcat (outhudbuffer, alphavalue(lsecs));
	if (compass_on) {
		strcat (outhudbuffer, " & SQC ");
		strcat (outhudbuffer, alphavalue(landing_pt_lon));
		strcat (outhudbuffer, ".");
		strcat (outhudbuffer, alphavalue(landing_pt_lat));
		strcat (outhudbuffer, ":");
		strcat (outhudbuffer, alphavalue((((Dword)(pos_x)) >> 14) - 100));
		strcat (outhudbuffer, ".");
		strcat (outhudbuffer, alphavalue((((Dword)(pos_z)) >> 14) - 100));
		areaclear (adapted, 254, 1, 0, 0, 5, 7, 64 + 0);
		areaclear (adapted, 256, 8, 0, 0, 1, 1, 64 + 63);
		
		//Fixed: Corrected the compass (SL)
		
		//Each character is 4 pixels wide.
		//N is char 0, E is character 10, S 20, W 30, the farthest point before N is 39.
		//The compass can be divided into 40 four-pixel-wide characters, for 160 total pixels,
		//of which 112 are visible at any given time.
		
		//NIV uses -sin=x and cos=z, where north is negative z. So 0 is south, 90 is west, proceeding clockwise...
		//For comparison, I usually use sin=x cos=y and radians instead of degrees, so 0 is down, PI/2 is east, proceeding counterclockwise...
		//The 'correct' way (the way they teach in math classes) is to use cos=x and sin=y, so 0 is east, PI/2 (or 90) is north, proceeding counterclockwise, but that feels unnatural to me. :P
		//P.S. I'm not making any judgements as to which way is better.
		//(SL)
		
		//It seems that if you turn LEFT, you turn clockwise directionally (from north to east, not west).	//I had this comment backwards before (SL)
		
		//Presumably this is why ccom=360-user_beta was being done before, but the compass directions then didn't line up anyways.
		//Doing 360-(180+user_beta) makes turning appear correct, but reverses east/west incorrectly so when you go 'east' you're really going 'west' (and your coordinates show it if you know how to read them, and you'll definitely notice if you transit to a different sector) - so that's unacceptable.
		
		//Originally:
		//ccom = 360 - user_beta;
		//if (ccom > 359) ccom -= 360;
		
		//Now:
		ccom = 180-user_beta;
		if (ccom<0) ccom+=360;
		if (ccom>360) ccom-=360;
		
		//Angles:
		//		beta		360-beta	180+beta
		//S 	0			0			180
		//SW	45			315			225
		//W		90			270			270
		//NW	135			225			315
		//N		180			180			0
		//NE	-135		135			45
		//E		-90			90			90
		//SE	-45			45			135
		
		//pixel 58 should be the center.
		
		crem = (ccom*160/360)-54;	//Change it from 360 degrees to 160, and shift it since the first pixel should be 58 pixels to the left of the one we want in the center.
		if (crem<0) crem+=158;
		cpos = crem/4;	//cpos is the first character # to show.
		crem %= 4;
		wrouthud (200 - (crem), 2, 28, compass + cpos);
	}
	else {
		if (!ontheroof || !nohud) {
			strcat (outhudbuffer, " & ");
			if (sys==4)
                                if (option_controlset == 0) {
                                   strcat (outhudbuffer, "5\\FLIGHTCTR R\\DEVICES D\\PREFS X\\SCREEN OFF 4\\EXTENDED");
                                } else {
                                   strcat (outhudbuffer, "1\\FLIGHTCTR 2\\DEVICES 3\\PREFS 4\\SCREEN OFF 5\\EXTENDED");
                                }
			else {
				cpos = strlen (outhudbuffer);
				outhudbuffer[cpos + 00] = '6';
				outhudbuffer[cpos + 01] = '\\';
				memcpy (outhudbuffer + cpos + 02, ctb + 20 + 27 * 0, 10);
				outhudbuffer[cpos + 12] = ' ';
				outhudbuffer[cpos + 13] = '7';
				outhudbuffer[cpos + 14] = '\\';
				memcpy (outhudbuffer + cpos + 15, ctb + 20 + 27 * 1, 10);
				outhudbuffer[cpos + 25] = ' ';
				outhudbuffer[cpos + 26] = '8';
				outhudbuffer[cpos + 27] = '\\';
				memcpy (outhudbuffer + cpos + 28, ctb + 20 + 27 * 2, 10);
				outhudbuffer[cpos + 38] = ' ';
				outhudbuffer[cpos + 39] = '9';
				outhudbuffer[cpos + 40] = '\\';
				memcpy (outhudbuffer + cpos + 41, ctb + 20 + 27 * 3, 10);
				outhudbuffer[cpos + 51] = 0;
				strupr (outhudbuffer);
			}
		}
	}
	wrouthud (2, 2, NULL, outhudbuffer);

	pp_delta = (pp_gravity - tp_gravity) * 0.25; tp_gravity += pp_delta;
	pp_delta = (pp_temp - tp_temp) * 0.05; tp_temp += pp_delta;
	pp_delta = (pp_pressure - tp_pressure) * 0.02; tp_pressure += pp_delta;
	pp_delta = (pp_pulse - tp_pulse) * 0.01; tp_pulse += pp_delta;
	//unit… di debugging dell'albedo:
	//sprintf (outhudbuffer, "GRAVITY %2.3f FG & TEMPERATURE %+3.1f@C & PRESSURE %2.3f ATM & PULSE %3.0f PPS", tp_gravity, tp_temp, tp_pressure, (float)albedo);
	if (movie == 0) {
	   switch (option_temperature_units) {
		case 0:
			sprintf (outhudbuffer, "GRAVITY %2.3f FG & TEMPERATURE %+3.1f@C & PRESSURE %2.3f ATM & PULSE %3.0f PPS", tp_gravity, tp_temp, tp_pressure, tp_pulse);
			break;
		case 1:
			sprintf (outhudbuffer, "GRAVITY %2.3f FG & TEMPERATURE %+3.1f@K & PRESSURE %2.3f ATM & PULSE %3.0f PPS", tp_gravity, tp_temp + 273.15, tp_pressure, tp_pulse);
			break;
		case 2:
			sprintf (outhudbuffer, "GRAVITY %2.3f FG & TEMPERATURE %+3.1f@F & PRESSURE %2.3f ATM & PULSE %3.0f PPS", tp_gravity, tp_temp*1.8 + 32, tp_pressure, tp_pulse);
			break;
	  }
	} else {
            switch (option_temperature_units) {
		case 0:
			sprintf (outhudbuffer, "GRAVITY %2.3f FG & TEMPERATURE %+3.1f@C & PRESSURE %2.3f ATM & FPS %2.2f", tp_gravity, tp_temp, tp_pressure, moviefps);
			break;
		case 1:
			sprintf (outhudbuffer, "GRAVITY %2.3f FG & TEMPERATURE %+3.1f@K & PRESSURE %2.3f ATM & FPS %2.2f", tp_gravity, tp_temp + 273.15, tp_pressure, moviefps);
			break;
		case 2:
			sprintf (outhudbuffer, "GRAVITY %2.3f FG & TEMPERATURE %+3.1f@F & PRESSURE %2.3f ATM & FPS %2.2f", tp_gravity, tp_temp*1.8 + 32, tp_pressure, moviefps);
			break;
	  }
	}
	wrouthud (2, 192, NULL, outhudbuffer);
	if (showmapz == 1 && compass_on)
	showmap(showmaptype);
	if (showdebug == 1) showpalette();	//show the palette's colours on the top of the screen.

	if (showplanet != 0) {
        		showplansurf(showplanet - 1, showplanetmode , showplanetadd);
	}
}

/* Salva una fotografia dello schermo sul file "SNAPXXXX.BMP":
   XXXX Š un numero progressivo di disambiguazione. */
//It's XXXXXXXX.BMP now. (SL)

extern Dword star_label_pos;
extern char star_label[25];
extern Dword planet_label_pos;
extern char planet_label[25];
int movienr;
char movieflashoff = 1;
char movie;
extern char movie;
extern float moviefps;
int moviefscap;
int moviestime;
int moviedeck = 1;
int movieexists;
char snapfilename[24];
void snapshot (Word forcenumber, char showdata)
{
	Dword prog;
	Uword pqw;
	double parsis_x, parsis_y, parsis_z;

	Uword ptr, c;
	char a, b, t[54];

	FILEPTR ih = sa_open (header_bmp);
	if (ih==NOFILE) return;
	READFILE (ih, t, 54);
	CLOSEFILE (ih);

	pqw = QUADWORDS;
	#ifndef WINDOWS
	QUADWORDS = 16000;
	if (movie == 0 || (movieflashoff == 0 && movie == 1)) {
		pclear(adaptor, 0);
	}
	if (movie == 1){
		if (movieexists == 1) {				//movie does NOT exist yet
			sprintf (snapfilename, "..\\MOVIES\\%03i", moviedeck);		//we just use snapfilename here, so we don't have to assign any more stuff
			mkdir("..\\MOVIES");
                        mkdir(snapfilename);										//and here we make the folder for the movie to record to.
		}
		if (movieflashoff == 1) {
			if (surlight <= 38) areaclear(adaptor, 1, 198, 319, 199, 0, 1, 127);	//bright line when surroundinglight <= 38 (bright line = 127)
				else areaclear(adaptor, 1, 198, 319, 199, 0, 1, 1);					//dark line when surroundinglight > 38 (dark line = 1)
		}
		moviefscap ++;
	}
	QUADWORDS = pqw;
	#endif
	
	if (!forcenumber) {
		prog = lastSnapshot;
		char recycled=0;
		do {
			if (!movie) {prog++; if (prog == 100000000) {	//Image limit increased to 99,999,999 (SL)
				if (recycled) {
					status("TOO MANY SNAPSHOTS", 300);
					return;
				} else {
					recycled=1;
					prog=0;
				}
			} }
			if (movie == 1) {									//Recording a movie instead of doing a screenshot? Do moviestuffs...
				movienr++;
				sprintf (snapfilename, "..\\MOVIES\\%03i\\%08d.BMP", moviedeck, movienr);
				remove(snapfilename);
			} else sprintf (snapfilename, "..\\GALLERY\\%08d.BMP", prog);	//Image limit increased to 99,999,999 (SL)
			ih = OPENFILE (snapfilename, OPEN_RB);
			if (ih != NOFILE) CLOSEFILE (ih);
		} while (ih != NOFILE);
		lastSnapshot = prog;
	}
	else
		sprintf (snapfilename, "..\\GALLERY\\WIDE%04d.BMP", forcenumber);	//Panoramic snapshots no longer overwrite pictures 9997-9999 if those happened to exist. (SL)
	if (showdata) {
		areaclear (adapted, 2, 191, 0, 0, 316, 7, 64 + 63);
	
		asm {	fld dzat_x
			frndint
			fstp parsis_x
			fld dzat_y
			frndint
			fstp parsis_y
			fld dzat_z
			frndint
			fstp parsis_z }
	
		strcpy (outhudbuffer, "LOCATION PARSIS: ");
		strcat (outhudbuffer, alphavalue(parsis_x));
		strcat (outhudbuffer, ";");
		strcat (outhudbuffer, alphavalue(-parsis_y));
		strcat (outhudbuffer, ";");
		strcat (outhudbuffer, alphavalue(parsis_z));
		if (ip_targetted > -1) {
			if (nearstar_p_owner[ip_targetted] > -1) {
				strcat (outhudbuffer, " & TGT: MOON N@");
				strcat (outhudbuffer, alphavalue(nearstar_p_moonid[ip_targetted]+1));
				strcat (outhudbuffer, " OF PLANET N@");
				strcat (outhudbuffer, alphavalue(nearstar_p_owner[ip_targetted]+1));
			}
			else {
				strcat (outhudbuffer, " & TGT: PLANET N@");
				strcat (outhudbuffer, alphavalue(ip_targetted+1));
			}
		}
		wrouthud (3, 192, NULL, outhudbuffer);
	
		if (ap_targetted == 1 && star_label_pos != -1) {
			areaclear (adapted, 14, 14, 0, 0, 102, 7, 64 + 63);
			wrouthud (15, 15, 20, star_label);
		}
	
		if (ip_targetted != -1 && planet_label_pos != -1) {
			areaclear (adapted, 14, 23, 0, 0, 102, 7, 64 + 63);
			wrouthud (15, 24, 20, planet_label);
		}
    }

	ih = CREATEFILE (snapfilename);
	if (ih ISFILEVALID) {
		a = 0;
		WRITEFILE (ih, t, 54);
		for (c=0; c<768; c+=3) {
			b = tmppal[c+2]*4; WRITEFILE (ih, &b, 1);
			b = tmppal[c+1]*4; WRITEFILE (ih, &b, 1);
			b = tmppal[c+0]*4; WRITEFILE (ih, &b, 1);
			WRITEFILE (ih, &a, 1);
		}
		for (ptr=63680; ptr<64000; ptr-=320) WRITEFILE (ih, &(adapted[ptr]), 320);
		CLOSEFILE (ih);
	} else {
		DebugPrintf(1, "Error. ih (%i) isn't valid. sn %s", ih, snapfilename);
	}
}

/*
    Consumi supplementari di litio, dal pi— dispendioso al pi— economico:
	- orbita vimana:			1 KD ogni 7 secondi.
	- inseguimento a punto lontano: 	1 KD ogni 18 secondi.
	- inseguimento a punto fisso:		1 KD ogni 29 secondi.
	- inseguimento a punto vicino:		1 KD ogni 33 secondi.
	- amplificatore di campo stellare:	1 KD ogni 41 secondi.
	- orbita geosincrona:			1 KD ogni 58 secondi.
	- lampada interna:			1 KD ogni 84 secondi.
	- cercapianeti:				1 KD ogni 155 secondi.
*/

Dword iqsecs = 0;
void additional_consumes()
{
	if (iqsecs < (Dword)secs)
		iqsecs = secs;
	//
	if (ip_targetted > -1 && pwr > 15000) {
		if (ip_reached && sync) {
			if (sync==1) // fixed-point chase
				if (!(iqsecs % 29)) { pwr--; iqsecs++; }
			if (sync==2) // far chase
				if (!(iqsecs % 18)) { pwr--; iqsecs++; }
			if (sync==3) // syncrone orbit
				if (!(iqsecs % 58)) { pwr--; iqsecs++; }
			if (sync==4) // high-speed orbit
				if (!(iqsecs %  7)) { pwr--; iqsecs++; }
			if (sync==5) // near chase
				if (!(iqsecs % 33)) { pwr--; iqsecs++; }
			if (sync==6) // high-speed near chase
				if (!(iqsecs %  7)) { pwr--; iqsecs++; }
		}
	}
	//
	if (pl_search		&& !(iqsecs % 155)) { pwr--; iqsecs++; }
	if (ilightv == 1	&& !(iqsecs %  84)) { pwr--; iqsecs++; }
	if (field_amplificator	&& !(iqsecs %  41)) { pwr--; iqsecs++; }
	//
	if (pwr <= 15000) {
		if (charge>0) {
			charge--;
			pwr = 20000;
			status ("FCS: READY", 100);
		} else if (charge<0) {	//HACK: If you set your Li+ negative, you have infinite fuel. (SL)
			pwr = 20000;
			status ("OMEGA", 100);
		} else {
			stspeed 	= 0;
			ip_reaching 	= 0;
			ip_reached 	= 1;
			ip_targetted 	= -1;
			if (pwr != 15000) {
				status ("POWER LOSS", 100);
				pwr = 15000;
			}
		}
	}
}
#endif
