#include "noctis-d.h"
#include "noctis-0.h"
#include "noctis-2.h"
#ifdef WINDOWS
#include "randalg.h"
#include "win.h"
#endif

extern char goesnet_command[];
extern char gnc_pos;

//#include "mem.h"

const double deg = M_PI / 180;
float liftx, liftz;
Word	opencapcount;
float	refx, refy, refz;
float	sp_x, sp_y, sp_z;
Word firstpush=1;
Word ape_probability=0;
Bool ape_zombie=0;
Bool ape_stargazer=0;
Word bull_probability=0;

/* Funzioni e variabili globali di tracciamento e gestione
   delle superfici planetarie, in poligonale (h! ce la far•?)

	Si, ce l'ho fatta, ahem... dunque...
	per tracciare in tempo utile una superficie di 40000 quadranti,
	ovvero 80000 triangoli, su una matrice di 200x200 (un po' tantino
	in effetti) ho applicato un procedimento di, boh...
	"focalizzazione" diciamo. Pi— probabilmente pu• chiamarsi
	"depth culling"... inclusi i riflessi, la funzione "fragment"
	passa al vaglio 160.000 poligoni per fotogramma, disegnandone
	comunque circa un decimo. E' importante ottimizzare quella,
	quando si vuole ottimizzare qualcosa... */

char 	sctype; // tipo di scenario.


float dsd1, dsd2;     // distanza dal sole (pri/sec)
float nray1, nray2;   // raggio del sole (pri/sec)
float latitude;	      // latitudine (0..90, 90=poli)
float exposure;	      // longitudine relativa al centro dell'area diurna.
float sun_x, sun_y, sun_z; // coordinate del "sole" locale.
Word   sh_delta;		// shift del puntatore di confronto per lo shading.

// dati riguardanti il "sole" primario se ci si trova
// attorno a un sole secondario (sistemi multipli di classe 8)
Word   pri_crepzone;
Word   pri_nightzone;
Word   pri_sun_x_factor;
float pri_latitude, pri_exposure;
float pri_x, pri_y, pri_z;
char degrass = 0;
char jumping;
char jetpack;
float buildingcount;
float mapmod = 1;
float mapcontr = 1;
extern char blinkhudlights;
extern char blinkhudlights_stay;
Word brightencnt = 63;
int visionmode = 0;
float fixed_step = 0;
char hopfind = 0;
char hideplants = 0;
char hidebeam = 0;
char showmapz = 0;
char showmapcol = 1;
char supvision = 0;
char showmaptype = 1;
char showdebug = 0;
char showplanet = 0;
char showplanetmode = 0;
int showplanetadd = 0;
char nightisoff = 0;

unsigned int tempi;
unsigned int tempb;
int tempx;
int tempy;
int tempz;
int tempn=1;


char  mirror = 0;     // effetto specchio d'acqua (agisce su "fragment").
char  waves_in = 0;   // flag di presenza delle onde sui mari.
char  waves_out = 0;  // flag di produzione di onde sui mari.
Dword  T_SCALE;	      // scala della texture, passata in H/V_MATRIXS.
char  glassified = 0;

float base_pp_temp;
float base_pp_pressure;

float hpoint (Dword px, Dword pz)
{ // Trova l'altezza di un punto sulla superficie.
  // Per migliorare la risoluzione, usa un procedimento d'interpolazione
  // bi-lineare, con 16384 gradazioni intermedie, tante quante le unit…
  // logiche che compongono il lato di un quadrante; considera anche
  // la divisione dei quadranti in due triangoli isosceli.
	Dword cpos;

	float h1, h2, h3, h4, icx, icz, py;

	cpos   = m200[pz>>14] + (px>>14);

	h1     = - ((Dword)(p_surfacemap[cpos])     << 11);
	h2     = - ((Dword)(p_surfacemap[cpos+1])   << 11);
	h3     = - ((Dword)(p_surfacemap[cpos+201]) << 11);
	h4     = - ((Dword)(p_surfacemap[cpos+200]) << 11);

	icx    = px & 16383;
	icz    = pz & 16383;

	if (icx+icz<16384) {
		py  = h1 + (h2 - h1) * (icx * qid);
		py += (h4 - h1) * (icz * qid);
	}
	else {
		py  = h3 + (h4 - h3) * ((16384-icx) * qid);
		py += (h2 - h3) * ((16384-icz) * qid);
	}

	return (py);
}

/*

	-----------------------------------------------------------------
	Collezione di funzioni interdipendenti per il tracciamento degli
	oggetti che si possono trovare sulla superficie dei vari pianeti.
	-----------------------------------------------------------------

*/

char  groundflares = 0;		// tipo di tracciamento del suolo.
Dword  mushscaling = 8191;	// range variabilit… (in bitmask) "greenmush"
float treescaling = 4096;	// scalatura alberi, di solito mushscaling/2
float treespreads = 0.75;	// scalatura rami ad ogni ricorsione
float treepeaking = 1.25;	// passa come "distance_from_perfection"
float branchwidth = 0.15;	// larghezza dei rami rispetto alla lunghezza
float rootheight  = 0.50;	// altezza del tronco rispetto a "treescaling"
char  rootshade   = 0x00;	// colore di base del tronco
char  treeflares  = 0x00;	// tipo di tracciamento rami.
char  leafflares  = 0x00;       // tipo di tracciamento foglie.

float rockscaling = 500;	// dimensioni delle rocce.
float rockpeaking = 250;	// altezza delle rocce.
Word   rockdensity = 15;		// densit… gruppi di rocce (bitmask).
char  quartz	  = 0;		// traccia quarzi trasparenti, se impostato.

Word   detail_seed = 12345;

void greenmush (float x, float y, float z,
		Uchar mask_1, Uchar mask_2,
		Dword scaling, Uchar colorgrade,
		Uchar colormask, char noseed)
{ // produce una serie di gruppi di minuscole sagome verdi, studiate per
  // fornire l'impressione delle fronde degli alberi pi— distanti.

	Dword	correction;
	Word	n1, m1, n2, m2;

	correction = scaling >> 1;
	x += correction;
	y += correction;
	z += correction;

	if (!noseed)
		fast_srand (((long)x>>14) + ((long)y>>14) + ((long)z>>14));

	m1 = 1 + fast_random (mask_1);
	for (n1 = 0; n1 < m1; n1++)
		if (getcoords (x - fast_random (scaling),
			       y - fast_random (scaling),
			       z - fast_random (scaling))) {
			m2 = 1 + fast_random (mask_2);
			for (n2 = 0; n2 < m2; n2++) {
				_DI = riga[_y_+fast_random(7)]+_x_+fast_random(7);
				_CL = colorgrade + fast_random (colormask);
				asm {	les ax, adapted
					mov es:[di+4], cl
					mov es:[di+5], cl
					mov es:[di+3], cl
					mov es:[di+324], cl
					mov es:[di-316], cl
					mov es:[di-636], cl }
			}
		}
}

void build_fractal_tree (float x, float y, float z,
			 float scaling, float reduction, float globalwidth,
			 long layers, long divisions, float distance_from_perfection,
			 unsigned char rootcolormask, unsigned char leafcolormask,
			 float branchdetail, char isrootnode, char occurrence)
{ // funzione ricorsiva: eventualmente traccia l'intero albero pseudo-casuale,
  // con una struttura multilivello, ma va usata con parsimonia perch‚ Š
  // ovviamente una cosa piuttosto laboriosa in termini di tempo.
  //
  // serve qualche spiegazione per i parametri, che sono davvero tantini...
  //
  // P(x;y;z)    - origine del tronco (punto medio della base del tronco)
  // scaling     - altezza del tronco (determina anche la lunghezza dei rami)
  // reduction   - coefficiente di riduzione della lunghezza dei rami,
  //		   calcolata rispetto a quella del tronco livello per livello
  // globalwidth - coefficiente che determina la larghezza dei rami,
  //		   calcolata rispetto alla loro lunghezza
  // layers	 - numero di processi ricorsivi di suddivisione del tronco
  //		   una buona tattica per disegnare ciuffi d'erba Š porre
  //		   questo parametro E il successivo entrambi a zero...
  // divisions   - maschera delle ramificazioni della cima di ogni ramo
  // branchdetail- step di rotazione nel tracciamento dei rami
  //		   (p.es. 120 traccia 360/120 = 3 poligoni per ramo)...
  //		   il minimo livello di dettaglio Š 360, un poligono per ramo,
  //		   180 fa i rami piatti ma visibili da ogni lato,
  //		   e infine 120 approssima piuttosto bene...
  // isrootnode  - chiamare la funzione con questo parametro impostato a 1
  //		   per ottenere un albero normale, anche se si possono
  //		   agevolmente disegnare dei cespugli semplicemente ponendo
  //		   questo flag a zero, poich‚ un cespuglio pu• essere anche
  //		   approssimato, in effetti, come un albero senza tronco
  // occurrence  - Š un contatore, va semplicemente posto a zero.
  //
  // rootcolormask Š il colore di base per il tronco e per i rami.
  // leafcolormask Š il colore di base per le foglie.
  //
  // distance_from_perfection, infine, Š un coefficiente in gradi, che
  // esprime di quanto i rami "figli" possono divaricarsi ad ogni ulteriore
  // suddivisione dei rami "padri": in pratica, distance_from_perfection
  // rappresenta l'irregolarit… generale dell'albero - ad esempio, per le
  // latifoglie bisognerebbe impostare questo parametro ad un valore alto
  // (diciamo all'incirca 1.25), mentre per qualcosa di pi— simile ad una
  // conifera questo valore andrebbe abbassato all'incirca a 0.3 .. 0.4
  // (ponendolo a zero si otterrebbero rami in una colonna verticale).

	
	int   subdivs;
	char  polycolor;
	char  pf = flares;

	float x2, y2, z2;
	float fx[4], fy[4], fz[4];
	float widthscale1, widthscale2;
	float b_angle, b_angle_delta, range, rotation, rlimit;
	float rot2, rot3;

	long hm, vm, lseed;
	unsigned char huge *previoustexture;

	widthscale1 = scaling * globalwidth;
	widthscale2 = reduction * scaling * globalwidth;

	if (isrootnode) {
		subdivs = 1;
		range = scaling * distance_from_perfection * 0.2;
	}
	else {
		subdivs = 1 + fast_random (divisions);
		range = scaling * distance_from_perfection * 0.5;
	}
	
	rlimit = 360 - branchdetail;
	b_angle = 0;
	if (subdivs) {
		b_angle_delta = (float)(2*M_PI) / (float)subdivs;
		b_angle = b_angle_delta * 0.5;
	}

	lseed = x + y + z + detail_seed;
	while (subdivs) {
		fast_srand (lseed);
		lseed += 3;
		//
		if (layers) {
			flares = treeflares;
			hm = H_MATRIXS; vm = V_MATRIXS;
			H_MATRIXS = 3; V_MATRIXS = 8;
			change_txm_repeating_mode();
			previoustexture = txtr;
			x2 = x + cos(b_angle) * range;
			z2 = z + sin(b_angle) * range;
			if (isrootnode)
				y2 = y - (fast_flandom() * rootheight + 0.1) * scaling;
			else
				y2 = y - (fast_flandom() + 0.25) * scaling * 0.25;
			fy[0] = y;
			fy[1] = y;
			fy[2] = y2;
			fy[3] = y2;
			polycolor = 9 * occurrence;
			for (rotation = 0; rotation <= rlimit; rotation += branchdetail) {
				fx[0] = x  + lft_cos[rotation               ] * widthscale1;
				fz[0] = z  + lft_sin[rotation               ] * widthscale1;
				fx[1] = x  + lft_cos[rotation + branchdetail] * widthscale1;
				fz[1] = z  + lft_sin[rotation + branchdetail] * widthscale1;
				fx[2] = x2 + lft_cos[rotation + branchdetail] * widthscale2;
				fz[2] = z2 + lft_sin[rotation + branchdetail] * widthscale2;
				fx[3] = x2 + lft_cos[rotation               ] * widthscale2;
				fz[3] = z2 + lft_sin[rotation               ] * widthscale2;
				if (isrootnode) {
					fy[0] = hpoint (fx[0], fz[0]);
					fy[1] = hpoint (fx[1], fz[1]);
				}
				if (facing (fx, fy, fz))
					polymap (fx, fy, fz, 4, polycolor + rootcolormask);
				txtr += 48;
				polycolor += 4;
			}
			H_MATRIXS = hm; V_MATRIXS = vm;
			change_txm_repeating_mode();
			txtr = previoustexture;
			build_fractal_tree (x2, y2, z2, scaling * reduction, reduction,
					    globalwidth, layers - 1, divisions, distance_from_perfection,
					    rootcolormask, leafcolormask, branchdetail, 0, occurrence + 1);
		}
		else {
			flares = leafflares;
			hm = H_MATRIXS; vm = V_MATRIXS;
			H_MATRIXS = 1; V_MATRIXS = 3;
			change_txm_repeating_mode();
			previoustexture = txtr;
			x2 = x + fast_flandom() * range - fast_flandom() * range;
			z2 = z + fast_flandom() * range - fast_flandom() * range;
			fy[0] = y;
			fy[1] = y;
			fy[2] = y - fast_flandom() * scaling;
			polycolor = fast_random (31);
			rot2 = 0; rot3 = 0;
			for (rotation = 0; rotation <= rlimit; rotation += branchdetail) {
				rot2 = rotation + 72; if (rot2 > 359) rot2 -= 360;
				rot3 = rotation + 36; if (rot3 > 359) rot3 -= 360;
				fx[0] = x  + lft_cos[rotation]	* widthscale1;
				fz[0] = z  + lft_sin[rotation]	* widthscale1;
				fx[1] = x  + lft_cos[rot2]	* widthscale1;
				fz[1] = z  + lft_sin[rot2]	* widthscale1;
				fx[2] = x2 + lft_cos[rot3]	* range + wdircos;
				fz[2] = z2 + lft_sin[rot3]	* range + wdirsin;
				polymap (fx, fy, fz, 3, polycolor + leafcolormask);
				greenmush (fx[2], fy[2], fz[2], 15, 3, 1023, 223, 31, 0);
				polycolor += 2;
			}
			H_MATRIXS = hm; V_MATRIXS = vm;
			change_txm_repeating_mode();
			txtr = previoustexture;
		}
		//
		subdivs--;
		b_angle += b_angle_delta;
	}

	flares = pf;
}

#define FORCE_LAT	11
#define FORCE_CON	22
#define GIANT_TREE	333

void albero (float x, float y, float z, long depth)
{ // disegna alberi ove richiesti.
	if (sctype==FOREST) { // If the surfacetype is forest, let's do some interesting changes to it, like bigger trees.. (MEGA)
		treescaling = 4096 * 5; //Make em 5 times as large!
		branchwidth = 0.15 / 4; //Make em 4 times as thin! (The 5 times as large treescaling already makes branchwidth 5 times as large, so here we divide branchwidth by 4..not 5, since that seems to be a bit ugly).
		rootheight = 1.00; //Make the branches start higher!
	}
	

	if (!hideplants) {
		fast_srand (x+y+z+3);
		Word treetype = fast_random(511);

		if (treetype == GIANT_TREE) {
			if (depth > 11) {
				greenmush (x, y - treescaling * 0.5, z, 07, 15, mushscaling, 223, 31, 0);
			} else if (depth > 07) {
				build_fractal_tree (x, y, z,
							2*treescaling, treespreads, 1.5*branchwidth,
							3, 2, 1.5*treepeaking, rootshade, 0xC0, 120, 1, 0);
			} else if (depth > 04) {
				build_fractal_tree (x, y, z,
							2*treescaling, treespreads, 1.5*branchwidth,
							4, 3, 1.5*treepeaking, rootshade, 0xC0, 120, 1, 0);
			} else {
				build_fractal_tree (x, y, z,
						2*treescaling, treespreads, 1.5*branchwidth,
						4, 3, 1.5*treepeaking, rootshade, 0xC0, 72, 1, 0);
			}
		} else if (depth > 20) {
			greenmush (x, y - treescaling * 0.5, z, 03, 07, mushscaling, 223, 31, 0);
		} else if (depth > 10) {
			greenmush (x, y - treescaling * 0.7, z, 07, 15, mushscaling, 223, 31, 0);
		} else if (depth > 03) {
			greenmush (x, y - treescaling * 0.9, z, 15, 31, mushscaling, 223, 31, 0);
		} else {
			treetype >>= 3;

			if (treetype == FORCE_LAT) {
				build_fractal_tree (x, y, z,
							treescaling, treespreads, branchwidth,
							2, 3, 2*treepeaking, 0x80, 0xC0, 120, 1, 0);
			} else if (treetype == FORCE_CON) {
				build_fractal_tree (x, y, z,
							treescaling, treespreads, branchwidth,
							2, 2, 0.5*treepeaking, 0x80, 0x40, 120, 1, 0);
			} else {
				build_fractal_tree (x, y, z,
						treescaling, treespreads, branchwidth,
						2, 2, treepeaking, rootshade, 0xC0, 120, 1, 0);
			}
		}
	}
}

void cespuglio (float x, float y, float z, long depth)
{ // disegna un cespuglio.
	// da 48 mt in poi: ammasso di foglie.
	if (!hideplants) {
		if (depth >= 3) {
			greenmush (x, y, z, 7, 7, mushscaling, 209, 31, 0);
			return;
		}

		switch (depth) {
			case 2: // 32 -- 48 mt: visibili i ramoscelli pi— grandi.
				build_fractal_tree (x, y, z, 3000, 0.75, 0.15, 1, 1, 1.5, 0x00, 0xC0, 180, 0, 0);
				break;
			case 1: // 16 -- 32 mt: visibili il 50% delle ramificazioni.
				build_fractal_tree (x, y, z, 3000, 0.75, 0.15, 1, 2, 1.5, 0x00, 0xC0, 120, 0, 0);
				break;
			case 0: //  0 -- 16 mt: cespuglio completo.
				build_fractal_tree (x, y, z, 3000, 0.75, 0.15, 1, 3, 1.5, 0x00, 0xC0, 120, 0, 0);
		}
	}
}

void ciuffo (float x, float y, float z, long depth)
{ // disegna un ciuffo d'erba.

	// da 64 mt in poi, non Š visibile.
	if (!hideplants && depth<4) {

		switch (depth) {
			case 3: // 48 -- 64 mt: qualche macchietta.
				greenmush (x, y, z, 3, 7, 1023, 216, 31, 0);
				break;
			case 2: // 32 -- 48 mt: visibile un filo d'erba.
				build_fractal_tree (x, y, z, 1000, 1.00, 0.25, 0, 0, 1.0, 0x00, 0xC0, 120, 0, 0);
				break;
			case 1: // 16 -- 32 mt: visibili il 50% dei fili d'erba.
				build_fractal_tree (x, y, z, 1000, 1.00, 0.25, 0, 7, 1.0, 0x00, 0xC0,  90, 0, 0);
				break;
			case 0: //  0 -- 16 mt: un ciuffo completo.
				build_fractal_tree (x, y, z, 1000, 1.00, 0.25, 0, 7, 1.0, 0x00, 0xC0,  60, 0, 0);
		}
	}
}

void roccia (float x, float y, float z, long depth)
{ // disegna una pietra fatta sulla base di un tetraedo per risparmiare tempo.
	// da 160 mt in poi: nulla di visibile.
	// questo significa che non devono mai essere visualizzate rocce.
	if (!hideplants && depth<8 && rockdensity) {
		float tx[4], ty[4], tz[4];
		float px[3], pz[3];
		float rs = rockscaling;

		char  rc[3], rcolor;
		int   cdown;

		fast_srand (detail_seed);

		// e questo che IN questo quadrante non ci sono rocce.
		cdown = fast_random (rockdensity);
		if (cdown) {

			// da 32 a 160 mt: solo un triangolino.		//"dots"
			if (depth > 2) {
				tx[0] = x; tx[1] = x; tx[2] = x + rockscaling - fast_flandom () * rockscaling;
				tz[0] = z; tz[1] = z; tz[2] = z + rockscaling - fast_flandom () * rockscaling;
				ty[0] = y - 100 - fast_flandom () * rockpeaking;
				ty[1] = y - 100 - fast_flandom () * rockpeaking;
				ty[2] = y - 100 - fast_flandom () * rockpeaking;
				rcolor = fast_random (64 + 7);
				if (facing (tx, ty, tz))
					poly3d (tx, ty, tz, 3, rcolor);
				return;
			} else {

				// da 16 a 32 mt: tre triagolini disposti a tetraedo, senza base.
				// da 0 a 16 mt: con texture, e sassolini multipli se necessari.

				rockscaling *= 5;
				setfx (quartz);

			rockrep:px[0] = x - fast_flandom () * rockscaling;
				pz[0] = z - fast_flandom () * rockscaling;
				px[1] = x;
				pz[1] = z + fast_flandom () * rockscaling;
				px[2] = x + fast_flandom () * rockscaling;
				pz[2] = z - fast_flandom () * rockscaling;

				rcolor = fast_random (64);
				rc[0] = rcolor + fast_random( 7);
				rc[1] = rcolor + fast_random(15);
				rc[2] = rcolor + fast_random(31);
			
				tx[2] = x; tz[2] = z;
				ty[2] = hpoint (x, z) - 100 - fast_flandom () * rockpeaking;
			
				tx[0] = px[0]; tx[1] = px[1];
				tz[0] = pz[0]; tz[1] = pz[1];
				ty[0] = hpoint (tx[0], tz[0]);
				ty[1] = hpoint (tx[1], tz[1]);
				if (facing (tx, ty, tz)) {
					if (depth < 2) {
						tx[3] = tx[2]; ty[3] = ty[2]; tz[3] = tz[2];
						polymap (tx, ty, tz, 4, rc[0]);
					}
					else
						poly3d (tx, ty, tz, 3, rc[0]);
				}
				tx[0] = px[1]; tx[1] = px[2];
				tz[0] = pz[1]; tz[1] = pz[2];
				ty[0] = hpoint (tx[0], tz[0]);
				ty[1] = hpoint (tx[1], tz[1]);
				if (facing (tx, ty, tz)) {
					if (depth < 2) {
						tx[3] = tx[2]; ty[3] = ty[2]; tz[3] = tz[2];
						polymap (tx, ty, tz, 4, rc[1]);
					}
					else
						poly3d (tx, ty, tz, 3, rc[1]);
				}
				tx[0] = px[2]; tx[1] = px[0];
				tz[0] = pz[2]; tz[1] = pz[0];
				ty[0] = hpoint (tx[0], tz[0]);
				ty[1] = hpoint (tx[1], tz[1]);
				if (facing (tx, ty, tz)) {
					if (depth < 2) {
						tx[3] = tx[2]; ty[3] = ty[2]; tz[3] = tz[2];
						polymap (tx, ty, tz, 4, rc[2]);
					}
					else
						poly3d (tx, ty, tz, 3, rc[2]);
				}
				x = x + fast_flandom() * 1000 * cdown - fast_flandom () * 1000 * cdown;
				z = z + fast_flandom() * 1000 * cdown - fast_flandom () * 1000 * cdown;
				y = hpoint (x, z); rockscaling *= 0.5;
				cdown--; if (cdown>0) goto rockrep;
			
				rockscaling = rs;
				resetfx ();
			}
		}
	}
}

/*

	-----------------------------------------------------------------
	Collezione di funzioni per il tracciamento e l'animazione delle
	forme di vita indigene dei pianeti abitabili.
	-----------------------------------------------------------------

*/

#define LFS 	100		// massimo numero di animali.
Word   animals  =   0;		// animali attualmente visibili.
char  ani_type [LFS];		// tipologia
Dword  ani_seed [LFS];		// seme pseudo per le modifiche alla forma.
float ani_scale[LFS];		// scala.
float ani_x    [LFS];		// posizione (X)
float ani_quote[LFS];		// quota rispetto al suolo.
float ani_z    [LFS];		// posizione (Z)
float ani_pitch[LFS];		// direzione in cui si spostano.
float ani_speed[LFS];		// velocit… attuale.
float tgt_quote[LFS];		// quota che vogliono raggiungere.
float tgt_speed[LFS];		// velocit… che vogliono raggiungere.
float tgt_pitch[LFS];		// direzione che vogliono acquisire.
char  ani_lcount[LFS];		// contatempo di vicinanza.
Uword ani_sqc[LFS];		// sub-quadrant coordinates (attuali).
char  ani_mtype[LFS];		// tipo di movimento.
	#define FELINE_LIKE	0
	#define RABBIT_LIKE	1
	#define KANGAROO_LIKE	2
	#define APE_LIKE 3
	
#define BIRD	1               // definizione tipologia (per classi).
#define REPTIL	4
#define MAMMAL  5
#define APEMAMMAL 6
#define BULLMAMMAL 7

// dati di definizione - classe uccelli - relativo PVfile: "birdy_ncc"

const Word bird_wings_center_p = 1;
const Word bird_wings_center_v = 0;

pvlist bird_wing1[3] = { {  0, 1,1,1,0 }, {  1, 1,1,1,0 }, {0xFFF,0,0,0,0} };
pvlist bird_wing2[3] = { {  2, 1,1,1,0 }, {  3, 1,1,1,0 }, {0xFFF,0,0,0,0} };

const Word bird_legs_center_p  = 18;
const Word bird_legs_center_v  = 1;

pvlist bird_legs[3]  = { { 18, 0,0,1,0 }, { 19, 0,1,0,0 }, {0xFFF,0,0,0,0} };

// dati di definizione - classe mammiferi - relativo PVfile: "mammal_ncc"

pvlist mamm_ears[5] = {
	{ 42, 0,1,0,0 },
	{ 45, 0,0,1,0 },
	{ 43, 1,0,0,0 },
	{ 44, 0,0,1,0 },
	{0xFFF,0,0,0,0}
};

const Word mamm_wrap_center_p  = 16;
const Word mamm_wrap_center_v  = 2;

pvlist mamm_reartoto[19] = {
	{  7, 0,0,1,1 },
	{  8, 1,1,1,1 },
	{  9, 1,1,1,1 },
	{ 14, 1,1,1,1 },
	{ 18, 0,1,1,0 },
	{ 12, 1,1,1,1 },
	{ 19, 1,0,0,1 },
	{ 21, 0,0,1,1 },
	{ 10, 1,1,1,1 },
	{ 15, 1,1,1,1 },
	{ 13, 1,1,1,1 },
	{ 11, 1,1,1,1 },
	{ 46, 1,1,1,1 },
	{ 47, 1,1,1,1 },
	{ 50, 1,1,1,1 },
	{ 51, 1,1,1,1 },
	{ 48, 1,1,1,0 },
	{ 49, 1,1,1,0 },
	{0xFFF,0,0,0,0}
};

pvlist mamm_legs[15] = {
	{  0, 1,1,1,1 }, // F-L
	{  2, 1,1,0,0 },
	{ 22, 1,0,0,0 },
	{  1, 1,1,1,1 }, // F-R
	{  3, 1,1,0,0 },
	{ 23, 0,1,0,0 },
	{  8, 0,0,1,1 }, // R-L
	{ 10, 1,1,1,1 },
	{ 14, 0,1,1,0 },
	{ 15, 1,1,1,1 },
	{ 12, 0,0,1,1 }, // R-R
	{ 13, 1,1,1,1 },
	{  9, 0,0,1,1 },
	{ 11, 1,1,1,1 },
	{0xFFF,0,0,0,0}
};

const Word mamm_lleg_center_p = 14;
const Word mamm_lleg_center_v = 0;

const Word mamm_rleg_center_p = 12;
const Word mamm_rleg_center_v = 0;

pvlist mamm_lleg[5] = {
	{  8, 0,0,1,1 }, // R-L
	{ 10, 1,1,1,1 },
	{ 14, 0,1,1,0 },
	{ 15, 1,1,1,1 },
	{0xFFF,0,0,0,0}
};

pvlist mamm_rleg[5] = {
	{ 12, 0,0,1,1 }, // R-R
	{ 13, 1,1,1,1 },
	{  9, 0,0,1,1 },
	{ 11, 1,1,1,1 },
	{0xFFF,0,0,0,0}
};


const Word mamm_larm_center_p = 22;
const Word mamm_larm_center_v = 2;

pvlist mamm_larm[4] = {
	{  0, 1,1,1,1 }, // F-L
	{  2, 1,1,0,0 },
	{ 22, 1,0,0,0 },
	{0xFFF,0,0,0,0}
};

const Word mamm_rarm_center_p = 23;
const Word mamm_rarm_center_v = 0;

pvlist mamm_rarm[4] = {
	{  1, 1,1,1,1 }, // F-R
	{  3, 1,1,0,0 },
	{ 23, 0,1,0,0 },
	{0xFFF,0,0,0,0}
};


const Word mamm_lfoot_center_p = 15;
const Word mamm_lfoot_center_v = 1;

pvlist mamm_lfoot[3] = {
	//{  8, 0,0,1,1 }, // R-L
	{ 10, 1,1,1,1 },
	//{ 14, 0,1,1,0 },
	{ 15, 1,1,1,1 },
	{0xFFF,0,0,0,0}
};

const Word mamm_rfoot_center_p = 11;
const Word mamm_rfoot_center_v = 1;
pvlist mamm_rfoot[3] = {
	//{ 12, 0,0,1,1 }, // R-R
	{ 13, 1,1,1,1 },
	//{  9, 0,0,1,1 },
	{ 11, 1,1,1,1 },
	{0xFFF,0,0,0,0}
};

const Word mamm_tail_center_p  = 46;
const Word mamm_tail_center_v  = 1;

pvlist mamm_tail[7] = {
	{ 46, 1,1,1,1 },
	{ 47, 1,1,1,1 },
	{ 50, 1,1,1,1 },
	{ 51, 1,1,1,1 },
	{ 48, 1,1,1,0 },
	{ 49, 1,1,1,0 },
	{0xFFF,0,0,0,0}
};


/*

	-----------------------------------------------------------------
	Collezione di funzioni interdipendenti per il tracciamento delle
	superfici di base che compongono l'orografia dei territori.
	Queste funzioni coordinano quelle che si occupano del
	tracciamento degli oggetti in superficie.
	-----------------------------------------------------------------

*/

#define  bk_lines_to_horizon	120
#define  culling_limit		50

void srf_detail (float x, float y, float z, long depth, char _class_)
{ // disegna un oggetto sulla superficie di un pianeta.
	double dotProduct = (x*cam_x + y*cam_y + z*cam_z);
	if (dotProduct>0 && (depth<=1 || maxDepth==-1 || depth<=maxDepth)) {		//(sctype!=FOREST || depth<5)) {	//depth<=1 || treeDensity/5000<depth
		switch (_class_) {

			case ROCKS: // rocce, sassi, massi, pietre, pietruzze etc...
				if (sctype==DESERT) {
					cacti (x, y, z, depth);
				} else {
					roccia (x, y, z, depth);
				}
				break;
			case VEGET: // vegetali che non rientrano nella classe alberi.
				ciuffo (x, y + 150, z, depth);
				break;
			case TREES: // alberi, appunto. e cespugli quasi-alberi.
				if (y > -15000)
					cespuglio (x, y, z, depth);
				else
					albero (x, y, z, depth);
				break;
			case NOTHING: // una parte non coperta dalla texture (rovine).
				break;
		}
	}
}

char gtx; // se attivo, traccia il livello del suolo con texture specifica
int  ipfx, ipfz; // centro di tracciamento (coordinate SQC dell'osservatore).
char nearest_fragment_already_traced; // flag di lavoro.
extern int formalbob;
void fragment (long x, long z)
{ // traccia un quadrante della superficie.

	char  poly1, poly2;

	int   c1, count, id, cl;

	long  h1, h2, h3, h4;
	long  x2 = x + 1, z2 = z + 1;

	float vx1[4], vy1[4], vz1[4];
	float vx2[4], vy2[4], vz2[4];

	float px, py, pz, icx, icz;
	float hp1, hp2, hp3, hp4, hp5, hp6, hp7, hp8;

	unsigned char rch1, rch2, rch3, rch4;

	unsigned int *ani_sqc_temp;

	if (x == ipfx && z == ipfz) {
		// si assicura di tracciare una sola volta
		// il frammento pi— vicino (quello che sta
		// "sotto ai piedi" dell'esploratore),
		// per evitare eventuali ridondanze che
		// sarebbero alquanto gravi in termini di
		// velocit….
		if (nearest_fragment_already_traced)
			return;
		else
			nearest_fragment_already_traced = 1;
	}
	else {
		// esegue un rapido calcolo per
		// dare un'occhiata alla profondit…
		// del frammento (distanza dall'osservatore)
		// calibrando i frammenti possibilmente visibili
		// rispetto a un range di 64 * radice di 2,
		// cioŠ 90. 64 infatti Š il limite di visibilit…
		// corrente, applicato al valore della distanza
		// pi— preciso che viene calcolato dopo (depth).
		c1 = x - ipfx;
		if (c1 < 0) c1 = -c1;
		cl = z - ipfz;
		if (cl < 0) cl = -cl;
		if (c1 + cl > 90) return;
	}

	/* -1- Traccia il frammento di superficie del landscape. */

	// fissa le coordinate piane del frammento (parte 1).
	vx1[0] = x  << 14;
	vx1[1] = x2 << 14;
	vz1[0] = z  << 14;
	vz1[2] = z2 << 14;

	// trova la distanza del frammento dall'osservatore.
	float dx    = pos_x - (0.5 * (vx1[0] + vx1[1]));
	float dz    = pos_z - (0.5 * (vz1[0] + vz1[2]));
	float hpdep = SQRT (dx*dx + dz*dz);
	long  depth = (long)(hpdep) >> 14;

	// limita la visibilit… in diagonale, pi— che altro per fare
	// uno sfondo su pianta rotonda, invece che quadrata, perch‚ cosŤ
	// si ottiene una sorta di curvatura dell'orizzonte, ormai alla
	// Terra piatta non ci crede pi— nessuno...
	// Poi: in Noctis IV ho deciso di tracciare in massima precisione,
	// quindi la limitazione deve essere presente, altrimenti Š lento.
	if (depth > 64) return;

	// fissa le coordinate piane del frammento (parte 2).
	vz1[1] = z  << 14;
	vx1[2] = x  << 14;
	vx1[3] = vx1[2]  ;
	vz1[3] = vz1[2]  ;
	vx2[0] = x2 << 14; vz2[0] = z  << 14;
	vx2[1] = x2 << 14; vz2[1] = z2 << 14;
	vx2[2] = x  << 14; vz2[2] = z2 << 14;
	vx2[3] = vx2[2]  ; vz2[3] = vz2[2]  ;

	// Considera pi— quadranti circostanti come i pi— vicini
	depth -= 1;
	if (depth < 0) depth = 0;

	// fissa le coordinate di elevazione.
	h1 = x  + m200[(unsigned)z];
	h2 = x2 + m200[(unsigned)z];
	h3 = x2 + m200[(unsigned)z2];
	h4 = x  + m200[(unsigned)z2];
	vy1[0] = - ((long)(p_surfacemap[h1]) << 11);
	vy1[1] = - ((long)(p_surfacemap[h2]) << 11);
	vy1[2] = - ((long)(p_surfacemap[h4]) << 11);
	vy2[0] = - ((long)(p_surfacemap[h2]) << 11);
	vy2[1] = - ((long)(p_surfacemap[h3]) << 11);
	vy2[2] = - ((long)(p_surfacemap[h4]) << 11);

	// componente di shading della superficie in questo punto
	if (sh_delta) {
		// luce incidente
		c1 = p_surfacemap[h1] - p_surfacemap[h1 + sh_delta];
	}
	else {
		// sole pressoch‚ a perpendicolo, luce diffusa
		fast_srand (h1 + global_surface_seed);
		c1 = 8 + fast_random (7);
	}

	// lieve effetto atmosferico sui quadranti a grande distanza
	// l'effetto "nebbia" Š aumentato per via della riduzione di
	// visibilit… in diagonale (da 80 quadranti a 64) in conseguenza
	// della decisione di tracciare in massima precisione.
	// Š passato da depth / 3 a depth / 2 (con uno shift, fra l'altro).
	if (c1 < 00) c1 = 00;
	c1 += depth >> 1;
	if (c1 > 32) c1 = 32;

	// depth culling dei territori lontani (per velocizzare).
	// Nei deserti, c'Š in genere sabbia, e questo costituisce
	// una piccola eccezione al culling: i granelli pi— lontani
	// dovrebbero apparire con grana pi— fine di quelli vicini,
	// e il culling ha l'effetto collaterale di fare andare le
	// cose esattamente al contrario.
	if (sctype == DESERT) {
		if (depth >= 4)
			culling_needed = 0;
		else
			culling_needed = 1;
	}
	else {
		if (depth >= 4)
			culling_needed = 1;
		else
			culling_needed = 0;
	}

	// tracciamento del suolo.
	if (!mirror) {
		// verifica visibilit… poligoni.
		poly1 = 0;
		if (facing(vx1, vy1, vz1))
			if (gtx||(vy1[0]+vy1[1]+vy1[2]!=0))
				poly1 = 1;
		poly2 = 0;
		if (facing(vx2, vy2, vz2))
			if (gtx||(vy2[0]+vy2[1]+vy2[2]!=0))
				poly2 = 1;
		if (poly1 || poly2) {
			// impostazione parametri della texture del suolo.
			txtr = p_background;
			rch1 = ruinschart[h1];
			rch2 = ruinschart[h2];
			rch3 = ruinschart[h3];
			rch4 = ruinschart[h4];
			if (rch1 == AF4 || rch2 == AF4 || rch3 == AF4 || rch4 == AF4) {
				//XSIZE = TEXTURE_XSIZE * 2;
				//YSIZE = TEXTURE_YSIZE * 2;
                                c1 += 192 + ((sin(secs*2))*15);
                                flares = 0;
			}
			/*if (rch1 == AF5 || rch2 == AF5 || rch3 == AF5 || rch4 == AF5) {
				//XSIZE = TEXTURE_XSIZE * 2;
				//YSIZE = TEXTURE_YSIZE * 2;
				//c1 %= 0x40;
                                c1 += 5 + ((sin(secs)*10));
				flares = 0;
			}
			if (rch1 == AF6 || rch2 == AF6 || rch3 == AF6 || rch4 == AF6) {
				//XSIZE = TEXTURE_XSIZE * 2;
				//YSIZE = TEXTURE_YSIZE * 2;
                                c1 = c1 / 4;
                                c1 += 30 +abs((sin(secs)*5));
				flares = 0;
			}*/
			if (rch1 == AF1 || rch2 == AF1 || rch3 == AF1 || rch4 == AF1) {
				XSIZE = TEXTURE_XSIZE * 2;
				YSIZE = TEXTURE_YSIZE * 2;
                                c1 %= 0x40; c1 += 0x40;
				flares = 0;
			}
			else {
				XSIZE = TEXTURE_XSIZE * T_SCALE;
				YSIZE = TEXTURE_YSIZE * T_SCALE;
				flares = groundflares;
			}
			// imposta il colore delle escrescenze erbose.
			if (groundflares == 8) {
				if (depth >= 16)
					flares = 0;
				else {
					escrescenze = c1 + 32 - (depth << 1);
					if (escrescenze > 32) escrescenze = 32;
				}
			}
			// traccia il suolo.
			if (poly1) polymap (vx1, vy1, vz1, 3, c1);
			if (poly2) polymap (vx2, vy2, vz2, 3, c1);
		}
		// traccia la capsuletta con cui si Š discesi: essa
		// emette una sorta di "raggio intrinsecamente luminoso",
		// che Š molto utile per ritrovarla, dato che il territorio
		// esplorabile Š molto vasto (ci si pu• allontanare fino
		// a coprire un raggio di 3 chilometri dal punto di sbarco).
		if (landed&&atl_x==x&&atl_z==z) {
			px = cam_x; py = cam_y; pz = cam_z;
			hp1 = (atl_x << 14) + atl_x2;
			hp2 = (atl_z << 14) + atl_z2;
			cam_x -= hp1; cam_z -= hp2;
			cam_y -= atl_y - 900; //hpoint (hp1, hp2) - 900; //Making cupola able to fly w/out user (SL)
			H_MATRIXS = 0;
			V_MATRIXS = 0;
			change_txm_repeating_mode();
			txtr = n_globes_map;
			cam_y += 515; polycupola (-1, 1); flares = 0; cupola (-1, 8);
			cam_y -=1030; polycupola (+1, 1); flares = 0; cupola (+1, 8);
			cam_y += 515;
			flares = 1;
			if (hidebeam == 0) {
				for (cl = 0; cl < nightzone*5 + 1; cl++) {
					/*-----------*/ stick3d (0, -2000, 0, 100, -2E6,   0);
					if (depth < 48) stick3d (0, -2050, 0,   0, -1E6,   0);
					if (depth < 24) stick3d (0, -2100, 0,   0, -5E5, 100);
				}
			}
			cam_x = px; cam_y = py; cam_z = pz;
		}
	}
	else {
		// verifica visibilit… poligoni.
		poly1 = 0;
		vy1[0] = -vy1[0];
		vy1[1] = -vy1[1];
		vy1[2] = -vy1[2];
		vy1[3] = -vy1[3];
		if ((vy1[0]+vy1[1]+vy1[2]!=0)&&!facing(vx1, vy1, vz1))
			poly1 = 1;
		poly2 = 0;
		vy2[0] = -vy2[0];
		vy2[1] = -vy2[1];
		vy2[2] = -vy2[2];
		vy2[3] = -vy2[3];
		if ((vy2[0]+vy2[1]+vy2[2]!=0)&&!facing(vx2, vy2, vz2))
			poly2 = 1;
		if (poly1 || poly2) {
			// impostazione parametri della texture dei riflessi.
			txtr = p_background;
			rch1 = ruinschart[h1];
			rch2 = ruinschart[h2];
			rch3 = ruinschart[h3];
			rch4 = ruinschart[h4];
			if (rch1 == AF1 || rch2 == AF1 || rch3 == AF1 || rch4 == AF1) {
				XSIZE = TEXTURE_XSIZE * 2;
				YSIZE = TEXTURE_YSIZE * 2;
				c1 %= 0x40; c1 += 0x40;
				flares = 0;
			}
			else {
				if (hpdep < 49152L) {
					cl = 1536 - ((long)(hpdep) >> 5);
					cl += TEXTURE_XSIZE;
					XSIZE = cl;
					YSIZE = cl;
				}
				else {
					XSIZE = TEXTURE_XSIZE;
					YSIZE = TEXTURE_YSIZE;
				}
				flares = groundflares;
				txtr += (x << 3);
				c1 &= 0xC0;
			}
			// traccia i riflessi del suolo.
			if (poly1) polymap (vx1, vy1, vz1, 3, c1);
			if (poly2) polymap (vx2, vy2, vz2, 3, c1);
		}
		// evita riflessi di oggetti perch‚ sarebbe davvero troppo.
		return;
	}

	/* -2- tracciamento forme di vita animali. */

	// oltre 1 Km, n‚ animali n‚ oggetti sono visibili.
	if (depth > 40) return;

	// verifica la visibilit… delle superfici del frammento.
	// (approssima in questo modo, per•, soltanto in profondit…,
	// perch‚ potrebbe accadere, per i frammenti pi— vicini,
	// che la superficie del suolo non sia visibile, mentre gli
	// oggetti che vi si ergono o gli animali che vi camminano sŤ...)
	if (depth > 8 && poly1+poly2 == 0) return;

      /*for (id = 0; id < animals; id++)
			if (ani_sqc[id] == h1)
				live_animal (id);*/

	/* The previous comment is incorrect (sort of (this comment was incorrect; it has been corrected)). The following code actually does this:
		int index=0;
		for (id = animals; id>0; id--, index++)
			if (ani_sqc[index] == h1)
				live_animal(animals-id);
		
		or
	
		for (id = animals; id>0; id--)
			if (ani_sqc[animals-id] == h1)
				live_animal(animals-id);	
	(SL)	
	*/
	
	/*
	cx = animals
	if (cx>=0) {
		si = ani_sqc_temp;
		ax = h1
		lfa:
			if (*si != ax) goto nah
			dx = animals - cx
			live_animal(dx)
			si+=2
			cx-=1
			if (cx!=0) goto lfa;
	(SL)
	*/
	
	ani_sqc_temp = ani_sqc;
	asm {   mov cx, animals
		cmp cx, 0
		jle nat
		mov si, word ptr ani_sqc_temp
		mov ax, word ptr h1 }
   lfa: asm {	cmp word ptr [si], ax
		jne nah
		push ax
		push cx
		push si
		mov dx, animals
		sub dx, cx }
		live_animal (_DX);
	asm {	pop si
		pop cx
		pop ax }
   nah: asm {	add si, 2
		dec cx
		jnz lfa }

	/* -3- Traccia gli oggetti presenti sulla superficie. */

	// se non sono previsti oggetti su questa superficie, lascia...
   nat:	if ((count = objectschart[h1].nr_of_objects) == 0) return;

	// diminuisce in generale il numero di oggetti visibili
	// nella distanza... eh, bŠ, anche la velocit… vuole la
	// sua parte, Š assurdo ma consigliabile. E si nota poco.
	if (depth > 16) {
		count >>= 1;
		if (!count) return;
	}
	
	// impostazione texture per gli oggetti.
	flares = 0;
	txtr = p_background;
	cl = T_SCALE >> 2;
	XSIZE = TEXTURE_XSIZE * cl;
	YSIZE = TEXTURE_YSIZE * cl;

	// ID del primo oggetto.
	id = 0;

	// calcola i vertici di riferimento della superficie.
	hp1 = vy1[0];
	hp2 = vy1[1];
	hp3 = vy2[1];
	hp4 = vy1[2];
	hp5 = (hp2 - hp1) * qid;
	hp6 = (hp4 - hp1) * qid;
	hp7 = (hp4 - hp3) * qid;
	hp8 = (hp2 - hp3) * qid;

	while (count) {
		// seleziona la tabella pseudo relativa al presente frammento.
		// (fornisce una base costante per tutti i valori estratti.)
		fast_srand (x * z * count);
		// estrae le coordinate degli oggetti dalla tabella,
		// calcolando l'origine cartesiana dell'oggetto come (px; py; pz),
		// usando misure in millimetri, con px e pz compresi tra 0 e 16383,
		// e con py che giace sul piano della superficie (livello del suolo).
		icx = fast_random (16383); px = vx1[0] + icx;
		icz = fast_random (16383); pz = vz1[0] + icz;
		if (icx+icz < 16384) {
			// il punto fa parte del triangolo #1.
			py  = hp1 + hp5 * icx;
			py += hp6 * icz;
		}
		else {
			// il punto fa parte del triangolo #2.
			py  = hp3 + hp7 * (16384 - icx);
			py += hp8 * (16384 - icz);
		}
		// disegna l'oggetto in questione...
		dz = px + pz;
		detail_seed = h1;
		switch (id) {
			case 0:	srf_detail (px, py, pz, depth, objectschart[h1].object0_class);
				break;
			case 1:	srf_detail (px, py, pz, depth, objectschart[h1].object1_class);
				break;
			case 2:	srf_detail (px, py, pz, depth, objectschart[h1].object2_class);
		}
		// passa al prossimo oggetto...
		id++; if (id > 2) id = 0;
		count--;
	}
}

void iperficie (int additional_quadrants)
{ // Traccia i poligoni della superficie, dirigendo la funzione precedente.
  // questa funzione Š centrata su ipfx;ipfz, e si prende cura di tracciare
  // i poligoni nell'ordine corretto rispetto alla distanza.

	int 	  b = beta;
	int	  x, z;

	if (b<0)
		b += 360;

	nearest_fragment_already_traced = 0;

	if (b<45||b>=315) {
		for (z=199; z>=ipfz - additional_quadrants;) { // -dlz
			for (x=0; x<ipfx;) { // +dlx
				fragment (x, z);
				x++;
			}
			for (x=199; x>=ipfx;) { // -dlx
				fragment (x, z);
				x--;
			}
			z--;
		}
		goto backoff;
	}

	if (b>=135&&b<225) {
		for (z=0; z<=ipfz + additional_quadrants;) { // +dlz
			for (x=0; x<ipfx;) { // +dlx
				fragment (x, z);
				x++;
			}
			for (x=199; x>=ipfx;) { // -dlx
				fragment (x, z);
				x--;
			}
			z++;
		}
		goto backoff;
	}

	if (b>=45&&b<135) {
		for (x=0; x<=ipfx + additional_quadrants;) { // +dlx
			for (z=199; z>ipfz;) { // -dlz
				fragment (x, z);
				z--;
			}
			for (z=0; z<=ipfz;) { // +dlz
				fragment (x, z);
				z++;
			}
			x++;
		}
		goto backoff;
	}

	if (b>=225&&b<315) {
		for (x=199; x>=ipfx - additional_quadrants;) { // -dlx
			for (z=199; z>ipfz;) { // -dlz
				fragment (x, z);
				z--;
			}
			for (z=0; z<=ipfz;) { // +dlz
				fragment (x, z);
				z++;
			}
			x--;
		}
		goto backoff;
	}

    backoff:
	BracketAnims(); //Bracket after displaying mountains to make them on top (bensel)
	flares = 0;
	H_MATRIXS = 16;
	V_MATRIXS = 16;
	change_txm_repeating_mode();
}

/*

	-----------------------------------------------------------------
	Collezione di funzioni interdipendenti per la definizione dei
	profili orografici di un'area di un pianeta. I pianeti sono
	principalmente suddivisi in aree e quadranti, come segue:

		- il lato di un'area Š di 6 Km e 552 metri;
		- il lato di ogni quadrante Š di 32 mt. e 768 mm.

	La superficie esplorabile di un pianeta Š costituita
	da 43200 aree, organizzate in una matrice di 360 x 120,
	una diversa dall'altra per caratteristiche orografiche
	e termografiche. Di un pianeta si pu• arrivare ad esplorare
	una superficie totale di 1.855.424 chilometri quadrati, il che
	significa, sŤ, molto meno della reale estensione di un pianeta,
	ma di certo abbastanza perch‚ ben pochi se ne possano accorgere.
	-----------------------------------------------------------------

*/

void round_hill (int cx, int cz, unsigned r, float h, float hmax, char allowcanyons)
{ // Una collina rotonda, o una montagna molto erosa (se la si fa grossa).
  // hmax entra in gioco se il flag "allowcanyons" Š a zero:
  //      quando l'altezza puntuale supera "hmax", per allowcanyons=0
  //      la funzione costruisce un altopiano sulla sommit… della collina,
  //	  mentre allowcanyons=1 fa ignorare il parametro "hmax" e, quando
  //	  l'altezza supera il limite massimo globale (127), scava un canyon
  //	  al centro della collina.
	//DebugPrintf(0, "round_hill(%i, %i, %u, %f, %f, %i)", (int)cx, (int)cz, (unsigned)r, (float)h, (float)hmax, (int)allowcanyons);
	#ifdef WEIRDDOSHILLS
	int x, z;

	float dx, dz, d;
	float y, v = (float)r / M_PI_2;

	for (x = cx-r; x < cx+r; x++)
		for (z = cz-r; z < cz+r; z++) {
			if (x>-1&&z>-1&&x<200&&z<200) {
				dx = x - cx;
				dz = z - cz;
				d  = SQRT (dx*dx + dz*dz);
				y  = cos (d / v) * h;
				if (y>=0) {
					y += p_surfacemap[200*(long)z+x];
					if (allowcanyons == 1) {  //regular pit in the middle
					    if (y>127)
					    y = 254 - y;
                                        }
					if (allowcanyons == 2) {  //volcano!
						if (y>127) {
							y = 254 - (y - (y/1.3)) - (127/1.3);
							if (y<123)
                                                        ruinschart[200*(long)z+x]=AF6;
						}
					}
					if (allowcanyons == 0) {  //no pit in middle. normal round hill.
						if (y>hmax)
							y = hmax;
					}
					p_surfacemap[200*(long)z+x] = y;
				}
			}
		}
	#else
	Dword dr = (Dword)r;
	Dword x, z;
	float d;
	Dword dx, dz;
	float y, v = ((float)r) / M_PI_2;
	
	Dword minx = cx - dr;
	Dword maxx = cx + dr;
	Dword minz = cz - dr;
	Dword maxz = cz + dr;
	if (minx<0) minx=0;
	if (minz<0) minz=0;
	if (minx>199) minx=199;
	if (minz>199) minz=199;
	if (maxx<0) maxx=0;
	if (maxz<0) maxz=0;
	if (maxx>199) maxx=199;
	if (maxz>199) maxz=199;
		
	//DebugPrintf(0, "x range=[%li,%li] z range=[%li,%li]", minx, maxx, minz, maxz);
	for (x = minx; x < maxx; x++) {
		for (z = minz; z < maxz; z++) {
			//if (x>-1&&z>-1&&x<200&&z<200) {
				dx = x - cx;
				dz = z - cz;
				d  = SQRT (dx*dx + dz*dz);
				y  = cos (d / v) * h;
				//DebugPrintf(0, "[%li,%li] y=%f", x, z, y);
				if (y>=0) {
					y += p_surfacemap[200*z+x];
					if (allowcanyons) {
						if (y>127)
							y = 254 - y;
					}
					else {
						if (y>hmax)
							y = hmax;
					}
					
					p_surfacemap[200*z+x] = (Uchar) y;
				}
			//}
		}
	}
	#endif
}

void smoothterrain (Word rounding)
{      // Smussa il profilo del terreno.
        Word n;
	while (rounding) {
		for (ptr = 0; ptr < 39798; ptr++) {
			n  = p_surfacemap[ptr];
			n += p_surfacemap[ptr + 1];
			n += p_surfacemap[ptr + 200];
			n += p_surfacemap[ptr + 201];
			p_surfacemap[ptr] = n >> 2;
		}
		rounding--;
	}
}

/*
void smoothterrain (Word rounding)
{
     // coded by Ees33
     // Fixed smoothing routine. Does not produce 'goofy stuff' on terrain edges.
     Uword x, y;
     Word avg;
     Word i, lastcorneravg;

     for(i=0;i<rounding;i++)
     {
        for(y=0;y<199;y++)
        {
           for(x=0;x<199;x++)
           {
              avg = (p_surfacemap[(200*y    )+x  ]+
                     p_surfacemap[(200*y    )+x+1]+
                     p_surfacemap[(200*(y+1))+x  ]+
                     p_surfacemap[(200*(y+1))+x+1])>>2;

              p_surfacemap[(200*y)+x] = avg;
           }
        }

        // smooth right and bottom edges
        for(y=0;y<199;y++)
        {
           avg = (p_surfacemap[(200*y)+198]+p_surfacemap[(200*(y+1))+198]+
                  p_surfacemap[(200*y)+199]+p_surfacemap[(200*(y+1))+199])>>2;

           p_surfacemap[(200*y)+199] = avg;
        }

        for(x=0;x<198;x++)
        {
           avg = (p_surfacemap[39600+x]+p_surfacemap[39600+x+1]+
                  p_surfacemap[39800+x]+p_surfacemap[39800+x+1])>>2;

           p_surfacemap[39800+x] = avg;
        }

        lastcorneravg = ((p_surfacemap[39798]+p_surfacemap[39799]) +
                         (p_surfacemap[39998]+p_surfacemap[39999]))>>2;

        p_surfacemap[39999] = lastcorneravg;
     }
}

void crosssmoothterrain ()
{
     // coded by Ees33
     // Fixed "cross" smoothing routine. Does not produce 'goofy stuff' on terrain edges.
     // This "cross" routine is called after a call to felisian_srf_darkline() in build_surface().
     // and smooths with a "cross" shape instead of a 2x2 square.
      
     Uword x, y;
     Word avg;

     for(y=1;y<198;y++)
     {
        for(x=0;x<199;x++)
        {
           if((x>0) && (x<199))
           {
             avg = (p_surfacemap[(200*y)+x]+
                    p_surfacemap[(200*(y-1))+x]+
                    p_surfacemap[(200*(y+1))+x]+
                    p_surfacemap[(200*y)+x-1]+
                    p_surfacemap[(200*y)+x+1])/5;
           } else if (x == 0) {
             avg = (p_surfacemap[(200*y)+x]+
                    p_surfacemap[(200*(y-1))+x]+
                    p_surfacemap[(200*(y+1))+x]+
                    p_surfacemap[(200*y)+x+1])/4;
           } else if (x == 199) {
             avg = (p_surfacemap[(200*y)+x]+
                    p_surfacemap[(200*(y-1))+x]+
                    p_surfacemap[(200*(y+1))+x]+
                    p_surfacemap[(200*y)+x-1])/4;
           }

           p_surfacemap[(200*y)+x] = avg;
        }
     }
}*/

void rockyground (int roughness, int rounding, char level)
{ // Produce una superficie pi— o meno accidentata.
	for (ptr = 0; ptr < 40000; ptr++)
		p_surfacemap[ptr] = RANDOM (roughness);
	smoothterrain (rounding);
	for (ptr = 0; ptr < 40000; ptr++) {
		if (p_surfacemap[ptr] >= abs(level)) {
			p_surfacemap[ptr] += level;
			if (p_surfacemap[ptr] > 127)
				p_surfacemap[ptr] = 127;
		}
		else
			p_surfacemap[ptr] = 0;
	}
}

void std_crater (unsigned char huge *map, int cx, int cz, int r,
		 int lim_h, float h_factor, float h_raiser, long align)
{ // Un cratere.
	int x, z;

	float dx, dz, d, y, h, fr;

	h = (float)r * h_factor;
	r = abs (r); fr = r;

	for (x = cx-r; x < cx+r; x++)
		for (z = cz-r; z < cz+r; z++) {
			if (x>-1&&z>-1&&x<align&&z<align) {
				dx = x - cx;
				dz = z - cz;
				d  = SQRT (dx*dx + dz*dz);
				if (d <= fr) {
					y  = sin (M_PI*(d/fr)) * h;
					y  = pow (y, h_raiser);
					y += map[align*(long)z+x];
					if (y<0) y = 0;
					if (y>lim_h) y = lim_h;
					map[align*(long)z+x] = (Uchar) y;
				}
			}
		}
}

void srf_darkline (unsigned char huge *map, int length,
		   int x_trend, int z_trend, long align)
{ // Una crepa scura (versione principalmente per textures).
	int fx = RANDOM(align), fz = RANDOM(align);
	long mapsize = align*align;
	unsigned location;
	//
	while (length) {
		fx += RANDOM(3) + x_trend;
		fz += RANDOM(3) + z_trend;
		location = align*(long)fz+fx;
		if (location>0 && location<mapsize) map[location] >>= 1;
		length--;
	}
}

// (by Ees33)
/*
Word inclusive_rand(Word min, Word max)
{
     Word incr = 0;

     incr = RANDOM(max-min+1);
     incr += min;

     return(incr);
}

// Canyon/mountain generation. Modified by Ees33.
//Fixed-up and jacked-up version of the original.
 
void felisian_srf_darkline (Uchar maybehuge *map, Word length,
                            Word ismtn, Word maxalt, Word x_trend,
                            Word z_trend, Dword align) */
void felisian_srf_darkline (unsigned char huge *map, int length,
			    int x_trend, int z_trend, long align)
{ // Un crepaccio (versione principalmente per superfici).
	/*Word fx = RANDOM(align), fz = RANDOM(align); // (by Ees33)
	Word peak, deviation, variability;
	Dword mapsize = align*align;
	Uword location;*/
	Word fx = RANDOM(align), fz = RANDOM(align);
	Word peak, deviation, variability;
	Dword mapsize = align*align;
	Uword location;
	
/*	deviation = RANDOM(25) - 50;		// (by Ees33)
	variability = 2 + RANDOM(10);

        if(((ismtn == 1) && (deviation < 0)) ||
           ((ismtn == 0) && (deviation > 0)))
        {
          deviation = -deviation;
        }*/
	deviation = RANDOM(25) - 50;
	variability = 2 + RANDOM(10);
	while (length) {
		fx += RANDOM(3) + x_trend;
		fz += RANDOM(3) + z_trend;
		deviation += RANDOM(variability) - (variability>>1);
    /*  if(((ismtn == 1) && (deviation < 0)) ||		// (by Ees33)
           ((ismtn == 0) && (deviation > 0)))
              {
                deviation = -deviation;  // (Ees33) correction
              }*/
		location = align*(Dword)fz+fx;
		if (location>0 && location<mapsize-1) {
			peak = map[location];
			peak += deviation;
			if (peak < 0) peak = 0;
			//if (peak > maxalt) peak = maxalt; 	// (by Ees33)
			if (peak > 127) peak = 127;
			map[location] = peak;

			if (location>align) {
				map[location-align] = peak;
			}
			map[location-1] = peak;
			if (location<mapsize-align) {
				map[location+align] = peak;
			}
			map[location+1] = peak;
		}
		length--;
	}
}

void asterism (unsigned char huge *map, int x, int y,
	       int base, int variation, int density,
	       int size, long align)
{ // Simile a un asterisco variabile. Viene usata per i ceppi d'erba.
	if (density <=0) return;

	float ad  = M_PI * 2 / (float)density;
	float ang = 0;

	float shift_d;
	long  shift_x;
	long  shift_y;
	long  shift_p;

	float color, var;

	while (ang < M_PI * 2) {
		shift_d  = (float)RANDOM(1000) / 1000;
		shift_d *= size;
		if (shift_d >= 1) {
			var = (float)variation / shift_d;
			color = base;
			while (shift_d > 0) {
				shift_x = cos (ang) * shift_d + x;
				shift_y = sin (ang) * shift_d + y;
				if (shift_x>0 && shift_y>0 && shift_x < align && shift_y < align) {
					shift_p = shift_y * align + shift_x;
					map[shift_p] = color;
				}
				color += var;
				shift_d--;
			}
		}
		ang += ad;
	}
}

/* Funzioni per la mappatura dei cieli planetari. */

void nebular_sky ()
{ // Cielo nebuloso, piuttosto alieno, con piccoli ammassi sparsi o striati.
	unsigned pqw = QUADWORDS;
	unsigned seed = RANDOM (10000);

	QUADWORDS = st_bytes / 4;

	asm {	les di, dword ptr s_background
		mov cx, st_bytes
		mov ax, seed }
rndpat:	asm {   add ax, cx
		xor dx, dx
		imul ax
		add ax, dx
		mov bl, al
		and bl, 0x3F
		mov es:[di], bl
		inc di
		dec cx
		jnz rndpat }

	lssmooth (s_background);

	if (RANDOM(2)) ssmooth (s_background);
	if (RANDOM(3)) psmooth_grays (s_background);

	QUADWORDS = pqw;
}

void cloudy_sky (Word density, Word smooths)
{ // Cielo con nuvole sparse, di tipo terrestre.
	Word 	 n = RANDOM (density + albedo);
	float    x, y, cx, cy, r, b;
	Uword p, pqw = QUADWORDS;

	QUADWORDS = st_bytes / 4;

	while (n>0) {
		cx = RANDOM (360);
		r = RANDOM (25) + 5;
		cy = RANDOM (50) + 25 + r;
		for (y = - r; y < r; y++)
			for (x = - 2*r; x < 2*r; x++) {
				if (SQRT(x*x*0.2+y*y)<r) {
					p = x + cx + 360 * (y+cy);
					if (p < st_bytes) {
						b = 1.4142 / SQRT((x+r)*(x+r)+(y+r)*(y+r));
						b *= 64; b += s_background[p];
						if (b>63) b = 63;
						s_background[p] = b;
					}
				}
			}
		n--;
	}

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

	QUADWORDS = pqw;
}

/* Funzioni che costruiscono rovine sulle superfici dei pianeti "storici",
   quali Felysia, le lune abitabili di Fal Galmatrifal ed pianeti Feniani.
   Viene chiamata tramite "build_surface" e quindi i semi random sono stati
   gi… impostati rispetto al global_surface_seed. Gli stili possibili sono:
   ------------------------------------------------------------------------
   0 - grattacieli
   1 - edifici quadrati senza tetto (solo resti di mura)
   2 - piazzali e colonnati (soprattutto tipici di Felysia)
   3 - palazzi
   4 - edifici coloniali a forma di X (stile Feniano)
   5 - edifici coloniali con tetto a cupola (stile Suricrasiano) */

Word average_of_y (Word ic, Word jc, Word ra)
{
	Word av = 0;
	Word ai = 1;
	Word ip, jp, pt;

	for (jp = jc - ra; jp < jc + ra; jp++) {
		for (ip = ic - ra; ip < ic + ra; ip++) {
			av += p_surfacemap[pt];
			ai++;
		}
	}
	av /= ai;

	return (av);
}

void make_ruins (char style1, char style2, char style3,
		 char style4, char style5, Word density)
{
	Word buildings = RANDOM(75)+25;
        buildingcount = buildings;
	switch (sctype) {
		case OCEAN:	buildings = RANDOM(4);
				if (!RANDOM(10)) buildings *= 2 + RANDOM(2);
				break;
		case FOREST:
			buildings = RANDOM(2);
			break;
		case PLAINS:	buildings = RANDOM(8);
				if (!RANDOM(5)) buildings *= 3 + RANDOM(2);
				break;
		case SHRUBLAND:
			buildings = RANDOM(4);
			break;
		case DESERT:	buildings = RANDOM(3);
				break;
		case ICY:	buildings = RANDOM(2);

	}

	Word peak;
	char bstyle;
	Uword ic, jc, ip, jp, ra, hr, pt, av, ai;

	buildings *= density;
	while (buildings) {
		ai = RANDOM(5);
		switch (ai) { //screwtime
			case 0: bstyle = style1; break;
			case 1: bstyle = style2; break;
			case 2: bstyle = style3; break;
			case 3: bstyle = style4; break;
			case 4: bstyle = style5;
		}
          
                switch (bstyle) {
		// Stili Felisiani antichi.
		case 0:
                        // grossi grattacieli					//large skyscrapers - These're boxes (SL)
			hr = 10 + RANDOM(25);
			ic = 20 + RANDOM(160);
			jc = 20 + RANDOM(160);
			ra =  1 + RANDOM(3);
		    like0:
			av = average_of_y (ic, jc, ra);
			for (jp = jc - ra; jp < jc + ra; jp++) {
				for (ip = ic - ra; ip < ic + ra; ip++) {
					pt = m200[jp] + ip;
					p_surfacemap[pt] = av + hr;
					if (!RANDOM(5)) p_surfacemap[pt]--;
					ruinschart[pt] = AF1;
				}
			}
			break;
		case 1:
			// edifici crollati (senza tetto)		//open pavilions (SL)
			hr = RANDOM(8);
			ic = 20 + RANDOM(160);
			jc = 20 + RANDOM(160);
			ra =  3 + RANDOM(5);
			for (ip = ic - ra; ip < ic + ra; ip++) {
				pt = m200[jc - ra] + ip;
				av = hr + RANDOM(2);
				p_surfacemap[pt] += av;
				if (av) ruinschart[pt] = AF1;
				pt = m200[jc + ra] + ip;
				av = hr + RANDOM(3);
				p_surfacemap[pt] += av;
				if (av) ruinschart[pt] = AF1;
			}
			for (jp = jc - ra; jp < jc + ra; jp++) {
				pt = m200[jp] + ic - ra;
				av = hr + RANDOM(2);
				p_surfacemap[pt] += av;
				if (av) ruinschart[pt] = AF1;
				pt = m200[jp] + ic + ra;
				av = hr + RANDOM(3);
				p_surfacemap[pt] += av;
				if (av) ruinschart[pt] = AF1;
			}
			break;
		case 2:
			// piazzali e colonnati					//pyramids, usually in rows, sometimes in squares (SL)
			hr = 5 + RANDOM(10);
			ic = 30 + RANDOM(140);
			jc = 30 + RANDOM(140);
			ra = 15 + RANDOM(15);
			av = average_of_y (ic, jc, ra);
			for (jp = jc - ra; jp < jc + ra; jp++) {
				for (ip = ic - ra; ip < ic + ra; ip++) {
					pt = m200[jp] + ip;
					p_surfacemap[pt] = av;
				}
			}
			ra /= 2;
			if (!RANDOM(3)) {
				ai = 2 + RANDOM(3);
				for (ip = ic - ra; ip < ic + ra; ip += ai) {
					pt = m200[jc - ra] + ip;
					p_surfacemap[pt] = av + hr + RANDOM(2);
					ruinschart[pt] = AF1;
					pt = m200[jc + ra] + ip;
					p_surfacemap[pt] = av + hr + RANDOM(3);
					ruinschart[pt] = AF1;
				}
			}
			if (!RANDOM(3)) {
				ai = 2 + RANDOM(3);
				for (jp = jc - ra; jp < jc + ra; jp += ai) {
					pt = m200[jp] + ic - ra;
					p_surfacemap[pt] = av + hr + RANDOM(2);
					ruinschart[pt] = AF1;
					pt = m200[jp] + ic + ra;
					p_surfacemap[pt] = av + hr + RANDOM(3);
					ruinschart[pt] = AF1;
				}
			}
			break;
		// Stili Felisiani coloniali.
		case 3:
			// palazzine e piccoli grattacieli				//These look like pyramids which've had the tops cut off. (SL)
			hr = 10 + RANDOM(10);
			ic = 20 + RANDOM(160);
			jc = 20 + RANDOM(160);
			ra =  1 + RANDOM(2);
			goto like0;
		case 4:
         		makecity:
			// edifici coloniali moderni, a forma di X		//An X with a spike pointing up in the center.
			hr =  1 + RANDOM(3);
			ic = 25 + RANDOM(150);
			jc = 25 + RANDOM(150);
			ra =  5 + RANDOM(5);
			if (!RANDOM(5)) ra *= 2;
			for (ip = ic - ra; ip < ic + ra; ip++) {
				pt = m200[jc] + ip;
				p_surfacemap[pt] += hr * (ra - abs(ip-ic) + 1);
				ruinschart[pt] = AF1;
			}
			for (jp = jc - ra; jp < jc + ra; jp++) {
				pt = m200[jp] + ic;
				p_surfacemap[pt] += hr * (ra - abs(jp-jc) + 1);
				ruinschart[pt] = AF1;
			}
			break;
		case 5:
			// edifici coloniali di Suricrasia (Ylastravenia)				//Things which resemble stardrifters - of varying heights, generally composed of two separate parts, a square box and a round cupola in the center. These may have different heights. May form hollow round towers, even towers missing several sides. (SL)
			// sono quadrati, ma hanno una cupoletta sul tetto
			hr = 10 + RANDOM(10);
			ic = 20 + RANDOM(160);
			jc = 20 + RANDOM(160);
			ra = 12 + RANDOM(8);
			av = average_of_y (ic, jc, ra);
			for (jp = jc - ra; jp < jc + ra; jp++) {
				for (ip = ic - ra; ip < ic + ra; ip++) {
					pt = m200[jp] + ip;
					p_surfacemap[pt] = av + hr;
					ruinschart[pt] = AF1;
				}
			}
			ra *= 2;
			ra /= 3;
			bstyle = RANDOM(2);
			for (jp = jc - ra; jp < jc + ra; jp++) {
				for (ip = ic - ra; ip < ic + ra; ip++) {
					pt   = m200[jp] + ip;
					ai   = (jp - jc) * (jp - jc);
					ai  += (ip - ic) * (ip - ic);
					ai   = (Uword)SQRT ((double)ai);
					peak = 3 * hr * cos (M_PI_2 * (double)ai / (double)ra);
					if (peak > 0)
						p_surfacemap[pt] = av + peak + 1;
					if (bstyle)
						ruinschart[pt] = AF1;
					else
						ruinschart[pt] = 0;
				}
			}
			break;
		/*case 6:
                        jc = 10 + RANDOM(180); //X-coordinate
                        jp = 10 + RANDOM(180); //Y-coordinate
                        ic = 0; //AddtoX
                        ip = 0; //AddtoY
                        av = RANDOM(10) + 5;
                        ai = p_surfacemap[(jp*200)+jc];
                        while (av > 0) {

                          ra = RANDOM(3) + 2;
                          hr = RANDOM(10) + 1;
                          if (ra == 1) {
                              ip = 1;
                              ic = 0;
                          }
                          if (ra == 2) {
                              ip = 0;
                              ic = 1;
                          }
                          if (ra == 3) {
                              ip = -1;
                              ic = 0;
                          }
                          if (ra == 4) {
                              ip = 0;
                              ic = -1;
                          }
                          while (hr > 0) {
                           if (jp < 199 & jp > 1) jp = jp + ip;
                           if (jc < 199 & jc > 1) jc = jc + ic;
                             ruinschart[(jp*200)+jc]=AF1;
                             p_surfacemap[((jp-1)*200)+(jc)]=ai;
                             p_surfacemap[((jp+1)*200)+(jc)]=ai;
                             p_surfacemap[((jp)*200)+(jc+1)]=ai;
                             p_surfacemap[((jp)*200)+(jc-1)]=ai;
                             hr--;
                          }
                          av--;
                        }
			goto makecity;*/

                        

                /*        break;
                case 7:        //custom! :D
                        jc = 20 + RANDOM(160); //X-coordinate
                        jp = 20 + RANDOM(160); //Y-coordinate
                        ic = 0; //AddtoX
                        ip = 0; //AddtoY
                        hr = 10;
                        ra = 0;
                        while (ra < 7) {
                           if (ra == 1) {
                              ip = 1;
                              ic = 0;
                              hr = 5;
                           }
                           if (ra == 2) {
                              ip = 0;
                              ic = 1;
                              hr = 5;
                           }
                           if (ra == 3) {
                              ip = -1;
                              ic = 0;
                              hr = 5;
                           }
                           if (ra == 4) {
                              ip = 0;
                              ic = -1;
                              hr = 5;
                           }
                           if (ra == 5) {
                              ip = -1;
                              ic = -1;
                              hr = 5;
                           }
                           if (ra == 6) {
                              ip = 1;
                              ic = 1;
                              hr = 5;
                           }
                           ra = ra + 1;
                           pt = 200*(jp+ip) + (jc+ic);
                           p_surfacemap[pt]=hr;
                           ruinschart[pt]=AF1;


                        }*/
		}
		buildings--;
	}
}

/* Funzione che costruisce la superficie del pianeta.
   Regolata dal seme global_surface_seed, per ottenere risultati coerenti. */

void build_surface ()
{
	Word cx, cz, cr, n, incl;
	float hf, hr, ht;
	Uword ptr1;

	char waswet;
	char frosty;
	char snowy;
	char liquid_water;

        /*Word ismtn, hcat, hcatr, maxalt;  // (by Ees33)
        FILE *fd;*/


	snowy     = 0;
	frosty    = 0;
	waswet    = 0;
	waves_in  = 0;
	waves_out = 0;
	T_SCALE	  = 32;
	quartz    = 0;
	gtx	  = 1; // suolo con texture, per default

	_fmemset (txtr, 16, 65535);
	_fmemset (p_surfacemap, 0, ps_bytes);
	_fmemset (objectschart, 0, oc_bytes);

	// regolazione dei parametri generali: coerente con il layout
	// del pianeta, e indipendente dalla superficie.
	fast_srand (global_surface_seed);
	srand (global_surface_seed);

	// normalmente, la superficie non Š trasparente o traslucida...
	groundflares = 0;

	// potrebbe esserlo? mah, per esempio in caso di ghiacci molto
	// particolari, o di interi pianeti fatti di sostanze trasparenti.
	// rarissimi, direi.
	cz = RANDOM (2);
	cx = RANDOM (100);
	//DebugPrintf(0, "cz=%i, cx=%i", (int)cz, (int)cx);
	if (cx > 97)
		groundflares = 2 + (2 * cz);
	if (cx > 45 && cx < 55) {
		if (nearstar_p_type[ip_targetted] == 3 && latitude > 75)
			groundflares = 2 + (2 * cz);
	}

	// normalmente, la superficie Š pi— o meno rocciosa...
	liquid_water = 0;
	for (ptr = 0; ptr < oc_bytes; ptr ++) {
		objectschart[ptr].object0_class = ROCKS;
		objectschart[ptr].object1_class = ROCKS;
		objectschart[ptr].object2_class = ROCKS;
	}

	// gli alberi: quando Š possibile la loro presenza,
	// vengono influenzati dalla latitudine della zona di sbarco.
	// Š piuttosto logico che ci siano delle latifoglie ai climi pi—
	// miti, e delle conifere a quelli pi— rigidi.
	if (latitude > 45)
		treepeaking = flandom() * 0.9 + 0.1;
	else
		treepeaking = flandom() + 0.75;
		
	// un dettaglio raro ma possibile: alberi fibrosi, con il tronco
	// simile a un grosso stelo... tanto si parla di ambienti alieni...
	switch (RANDOM(3)) {
		case 0: rootshade = 0x00; break;
		case 1: rootshade = 0x80; break;
		case 2: rootshade = 0xC0; break;
	}
	// altro dettaglio parecchio insolito, che per• conviene sia
	// davvero molto raro: alberi trasparenti (e chi lo sa? magari...)
	switch (RANDOM(30)) {
		case 7:  treeflares = 1; break;
		case 8:  treeflares = 2; break;
		case 9:  treeflares = 4; break;
		default: treeflares = 0;
	}
	// pi— probabile... foglie trasparenti... credo sia pi— plausibile.
	switch (RANDOM(15)) {
		case 7:  leafflares = 1; break;
		case 8:  leafflares = 2; break;
		case 9:  leafflares = 4; break;
		default: leafflares = 0;
	}
	// gli altri parametri degli alberi, bŠ... sono piuttosto casuali.
	treescaling = 3000 + flandom() * 3000 - flandom() * 1500;
	treespreads = 0.75 + flandom() * 0.50 - flandom() * 0.50;
	branchwidth = 0.05 + flandom() * 0.15;
	rootheight  = (0.05 + flandom());

	mushscaling = 4095;
	if (treescaling > 4096) mushscaling = 8191;

	// bump mapping di superficie:
	// Š spesso coperta d'escrescenze erbose nel caso si tratti di un
	// pianeta abitabile e lo scenario non sia un ghiacciaio/deserto...
	if (nearstar_p_type[ip_targetted] == 3) {
		if (sctype != ICY && sctype != DESERT) {
			if (RANDOM(4))
				groundflares = 8;
		}
	}
	Dword rndval = 0;
	
	// veniamo all'ambiente di superficie...
	// esso dipende strettamente dalle coordinate di sbarco.
	//Now uses a better seed (SL)
	fast_srand (local_surface_seed);
	SRAND (local_surface_seed);
	glassified=0;
	#if defined(ALL) || defined(TEMPERATURE)
		double kpp_temp = pp_temp + 273.15;
	#endif
	#if defined(ALL)
	if (option_temperature && kpp_temp>1000) {
	#else
	#if defined(TEMPERATURE)
	if (kpp_temp>1000) {
	#endif
	#endif		
	#if defined(ALL) || defined(TEMPERATURE)
		if (kpp_temp>5000) {	//melted core
			liquid_water = 1;
			rockyground (25, 4, -20);
			sctype=ALLLAVA;
		} else if (kpp_temp>3000) {	//core fully visible, partially melted
			double melt = (kpp_temp-3000)/2000.0;
			liquid_water = 1;
			rockyground (25, 4, -((long)(melt*10)+10));
			sctype=LAVA;
			//frosty = 1;
		} else if (kpp_temp>1000) {	//strip dirt off
			double strip = (kpp_temp-1000)/2000.0;
			rockscaling = 50 + RANDOM (75);
			rockpeaking = 30 + RANDOM (25);
			if (RANDOM(3))
				rockdensity = 31;
			else
				rockdensity = 0;
			rockyground (15, 4, -((long)(strip*10)));
			frosty = 1;
			gtx = 0;
			waswet = 1;
			glassified=1;
			sctype=GLASSIFIED;
		}
		if (liquid_water) {
			gtx = 0;
			waves_in = 1;
			waves_out = 1;
			waswet = 1;
			// texture sabbiosa, direi...
			T_SCALE = 128;
			n = RANDOM (30) + 2;
			ptr = 65535;
			while (ptr) {
				txtr[ptr] = RANDOM(n);
				ptr--;
			}
			// moltissimi sassolini, se ci sono.
			rockscaling = 50 + RANDOM (75);
			rockpeaking = 30 + RANDOM (25);
			if (RANDOM(3))
				rockdensity = 31;
			else
				rockdensity = 0;
			// ma aspetta un attimo: non possono
			// esserci dei sassi galleggianti.
		} 
		if (frosty) {
			T_SCALE = 32;
			
			n = RANDOM (16) + 16;
			ptr = 65535;
			while (ptr) {
				txtr[ptr] = RANDOM(n);
				ptr--;
			}
			n = 1 + RANDOM(3);
			while (n>0) {
				ptr = 65535 - 257;
				while (ptr) {
					cx = txtr[ptr] + txtr[ptr+1] + txtr[ptr+256] + txtr[ptr+257];
					txtr[ptr] = cx >> 2;
					ptr--;
				}
				n--;
			}
			T_SCALE = 16 + RANDOM(48);
			n = RANDOM (250);
			while (n>0) {
				srf_darkline (txtr, 100 + RANDOM(200), -RANDOM(2), 0, 256);
				n--;
			}
		}
		
	} else {
	#endif
		if (nearstar_p_type[ip_targetted]!=3) sctype = nearstar_p_type[ip_targetted]+16;
		switch (nearstar_p_type[ip_targetted]) {
	
			// case 0: ATTUALMENTE non considerato: Š un pianeta vulcanico.
	                case 0:
			//double melt = (kpp_temp-3000)/2000.0;
			liquid_water = 1;
			rockyground (25, 4, -((long)(-1.25*10)+10));
			//sctype=LAVA;
				n = RANDOM(10);
				if (n>6) { //Huge volcano, only one.
                                  tempx=100; tempy=100; tempb=2;
                                  round_hill (tempx,tempy,40 + RANDOM(30),200, 0, tempb);
                                  n=0;
                                  tempi=3000;
                                  goto makelava;
                                }
				while (n>0) { // Multiple smaller volcanoes
						tempx=RANDOM(180)+10;
						tempy=RANDOM(180)+10;
						//tempb=RANDOM(2)+1;
						tempb=2;
					round_hill (tempx,
							tempy,
							RANDOM(10)+15,
							200, 0, tempb);
					n--;
                                        if (tempb==2)
                                        tempn=1+RANDOM(2);
                                        else tempn=0;

               while (tempn>0){   //Volcano fluid! Yay! :D
                tempi = 450 + RANDOM (200);
                //tempx=100;
                //tempy=100;
                makelava:
                tempb=(tempy*200)+tempx;
                                  //tempz=RANDOM(3) - 1; //if (tempz < 0) tempz = 0; //if (tempz > 250) tempz = 0;
                while (tempi > 0) {
                  tempx=tempx+RANDOM(3)-1;
                  tempy=tempy+RANDOM(3)-1;
                  if (tempy >=198 || tempy <= 2 || tempx >=198 || tempx <=2)
                  goto nodrawlava;
                  tempb=(tempy*200)+tempx;
                  ////tempb=RANDOM(40000)+25534;
                  //if (tempn > 500)
                  ruinschart[tempb] = AF6;
                  //else ruinschart[tempb] = AF4;
   	          p_surfacemap[tempb] = abs(p_surfacemap[tempb]-1);
   	          p_surfacemap[tempb-1] = abs(p_surfacemap[tempb-1]-1);
   	          p_surfacemap[tempb+1] = abs(p_surfacemap[tempb+1]-1);
   	          p_surfacemap[tempb-200] = abs(p_surfacemap[tempb-200]-1);
   	          p_surfacemap[tempb+200] = abs(p_surfacemap[tempb+200]-1);
   	          if (tempi > 500) {
                    //p_surfacemap[tempb+400] = abs(p_surfacemap[tempb+400]-1);
                    //p_surfacemap[tempb-400] = abs(p_surfacemap[tempb-200]-1);
                    //p_surfacemap[tempb+2] = abs(p_surfacemap[tempb+2]-1);
                    //p_surfacemap[tempb-2] = abs(p_surfacemap[tempb-2]-1);
   	            ruinschart[tempb-1] = AF6;
   	            ruinschart[tempb+1] = AF6;
   	            ruinschart[tempb-200] = AF6;
   	            ruinschart[tempb+200] = AF6;
   	          }
                  nodrawlava:
                  tempi = tempi - 1;
                }
                tempn--;
               }
 }
			break;

			case 1: // rocciosi (stile luna)
				// terreno molto liscio ed estremamente arrotondato.
				// ma ci sono casi in cui Š tutto l'opposto.
				n = RANDOM(5);
				if (n <= 2) rockyground (25, 4 + RANDOM (4), 0);
				if (n == 3) rockyground (5 + RANDOM(5), 1, 1);
				if (n == 4) rockyground (10, 2, -RANDOM(5));
	
				n = RANDOM(48) + 32 - raw_albedo;	//Fixing this to raw albedo so terrain doesn't change in a sector due to atmospheric conditions or nighttime (SL)
				if (n > 30) n = 30;
				if (n < 0) n = 0;
				while (n>0) {
					hf = (float)RANDOM(32) * 0.01;
					hr = (float)(RANDOM(20) + 5) * 0.075;
					std_crater (p_surfacemap,
							RANDOM(200), RANDOM(200),
							RANDOM(50) + 5, 127, hf, hr, 200);
					n--;
				}
				n = RANDOM(48) + 64 - raw_albedo;	//Fixing this to raw albedo so terrain doesn't change in a sector due to atmospheric conditions or nighttime (SL)
				if (n < 0) n = 0;
				hf = 0.35; //if (nightzone) hf = 0.1;	//Craters shouldn't get shallower at night-time! O_o (SL)
				while (n>0) {
					cx = RANDOM (200);
					cz = RANDOM (200);
					cr = RANDOM (32) + 10;
					std_crater (txtr, cx, cz, cr, 31, hf, 1, 256);
					if (cr%2) std_crater (txtr, cx + cr/3, cz + cr/3, -cr, 31, hf, 1, 256);
					n--;
				}
				n = RANDOM(100);
				while (n>0) {
					srf_darkline (txtr, RANDOM(1000), -1, -1, 256);
					n--;
				}
				// molte piccole rocce aguzze, o nulla...
				rockdensity = (15 + 16 * RANDOM(2)) * RANDOM(2);
				rockscaling = 150 + RANDOM (500);
				rockpeaking = 100 + RANDOM (300);
				break;
	
			case 2: // con spessa atmosfera (pianeti "venusiani")
				rockyground (10, 1, 0);
				n = raw_albedo + RANDOM (100);	//Fixing this to raw albedo so terrain doesn't change in a sector due to atmospheric conditions or nighttime (SL)
				while (n>0) { // basse colline e frequenti altipiani,
						// oceani e mari sono rari ma possibili...
					round_hill (RANDOM(200),
							RANDOM(200),
							RANDOM(100) + 50,
							RANDOM( 50) + 10, 0, 1);
					n--;
				}
				// per i dettagli di superficie, due scenari possibili:
				switch (RANDOM(2)) {
					case 0: // questo nebuloso, indefinito.
						n = raw_albedo + RANDOM(200) - RANDOM (100);	//Fixing this to raw albedo so terrain doesn't change in a sector due to atmospheric conditions or nighttime (SL)
						hf = (float)RANDOM(10) * 0.02;
						if (n<0) n = 0;
						while (n>0) {
							cx = RANDOM (256);
							cz = RANDOM (256);
							cr = RANDOM (8)+8;
							if (RANDOM(2))
								std_crater (txtr, cx, cz, -cr, 31, hf, 1, 256);
							else
								std_crater (txtr, cx, cz, cr, 31, hf, 1, 256);
							n--;
						}
						break;
					case 1: // e questo con irregolarit… sparse...
						n = raw_albedo + RANDOM(500);	//Fixing this to raw albedo so terrain doesn't change in a sector due to atmospheric conditions or nighttime (SL)
						ptr = RANDOM (2000);
						while (n>0) {
							srf_darkline (txtr, RANDOM(ptr), -1, -1, 256);
							n--;
						}
				}
				// di solito poche grosse rocce erose
				rockscaling = 500 + RANDOM (500);
				rockdensity = 7 + 8 * RANDOM(2);
				rockpeaking = 50 + RANDOM (150);
				break;
	
			case 3: // abitabili

				gtx = 0; // pu• esserci acqua liquida,
					 // quindi non tracciare i poligoni
					 // al livello del suolo a meno che
					 // non sia un particolare scenario
					 // tra quelli descritti sotto.
				switch (sctype) {
					case OCEAN:
						waves_in = 1;
						waves_out = 1;
						// se non Š proprio mare aperto,
						// si pu• considerare un paesaggio
						// "in riva al mare", usando il
						// codice delle PLAINS.
						if (raw_albedo > 20) {	//Fixing this to raw albedo so terrain doesn't change in a sector due to atmospheric conditions or nighttime (SL)
							waswet = 1;
							waves_in = 0;
							goto revert;
						}
						// albedo pi— basse, ma comunque pi—
						// alte di quella del mare aperto(16):
						// scogli sparsi che rompono le onde,
						// nel qual caso il mare Š calmo...
						if (raw_albedo > 16 && RANDOM(2)) {	//Fixing this to raw albedo so terrain doesn't change in a sector due to atmospheric conditions or nighttime (SL)
							rockyground (10, RANDOM(2), -5);
							waves_in = 0;
						}
						// mentre in pieno oceano,
						// al limite potrebbe esserci
						// un'isoletta... raro, ma possibile.
						if (!RANDOM(3)) {
							cx = RANDOM(100) + 50;
							cz = RANDOM(100) + 50;
							round_hill (cx + RANDOM(15),
									cz + RANDOM(15),
									RANDOM(100) + 25,
									RANDOM(10) + 1, 0, 1);
							round_hill (cx, cz,
									RANDOM(100) + 25,
									RANDOM(100) +  1, 0, 1);
							waswet = 1;
							goto addtrees;
						}
						// texture sabbiosa, direi...
						T_SCALE = 128;
						n = RANDOM (30) + 2;
						ptr = 65535;
						while (ptr) {
							txtr[ptr] = RANDOM(n);
							ptr--;
						}
						// moltissimi sassolini, se ci sono.
						rockscaling = 50 + RANDOM (75);
						rockpeaking = 30 + RANDOM (25);
						if (RANDOM(3))
							rockdensity = 31;
						else
							rockdensity = 0;
						// ma aspetta un attimo: non possono
						// esserci dei sassi galleggianti.
						liquid_water = 1;
						break;
					case FOREST:
					case SHRUBLAND:
					case PLAINS:
						// basse colline, oppure montagne
						// vere e proprie (in effetti, tutte
						// le zone ricche di vegetazione
						// rientrano in questo scenario),
						// allora diciamo cosŤ...
					revert:
						rndval = RANDOM(2);
						//DebugPrintf(0, "Moo. LSS=%li. rndval=%li", local_surface_seed, rndval);
						
						if (rndval) {
							// nell'un caso, le pianure.
							ptr = RANDOM(50) + 5;
							while (ptr) {
								round_hill (RANDOM(200),
										RANDOM(200),
										RANDOM(200) + 1,
										RANDOM( 30) + 1, 0, 1);
								ptr--;
							}
						}
						else {
							// nell'altro caso, i monti.
							ptr = RANDOM(25) + 10;
							while (ptr) {
								round_hill (RANDOM(200),
										RANDOM(200),
										RANDOM(200) + 1,
										RANDOM(100) + 1, 0, 1);
								ptr--;
							}
						} 
						//rndval = RANDOM(200);
						//DebugPrintf(0, "Last test. rndval=%li", rndval);
						
					  addtrees: // alberi sui rilievi...
						// in certi casi, pianure steppose...
						//n = RANDOM (6);
						int primeClass, secondaryClass;
						primeClass = NOTHING; secondaryClass = NOTHING;
						switch (sctype) {
							case PLAINS:
								primeClass = TREES;
								secondaryClass = VEGET;
								break;
							case FOREST:
								primeClass = TREES;
								secondaryClass = TREES;
								break;
							case SHRUBLAND:
								primeClass = VEGET;
								secondaryClass = VEGET;
								break;
							case OCEAN:
								primeClass = TREES;
								secondaryClass = VEGET;
								break;
							default:
								primeClass = TREES;
								secondaryClass = VEGET;
								break;
						}
						for (ptr = 0; ptr < oc_bytes; ptr ++) {
							switch (p_surfacemap[ptr] / 25) {
								case 0:	objectschart[ptr].object1_class = VEGET;
									objectschart[ptr].object2_class = primeClass;
									if (sctype==FOREST) objectschart[ptr].object0_class = primeClass;
									break;
								case 1:	objectschart[ptr].object1_class = secondaryClass;
									objectschart[ptr].object2_class = primeClass;
									if (sctype==FOREST) objectschart[ptr].object0_class = primeClass;
									break;
								case 2:	objectschart[ptr].object1_class = primeClass;
									objectschart[ptr].object2_class = primeClass;
									if (sctype==FOREST) objectschart[ptr].object0_class = primeClass;
									break;
								default: objectschart[ptr].object0_class = primeClass;
									objectschart[ptr].object1_class = primeClass;
									objectschart[ptr].object2_class = primeClass;
							}
						}
						// e texture con erba brada...
						T_SCALE = 128;
						n = RANDOM (15) + 2;
						ptr = 65535;
						while (ptr) {
							txtr[ptr] = RANDOM(n);
							ptr--;
						}
						n = 100 + RANDOM (500);
						while (n>0) {
							asterism (txtr, RANDOM(256), RANDOM(256),
								  RANDOM(16), RANDOM(16), RANDOM(25) + 6,
								  RANDOM(15) + 6, 256);
							n--;
						}
						// quasi mai si rende visibile
						// il livello dell'orizzonte
						// (Š troppo piatto, indecorato)
						// ma a meno che non sia una localit…
						// di mare abbastanza scoperta...
						// in tal caso l'orizzonte Š quasi
						// sempre costituito dal mare stesso:
						// in un caso su 5, si trover… uno
						// scenario strano ma interessante:
						// pozze d'acqua tra i cespugli,
						// un luogo "paludoso"...
						//for (ptr=0; ptr<oc_bytes; ptr++) {
						//	DebugPrintf(0, "%li = %li", (Dword)ptr, (Dword)(p_surfacemap[ptr]));
						//}
						if (!waswet || (waswet && !RANDOM(5))) {
							for (ptr = 0; ptr < oc_bytes; ptr ++)
								p_surfacemap[ptr] += fast_random (3);
						}
						// qualche sasso tanto per dire...
						rockscaling = 100 + RANDOM (200);
						rockpeaking = 100 + RANDOM (200);
						rockdensity = 3 + 4 * RANDOM(2);
						// a ogni modo, togli tutti gli
						// oggetti dagli specchi d'acqua.
						if (waswet)
							liquid_water = 1;
						else
							gtx = 1;
						break;

					case DESERT:
						// beh, dune... e un palo
						// per andarci ovviamente a sbattere
						// (scherzavo, per il palo)
						// pi— alti i dislivelli,
						// maggiore lo smoothing,
						// cosŤ vengono fuori dune
						// arrotondate dal vento...
						n = RANDOM(100);
						rockyground (50 + n, 5 + (n>>4), 0);
						for (ptr = 0; ptr < oc_bytes; ptr ++) {
							//In the desert, ROCKS are drawn as cacti instead, since objectN_class is only 2 bits in size (so we can't make a separate CACTI type)
							switch (p_surfacemap[ptr] / 25) {
									case 0:	objectschart[ptr].object2_class = ROCKS;
									objectschart[ptr].object0_class = NOTHING;
									objectschart[ptr].object1_class = NOTHING;
									break;
								case 1:	objectschart[ptr].object1_class = ROCKS;
									objectschart[ptr].object0_class = NOTHING;
									objectschart[ptr].object2_class = NOTHING;
									break;
								case 2:	objectschart[ptr].object0_class = ROCKS;
									objectschart[ptr].object1_class = NOTHING;
									objectschart[ptr].object2_class = ROCKS;
									break;
								default:
									objectschart[ptr].object0_class = ROCKS;
									objectschart[ptr].object1_class = ROCKS;
									objectschart[ptr].object2_class = ROCKS;
							}
						}
						// texture a grana grossa, ghiozza.
						T_SCALE = 128;
						ptr = 65535;
						while (ptr) {
							txtr[ptr] = RANDOM(32);
							ptr--;
						}
						n = 2;
						while (n>0) {
							ptr = 65535 - 257;
							while (ptr) {
								cx = txtr[ptr] + txtr[ptr+1] + txtr[ptr+256] + txtr[ptr+257];
								txtr[ptr] = cx >> 2;
								ptr--;
							}
							n--;
						}
						n = 3;
						while (n>0) {		//Fix the textures. We don't want an UGHLY bright line at the side!
						ptr = 2056;
							while (ptr) {
								cx = txtr[65535-ptr] + txtr[65534-ptr] + txtr[ptr] + txtr[ptr+1];
								txtr[65535-ptr] = cx >> 2;
								ptr--;
							}
							n--;
						}
						// qui Š tutta sabbia:
						rockdensity = 0; // niente sassi
						gtx = 1; // suolo texturizzato
						break;
	
					case ICY:
						snowy = 0;
						frosty = 0;
						// mah, quattro tipi di orografia.
						switch (RANDOM(4)) {
							case 0: // praticamente piana,
								// distesa nevosa...
								rockyground (15, 5, 0);
								snowy = 1;
								break;
							case 1:	// brulla distesa di
								// ghiaccio permanente
								rockyground (10 + RANDOM(10), 1 + RANDOM(2), 0);
								frosty = 1;
								break;
							case 2: // colline di neve...
								ptr = RANDOM (50) + 50;
								while (ptr) {
									round_hill (RANDOM(200),
											RANDOM(200),
											RANDOM(200) + 1,
											RANDOM( 75) + 1, 0, 1);
									ptr--;
								}
								snowy = 1;
								break;
							case 3: // e anche icebergs...
								rockyground (50 + RANDOM(50), 3 + RANDOM(3), -(RANDOM(40) + 20));
								frosty = 1;
								break;
						}
						// qualche sasso? raro e grosso.
						rockscaling = 200 + RANDOM (500);
						rockpeaking = 150 + RANDOM (250);
						rockdensity = 2 * RANDOM(2);
						//if (abs(landing_pt_lat-60)<56) {
							for (ptr = 0; ptr < oc_bytes; ptr ++) {
								if (p_surfacemap[ptr]>0) {
									/*if (abs(landing_pt_lat-60)<56) {
										objectschart[ptr].object2_class = TREES;
									}*/
									if (abs(landing_pt_lat-60)<52) {
										objectschart[ptr].object1_class = TREES;
									}
									objectschart[ptr].object0_class = TREES;
								}
							}
						//}
					   similar:	if (snowy || frosty) { // textures "nevose"
							T_SCALE = 32;
							n = RANDOM (16) + 16;
							ptr = 65535;
							while (ptr) {
								txtr[ptr] = RANDOM(n);
								ptr--;
							}
							n = 1 + RANDOM(3);
							while (n>0) {
								ptr = 65535 - 257;
								while (ptr) {
									cx = txtr[ptr] + txtr[ptr+1] + txtr[ptr+256] + txtr[ptr+257];
									txtr[ptr] = cx >> 2;
									ptr--;
								}
								n--;
							}
							n = 2;
							while (n>0) {  //Fix the textures. We don't want an UGHLY bright line at the side!
								ptr = 2056;
								while (ptr) {
									cx = txtr[65535-ptr] + txtr[65534-ptr] + txtr[ptr] + txtr[ptr+1];
									txtr[65535-ptr] = cx >> 2;
									ptr--;
								}
								n--;
							}
						}
						if (frosty) { // textures "ghiacciate"
							T_SCALE = 16 + RANDOM(48);
							n = RANDOM (250);
							while (n>0) {
								srf_darkline (txtr, 100 + RANDOM(200), -RANDOM(2), 0, 256);
								n--;
							}
						}
                                              
						break;
				}
	                          
				// I quarzi si possono trovare anche sui pianeti
				// abitabili, ma solo a volte...
				if (!RANDOM(5)) quartz = 1;

				break;
	
			case 4:	// descritto come "di medie dimensioni, pietroso
				// (petroso) e corrugato". Š un pianeta roccioso
				// che non ha pressoch‚ nessun cratere d'impatto,
				// ma la cui superficie Š disseminata di enormi
				// massi grandi come case. nel sistema solare
				// un possibile corrispondente Š la superficie
				// di phobos, ma per certi versi lo sarebbe anche
				// la Luna, se non avesse crateri...
	
				// il terreno Š piuttosto liscio, di per s‚,
				// con dislivelli simili a colline molto schiacciate,
				// che possono essere inframezzate da ampie pianure...
				rockyground (15, 3 + RANDOM (3), -RANDOM(5));
	
				// e ora si aggiungono i pietroni della descrizione.
				// pu• anche non essercene nessuno, in un quadrante...
				n = RANDOM (15);
				while (n>0) {
					hf = RANDOM (15) + 7;
					hr = hf * (flandom() * 3.5 + 3.5);
					ht = hr * (flandom() * 0.2 + 0.3);
					if (ht > 127) ht = 127;
					round_hill (RANDOM(200),
							RANDOM(200),
							hf, hr, ht, 0);
					n--;
				}
				
				// vanno per• arrotondati un po', perch‚ in effetti
				// Š presumibile che siano coperti di polvere...
				smoothterrain (1 + RANDOM(2));
				
				// qui disegna dei piccolissimi crateri sulla texture
				// di superficie... che pi— che altro rappresentano
				// macchie e avvallamenti nelle zone a albedo bassa.
				n = 64 - raw_albedo;	//Fixing this to raw albedo so terrain doesn't change in a sector due to atmospheric conditions or nighttime (SL)
				hf=0.25;	//Crater depth shouldn't change at night. (SL)
				/*
				if (nightzone)
					hf = 0.50;
				else
					hf = 0.25;
				*/
				
				while (n>0) {	//This was while (n) { - this change fixs a freeze bug which happened if raw_albedo was higher than 64. (SL)
					cx = RANDOM (150) + 25;
					cz = RANDOM (150) + 25;
					cr = RANDOM ( 10) + 15;
					std_crater (txtr, cx, cz, -cr, 31, hf, 1, 256);
					n--;
				}
				
				// piccoli sassi a grappoli, frammenti dei grandi
				// massi e polveri addensate..
				rockscaling = 100 + RANDOM (200);
				rockdensity = 3 + 4 * RANDOM(2);
				rockpeaking = 100 + RANDOM (200);
				
				break;
	
			case 5: // con atmosfera sottile (marte etc...)
				// possono avere un terreno piuttosto accidentato,
				// e raramente liscio: Š anche prevista la possibilit…
				// di pozze d'acqua date dalla presenza del permafrost,
				// per• sono gelate e ci si pu• viaggiare sopra...
				// scenari principali: pianure, territori accidentati.
				if (RANDOM(2)) {
					n = 5 + RANDOM(10);
					if (raw_albedo > 48) n /= 2;	//Fixing this to raw albedo so terrain doesn't change in a sector due to atmospheric conditions or nighttime (SL)
					rockyground (n, 1, 0);
				}
				else {
					n = 15 + RANDOM(32);
					if (raw_albedo > 48) n /= 2;	//Fixing this to raw albedo so terrain doesn't change in a sector due to atmospheric conditions or nighttime (SL)
					rockyground (n, 1, -RANDOM(24));
				}
				// va incluso qualche cratere eroso: Š possibile...
				n = RANDOM(68) - raw_albedo;	//Fixing this to raw albedo so terrain doesn't change in a sector due to atmospheric conditions or nighttime (SL)
				if (n > 10) n = 10;
				if (n < 1)  n = 1;
				while (n>0) {
					hf = (float)RANDOM(5) * 0.015;
					hr = (float)(RANDOM(10) + 10) * 0.27;
					std_crater (p_surfacemap,
							RANDOM(200), RANDOM(200),
							RANDOM(35) + 5, 127, hf, hr, 200);
					n--;
				}
				// molte pietre e pietruzze... sŤ, sŤ...
				// per• non Š detto che siano tantissime, e
				// in certi punti il terreno potrebbe essere sgombro.
				rockscaling = 50 + RANDOM (400);
				rockpeaking = 50 + RANDOM (250);
				rockdensity = 1 + 30 * RANDOM(2);
				// zone ad albedo alta sono coperte di nubi brillanti
				if (albedo > 50) {
					sky_brightness *= 2;
					if (sky_brightness > 63) sky_brightness = 63;
				}
				// zone ad albedo medio-alta: si tratta di vulcani,
				// ci sono molte rocce grandi e la superficie Š
				// fatta "a padella", descrive ampie curve.
				if (raw_albedo > 40 && raw_albedo <= 50) {	//Fixing this to raw albedo so terrain doesn't change in a sector due to atmospheric conditions or nighttime (SL)
					rockscaling *= 2;
					rockdensity = 15 + 16 * RANDOM(2);
					hf = (float)RANDOM(5) * 0.01;
					hr = (float)(RANDOM(5) + 5) * 0.5;
					std_crater (p_surfacemap,
							90 + RANDOM(20), 90 + RANDOM(20),
							100 + RANDOM(10), 127, hf, hr, 200);
				}
				// e per quanto riguarda i dettagli sulla superficie,
				// roba molto irregolare: crepe, sassi e buche...
				ptr = RANDOM (1500) + 500;
				n = raw_albedo * 5;	//Fixing this to raw albedo so terrain doesn't change in a sector due to atmospheric conditions or nighttime (SL)
				while (n>0) {
					srf_darkline (txtr, RANDOM(ptr), -1, -1, 256);
					n--;
				}
				break;
	
			case 7: // gelidi, solcati di strie.
				//Fixing this to raw albedo so terrain doesn't change in a sector due to atmospheric conditions or nighttime (SL)
				rockyground (10 - (raw_albedo / 8), 0, 20 + RANDOM(100));
				n = raw_albedo - RANDOM(raw_albedo) + 10;
				while (n>0) { // fai qualche crepaccio nella superficie
					srf_darkline (p_surfacemap, RANDOM(500), -1, -1, 200);
					n--;
				}
				n = raw_albedo + RANDOM(200) - RANDOM (100); if (n<0) n = 0;
				while (n>0) { // e aggiungi piccoli crateri "a macchia"
					cx = RANDOM (192) + 32;
					cz = RANDOM (192) + 32;
					cr = RANDOM ( 16) + 16;
					std_crater (txtr, cx, cz, -cr, 31, 0.15, 1, 256);
					n--;
				}
				n = raw_albedo + RANDOM(100) - RANDOM (50); if (n<0) n = 0;
				n /= 2; while (n>0) { // ma sŤ, anche qualche crepetta pi— piccola, sparsa...
					srf_darkline (txtr, RANDOM(100), -RANDOM(2), -RANDOM(2), 256);
					n--;
				}
				// pietre? poche. qualcuna, di media taglia...
				rockscaling = 50 + RANDOM (400);
				rockpeaking = 50 + RANDOM (200);
				rockdensity = 3 + 4 * RANDOM(2);
				break;
	
			case 8: // lattiginosi (pianeti al quarzo).
				// le zone pi— scure sono coperte di strutture
				// piuttosto allungate, simili a duomi tettonici.
				if (raw_albedo < 20) {
					ptr = 100 - raw_albedo;
					while (ptr) {
						hr = RANDOM (300);
						round_hill (RANDOM(150) + 25,
								RANDOM(150) + 25,
								RANDOM(  5) + 2,
								hr + 1, 127, 0);
						ptr--;
					}
					smoothterrain (2 + RANDOM(3));
				}
				// altrove, sono normalmente coperti di montagnole,
				// o da agglomerati informi...
				if (raw_albedo>=100) {
					ptr = 0;
				} else {
					ptr = (100 - raw_albedo) * 2;
				}
				while (ptr) {
					round_hill (RANDOM(200),
							RANDOM(200),
							RANDOM( 25) + 1,
							RANDOM( 25) + 1, 0, 1);
					ptr--;
				}
				// abbastanza roccioso, sŤ... direi.
				// quarziti molto irregolari, Š ovvio...
				quartz = 1;
				rockscaling = 50 + RANDOM (300);
				rockpeaking = 50 + RANDOM (300);
				rockdensity = 7 + 8 * RANDOM(2);
				// le macchie chiare sono zone pi— pianeggianti...
				// quarzo fuso e successivamente risolidificato
				// da estrusioni calde dall'interno: meno sassi qui.
				if (raw_albedo > 40) {
					rockscaling *= 0.5;
					rockpeaking = rockscaling;
					rockdensity = 3 + 4 * RANDOM(2);
					smoothterrain (1 + RANDOM(10));
				}
				// ripeti una texture "nevosa" o "ghiacciata".
				// non ci stanno male.
				snowy = 0; frosty = 0;
				if (RANDOM(2))
					snowy = 1;
				else
					frosty = 1;
				goto similar;

		}
	#if defined(ALL) || defined(TEMPERATURE)
	}
	#endif
	n = RANDOM (5);
	if (n) {
		while (n>0) { // crepacci nella superficie possono essere ovunque
                        /*// mountain/canyon generation	// (by Ees33)
                        ismtn = RANDOM(10);
			if(ismtn != 1) ismtn = 0;
                
                        // (Ees33) Get a height category and set
                        // maximum altitude value.
                        if(ismtn == 1)
                        {
                          hcat = 0;          // normal height 
                          hcatr = RANDOM(20);
                          if(hcatr == 1)
                          {
                            hcat = 1;        // intermediate heights (1 in 20) 
                            hcatr = RANDOM(10);
			    if(hcatr == 1)
                            {
                              hcat = 2;      // 300ers (1 in 200) 
                              hcatr = RANDOM(2);
                              if(hcatr == 1)
                              {
                                hcat = 3;    // 400ers (1 in 400) 
                                hcatr = RANDOM(4);
                                if(hcatr == 1)
                                  hcat = 4;  // 500ers (1 in 1600) 
                              }
                            }
			  }
                
                          // Choose maximum altitude value and adjust variability parameter.
                          switch(hcat)
                          {
                                case 0:
                                     maxalt = 127;
                                     break;
                                case 1:
				     maxalt = inclusive_rand(128, 146);
				     break;
				case 2:
				     maxalt = inclusive_rand(147, 195);
				     break;
				case 3:
				     maxalt = inclusive_rand(196, 244);
				     break;
				case 4:
				     maxalt = inclusive_rand(245, 255);
				     break;
				default:
				     maxalt = 127;
			  }
			}

			// Do canyon/mountain generation.
			felisian_srf_darkline (p_surfacemap, RANDOM(500), ismtn, maxalt, -1, -1, 200);
			*/
			felisian_srf_darkline (p_surfacemap, random(500), -1, -1, 200);
			n--;
		}
		///*	// (by Ees33)
		ptr1 = 200;
		while (ptr1 < 38800) {
			n = p_surfacemap[ptr1];
			n += p_surfacemap[ptr1 - 1];
			n += p_surfacemap[ptr1 + 1];
			n += p_surfacemap[ptr1 - 200];
			n += p_surfacemap[ptr1 + 200];
			p_surfacemap[ptr1] = n / 5;
			ptr1++;
			}
		//*/	// (by Ees33)
               // crosssmoothterrain(); // (Ees33) fixed-up smoother
		//}
	}

	// gli oggetti, ovviamente, tendono a distribuirsi pi— numerosi
	// sulle zone pianeggianti, rotolando gi— dai rilievi:
	// questo vale anche per i vegetali, anche se le erbacce
	// potrebbero rimanere attaccate, ma vengono gestite
	// separatamente dal codice dello scenario "plains".
	treeDensity=0;
	for (ptr = 0; ptr < oc_bytes; ptr ++) {
		incl  = abs (p_surfacemap[ptr] - p_surfacemap[ptr +   1]);
		incl += abs (p_surfacemap[ptr] - p_surfacemap[ptr + 200]);
		if (sctype==FOREST) {
			incl*=.5;
		} else if (sctype==SHRUBLAND) {
			incl*=1.5;
		} else if (sctype==ICY) {
			int i = (abs(landing_pt_lat-60))-45;
			i*=2;
			if (i>1) incl=incl + i*i;
		}
		if (incl < 10) {
			objectschart[ptr].nr_of_objects = RANDOM (4);
		} else if (incl < 15) {
			objectschart[ptr].nr_of_objects = RANDOM (3);
		} else if (incl < 20) {
			objectschart[ptr].nr_of_objects = RANDOM (2);
		} else  {
			int i = RANDOM (incl);
			if (i<10) {
				objectschart[ptr].nr_of_objects = 1;
			} else {
				objectschart[ptr].nr_of_objects = 0;
			}
		}
		if (sctype==FOREST && objectschart[ptr].nr_of_objects<3) {
			objectschart[ptr].nr_of_objects++;
		}
		for (int a=0, id=0; a<objectschart[ptr].nr_of_objects; a++, id++) {
			if (id==3) id=0;
			switch (id) {
				case 0:
					if (objectschart[ptr].object0_class==TREES) treeDensity++;
					break;
				case 1:
					if (objectschart[ptr].object1_class==TREES) treeDensity++;
					break;
				case 2:
					if (objectschart[ptr].object2_class==TREES) treeDensity++;
					break;
			}
		}
	}

	/*#define OC(A, B, C, D) objectschart[50].object0_class=A; objectschart[50].object1_class=B; objectschart[50].object2_class=C; objectschart[50].nr_of_objects=D; DebugPrintf(0, "OC(%s, %s, %s, %i) = %i", #A, #B, #C, (D), ruinschart[50]);
	for (int a=0; a<4; a++) {
		OC(ROCKS, ROCKS, ROCKS, a);
		OC(ROCKS, ROCKS, VEGET, a);
		OC(ROCKS, ROCKS, TREES, a);
		OC(ROCKS, ROCKS, NOTHING, a);
	}
	for (ptr = 0; ptr < oc_bytes; ptr ++) {
		objectschart[ptr].object0_class=ROCKS;
		objectschart[ptr].object1_class=ROCKS;
		objectschart[ptr].object2_class=TREES;
		objectschart[ptr].nr_of_objects=0;
	}*/
	//Depth-limit for when there are a lot of trees. (SL)
	if (treeDensity<1650) {	//This entails no depth limit.
		maxDepth=-1;
	} else if (treeDensity>105600) {	//This would result in a maxDepth of 2 or less, and we don't want to make it less than 2.
		maxDepth=2;
	} else {
		maxDepth = (int) (10-SQRT(treeDensity/1650.0));
	}
	
	// se c'Š acqua liquida sulla superficie, non possono esserci
	// oggetti che vi galleggiano: Š opinabile, ma per ora lasciamo
	// perdere eventuali alghe, pezzi di legno...
	if (liquid_water) {
		for (ptr = 0; ptr < oc_bytes; ptr ++) {
			if (!p_surfacemap[ptr])
				objectschart[ptr].nr_of_objects = 0;
		}
	}

	////////////////////////////////////////////////////////////////////
	// INIZIO MODIFICHE STORICHE

	// reimpostazione seeds.
	// qualche pezzo di codice precedente sembra influire
	// sulla distribuzione delle rovine. Sospetto si tratti
	// del frammento che ridistribuisce gli oggetti a seconda
	// delle zone pi— o meno pianeggianti, in quanto qualche
	// byte dell'orografia del territorio sembra cambiare
	// (a volte, errori di sconfinamento dovuti a procedimenti
	// di arrotondamento, ecc...) l'orografia, per•, se cambia,
	// di certo cambia in minuscoli particolari, perch‚ si direbbe
	// generalmente costante.

	//Now uses a better seed (SL)
	fast_srand (local_surface_seed);
	SRAND (local_surface_seed);
	
	FastBool homeSystemWithRuins = False;
	if ((Dword)(nearstar_identity * 1E6) == -37828) {
		// Questa stella Š Balastrackonastreya
		if (ip_targetted == 3) {
			//DebugPrintf(1, "FELYSIA!");
			// Questo mondo Š Felysia:
			// la gravit… Š gi… regolata da una costante
			// in modo che Felysia abbia 1 FG (Felysian G),
			// ma la pressione va regolata; per estrazione
			// pseudo-casuale altrimenti sarebbe circa 1.2 ATM.
			base_pp_pressure = 1;
			// Le rovine qui sono imponenti, tutte storiche.
			make_ruins (0,1,1,2,2, 3);
			homeSystemWithRuins=True;
		}
		else {
			//DebugPrintf(1, "BALASTRACKONASTREYA!");
			// Costruisce rovine sugli altri pianeti abitabili
			// attorno a Balastrackonastreya. In particolare si
			// tratta delle due lune di Fal Galmatrifal.
			// Squallide palazzine, qualche rimasuglio di
			// edifici pi— grandi, e tardi edifici coloniali.
			if (nearstar_p_type[ip_targetted] == 3) {
				make_ruins (3,3,3,1,4, 1);
				homeSystemWithRuins=True;
			}
		}
	}

	if ((Dword)(nearstar_identity * 1E5) == 1599551984L) {
		//DebugPrintf(1, "FENIA!");
		// Questa stella Š Fenia
		// Peach, base navale storica:
		// molti grattacieli, grossi edifici rovinati (industrie).
		if (ip_targetted == 2) {
			make_ruins (0,0,0,1,1, 2);
			homeSystemWithRuins=True;
		}
		// Pleasance, zona residenziale:
		// palazzi, piazze, colonnati decorativi, edifici coloniali.
		if (ip_targetted == 3) {
			make_ruins (2,2,3,3,4, 2);
			homeSystemWithRuins=True;
		}
		// Wetwick, mondo coloniale periferico:
		// principalmente stili coloniali, e qualche rara palazzina.
		if (ip_targetted == 6) {
			make_ruins (3,4,4,4,4, 1);
			homeSystemWithRuins=True;
		}
	}

	if ((Dword)(nearstar_identity * 1E8) == -11543634L) {
		//DebugPrintf(1, "YLASTRAVENIA!");
		// Questa stella Š Ylastravenia, fu esplorata
		// per prima (Š vicinissima a Balastrackonastreya)
		// ed il quarto pianeta, Suricrasia, venne colonizzato
		// con uno stile tutto particolare...
		if (ip_targetted == 3) {
			make_ruins (2,4,5,5,5, 2);
			homeSystemWithRuins=True;
			// Il "Suricrasian Cube" era l'unica formazione
			// nota prima che riaggiustassi i semi per le
			// rovine. Dopo la normalizzazione di tali semi,
			// Š sparito. Si tratta semplicemente di un grosso
			// cubo, e questo frammento si occupa di
			// ripristinarlo come appariva nella vecchia
			// fotografia SNAP0106, o almeno all'incirca
			// come appariva in quella foto.
			if (landing_pt_lon == 18 && landing_pt_lat == 60) {
				for (ptr = 112; ptr < 112 + 25; ptr++) {
					for (ptr1 = 103; ptr1 < 103 + 25; ptr1++) {
						p_surfacemap[m200[ptr1] + ptr] = 127;
						if (ptr1 == 103 + 1 || ptr1 == 103 + 2)
							ruinschart[m200[ptr1] + ptr] = AF1;
					}
					if (ptr == 112 + 19 || ptr == 112 + 20 || ptr == 112 + 2 || ptr == 112 + 3) {
						for (ptr1 = 103; ptr1 < 103 + 25; ptr1++)
							ruinschart[m200[ptr1] + ptr] = AF1;
					}
				}
			}
		}
	}
	
	
	if (homeSystemWithRuins) {
		ape_probability=0;
	} else {
		SRAND (global_surface_seed_raw);
		fast_srand (global_surface_seed_raw);
		for (Word temp=0; temp<42; temp++) {
			fast_random(temp+100);
		}
		Dword randomRuins = 0;
		for (Word a=0; a<8; a++) {
			randomRuins+=fast_random(1023)+1;
		}
		randomRuins-=4192;
		if (randomRuins>0) {
			randomRuins/=364;
		} else {
			randomRuins=0;
		}
		randomRuins-=3;
		if (randomRuins<0) {
			randomRuins=0;
		}
		if (ape_probability>=7) {
			if (randomRuins<ape_probability) {
				randomRuins = ape_probability;
			}
		}
		if (randomRuins>6) randomRuins=6;
		Dword * nsid = (Dword*) (&nearstar_identity);
		Dword starSeed1 = *nsid;
		Dword starSeed2 = *(nsid+1);

		//DebugPrintf(0, "starSeed1=0x%lx starSeed2=0x%lx ip_targetted=%li", starSeed1, starSeed2, (Dword)ip_targetted);
		if (starSeed1==0xe514c091 && starSeed2==0xc0d7103d && ip_targetted==2) {	//Ozoch's ruins planet
			randomRuins=3;
		}
		//This section is probably a little confusing. The reason is some specific optimizations to keep the size of this code low. (SL)
		//There are only 9 possible initial values for randomRuins. Anything above 9 is used for something special in this loop.
		while (randomRuins>0) {
			switch (randomRuins) {
				case 1: {
					goto c4;
				} case 2: {
					goto c4;
				} case 3: {
					//Scattered ruins tiles at varying heights.
					Dword minHeight = RANDOM(100);
					Dword maxHeight = RANDOM(100)+minHeight;
					Dword roll = RANDOM(500)+RANDOM(500)+100;
					Dword odds = RANDOM(100)+RANDOM(100);
					if (starSeed1==0xe514c091 && starSeed2==0xc0d7103d && ip_targetted==2) {	//Ozoch's ruins planet
						minHeight=50;
						maxHeight=100;
						roll=100;
						odds=20;
					}
					fast_srand (local_surface_seed);
					SRAND (local_surface_seed);
					for (ptr = 0; ptr < oc_bytes; ptr ++) {
						if (p_surfacemap[ptr]>=minHeight && p_surfacemap[ptr]<maxHeight) {
							if (RANDOM(roll)<=odds) {
								ruinschart[ptr] = AF1;
							}
						}
					}
					randomRuins=0;
					break;
				} case 4: {
					c4:
					Dword amountMultiple = (randomRuins<=4?randomRuins:3);
					
					//Occasional ruins on the planet, of varying types, in all climates.
					//1 and 2 jump to this code too. 1 has a density of RANDOM(5), 2 has a density of RANDOM(20), and 4 has a density of RANDOM(80).
					//Anything above that has a density of RANDOM(45).
					
					Dword types[5];
					for (int a=0; a<5; a++) {
						Dword type = RANDOM(6);
						if (type<a) {
							type=types[type];
						}
						types[a] = type;
					}
					
					Dword amt = RANDOM(5*amountMultiple*amountMultiple);
					fast_srand (local_surface_seed);
					SRAND (local_surface_seed);
					make_ruins (types[0], types[1], types[2], types[3], types[4], amt);
					if (randomRuins<=4) {
						randomRuins=0;
					} else {
						randomRuins+=10;
					}
					break;
				} case 5: {
					//ruins and craters
					goto c4;
				} case 15: {
					for (ptr = 0; ptr < oc_bytes; ptr ++) {
						p_surfacemap[ptr]=50;
					}
					//This places the craters
					Dword minr = RANDOM(30)+10;
					Dword maxr = RANDOM(50)+minr;
					fast_srand (local_surface_seed);
					SRAND (local_surface_seed);
					//n = RANDOM(68) - raw_albedo;
					//if (n > 50) n = 50;
					//if (n < 1)  n = 1;
					n=50;
					while (n>0) {
						hf = (float)RANDOM(5) * 0.015;
						hr = (float)(RANDOM(10) + 10) * 0.27;
						std_crater (p_surfacemap,
								RANDOM(200), RANDOM(200),
								RANDOM(maxr-minr)+minr, 127, hf, hr, 200);
						n--;
					}
					randomRuins=0;
					break;
				} case 6: {
					goto c4;
				} case 16: {
					//extremely rare zombies
					int newProbability = RANDOM(5)+1;
					if (ape_probability < newProbability) {
						ape_probability = newProbability;
					}
					ape_zombie=1;
					randomRuins=0;
					break;
				} default: {
					randomRuins=0;
					break;
				}
			}
		}
	}
	/*if (ape_probability>0) {
		SRAND (global_surface_seed_raw);
		fast_srand (global_surface_seed_raw);
		if (RANDOM(10)==1) {
			ape_stargazer=True;
		} else {
			ape_stargazer=False;
		}
	}*/
	
	// FINE MODIFICHE STORICHE
	////////////////////////////////////////////////////////////////////

	// infine si calcola la mappa di shading.
	sh_delta = 0;
	if (fabs(sun_x) > 0.33 * dsd1) {
		if (sun_x > 0)
			sh_delta = 1;
		else
			sh_delta = -1;
	}
	if (fabs(sun_z) > 0.33 * dsd1) {
		if (sun_z > 0)
			sh_delta += 200;
		else
			sh_delta -= 200;
	}
}

/* Funzione che definisce il cielo visto da un pianeta.
   Oltretutto, definisce anche: tavola colori, temperatura e pressione. */

void create_sky (char atmosphere)
{
	// filtri colorati di base.

	float br = (float)sky_red_filter / 64,
	      bg = (float)sky_grn_filter / 64,
	      bb = (float)sky_blu_filter / 64;

	float tr = (float)gnd_red_filter / 64,
	      tg = (float)gnd_grn_filter / 64,
	      tb = (float)gnd_blu_filter / 64;

	float fr[4], fg[4], fb[4];	// filtri colorati per 4 sfumature.
	float al = (albedo / 64);	// costante di albedo

	// calcola il fattore "distanza dal sole" per l'intensit… della luce
	// Š infuenzato anche dal tipo di stella.

	float sb, dfs;
	Word   owner = nearstar_p_owner[ip_targetted];

	if (owner == -1)
		dfs = 1 - ((float)(ip_targetted) * 0.05);
	else
		dfs = 1 - ((float)(owner) * 0.05);

	if (!atmosphere)
		sb = 1;
	else {
		sb = (float)sky_brightness / 24;
		if (nightzone) dfs *= 0.5;
	}

	if (owner > 2)
		sb *= (dfs * dfs);
	else
		dfs = 1;

	switch (nearstar_class) {
		case  0: dfs *= 1.0; break;
		case  1: dfs *= 1.5; break;
		case  2: dfs *= 0.5; break;
		case  3: dfs *= 0.8; break;
		case  4: dfs *= 1.2; break;
		case  5: dfs *= 0.1; break;
		case  6: dfs *= 0.1; break;
		case  7: dfs *= 0.4; break;
		case  8: dfs *= 0.9; break;
		case  9: dfs *= 1.3; break;
		case 10: dfs *= 0.5; break;
		case 11: dfs *= 0.2; break;
	}

	// calcola il fattore di saturazione (influenza i pianeti abitabili
	// quando piove, tende a far scivolare le sfumature verso il grigio)

	float saturation = 1 - (0.15 * rainy);
	Word shade_nr;

	fast_srand (global_surface_seed);
	SRAND (global_surface_seed);

	switch (nearstar_p_type[ip_targetted]) {

	        case 0:
	                fr[0]= tr*2;
	                fg[0]= tg/1.5;
	                fb[0]= tb/1.5;

                        fr[1]= 20 * tr;
	                fg[1]= 10 * tg/1.5;
	                fb[1]= 10 * tb/1.5;

                        fr[2]= tr;
	                fg[2]= tg;
	                fb[2]= tb;

                        fr[3]= 1;
	                fg[3]= 0;
	                fb[3]= 0;

	                //nebular_sky ();
	                cloudy_sky (10, 2);
	                cloudy_sky (10, 2);
	                cloudy_sky (10, 2);

	                break;

		case 1: // rocciosi (stile luna)

			pp_pressure = 0;

		 like1:	// colori per le terre emerse.
			// simili a quelli della superficie vista dallo
			// spazio, che tendono a essere alquanto grigiastri.
			fr[0] = tr;// * 0.5 + 0.5 * al;
			fg[0] = tg;// * 0.5 + 0.5 * al;
			fb[0] = tb;// * 0.5 + 0.5 * al;
			// colori per il cielo.
			// non c'Š il cielo. non c'Š aria.
			// ma servono per le stelle, belle brillanti.
			fr[1] = 1.5;
			fg[1] = 1.5;
			fb[1] = 1.5;
			// colori per l'orizzonte.
			// come quelli delle terre emerse, ma pi— sbiaditi.
			fr[2] = 2 * fr[0];
			fg[2] = 2 * fg[0];
			fb[2] = 2 * fb[0];
			// colori per la vegetazione.
			// non c'Š vegetazione, quindi per ora nulli.
			fr[3] = 0.0;
			fg[3] = 0.0;
			fb[3] = 0.0;

			break;

		case 2: // con spessa atmosfera (pianeti "venusiani")

			// colori per tutto.
			// per questo specifico tipo di pianeta,
			// quelli del cielo sono pressoch‚ uguali
			// a quelli delle nubi. quelli del terreno
			// sono il negativo fotografico, perch‚ il
			// cielo filtra interamente i colori opposti.
			fr[0] = 1.2 - tr;
			fr[1] = tr + flandom()*0.15 - flandom()*0.15 + 0.3;
			fr[2] = tr + flandom()*0.30 - flandom()*0.30 + 0.2;
			fr[3] = tr + flandom()*0.45 - flandom()*0.45 + 0.1;
			fg[0] = 1.2 - tg;
			fg[1] = tg + flandom()*0.15 - flandom()*0.15 + 0.3;
			fg[2] = tg + flandom()*0.30 - flandom()*0.30 + 0.2;
			fg[3] = tg + flandom()*0.45 - flandom()*0.45 + 0.1;
			fb[0] = 1.2 - tb;
			fb[1] = tb + flandom()*0.15 - flandom()*0.15 + 0.3;
			fb[2] = tb + flandom()*0.30 - flandom()*0.30 + 0.2;
			fb[3] = tb + flandom()*0.45 - flandom()*0.45 + 0.1;

			nebular_sky (); // cielo adatto all'uopo.

			pp_pressure = fast_flandom() * 20 + albedo + 1;

			break;

		case 3: // abitabili
			SetFelisianPlanetColors(fr, fg, fb, tr, tg, tb, br, bg, bb, sctype);
		
			pp_pressure = fast_flandom() * 0.8 + 0.6;

			break;

		case 4: // pietrosi e corrugati...
			pp_pressure = fast_flandom() * 0.1;
			goto like1;

		case 5: // con atmosfera sottile (marte etc...) //MARSCOLOUR

			// colori per le terre emerse.
			// mah... in genere simili a quelli della superficie
			// vista dallo spazio, ma qualche variazione Š
			// possibile, plausibile... dovuta ai componenti
			// del suolo locale.
			
			/*
			//New thin-atmo planet colors:
			fr[0] = 1.6  * (tr * 1.5) + flandom() * al;
			fg[0] = 1.10 * (tg * 1.5) + flandom() * al;
			fb[0] = 0.64 * (tb * 1.5) + flandom() * al;
			// colori per il cielo.
			// sono pressoch‚ ininfluenti, ma quasi costanti.
			fr[1] = 2.28 * tb + 0.228 * flandom() * al;
			fg[1] = 2.07 * tg + 0.207 * flandom() * al;
			fb[1] = 1.86 * tr + 0.186 * flandom() * al;
			*/
		
			//Old thin-atmo planet colors:
			
			fr[0] = tr + 0.33 * flandom() * al;
			fg[0] = tg + 0.33 * flandom() * al;
			fb[0] = tb + 0.33 * flandom() * al;
			// colori per il cielo.
			// sono pressoch‚ ininfluenti, ma quasi costanti.
			fr[1] = 0.8 * tb + 0.2 * flandom() * al;
			fg[1] = 0.8 * tg + 0.2 * flandom() * al;
			fb[1] = 0.8 * tr + 0.2 * flandom() * al;
			
			// colori per l'orizzonte.
			// come quelli delle terre emerse, ma pi— sbiaditi.
			fr[2] = 0.5 + fr[0] * 0.5 * al;
			fg[2] = 0.5 + fg[0] * 0.5 * al;
			fb[2] = 0.5 + fb[0] * 0.5 * al;
			// colori per la vegetazione.
			// non c'Š vegetazione, quindi per ora nulli.
			fr[3] = 0.0;
			fg[3] = 0.0;
			fb[3] = 0.0;

			// l'atmosfera lascia vedere le stelle
			// per quasi tutto il giorno, di solito...
			sky_brightness = (float)sky_brightness * 0.65;

			// l'aspetto del cielo, anche qui, pu• essere nuvoloso,
			// ma con subi sottili e poco marcate, e foschia appena percepibile.
			cloudy_sky (10, 2);

			pp_pressure = fast_flandom() * 0.05 + 0.01;

			break;

	     // case 6: non considerato: Š un gigante gassoso.

		case 7:	// gelido, solcato di strie (tipo Europa)

			pp_pressure = fast_flandom() * 0.02;

		 like7:	// colori per le terre emerse. molto chiari.
			// simili a quelli della superficie vista dallo
			// spazio, che tendono a essere alquanto grigiastri.
			fr[0] = tr + flandom() * al;
			fg[0] = tg + flandom() * al;
			fb[0] = tb + flandom() * al;
			// colori per il cielo.
			// non c'Š il cielo. non c'Š aria.
			// ma servono per le stelle, brillanti.
			fr[1] = 1.3;
			fg[1] = 1.4;
			fb[1] = 1.5;
			// colori per l'orizzonte.
			// come quelli delle terre emerse, ma pi— sbiaditi.
			fr[2] = 0.5 + fr[0];
			fg[2] = 0.5 + fg[0];
			fb[2] = 0.5 + fb[0];
			// colori per la vegetazione.
			// non c'Š vegetazione, quindi per ora nulli.
			fr[3] = 0.0;
			fg[3] = 0.0;
			fb[3] = 0.0;

			break;

		case 8:	// lattiginoso.
			pp_pressure = fast_flandom() + 0.2;
			goto like7;

	     // case 9: non considerato: Š un oggetto substellare.
	     // case 10: non considerato: Š una stella compagna.

	}

	// evita gradienti negativi, non hanno senso.
	for (shade_nr = 0; shade_nr < 4; shade_nr++) {
		if (fr[shade_nr] < 0) fr[shade_nr] = 0;
		if (fg[shade_nr] < 0) fg[shade_nr] = 0;
		if (fb[shade_nr] < 0) fb[shade_nr] = 0;
	}

	// correzione saturazione colori (foschia e pioggia, ove plausibili).
	if (nearstar_p_type[ip_targetted] == 3 || nearstar_p_type[ip_targetted] == 5) {
		for (shade_nr = 0; shade_nr < 4; shade_nr++) {
			fr[shade_nr] = (fr[shade_nr] - 0.5) * saturation + 0.5;
			fg[shade_nr] = (fg[shade_nr] - 0.5) * saturation + 0.5;
			fb[shade_nr] = (fb[shade_nr] - 0.5) * saturation + 0.5;
		}
	}
	
	// calcolo della temperatura.

	#if defined(ALL)
	if (option_temperature==0) {
	#endif
	#if defined(ALL) || !defined(TEMPERATURE)
		pp_temp = 90 - dsd1 * 0.33;
		if (!atmosphere) {
			pp_temp -= 44;
			pp_temp *= fabs(pp_temp * 0.44);
			if (nightzone)
				pp_temp *= 0.3;
			else
				pp_temp *= 0.3 + exposure * 0.0077;
		}
		else {
			if (nightzone)
				pp_temp *= 0.6;
			else
				pp_temp *= 0.6 + exposure * 0.0044;
		}
	
		pp_temp -= (0.5 + 0.5 * fast_flandom()) * abs (landing_pt_lat - 60);
	
		if (pp_temp < -269)
			pp_temp = -269 + 4 * fast_flandom();
	
                
                if (nearstar_p_type[ip_targetted] == 2)
			pp_temp += fast_flandom() * 150;
	
		if (nearstar_p_type[ip_targetted] == 3) {
			switch (sctype) {
				case OCEAN:
					while (pp_temp < +10) pp_temp += fast_flandom() * 5;
					while (pp_temp > +60) pp_temp -= fast_flandom() * 5;
					break;
				case FOREST:
					while (pp_temp < -10) pp_temp += fast_flandom() * 5;
					while (pp_temp > +52) pp_temp -= fast_flandom() * 5;
					break;
				case PLAINS:
					while (pp_temp < -10) pp_temp += fast_flandom() * 5;
					while (pp_temp > +45) pp_temp -= fast_flandom() * 5;
					break;
				case SHRUBLAND:
					while (pp_temp < 0) pp_temp += fast_flandom() * 5;
					while (pp_temp > +60) pp_temp -= fast_flandom() * 5;
					break;
				case DESERT:
					while (pp_temp < +20) pp_temp += fast_flandom() * 5;
					while (pp_temp > +80) pp_temp -= fast_flandom() * 5;
					break;
				case ICY:
					while (pp_temp <-120) pp_temp += fast_flandom() * 5;
					while (pp_temp >  +4) pp_temp -= fast_flandom() * 5;
			}
		}

	#endif
	#if defined(ALL)
	} else {
	#endif
		#if defined(ALL) || defined(TEMPERATURE)
		pp_temp = GetRawTemperatureAt(dsd1) + 273.15;	//Work on temps in Kelvin
		if (!atmosphere) {
			if (nightzone)
				pp_temp *= 0.3;
			else
				pp_temp *= 0.3 + exposure * 0.0077;
		}
		else {
			if (nightzone)
				pp_temp *= 0.6;
			else
				pp_temp *= 0.6 + exposure * 0.0044;
		}
	
		pp_temp -= (0.75 + 0.75 * fast_flandom()) * (abs (landing_pt_lat - 60)-20);
	
		if (nearstar_p_type[ip_targetted] == 2)
			pp_temp += fast_flandom() * 150;
	
		if (nearstar_p_type[ip_targetted] == 3) {
			switch (sctype) {
				case OCEAN:
					while (pp_temp < +10 + 273.15) pp_temp += fast_flandom() * 5;
					while (pp_temp > +60 + 273.15) pp_temp -= fast_flandom() * 5;
					break;
				case FOREST:
					while (pp_temp < -10 + 273.15) pp_temp += fast_flandom() * 5;
					while (pp_temp > +52 + 273.15) pp_temp -= fast_flandom() * 5;
					break;
				case PLAINS:
					while (pp_temp < -10 + 273.15) pp_temp += fast_flandom() * 5;
					while (pp_temp > +45 + 273.15) pp_temp -= fast_flandom() * 5;
					break;
				case SHRUBLAND:
					while (pp_temp < 0 + 273.15) pp_temp += fast_flandom() * 5;
					while (pp_temp > +60 + 273.15) pp_temp -= fast_flandom() * 5;
					break;
				case DESERT:
					while (pp_temp < +20 + 273.15) pp_temp += fast_flandom() * 5;
					while (pp_temp > +80 + 273.15) pp_temp -= fast_flandom() * 5;
					break;
				case ICY:
					while (pp_temp <-120 + 273.15) pp_temp += fast_flandom() * 5;
					while (pp_temp >  +4 + 273.15) pp_temp -= fast_flandom() * 5;
			}
		}
		
		//special effects
		if (pp_temp>1000) {
			double strip;
			double r = fr[0]; double g = fg[0]; double b = fb[0];
			if (pp_temp>5000) {	//melted core
				strip = .5;
			} else if (pp_temp>3000) {	//core fully visible, partially melted
				//double melt = (pp_temp-2000)/2000.0;
				strip = .5;
			} else if (pp_temp>1000) {	//strip dirt off
				strip = (pp_temp-1000)/1000.0*.5;
				/*fr[0] = tr + flandom() * al;
				fg[0] = tg + flandom() * al;
				fb[0] = tb + flandom() * al;
				// colori per il cielo.
				// non c'Š il cielo. non c'Š aria.
				// ma servono per le stelle, brillanti.
				fr[1] = 1.3;
				fg[1] = 1.4;
				fb[1] = 1.5;
				// colori per l'orizzonte.
				// come quelli delle terre emerse, ma pi— sbiaditi.
				fr[2] = 0.5 + fr[0];
				fg[2] = 0.5 + fg[0];
				fb[2] = 0.5 + fb[0];
				// colori per la vegetazione.
				// non c'Š vegetazione, quindi per ora nulli.
				fr[3] = 0.0;
				fg[3] = 0.0;
				fb[3] = 0.0;*/
			}
			double stripcolor = (r+g+b)*strip/3;
			double radd = (pp_temp-2000)/500;
			double gadd = (pp_temp-4000)/500;
			double badd = (pp_temp-6000)/500;
			if (radd>4) radd=4-radd;
			if (gadd>4) gadd=4-gadd;
			if (badd>4) badd=4-badd;
			if (radd<0) radd=0;
			if (gadd<0) gadd=0;
			if (badd<0) badd=0;
			fr[0]=r*(1-strip)+stripcolor+radd;
			fg[0]=g*(1-strip)+stripcolor+gadd;
			fb[0]=b*(1-strip)+stripcolor+badd;
		}
		pp_temp-=273.15;	//change it back to celsius
		if (pp_temp < -269)
			pp_temp = -269 + 4 * fast_flandom();
	
		#endif
	#if defined(ALL)
	}
	#endif
	
	// prepara le sfumature
	fr[0]*=64 * dfs;      fg[0]*=64 * dfs;      fb[0]*=64 * dfs;
	fr[1]*=64 * dfs * sb; fg[1]*=64 * dfs * sb; fb[1]*=64 * dfs * sb;
	fr[2]*=64 * dfs;      fg[2]*=64 * dfs;      fb[2]*=64 * dfs;
	fr[3]*=64 * dfs;      fg[3]*=64 * dfs;      fb[3]*=64 * dfs;

	// se non c'Š atmosfera, stelle sempre ben visibili.
	// alternativamente, si rendono visibili di notte.
	if (!atmosphere) {
	  if (nearstar_p_type[ip_targetted] != 0) {
		shade (surface_palette, 64, 64, 0, 0, 0, 100, 110, 120);
	  } else {
             	shade (surface_palette,   64, 44,     0,     0,     0, fr[0], fg[0], fb[0]);
	        shade (surface_palette,  108, 20, fr[0], fg[0], fb[0], fr[1], fg[1], fb[1]);
          }
	} else {
		if (nightzone) {
			//shade (surface_palette, 64, 64, 0, 0, 0, 60, 62, 64); //white sky
			shade (surface_palette, 64, 64, fr[1]/8, fg[1]/8, fb[1]/8, fr[1], fg[1], fb[1]); //original planetcolour sky (modded)
			/*if (nearstar_p_type[ip_targetted] == 3) {
				shade (surface_palette, 0, 64, 0, 0, 0, 64, 62, 60);
				shade (surface_palette, 128, 64, 0, 0, 0, 64, 64, 64);
				shade (surface_palette, 192, 64, 8, 12, 16, 56, 60, 64);
				goto nightcolors;
			}*/ //original white surfacecolours
			/*if (nearstar_p_type[ip_targetted] == 3) {
				shade (surface_palette, 0, 64, 0, 0, 0, fr[0], fg[0], fb[0]);
				shade (surface_palette, 128, 64, 0, 0, 0, fr[2], fg[2], fb[2]);
				shade (surface_palette, 192, 64, 8, 12, 16, fr[3], fg[3], fb[3]);
				goto nightcolors;
			}*/    //original planetcolour surface (modded)
			/*if (nearstar_p_type[ip_targetted] == 3) {
				shade (surface_palette, 0, 64, 0, 0, 0, fr[1], fg[1], fb[1]);
				shade (surface_palette, 128, 64, 0, 0, 0, fr[1], fg[1], fb[1]);
				shade (surface_palette, 192, 64, 0, 0, 0, fr[1], fg[1], fb[1]);
				goto nightcolors;
			}*/   //original planetcolour surface (modded, infrareddish)
			/*if (nearstar_p_type[ip_targetted] == 3) {
				shade (surface_palette, 0, 64, 0, 0, 0, ((fr[1]*9)+fr[0])/10, ((fg[1]*9)+fg[0])/10, ((fb[1]*9)+fb[0])/10);
				shade (surface_palette, 128, 64, 0, 0, 0, ((fr[1]*5)+fr[2])/6, ((fg[1]*5)+fg[2])/6, ((fb[1]*5)+fb[2])/6);
				shade (surface_palette, 192, 64, 0, 0, 0, ((fr[1]*5)+fr[3])/6, ((fg[1]*5)+fg[3])/6, ((fb[1]*5)+fb[3])/6);
				goto nightcolors;
			}*/  //original planetcolour surface (modded, infrareddish, Mark II)
			/*if (nearstar_p_type[ip_targetted] == 3) {
				shade (surface_palette,   0, 44,     0,     0,     0, ((fr[1]*9)+fr[0])/10, ((fg[1]*9)+fg[0])/10, ((fb[1]*9)+fb[0])/10);
				shade (surface_palette,  44, 20, ((fr[1]*9)+fr[0])/10, ((fg[1]*9)+fg[0])/10, ((fb[1]*9)+fb[0])/10, fr[1], fg[1], fb[1]);	

				shade (surface_palette, 128, 10,     0,     0,     0, ((fr[1]*9)+fr[0])/10, ((fg[1]*9)+fg[0])/10, ((fb[1]*9)+fb[0])/10);
				shade (surface_palette, 138, 44, ((fr[1]*9)+fr[0])/10, ((fg[1]*9)+fg[0])/10, ((fb[1]*9)+fb[0])/10, ((fr[1]*9)+fr[2])/6, ((fg[1]*9)+fg[2])/6, ((fb[1]*9)+fb[2])/6);
				shade (surface_palette, 182, 10, ((fr[1]*9)+fr[2])/6, ((fg[1]*9)+fg[2])/6, ((fb[1]*9)+fb[2])/6, fr[1], fg[1], fb[1]);

				shade (surface_palette, 192, 10,     0,     0,     0, ((fr[1]*9)+fr[0])/10, ((fg[1]*9)+fg[0])/10, ((fb[1]*9)+fb[0])/10);
				shade (surface_palette, 202, 44, ((fr[1]*9)+fr[0])/10, ((fg[1]*9)+fg[0])/10, ((fb[1]*9)+fb[0])/10, ((fr[1]*9)+fr[3])/6, ((fg[1]*9)+fg[3])/6, ((fb[1]*9)+fb[3])/6);
				shade (surface_palette, 246, 10, ((fr[1]*9)+fr[3])/6, ((fg[1]*9)+fg[3])/6, ((fb[1]*9)+fb[3])/6, fr[1], fg[1], fb[1]);
				goto nightcolors;
			}*/ //True nightcolours, modded. "Mark III"
			if (nearstar_p_type[ip_targetted] == 3) {
				fr[0] = ((fr[1]*9)+fr[0])/10;
				fg[0] = ((fg[1]*9)+fg[0])/10;
				fb[0] = ((fb[1]*9)+fb[0])/10;
				fr[2] = ((fr[1]*9)+fr[2])/6;
				fg[2] = ((fg[1]*9)+fg[2])/6;
				fb[2] = ((fb[1]*9)+fb[2])/6;
				fr[3] = ((fr[1]*9)+fr[3])/6;
				fg[3] = ((fg[1]*9)+fg[3])/6;
				fb[3] = ((fb[1]*9)+fb[3])/6;
				goto daycolors;
			} //True nightcolours, modded. "Mark III", memoryfixed.
			fr[0] *= 0.33;
			fg[0] *= 0.44;
			fb[0] *= 0.55;
			fr[2] *= 0.33;
			fg[2] *= 0.44;
			fb[2] *= 0.55;
			fr[3] *= 0.33;
			fg[3] *= 0.44;
			fb[3] *= 0.55;
		}
		else
			shade (surface_palette, 64, 64, 0, 0, 0, fr[1], fg[1], fb[1]); //normal sky
			//shade (surface_palette, 64, 32, 0, 0, 100, 0, 100, 0); //zOMG rainbow sky (1)
			//shade (surface_palette, 96, 32, 0, 100, 0, 100, 0, 0); //zOMG rainbow sky (2)
			//shade (surface_palette, 96, 32, 100, 50, 0, 100, 100, 0); //zOMG sunset (1)
			//shade (surface_palette, 64, 32, 0, 20, 80, 100, 50, 0); //zOMG sunset (2)
	}
	daycolors:
	if (nearstar_p_type[ip_targetted] != 0) {
        // sfumatura per il suolo.
	shade (surface_palette,   0, 44,     0,     0,     0, fr[0], fg[0], fb[0]);
	shade (surface_palette,  44, 20, fr[0], fg[0], fb[0], fr[1], fg[1], fb[1]);

	// sfumatura per l'orizzonte.
	shade (surface_palette, 128, 10,     0,     0,     0, fr[0], fg[0], fb[0]);
	shade (surface_palette, 138, 44, fr[0], fg[0], fb[0], fr[2], fg[2], fb[2]);
	shade (surface_palette, 182, 10, fr[2], fg[2], fb[2], fr[1], fg[1], fb[1]);

	// sfumatura per la vegetazione.

	shade (surface_palette, 192, 10,     0,     0,     0, fr[0], fg[0], fb[0]);
	shade (surface_palette, 202, 44, fr[0], fg[0], fb[0], fr[3], fg[3], fb[3]);
	shade (surface_palette, 246, 10, fr[3], fg[3], fb[3], fr[1], fg[1], fb[1]);
	} else {  //colours of internally hot worlds
	  shade (surface_palette,   0, 64,     0,     0,     0, 15, 10, 8);   //v1 surface
	  //shade (surface_palette, 192, 64,     50,     0,     0, 63, 40, 0);  //v1 lava
          //shade (surface_palette, 192, 20,     50,     0,     0, 53, 30, 0); //v2 lava
          //shade (surface_palette, 212, 30,     53,    30,     0, 63, 40, 0); //v2 lava
          //shade (surface_palette, 242, 24,     63,    40,     0, fr[1], fg[1], fb[1]); //v2 lava
          shade (surface_palette, 192, 50,     40,     0,     0, 52, 10, 0);  //v3 lava
          shade (surface_palette, 242, 14,     52,    10,     0, 55, 20, 0);  //v3 lava
        }

    nightcolors:

	
	base_pp_temp = pp_temp;
	base_pp_pressure = pp_pressure;
}

/* Funzione che definisce le forme di vita proprie ai pianeti abitabili. */

//extern Udword pvfile_datatop;	//Needed if we're printing the pv space used at the end of setup_animals.

void setup_animals ()
{
	Word n, p, x;

	Word bird_probability;
	Word reptil_probability;
	Word mammal_probability;

	// impostazione numero animali.
	// questo parametro dipende dal tipo di scenario.
	// non sono assolutamente considerate possibilit… di vita
	// su pianeti non classificati come abitabili.

	if (nearstar_p_type[ip_targetted] != 3) {
		animals = 0;
		return;
	}
	
	switch (sctype) {
		case OCEAN:  animals = LFS/5  + RANDOM (LFS-LFS/5); break;
		case FOREST: animals = LFS/3.5  + RANDOM (LFS-LFS/3.5); break;
		case PLAINS: animals = LFS/2  + RANDOM (LFS-LFS/2); break;
		case SHRUBLAND: animals = LFS/6  + RANDOM (LFS-LFS/3.5); break;
		case DESERT: animals = LFS/10 + RANDOM (LFS/5);     break;
		case ICY:    animals = LFS/10 + RANDOM (LFS/2);     break;
	}
	
	// impostazione seme pseudo e scala.
	// questo parametro dipende dal seme globale del pianeta.

	SRAND (global_surface_seed);
	fast_srand (global_surface_seed);

	for (n = 0; n < animals; n++) {
		ani_seed[n]  = fast_random (0xFFFFFFFF);
		ani_scale[n] = 10 * flandom() + 5;
	}

	// impostazione tipologia animali.
	// questo parametro dipende dal seme globale e dal tipo di scenario.

	switch (sctype) {
		case OCEAN:	bird_probability   = 1 + RANDOM(9);
				reptil_probability = 5 + RANDOM(4);
				mammal_probability = 0;
				bull_probability = 0;
				break;
		case FOREST:	bird_probability   = 7 + RANDOM(11);
				reptil_probability = 0 + RANDOM(1);
				mammal_probability = 7 + RANDOM(8);
				bull_probability = 0+RANDOM(1);
				break;
		case PLAINS:	bird_probability   = 5 + RANDOM(9);
				reptil_probability = 3 + RANDOM(3);
				mammal_probability = 5 + RANDOM(4);
				bull_probability = 1+RANDOM(2);
				break;
		case SHRUBLAND:	bird_probability   = 3 + RANDOM(5);
				reptil_probability = 2 + RANDOM(4);
				mammal_probability = 3 + RANDOM(5);
				bull_probability = 2+RANDOM(4);
				break;
		case DESERT:	bird_probability   = 1 + RANDOM(2);
				reptil_probability = 9 + RANDOM(9);
				mammal_probability = 1 + RANDOM(2);
				bull_probability = 5+RANDOM(5);
				break;
		case ICY:	bird_probability   = 2 + RANDOM(2);
				reptil_probability = 0;
				mammal_probability = 0 + RANDOM(2);
				bull_probability = 0;
				break;
	}
	
	//This lowers the chance with low temperature (SL)
	double kelvinTemp = base_pp_temp+273.15;
	if (base_pp_temp<0) {
		bird_probability=(int) (bird_probability*(kelvinTemp/200.0));
		reptil_probability=(int) (reptil_probability*(kelvinTemp/200.0));
		mammal_probability=(int) (mammal_probability*(kelvinTemp/200.0));
	}
	//Dword numC0 = 0;
	for (n = 0; n < animals; n++) {
		while (1) {
			x = RANDOM(4+ape_probability);
			if (x>=4) {
				x=4;
				p = RANDOM (20);
			} else {
				p = RANDOM (18);
			}
			if (x == 0 && p <= bird_probability) {
				ani_type[n] = BIRD;
				goto anitypeselected;
			}
			if (x == 1 && p <= reptil_probability) {
				ani_type[n] = REPTIL;
				goto anitypeselected;
			}
			if (x == 2 && p <= mammal_probability) {
				ani_type[n] = MAMMAL;
				goto anitypeselected;
			}
			if (x == 3 && p <= bull_probability) {
				ani_type[n] = BULLMAMMAL;
				goto anitypeselected;
			}
			if (x == 4 && p <= ape_probability) {
				ani_type[n] = APEMAMMAL;
				//numC0++;
				goto anitypeselected;
			}
		}
		anitypeselected:
		#ifdef WINDOWS
		0;
		#endif
	}
	//DebugPrintf(0, "NumC0: %li", numC0);
	// impostazione posizione attuale e dati accessori sugli animali.
	// questi parametri sono del tutto casuali: certo, solo insetti
	// e uccelli possono volare, e quindi c'Š da tenerne conto.

	SRAND (secs);
	fast_srand (secs);
	
	for (n = 0; n < animals; n++) {
		ani_x[n] = flandom() * 3276800;
		ani_z[n] = flandom() * 3276800;
		if (ani_type[n] == BIRD)
			ani_quote[n] = flandom() * 25000;
		else
			ani_quote[n] = 0;
		ani_pitch[n] = flandom() * 360;
		ani_speed[n] = flandom() * 100;
		tgt_pitch[n] = ani_pitch[n];
		tgt_speed[n] = ani_speed[n];
		tgt_quote[n] = ani_quote[n];
		ani_lcount[n] = 0;
		ani_sqc[n] = ani_z[n] / 16384;
		ani_sqc[n] = m200[ani_sqc[n]] + ani_x[n] / 16384;
		if (ani_type[n]==BIRD && sctype == ICY) {
			//Maybe we could add penguins? (SL)
			float f = (flandom() + flandom()) * (pp_temp+273.15) / 2;
			if (f<100) {
				//Make 'em penguins. Somehow. Hmm. Let's look at polyvert. (SL)
			}
		} else if (ani_type[n]==REPTIL) {
			//ani_mtype[n] = 
		} else {
			if (ani_type[n]==APEMAMMAL) {
				ani_mtype[n] = APE_LIKE;
				ani_type[n]=MAMMAL;
			} else if (ani_type[n]==BULLMAMMAL) {
				//TEMPORARY. WORKPVNOTE: Trying to get workpv to work.
				//ani_mtype[n] = APE_LIKE;
				//ani_type[n]=MAMMAL;
				ani_mtype[n] = BULL_LIKE;
				ani_type[n]=MAMMAL;
			} else {
				ani_mtype[n] = RANDOM(3);
				
			}
		}
	}

	// caricamento forme di base.

	unloadallpv ();
	fast_srand (global_surface_seed);

	// mammiferi:
	loadpv (mamm_base, mammal_ncc,
		1, 0.5 + 0.5*flandom(), 0.75 + 0.5*flandom(),
		0, 0, 0, fast_random(0xC0), 1);
	modpv (mamm_base, -1, -1, 2*flandom(), 2*flandom(), 2*flandom(), 45 - 90 * flandom(), 0, 0, mamm_ears);
	//loadpv (mamm_result, mammal_ncc, 1, 1, 1, 0, 0, 0, 0x80, 1);
	//loadpv (generic_result, mammal_ncc, 1, 1, 1, 0, 0, 0, 0x80, 1);
	workpv (generic_result, mamm_base);
	
	//

	// uccelli:
	loadpv (bird_base, birdy_ncc,
		1, 0.3 + flandom(), 0.75 + flandom(),
		0, 0, 0, fast_random(0xC0), 1);
	//loadpv (bird_result, birdy_ncc, 1, 1, 1, 0, 0, 0, 0x80, 1);
	
	
	loadpvs(bull_base, bull_ncc,
		1, 0.5 + 0.5*flandom(), 0.75 + 0.5*flandom(),
		0, 0, 0, fast_random(0xC0), 1);
	//loadpvs(bull_result, bull_ncc, 1, 1, 1, 0, 0, 0, 0x80, 1);
	modpv(bull_base, -1, -1, 1, 1, 1, -90, 0, 0, NULL);
	modpv(bull_base, -1, -1, 1, 1, 1, 0, 90, 0, NULL);
	
	//DebugPrintf(1, "pv space used: %li.", (long)pvfile_datatop);	//11492
}

/* Questa funzione aggiorna sp_x;y;z in modo da tener conto della distanza
   dalla superficie (il parametro height) e dell'orientamento della normale
   alla superficie in quel punto. sp_x;y;z stanno per "stepping pos x;y;z" */

//NOTE: This could maybe read outside p_surfacemap if the player were at the edge of the map (but not just any edge, it'll only do it on two).
//But I've left it alone since the player should never be at the edge of the map.
//(SL)
void add_height (Dword px, Dword pz, float height)
{
	Dword cpos;

	float x[3], y[3], z[3];
	float h1, h2, h3, h4, icx, icz;

	cpos   = m200[pz>>14] + (px>>14);

	h1     = - ((Dword)(p_surfacemap[cpos])     << 11);
	h2     = - ((Dword)(p_surfacemap[cpos+1])   << 11);
	h3     = - ((Dword)(p_surfacemap[cpos+201]) << 11);
	h4     = - ((Dword)(p_surfacemap[cpos+200]) << 11);

	icx    = px & 16383;
	icz    = pz & 16383;

	if (icx+icz<16384) {
		x[0] = (px>>14) << 14; y[0] = h1; z[0] = (pz>>14) << 14;
		x[1] = ((px>>14) + 1) << 14; y[1] = h2; z[1] = z[0];
		x[2] = x[0]; y[2] = h4; z[2] = ((pz>>14) + 1) << 14;
	}
	else {
		x[0] = ((px>>14) + 1) << 14; y[0] = h2; z[0] = (pz>>14) << 14;
		x[1] = x[0]; y[1] = h3; z[1] = ((pz>>14) + 1) << 14;
		x[2] = (px>>14) << 14; y[2] = h4; z[2] = z[1];
	}

	pnorm (x, y, z);

	sp_x += (pnx * height - sp_x) * 0.25;
	sp_y += (pny * height - sp_y) * 0.25;
	sp_z += (pnz * height - sp_z) * 0.25;
}

/* Ciclo principale nell'esplorazione delle superfici planetarie. */

float tiredness = 0;

char exitflag = 0; // flag: se settato al ritorno di planetary_main,
		   // significa che c'Š stato un quit sulla superficie.
char entryflag = 0;// flag: se settato all'ingresso di planetary_main,
		   // significa che si sta recuperando la situazione
		   // di superficie.
extern void FitOutHudBuffer(Word min, Word max);
   /* extern Word ismtn, hcat, hcatr, maxalt;  // (by Ees33)
        extern FILE *fd;*/
void planetary_main ()
{
	fcs_status_delay=0;
	hopfind=0; hideplants=0;
	Word returnToStart = 0;
	/*global*/opencapcount= 1;
	Word	 opencapdelta = 0;
	Word	 openhudcount = 180;
	Word	 openhuddelta = 0;
	char	 hud_closed   = 1;
	landed    	   = 0;
	lifter_homing = 0;
	lifter_vertical = -1;	//landing=-1, hovering=0, leaving=1
	fixed_step=0;
	float    backup_dzat_x = dzat_x; dzat_x = 0;
	float    backup_dzat_y = dzat_y; dzat_y = 0;
	float    backup_dzat_z = dzat_z; dzat_z = 0;
	char     bfa	    = 0;
	bfa                = field_amplificator;
	field_amplificator = 0;
	float gravity;
	// backup colori di ritorno.
	memcpy (return_palette, tmppal, 768);
	gravity = nearstar_p_ray[ip_targetted];
	planet_grav = gravity * 2000;
	pp_gravity = gravity * 38.26;
	gravity *= 1E4;
	char nofog = 0;

	char binstat = 0;
	char nobrighten;
	char advstat = 0;
	char moviestat = 0;
	Word earthtime = 0;
	char mooses;
	char portablegoes = 0;
	char portablegoesbgr = 1;
	//char pgoestypestr[77] = "PORTABLEGOES - TAB TO MAKE BACKGROUND TRANSPARANT, TYPE TO SET COMMAND";
	char goesnetCommandWasBlank = 0;
	if (strlen(goesnet_command)==0) {
		sprintf(goesnet_command, "PORTABLEGOES - TAB TO MAKE BACKGROUND TRANSPARANT, TYPE TO SET COMMAND");
		goesnetCommandWasBlank = 1;
		gnc_pos = 0;
	}
	char helpison = 0;
	int helppage = 0;
	char *filetouse;
//	pgoestypestr[0]=NULL;
	extern char force_update;
	extern int active_screen;
	int moosepage;
	#if defined(ALL) || !defined(FLYING_LANDER)
	Word	bounces = 0;
	#endif
	char about = 0;
	char     flash      = 1;
	char     flashes    = 0;
	char     flashed    = 0;
	char     recover    = 0;
	char     atmosphere = 1;

	int moviedelay;
	int moviefsec = 1;
	extern int movieexists;
	extern char movie;
	extern int movienr;
	extern char movieflashoff;
	extern int moviefscap;
	extern int moviestime;
	extern int moviedeck;
	
	char	 widesnapping = 0, snapping=0;
	Word 	 w, lw = 10, now = 25, waveratio = 5, waveblur = 0;
	Word      flick, flicks, fshift;
	float	 upanddown = 0, waving_y = 0, dfc = 0; //, maxdfc;
	Word	resolve;
	double lsecs;
	
	float    crcy, temp;
	#define formalheight 1000
	float formalappr = 0;
	float formalbob = 0;
	int formalapprst;
	float	 backup_cam_x, backup_cam_y, backup_cam_z;
	float	 backup__alfa, backup__beta;
	float 	 drop_x, drop_y, drop_z;
	float	 pos_x0, pos_z0, bkshift, bkstep, directional_beta;
	
	float 	 x[4] = { +2e6, +2e6, -2e6, -2e6 };
	float 	 y[4] = { +4e5, +4e5, +4e5, +4e5 };
	float 	 z[4] = { +2e6, -2e6, -2e6, +2e6 };

	float 	 xx[4], yy[4], zz[4];
	float    wx[25], wy[25], wz[25], wr[25], wh[25], wl[25], wd[25];
	Uword fallingdmgcolor = 0;
	
	Word colorMix = -1;
	//If we transition to another sector, we'll jump back to 'begin'. (SL)
	begin:
	char landerStuck = 0;

	fast_srand(CLOCK());
	
	lsecs=secs+fast_random(63)+20;	//Don't change that from 63, except to (2^N)-1 where N is any integer>=1. (SL)

	if (returnToStart!=2) {
		recover = 0;
		resolve = 1;
		#if defined(ALL) || !defined(FLYING_LANDER)
		bounces=0;
		#endif
		lw=10; now=25; waveratio=5; waveblur=0;
		upanddown=0; waving_y=0; dfc=0;
		flash=1; flashes=0; flashed=0;
		dlt_alfa = 0; dlt_beta = 0;
		fallingdmgcolor = 0;
	}
	
	crcy = hpoint (pos_x, pos_z) - formalappr - ((sin(formalbob) + 1) * 10); //higher

	dzat_x = 0; dzat_y = 0; dzat_z = 0;
	planet_xyz (ip_targetted);
	dzat_x = plx;
	dzat_y = ply;
	dzat_z = plz;
	// calcolo della distanza dalla stella primaria
	double dxx = dzat_x - nearstar_x;
	double dyy = dzat_y - nearstar_y;
	double dzz = dzat_z - nearstar_z;
	dsd = SQRT (dxx*dxx + dyy*dyy + dzz*dzz) + 1;
	dsdSq = dsd*dsd;
	const int widesnappingangle = 71;
	dzat_x = 0; dzat_y = 0; dzat_z = 0;
	
	Uword pqw = QUADWORDS;
	Dword  	 cpos;

	
	char	 secondarysun = 0;
	//char 	 orbitingplanet = 0;	//Not used right now (SL)
	Word  	 ts, te, ll, plwp;
	Word  	 te_ll_distance, te_ll_distance_1, te_ll_distance_2;
	Word  	 ts_ll_distance, ts_ll_distance_1, ts_ll_distance_2;

	float	 secondary_nearstar_x;
	float	 secondary_nearstar_z;
	float	 pri_to_sec_distance, compdist;

	// Questo pezzo controlla se c'Š una stella molto vicina a parte
	// la primaria (in sistemi multipli). La pi— vicina delle compagne
	// viene mostrata anche sulla superficie. E' chiamata qui il
	// "sole secondario".

	dsd1 = dsd;
	nray1 = nearstar_ray;

	compdist = 1E9;
	w = 0; while (w < nearstar_nop) {
		if (nearstar_p_type[w] == 10) {
		if (nearstar_p_qsortdist[w] < compdist) {
			compdist = nearstar_p_qsortdist[w];
			dsd2 = nearstar_p_qsortdist[w];
			nray2 = nearstar_p_ray[w];
			planet_xyz (w);
			secondary_nearstar_x = plx;
			secondary_nearstar_z = plz;
			pri_to_sec_distance  = (nearstar_x - plx) * (nearstar_x - plx);
			pri_to_sec_distance += (nearstar_y - ply) * (nearstar_y - ply);
			pri_to_sec_distance += (nearstar_z - plz) * (nearstar_z - plz);
			pri_to_sec_distance  = SQRT (pri_to_sec_distance);
			pri_latitude = (nearstar_y - ply) / pri_to_sec_distance;
			pri_latitude = atan (pri_latitude) / deg;
			secondarysun = 1;
		}}
		w++;
	}

	// Se invece si tratta di un pianeta che gira attorno ad una
	// delle stelle compagne della primaria, il sole secondario
	// diventa il primario, dato che i fattori di esposizione
	// (crepzone e nightzone) erano gi… stati calcolati per la
	// stella compagna cui il pianeta appartiene, per via dei
	// controlli svolti dalla f. "cplx_planet_viewpoint".

	if (nearstar_p_owner[ip_targetted] != -1 &&
	    nearstar_p_type[nearstar_p_owner[ip_targetted]] == 10) {
		dsd1 = nearstar_p_qsortdist[nearstar_p_owner[ip_targetted]];
		nray1 = nearstar_p_ray[nearstar_p_owner[ip_targetted]];
		dsd2 = dsd;
		nray2 = nearstar_ray;
		secondary_nearstar_x = nearstar_x;
		secondary_nearstar_z = nearstar_z;
		planet_xyz (nearstar_p_owner[ip_targetted]);
		pri_to_sec_distance  = (nearstar_x - plx) * (nearstar_x - plx);
		pri_to_sec_distance += (nearstar_y - ply) * (nearstar_y - ply);
		pri_to_sec_distance += (nearstar_z - plz) * (nearstar_z - plz);
		pri_to_sec_distance  = SQRT (pri_to_sec_distance);
		pri_latitude = (ply - nearstar_y) / pri_to_sec_distance;
		pri_latitude = atan (pri_latitude) / deg;
		secondarysun = 1;
	}
	
	
	
/* operazioni preliminari generali. */

	if (returnToStart==0) {
		// Dissolvenza al nero (blank frame).
		for (w=64; w>=0; w-=4) {
			tavola_colori (return_palette, 0, 256, w, w, w);
			//nobrighten = 1;
			ll = CLOCK(); while (ll == CLOCK()) {}
		}
	}
	
	// regolazione della forza di gravit….
	
	// inizializzazione coordinate di stepping.
	if (returnToStart!=2) {
		sp_x = 0;
		sp_y = 0;
		sp_z = 0;
	}
	
	
	if (returnToStart!=2) {
		// inizializzazione dati per le onde.
		w = now;
		while (w) {
			w--;
			wy[w] = 50;
			wx[w] = 1E6 + RANDOM (30000) - RANDOM (30000);
			wz[w] = 1E6 + RANDOM (30000) - RANDOM (30000);
			wr[w] = 25E5 - (float) RANDOM (2500) * 1000;
			wd[w] = - RANDOM (500) - 500;
			wl[w] = RANDOM (5000) + 1000;
			wh[w] = RANDOM (1500);
			if (wh[w]<0) wh[w] = RANDOM (100);
		}
		w = 10; while (w<now) { wr[w] = 0; w++; }
		// preparazione di alcune variabili di controllo.
		flashed            = 0;
	}
	
	// "latitude" andr… da 0 a 90.
	// il range di "landing_pt_lat" va da -60 a +60.
	// quindi moltiplicando il valore assoluto per 1.5 si ottiene
	// un range da 0 a 90 gradi. 0 Š l'equatore, 90 sono i poli.
	
	//"landing_pt_lat" actually ranges from 1-119, subtracting 60 from it gives -59 - 59, so latitude ranges from 0-88.5, not 90. (SL)
	latitude  	   = (float)(abs (landing_pt_lat - 60)) * 1.5;

	//This would give 0-90: (SL)
	//latitude  	   = (float)(abs (landing_pt_lat - 60)) * (90/59);
	
	// "exposure" segnala l'esposizione alla stella che fa da sole.
	// la variabile "crepzone" ha un range di variabilit… che,
	// nell'area diurna, abbraccia 230 gradi in longitudine, dato che
	// i due terminatori sono calcolati a partire da +35 e +165 gradi
	// dal punto che rappresenta il punto al bordo destro del disco
	// planetario visto dalla stella. Il range di 230 gradi Š per•
	// normalizzato in modo da far coincidere i terminatori con zero
	// e il sole a perpendicolo con la sua met…, quindi con 115 gradi.
	// Normalmente il range diurno come quello notturno dovrebbero
	// occupare entrambi 180 gradi. Per•, per via delle funzioni che
	// tracciano i globi e delle loro estreme ottimizzazioni, il range
	// notturno Š stato rimpicciolito perch‚ i terminatori coincidano
	// effettivamente con i bordi del disco planetario quando lo si
	// osserva "in controluce" stagliantesi contro la sua stella.
	// Il trucco in genere non si nota; si ha l'effettiva impressione
	// che l'area diurna copra un'area considerevolmente maggiore, ma
	// dato che i terminatori coincidono sembra tutto regolare...
	// d'altronde, le sfere non posso tracciarle che cosŤ, se voglio
	// abbastanza velocit….
	// "exposure" viene normalizzato per l'area diurna fra 0 e 90 gradi,
	// e in pratica rappresenta la declinazione del sole locale: zero
	// significa che il sole Š all'orizzonte.
	exposure	   = (float)(crepzone) * 0.7826; // 90/115

	// "sun_x_factor" prende il valore -1 quando il sole Š verso il lato
	// ovest (tramonto), altrimenti prende il valore +1. Per calcolare
	// le tre coordinate del sole si parte dalle coordinate come
	// sarebbero se entrambi gli angoli (latitude ed exposure) fossero
	// pari a zero, poi si ruota il tutto. Se gli angoli fossero zero,
	// allora sarebbe x = -d; y = 0; z = 0. Dove "d" = distanza del sole.
	// Le formule di rotazione a questo punto diventano:
	//	rx = -d * cos(beta);
	//	ry = -d * sin(beta) * sin(alfa);
	//	rz = d * sin(beta) * cos(alfa);
	// dove la "x" di partenza Š la distanza del sole,
	// "alfa" Š la latitudine e "beta" l'angolo d'incidenza
	// orizzontale altrimenti chiamato "exposure".
	// Infine bisogna tener conto della direzione da cui viene
	// la luce del sole (verso l'alba/verso il tramonto), che non
	// viene considerata da "exposure" ("exposure" non ha segno).
	// Per questo c'Š la variabile "sun_x_factor".
	// Il tutto viene implementato come:
	alfa = deg * (90 - latitude);
	beta = deg * exposure;
	sun_x = -dsd1 * cos(beta) * sun_x_factor;
	sun_y = -dsd1 * sin(beta) * sin(alfa);
	sun_z = +dsd1 * sin(beta) * cos(alfa);

//	z2 = z * cos(beta) - x * sin(beta);
//	rz = z2 * cos(alfa) + y * sin(alfa);
//	rx = x * cos(beta) + z * sin(beta);
//	ry = y * cos(alfa) - z2 * sin(alfa);

//	rz = (z * cos(beta) - x * sin(beta)) * cos(alfa) + y * sin(alfa);
//	rx = x * cos(beta) + z * sin(beta);
//	ry = y * cos(alfa) - (z * cos(beta) - x * sin(beta)) * sin(alfa);

//	rx = x * cos(beta);
//	ry = x * sin(beta) * sin(alfa);
//	rz = -x * sin(beta) * cos(alfa);

	// Ora, eventualmente, si proietta il sole primario.
	// Succede quando ci si trova attorno ad una stella secondaria
	// di un sistema multiplo (classe 8). Vanno ripetuti tutti i
	// calcoli, compresi quelli svolti dalla f. "planets", purtroppo.
	if (!secondarysun) goto nosecondarysun;
	//
	pri_nightzone = 0;
	//
	planet_xyz (ip_targetted);
	plwp = 89 - planet_viewpoint (secondary_nearstar_x, secondary_nearstar_z);
	plwp += nearstar_p_rotation[ip_targetted];
	plwp %= 360; if (plwp < 0) plwp += 360;
	//
	ts = plwp + 350; if (ts >= 360) ts -= 360;
	te = ts + 130; if (te >= 360) te -= 360;
	ll = landing_pt_lon;
	//
	if (ts > te) {
		if (ll >= ts
			|| ll < te)
				pri_nightzone = 1;
	}
	else {
		if (ll >= ts
			&& ll < te)
				pri_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) {
		pri_sun_x_factor = +1;
		pri_crepzone = ts_ll_distance;
	}
	else {
		pri_sun_x_factor = -1;
		pri_crepzone = te_ll_distance;
	}	
	// E con questo si sono finiti i calcoli fatti normalmente dalla
	// funzione "planets". Per• resta da ripetere i calcoli di prima,
	// su altre variabili col prefisso "pri_".
	// Oh, naturalmente bisogna usare "dsd2" al posto di "dsd1".
	pri_exposure = (float)(pri_crepzone) * 0.7826; // 90/115
	alfa = deg * (90 - latitude + pri_latitude);
	beta = deg * pri_exposure;
	pri_x = -dsd2 * cos(beta) * pri_sun_x_factor;
	pri_y = -dsd2 * sin(beta) * sin(alfa);
	pri_z = +dsd2 * sin(beta) * cos(alfa);
	nosecondarysun:

	// regolazione della direzione del vento.
	wdir = flandom() * 2 * M_PI;

	// regolazione dell'intensit… del vento.
	iwp = flandom () * 0.5 - flandom() * 0.5;
	rwp = flandom () * 50 - flandom() * 50;

	
	/* selezione della tabella pseudo valida per tutto il pianeta
   (cambia solo con la latitudine, ma Š previsto che sia cosŤ, dato
   che bisogna differenziare gli ambienti caldi da quelli freddi). */
	
	
	//Moved this before 'operazioni preliminari per...' since we now need global_surface_seed in that. (SL)
	global_surface_seed = (nearstar_p_ray[ip_targetted]
			      + nearstar_p_orb_ray[ip_targetted]
			      + nearstar_p_orb_orient[ip_targetted]) * 4112;	//I wonder what the 4112 is for (SL)
	global_surface_seed_raw = global_surface_seed;
	
	if (nearstar_p_type[ip_targetted] == 3) {
		SRAND (global_surface_seed + landing_pt_lon);
		if (latitude > 25 + (global_surface_seed % 15) + RANDOM(5))
			global_surface_seed++;
	}
	
	local_surface_seed = (MixSeeds(global_surface_seed, landing_pt_lon, landing_pt_lat));
	
	//Also tried this: local_surface_seed = 1812433253UL*(global_surface_seed*42840 + (119*landing_pt_lon + (landing_pt_lat-1)));	//This should prevent duplication of sectors. (SL)
	//Ranges: lon = 0 to 359, lat = 1 to 119, and 360*119 = 42840 (SL)
	
	
	/* operazioni preliminari per ogni tipo di pianeta. */

	switch (nearstar_p_type[ip_targetted]) {
                case 0: atmosphere = 1;
                        sky_brightness = 62;
		case 1: sky_brightness = 0;
			atmosphere = 0;
			break;
		case 2: sky_brightness = 63 - nightzone * 31;
			break;
		case 3:	// attribuzione pseudo-casuale degli scenari
			// per le caratteristiche generali del pianeta...
			//Now uses a better seed (SL)
			sctype = GetTerrainType(raw_albedo, ip_targetted, NULL, landing_pt_lat, landing_pt_lon, 0);
			// correzioni casuali guidate all'umidit… del cielo
			// (specie in caso di deserti e ghiacciai, dove
			// praticamente non pu• piovere)
			fast_srand (local_surface_seed);
			SRAND (local_surface_seed);
	
			switch (sctype) {
				case FOREST:	rainy *= fast_flandom()*2 + 1;
						break;
				case SHRUBLAND:	rainy /= fast_flandom()*2 + 1;
						break;
				case DESERT:	rainy /= fast_flandom()*4 + 2;
						break;
				case ICY:	rainy /= fast_flandom()*3 + 2;
						break;
			}
			if (rainy < 0) rainy = 0;
			if (rainy > 5) rainy = 5;
			break;
		case 4: sky_brightness = 0;
			atmosphere = 0;
			break;
		case 7: sky_brightness = 0;
			atmosphere = 0;
			break;
	}

/* generazione del cielo (in sfondo). */
	
	if (returnToStart==2) {
                if (!supvision && !showmapz) {
	        	memcpy(old_surface_palette, surface_palette, 768);
		        tavola_colori_brightness (old_surface_palette, 0, 256,
			   63, 63, 63, brightencnt);
                }
		resolve=67;
		colorMix=0;
		nobrighten=1;
	} else {
		colorMix=-1;
	}

	_fmemset (s_background, sky_brightness, st_bytes);
	create_sky (atmosphere);

	vptr = 0;
	for (cpos=0; cpos<bk_lines_to_horizon; cpos++) {
		for (mpul=0; mpul<360; mpul++) {
			crcy = (float) s_background[vptr] * cpos;
			crcy /= bk_lines_to_horizon;
			if (nightzone)
				s_background[vptr] = crcy / 2;
			else
				s_background[vptr] = crcy;
			vptr++;
		}
	}
	BUFFERCHECK
	
	SRAND (global_surface_seed_raw);
	fast_srand (global_surface_seed_raw);
	ape_probability = 0; //(RANDOM(6)+RANDOM(6)+modRandom(6)+modRandom(6)+modRandom(6));
	for (Word a=0; a<8; a++) {
		ape_probability+=fast_random(1023)+1;
	}
	ape_probability-=4192;
	if (ape_probability>0) {
		ape_probability/=364;
		//ape_probability/=745;
		if (ape_probability>20) ape_probability=20;
	} else {
		ape_probability=0;
	}
	if (ape_probability>0) {
		switch (sctype) {
			case OCEAN:
				ape_probability-=3;
				break;
			case PLAINS:
				ape_probability-=1;
				break;
			case SHRUBLAND:
				ape_probability-=2;
				break;
			case DESERT:
				ape_probability-=4;
				break;
			case ICY:
				ape_probability-=4;
				break;
		}
	}
	if (ape_probability<0) ape_probability=0;
	Dword pBullProb = 0;
	for (Word b=0; b<8; b++) {
		pBullProb+=fast_random(1023)+1;
	}
	pBullAngle=1;
	if (pBullProb<2048) {
		pBullType=BULL_SPINNER;
		//status("SPINNER", 50);
	} else if (pBullProb<4096) {
		pBullType=BULL_RUNNER;
		//status("RUNNER", 50);
	} else if (pBullProb<6144) {
		pBullType=BULL_JUMPER;
		pBullAngle=((double)pBullProb-4096.0)/2048.0;
		//status("JUMPER", 50);
		//sprintf(fcs_status_extended, "JUMPER %0.6f", pBullAngle);
	} else {
		pBullType=BULL_SOMERSAULTER;
		//status("SOMERSAULTER", 50);
	}
	
	/* generazione superficie. */
	build_surface ();
	if (returnToStart!=2) {
		/* generazione animali e altre forme di vita indigene, qualora presenti. */
		setup_animals ();
	}
	
	/* inizio del ciclo d'esplorazione. */
	FILEPTR ih;
	FILEPTR oh;
	FILEPTR	i9997;
	FILEPTR i9998;
	FILEPTR i9999;
	char	t[54];

	Dword prog;
	Dword	line;

	exitflag = 0;
	//DebugPrintf(0, "Here.");
		
	if (entryflag) {
		sfh = OPENFILE (surface_file, OPEN_RB);
		if (sfh != NOFILE) {
			//DebugPrintf(0, "Loading file.");
			READFILE (sfh, &landing_pt_lon, 2);
			READFILE (sfh, &landing_pt_lat, 2);
			READFILE (sfh, &atl_x, 4);
			READFILE (sfh, &atl_z, 4);
			//atl_x = 1638400>>14; atl_z = 1638400>>14;
			READFILE (sfh, &atl_x2, 4);
			READFILE (sfh, &atl_z2, 4);
			READFILE (sfh, &pos_x, 4);
			READFILE (sfh, &pos_y, 4);
			READFILE (sfh, &pos_z, 4);
			READFILE (sfh, &user_alfa, 4);
			READFILE (sfh, &user_beta, 4);
			READFILE (sfh, &openhuddelta, 2);
			READFILE (sfh, &openhudcount, 2);
			READFILE (sfh, &hud_closed, 1);
			//DebugPrintf(0, "landing_pt_lon=%i landing_pt_lat=%i atl_x=%lli atl_z=%lli atl_x2=%lli atl_z2=%lli pos_x=%f pos_y=%f pos_z=%f user_alfa=%f user_beta=%f openhuddelta=%i openhudcount=%i hud_closed=%i", landing_pt_lon, landing_pt_lat, atl_x, atl_z, atl_x2, atl_z2, pos_x, pos_y, pos_z, user_alfa, user_beta, openhuddelta, openhudcount, (int)hud_closed);
			atl_y   = hpoint ((atl_x << 14) + atl_x2, (atl_z << 14) + atl_z2);
			CLOSEFILE (sfh);
			landed = 1;
			lifter_homing=0;
			lifter_vertical=-1;
			opencapdelta = 0;
			opencapcount = 0;
			liftx=float(((atl_x << 14) + atl_x2));
			liftz=float(((atl_z << 14) + atl_z2));
		} else {
			//DebugPrintf(0, "NSF");
			goto nosurfacefile;
		}
	} else {
	    nosurfacefile:
		//DebugPrintf(0, "Foom.");
			
		if (returnToStart==0) {
			pos_x = 1638400; pos_z = 1638400;
			pos_y = hpoint (pos_x, pos_z) - 3.2E5;
			opencapdelta=-1;
		} else if (returnToStart==1) {
			pos_y = hpoint (pos_x, pos_z);
			if (!landed) {
				pos_y -= 30000;
			}
			atl_y   = hpoint ((atl_x << 14) + atl_x2, (atl_z << 14) + atl_z2);
		}
		if (returnToStart!=2) {
			shift = 0; step = 0;
			directional_beta = user_beta;
		}
	}
	returnToStart=0;
	SRAND (CLOCK());
	BUFFERCHECK
	
	
	do {
		// inizio sincronizzazione e risolvenza dal "blank frame".
		if (ip_targetted==-1) {
			status("LOST PLANET LOCK!", 500);
			returnToStart=0;
			break;
		}
		sync_start ();
		getsecs ();
		fast_srand (secs/2);
		if (colorMix>-1) {
			//Right now color-mixing takes precedence over fading.
			colorMix=MixColors(old_surface_palette, surface_palette, 0, 256, colorMix, brightencnt);
			if (colorMix!=-1) nobrighten = 1;
		} else if (resolve <= 63) {
			tavola_colori_brightness (surface_palette, 0, 256,
			       resolve, resolve, resolve, brightencnt);
			resolve += 4;
			nobrighten = 1;
		} else if (resolve!=67) {	//force palette to normal setting even if somehow it doesn't get there on its own
			tavola_colori_brightness (surface_palette, 0, 256,
				       63, 63, 63, brightencnt);
			resolve=67;
			nobrighten=1;
		}
		// calcolo delle costanti trigonometriche degli effetti vento
		wdirsin = 10 * sin (wdir) * wp;
		wdircos = 10 * cos (wdir) * wp;
		// riduzione stanchezza (semprech‚ si stia fermi)
		tiredness *= 0.9977;
		pp_pulse = (1 + tiredness) * 118;
		pp_pulse += fast_flandom () * 8;
		pp_pulse -= fast_flandom () * 8;
		// variazioni atmosferiche (se c'Š, l'atmosfera)
		if (atmosphere) {
			pp_pressure = base_pp_pressure;
			//if (landed) {
			//	pp_pressure += pos_y * 0.000001;
			//}
			pp_pressure *= 1 + fast_flandom () * 0.005;
			pp_pressure /= 1 + fast_flandom () * 0.005;
			
  			//Below, the pressure now goes as an exponential, which
			//should be more realistic than the linear relationship:
			//P = P0 * exp (-g * h / H)
			//where P0 is the pressure at sea level, g is the gravitational
			//acceleration, h is the height, and H is the scale height.
			//pos_y is like height, but increases as you go down.
			//Given the references to posy += gravity, I'm guessing gravity
			//is g.
	  		//Before, this line was above the previous two lines.
			//However, those two lines introduce slight random
			//fluctuations.  There is a chance that those fluctuations
			//would be larger than the pressure, leading to negative
			//pressures.  Now, the fluctuations are factored in before
			//the height is included.
			//Before, the pressure would reach zero from 1 atm when
			//pos_y = -1000000.  That will now be the scale height, though
			//in reality, you'd have to factor in the composition of
			//the atmosphere and other things.  For comparison, Earth's
			//scale height is 7.4 km.
			//(Those comments, and the pp_pressure*= line below were by 'The reflection')
			if (landed) {
				pp_pressure *= exp (pos_y * planet_grav / 100000000);
			}
			
			pp_temp = base_pp_temp+273.15;
			pp_temp += pos_y * 0.000025;
			pp_temp *= 1 + fast_flandom () * 0.005;
			pp_temp /= 1 + fast_flandom () * 0.005;
			pp_temp-=273.15;	//change it back to celsius
			if (pp_temp < -269)
				pp_temp = -269 + 4 * fast_flandom();
		
		}
		// avanzamento fisso (tasti da 0 a 9)
		step += fixed_step;
		// reazione ai movimenti del mouse.
		
		bkshift = shift;
		bkstep = step;
		mpul = 0;
		mouse_input ();
		int ml = (option_mouseLook>0)?2:0;
		FastBool mlook = (mpul&2) ^ (ml);
		if (mpul&2) {
			shift += mdltx;
		} else {
			dlt_beta -= (float) mdltx / 6;
		}
		
		//(1 and 0) or (0 and 1)
		if (mlook) {
			if (option_mouseLook==1) {
				dlt_alfa += (float) mdlty / 8;
			} else {
				dlt_alfa -= (float) mdlty / 8;
			}
		} 
		if (pos_y == 0) {
			if (nearstar_p_type[ip_targetted] == 3) {
				if (sctype == ICY) {
					if (mpul&1) step += 150 * landed;
					if (!mlook) step -= 10 * mdlty * landed;
				}
				else {
					if (sctype == PLAINS) {
						if (mpul&1) step += 75 * landed;
						if (!mlook) step -= 5 * mdlty * landed;
					}
					else {
						if (mpul&1) step += 50 * landed;
						if (!mlook) step -= 2 * mdlty * landed;
					}
				}
			#if defined(ALL) || defined(TEMPERATURE)
			} else if (glassified) {
				if (mpul&1) step += 150 * landed;
				if (!mlook) step -= 10 * mdlty * landed;
			#endif
			} else {
				if (mpul&1) step += 125 * landed;
				if (!mlook) step -= 5 * mdlty * landed;
			}
		}
		else {
			if (mpul&1) step += 75 * landed;
			if (!mlook) step -= 5 * mdlty * landed;
		}
		tiredness += fabs(step) * 0.000001;
		
		// causa una scivolata su pareti ripide discese rapidamente,
		// mentre in circostanze normali aggiorna la direzione di
		// avanzamento (che pu• non coincidere con quella in cui si
		// guarda, appunto durante le scivolate o per brevi voli su
		// pianeti con scarsa gravit…).
		if (pos_y < crcy && (!option_flying_lander || landed) && !jetpack) { //added if jetpack is OFF (MEGA)
			shift = bkshift;
			step = bkstep;
		}
		else
			directional_beta = user_beta;
		// nella capsula non pu• muoversi autonomamente.
		if (opencapdelta>0 && (recover==1 || !option_flying_lander)) {
			shift = 0;
			step = 0;
		}
		// normalizzazione degli angoli visuali.
		user_alfa += dlt_alfa;
		dlt_alfa /= 1.5; if (fabs(dlt_alfa)<0.25) dlt_alfa = 0;
		if (user_alfa<-54.3) {
			user_alfa = -54.3;
			dlt_alfa = 0;
		}
		if (user_alfa>+52.9) {
			user_alfa = +52.9;
			dlt_alfa = 0;
		}
		user_beta += dlt_beta;
		dlt_beta /= 1.5; if (fabs(dlt_beta)<0.25) dlt_beta = 0;
		if (widesnapping == 1) user_beta += widesnappingangle;
		if (widesnapping == 2) user_beta -= 2 * widesnappingangle;
		while (user_beta>180) user_beta -= 360;
		while (user_beta<-180) user_beta += 360;
		// moto proprio del player.
		refx = pos_x; refz = pos_z;
		// moto trasversale.
		if (slide!=0) {
			alfa = 0; beta = directional_beta - 90; change_angle_of_view (); p_Forward (slide);
			
		}
		alfa = 0; beta = directional_beta - 90; change_angle_of_view (); p_Forward (shift);
		// moto diretto.
		alfa = 0; beta = directional_beta; change_angle_of_view (); p_Forward (step);
		// attrito.
		if (pos_y >= crcy) {
			shift /= 1.5; if (fabs(shift)<0.5) shift = 0;
			step /= 1.25; if (fabs(step)<0.5) step = 0;
		#if defined(ALL) || defined(FLYING_LANDER)
		} else if (option_flying_lander) {
			shift /= 1.5; if (fabs(shift)<0.5) shift = 0;
			step *= .99; if (fabs(step)<0.5) step = 0;
		#endif
		}
		// resistenza in salita.

		if (landed && !jumping) { //I added !jumping. That fixes the "jumping slowdown on steep slopes" bug. (MEGA)
			drop_x  = pp_gravity * 0.012;
			drop_x *= hpoint (refx, refz) - hpoint (pos_x, pos_z);
			drop_x -= 2.4;
		} else {
			drop_x=0;
		}
		if (drop_x > 0) {
			if (drop_x > 1)
				drop_x = 1;
			else
				drop_x *= drop_x;
			shift *= 1 - drop_x;
			step *= 1 - drop_x;
			pos_x = refx;
			pos_z = refz;
			alfa = 0; beta = directional_beta - 90; change_angle_of_view (); p_Forward (shift);
			alfa = 0; beta = directional_beta; change_angle_of_view (); p_Forward (step);
		}
		if (pos_y > crcy - 1200)
			user_alfa /= 1 + fabs(step) * 0.000064;
		
		// normalizzazione area di movimento.
		drop_x = pos_x - 1.6384E6;
		drop_z = pos_z - 1.6384E6;
		//Making it square to make it easier to make transitions (SL)
		//Also, lander can now travel to the edge (instead of only halfway) (SL)
		Word xchange=0;
		Word zchange=0;
		if (drop_x>1.3E6) xchange=1;	//east edge
		if (drop_x<-1.3E6) xchange=-1;	//west edge
		if (drop_z>1.3E6) zchange=1;	//south edge
		if (drop_z<-1.3E6) zchange=-1;	//north edge
		if (xchange!=0 || zchange!=0) {
			landing_pt_lat+=zchange;
			landing_pt_lon+=xchange;
			if (landing_pt_lat > 119 || landing_pt_lat < 1) {
				landing_pt_lat -= zchange;
				landing_pt_lon += 180;	//move us to the other side of the globe
				//Change these so that the rest of the algorithm will act as though we were moving from one tile north of where we are.
				zchange = -zchange;
				drop_z=-drop_z;
				pos_z = 1.6384E6 + drop_z;
				//Turn the user to face in the opposite direction.
				user_beta += 180;
				if (user_beta > 180) user_beta-=360;
			}
			if (landing_pt_lon >= 360) landing_pt_lon -= 360;
			if (landing_pt_lon < 0) landing_pt_lon += 360;
			double newx = pos_x - xchange*2.6E6;
			double newz = pos_z - zchange*2.6E6;
			if (zchange!=0) {
				pos_z = 1.6384E6 - drop_z*.98;		// - drop_z*.9;
				newz = 1.6384E6 - drop_z*1.0;
			}
			if (xchange!=0) {
				pos_x = 1.6384E6 - drop_x*.98;			// - drop_x*.9;
				newx = 1.6384E6 - drop_x*1.0;
			}
			double diffx = pos_x-newx;
			double diffz = pos_z-newz;
			newx-=diffx*5;
			newz-=diffz*5;
			//newx-=xchange*2.6E6;
			//newz-=zchange*2.6E6;
			atl_x = ((long) newx) >> 14;
			atl_z = ((long) newz) >> 14;
			atl_x2 = (long) (((long) newx) - (atl_x<<14));
			atl_z2 = (long) (((long) newz) - (atl_z<<14));
			if (landed) {
				lifter_homing=1;
			}
			//change lon/lat
			//move player
			//move lifter
			//(lifter_vertical)
			returnToStart=1;
			entryflag=0;
			break;
		}
		/*
		drop_y = SQRT(drop_x*drop_x + drop_z*drop_z);
		if (landed)
			maxdfc = 1.5000E6;
		else
			maxdfc = 0.7500E6;
		if (drop_y > maxdfc) {
			drop_y -= maxdfc;
			drop_y *= 0.000001;
			drop_y  = 1 - drop_y;
			drop_x *= drop_y;
			drop_z *= drop_y;
			pos_x   = drop_x + 1.6384E6;
			pos_z   = drop_z + 1.6384E6;
		}*/
		// visualizzazione fulmini (ove presenti).
		// lightning
		if (flashed) {
			tavola_colori_brightness (surface_palette, 0, 256, 63, 63 - fallingdmgcolor, 63 - fallingdmgcolor, brightencnt); // we don't want the thing to turn white again when you're hurt!
			flashed = 0;
		}
		if (!flash) {
			flashes++; if (flashes>30) flashes = 30;
			ptr = 40000;
			while (ptr) {
				s_background[ptr] = 63 - s_background[ptr];
				ptr--;
			}
			// (p.s. i fulmini illuminano anche il suolo, un po')
			w = RANDOM (64) + 64;
			if (fallingdmgcolor == 0)
				tavola_colori_brightness (tmppal, 0, 256, w, w, w, brightencnt);
			if (fallingdmgcolor != 0)	// looks like you're hurt! Make the lightning red!
				tavola_colori_brightness (tmppal, 0, 256, w, w - fallingdmgcolor, w - fallingdmgcolor, brightencnt);
			flashed = 1;
		}

		// tracciamento del cielo (che ovviamente Š lo sfondo).
		alfa = user_alfa; beta = user_beta;
		ptr = ((Dword)(5*beta)%5) - 320*((Dword)(4*(alfa+180))%4) - 4;
		ptr -= (Dword)(beta / 72) * 320;
		ptr -= 639;
		background (360*(Dword)(alfa+51)-(Dword)(beta)%360,
			    adapted, s_background, n_offsets_map,
			    om_bytes, ptr);
		BUFFERCHECK
		/*
		BUG:	Ptr is being called with (a?) very high values for 'ptr' (screenshift) which is/are causing a buffer overflow in adapted (the target).
			For now we handle it by not writing to the target buffer if we would be writing out of bounds.
		
		
		void background (Uword start,
		 Uchar maybefar *target,
		 Uchar maybefar *background,
		 Uchar maybefar *offsetsmap,
		 Uword total_map_bytes,
		 Uword screenshift)
		*/
		// backup zone di cielo coperte dai fulmini.
		if (!flash) {
			ptr = 40000;
			while (ptr) {
				s_background[ptr] = 63 - s_background[ptr];
				ptr--;
			}
		}
		// disegna le stelle, se Š il caso di farlo.
		// il punto di vista Š dell'astrozattera,
		// ma gli angoli sono quelli del protagonista.
		if (sky_brightness < 32 && rainy < 2.0) {
			cam_x = backup_dzat_x;
			cam_y = backup_dzat_y;
			cam_z = backup_dzat_z;
			alfa = user_alfa;
			beta = user_beta;
			change_angle_of_view();
			sky (0x003E);
		}
		// tracciamento del "sole" locale.
		// qui il punto di vista Š fittizio:
		// Š l'origine degli assi perch‚ il
		// sole ha delle coordinate proiettate
		// rispetto a molti fattori...
		// e vengono calcolate prima di entrare
		// nel ciclo di esplorazione.
		if (!nightzone && rainy < 2.5) {
			alfa = user_alfa;
			beta = user_beta;
			change_angle_of_view();
			cam_x = 0; cam_y = 0; cam_z = 0;
			if (atmosphere)
				whitesun (adapted, sun_x, sun_y, sun_z,
					  4 * nray1, 0);
			else
				whitesun (adapted, sun_x, sun_y, sun_z,
					  3 * nray1, 0.5);
		}
		if (secondarysun) {
			if (!pri_nightzone && rainy < 2.0) {
				alfa = user_alfa;
				beta = user_beta;
				change_angle_of_view();
				cam_x = 0; cam_y = 0; cam_z = 0;
				if (atmosphere)
					whitesun (adapted, pri_x, pri_y, pri_z,
						  4 * nray2, 0);
				else
					whitesun (adapted, pri_x, pri_y, pri_z,
						  3 * nray2, 0.5);
			}
		}
		// il cielo ha come colore di base 64.
		mask_pixels (adapted+2880, 64);
		// inizializzazione superficie dell'orizzonte.
		QUADWORDS = 256;
		for (ptr = 0; ptr < 32; ptr++)
			pclear (&n_globes_map[ptr<<10], ptr >> 1);
		QUADWORDS = pqw;
		txtr = n_globes_map;
		// tracciamento dell'orizzonte.
		// punto di vista: all'incirca quello dell'utente,
		// ma l'angolo beta (orientamento) viene
		// sempre impostato a zero perch‚ la superficie
		// Š tracciata con una semi-texture e comunque
		// non cambia girandosi attorno: cambia solo se
		// si guarda verso l'alto o verso il basso.
		// inoltre, le coordinate X/Z dell'utente non
		// influiscono sull'aspetto dell'orizzonte,
		// mentre la y Š amplificata per far coincidere
		// l'orizzonte con il bordo del landscape (che
		// in realt… Š pi— vicino perch‚ altrimenti sarebbe
		// problematico disegnare qualcosa di pi— lontano).
		cam_x = 0;
		cam_y = pos_y - 1E4;
		cam_z = 0;
		alfa = user_alfa + 12;
		beta = 0;
		change_angle_of_view ();
		#if defined(ALL) || defined(TEMPERATURE)
		if (glassified) {
			culling_needed = 1;
			if (nightzone) {
				ptr = albedo / 4;
				poly3d (x, y, z, 4, ptr);
			} else {
				ptr = albedo / 2;
				polymap (x, y, z, 4, ptr);
			}
			
			/*if (nightzone)
				poly3d (x, y, z, 4, 128);
			else
				polymap (x, y, z, 4, 144);*/
			// disegna il riflesso della superficie...
			if (!waves_in) {
				backup_cam_x = cam_x;
				backup_cam_y = cam_y;
				backup_cam_z = cam_z;
				backup__alfa = alfa;
				backup__beta = beta;
				from_user ();
				cam_x += sp_x;
				cam_y += sp_y + waving_y;
				cam_z += sp_z;
				mirror = 1;
				halfscan_needed = 1;
				txtr = p_background;
				ipfx = ((long)(cam_x)) >> 14;
				ipfz = ((long)(cam_z)) >> 14;
				iperficie (0);
				txtr = n_globes_map;
				halfscan_needed = 0;
				cam_x = backup_cam_x;
				cam_y = backup_cam_y;
				cam_z = backup_cam_z;
				alfa  = backup__alfa;
				beta  = backup__beta;
				change_angle_of_view ();
			}
			// luccichŤi generici
			// appaiono semisolidificati, sul ghiaccio
			fast_srand ( ((long)(pos_x)>>10) + ((long)(pos_z)>>10) );
			flicks = fabs(wp*50) + 100;
			for (flick = 0; flick < flicks; flick++) {
				int randroll = fast_random(32767);
				if (randroll<gl_bytes) {	//gl_bytes is only 22586, so without this check, Noctis was having a buffer overflow. In the windows version, that caused crashes in icy areas. (SL)
					n_globes_map[randroll] = 16 + fast_random(15);
				}
			}
			// luccichŤi mirati (in riflesso diretto della luce della stella)
			if (!nightzone) {
				fshift = xsun_onscreen - x_centro_f;
				fshift = (float)fshift * -0.34;
				fshift += 90;
				if (fshift>0 && fshift<256) {
					flicks = 250 + fabs(wp*25);
					for (flick = 0; flick < flicks; flick++) {
						ptr = fshift + (fast_random(127) << 8) + fast_random(63);
						if (ptr<gl_bytes) {	//gl_bytes is only 22586, so without this check, Noctis was having a buffer overflow. In the windows version, that caused crashes in icy areas. (SL)
							n_globes_map[ptr] = 16 + fast_random(15);
						}
					}
				}
			}
			setfx (1); // poligoni lucidi
			polymap (x, y, z, 4, 0);
			setfx (0); // poligoni normali
			culling_needed = 0;
		} else 
		#endif
		if (nearstar_p_type[ip_targetted] == 3) {
			// orizzonte per pianeti abitabili.
			if (sctype == PLAINS || sctype == DESERT || sctype==FOREST || sctype==SHRUBLAND) {
				if (sctype == DESERT) {
					// sfondo per deserti.
					if (nightzone)
						polymap (x, y, z, 4, 128);
					else
						polymap (x, y, z, 4, 160);
				} else if (sctype == SHRUBLAND) {
					// sfondo per shrubland.
					if (nightzone)
						polymap (x, y, z, 4, 16);
					else
						polymap (x, y, z, 4, 64);
				}
				else {
					// sfondo per prati.
					if (nightzone)
						polymap (x, y, z, 4, 0);
					else
						polymap (x, y, z, 4, 32);
				}
			} else {
				// mare, per liquido o ghiacciato che sia.
				culling_needed = 1;
				if (nightzone)
					poly3d (x, y, z, 4, 128);
				else
					polymap (x, y, z, 4, 144);
				// disegna il riflesso della superficie...
				if (!waves_in) {
					backup_cam_x = cam_x;
					backup_cam_y = cam_y;
					backup_cam_z = cam_z;
					backup__alfa = alfa;
					backup__beta = beta;
					from_user ();
					cam_x += sp_x;
					cam_y += sp_y + waving_y;
					cam_z += sp_z;
					mirror = 1;
					halfscan_needed = 1;
					txtr = p_background;
					ipfx = ((Dword)(cam_x)) >> 14;
					ipfz = ((Dword)(cam_z)) >> 14;
					iperficie (0);
					txtr = n_globes_map;
					halfscan_needed = 0;
					cam_x = backup_cam_x;
					cam_y = backup_cam_y;
					cam_z = backup_cam_z;
					alfa  = backup__alfa;
					beta  = backup__beta;
					change_angle_of_view ();
				}
				// luccichŤi generici
				if (sctype == ICY) {
					// appaiono semisolidificati, sul ghiaccio
					fast_srand ( ((Dword)(pos_x)>>10) + ((Dword)(pos_z)>>10) );
				}
				else {
					// e molto pi— variabili sull'acqua
					fast_srand (pos_x+pos_z+CLOCK()*3);
				}
				flicks = fabs(wp*50) + 100;
				for (flick = 0; flick < flicks; flick++)
					n_globes_map[fast_random(32767)] = 16 + fast_random(15);
				// luccichŤi mirati (in riflesso diretto della luce della stella)
				if (!nightzone) {
					fshift = xsun_onscreen - x_centro_f;
					fshift = (float)fshift * -0.34;
					fshift += 90;
					if (fshift>0 && fshift<256) {
						flicks = 250 + fabs(wp*25);
						for (flick = 0; flick < flicks; flick++) {
							//Fixed buffer overflow by moving the +fast_random(63) and adding bounds wrapping (SL)
							ptr = fshift + (fast_random(127) << 8) + fast_random(63);
							if (ptr >= 32768) {
								ptr -= 36768;
							}
							n_globes_map[ptr] = 16 + fast_random(15);
						}
					}
				}
				setfx (1); // poligoni lucidi
				polymap (x, y, z, 4, 0);
				setfx (0); // poligoni normali
				culling_needed = 0;
			}
		}
		else {
			// orizzonte planetario (standard)
			if (nightzone)
				ptr = albedo / 4;
			else
				ptr = albedo / 2;
			polymap (x, y, z, 4, ptr);
		}
		txtr = p_background;
		// variazioni alla posizione: moto ondoso.
		upanddown += 0.1;	//To decrease bobbing, this was reduced to 0.1. It was originally 0.2.
		pos_x0 = pos_x - 1E6;
		pos_z0 = pos_z - 1E6;
		if (waves_in || waves_out) {
			if (crcy - ((-1 * sin(formalbob) *10)-11) + formalappr > 0) {
				if (waves_in) {
					drop_y    = SQRT (pos_x0*pos_x0 + pos_z0*pos_z0) / (1E5 - 1E3*wp);
					waving_y  = drop_y * sin(upanddown) - drop_y;
				}
				else
					waving_y  = 0;
				waving_y += 50 * sin(upanddown) - 100;	//Was waving_y += 50 * sin(upanddown) - 100;
			}
			else
				waving_y = 0;
		}
		// variazioni alla posizione: "saltellamento".
		// nell'acqua simula il movimento oscillatorio dovuto
		// alle onde ed al nuoto. sulla terraferma, tende ad
		// orientare verticalmente lo sguardo in modo da seguire
		// l'andamento dei rilievi (salite e discese).
		if (landed && user_alfa>-40 && user_alfa<40) {
			if (waving_y && !jumping)
				dlt_alfa += sin(upanddown)/3;		//To decrease bobbing, the /3 was added.
			else {
				//This code was making the user look down every time the time-based resync was performed.
				//Now it only does it when we jump or use the jetpack.
				// (SL)
				if (jumping && pos_y > crcy - 2400) {
					drop_x = ((float)(crcy) - pos_y) * 0.001;
					if (drop_x < 0) drop_x *= 1.67;
					//dlt_alfa += drop_x;	//commenting this out gives you full control over your head again.. :) (MEGA)
				}
			}
		}
		// variazioni alla posizione:
		// attribuisce "consistenza" al suolo ed ai suoi dislivelli,
		// e controlla gli effetti del vento quando si Š sospesi
		// a mezz'aria (durante un grosso salto o scendendo con la
		// capsula). inoltre controlla l'accelerazione gravitazionale.
		crcy = hpoint (pos_x, pos_z) - formalappr - ((sin(formalbob) + 1) * 10); //higher
		#ifdef ALL
		if (!option_flying_lander) {
		#endif
		#if defined(ALL) || !defined(FLYING_LANDER)
			pos_y += gravity;
			if (pos_y > crcy) {
				pos_y = crcy;
				if (!landed) {
					refy = hpoint (pos_x, pos_z);
					compdist = -1000000;
					temp = 0;
					while (temp < 2*M_PI) {
						drop_x = pos_x - 1024 * sin(temp);
						drop_z = pos_z + 1024 * cos(temp);
						drop_y = hpoint (drop_x, drop_z) - refy;
						if (drop_y > compdist) {
							compdist = drop_y;
							wdir = temp;
						}
						temp += 0.025;
					}
					if (!opencapdelta && gravity < 250
					&& (compdist < 512 || bounces > 10)) {
						atl_x	= ((Dword)pos_x) >> 14;
						atl_z	= ((Dword)pos_z) >> 14;
						atl_x2	= pos_x - (atl_x<<14);
						atl_z2	= pos_z - (atl_z<<14);
						pos_y   = hpoint (pos_x, pos_z);
						atl_y	= pos_y;
						gravity = 0;
						landed = 1;
						lifter_homing = 0;
						lifter_vertical = -1;
						/*	Previously, we did this:
						pos_x   = ((((Dword)pos_x) >> 14) << 14) + 8192;
						pos_z   = ((((Dword)pos_z) >> 14) << 14) + 8192;
						pos_y   = hpoint (pos_x, pos_z);
						atl_x   = ((Dword)pos_x) >> 14;
						atl_z   = ((Dword)pos_z) >> 14;
						atl_x2  = 8192;
						atl_z2  = 8192;
						atl_y   = hpoint ((atl_x << 14) + atl_x2, (atl_z << 14) + atl_z2);
						*/
					}
					else {
						bounces++;
						gravity = - 0.32 * gravity;
					}
				}
			}
			else {
				if (landed) {
					if (pos_y > crcy - 300) {
						drop_y = planet_grav * (pos_y - crcy) * 0.00333; // 1/300
						gravity += drop_y;
					}
					else
						gravity += planet_grav;
				}
				else {
					gravity += planet_grav * 0.16;
					pos_x -= sin(wdir) * wp * 10;
					pos_z += cos(wdir) * wp * 10;
				}
			}
		#endif
		#ifdef ALL
		} else {
		#endif
		#if defined(ALL) || defined(FLYING_LANDER)
			//lifter_vertical is handled elsewhere.
			if (landed) {
				pos_y += gravity;
				if (pos_y > crcy) {
					pos_y = crcy;
				} else {
					if (pos_y > crcy - 300) {
						drop_y = planet_grav * (pos_y - crcy) * 0.00333; // 1/300
						gravity += drop_y;
					}
					else
						gravity += planet_grav;
				}
			}
		#endif
		#if defined(ALL)
		}
		#endif
		if (pos_y > (crcy - 200)){ //disable Jumping whenever you're on the ground again. (MEGA)
			jumping = 0;
			jetpack = 0;
		}
		if (pos_y < (crcy - 200)){
			jumping = 1;
		}
		// controlla se si Š tornati alla capsula.
		if (landed) {
			drop_x = pos_x - ((atl_x << 14) + atl_x2);
			drop_z = pos_z - ((atl_z << 14) + atl_z2);
			drop_y = pos_y - atl_y;	//So the lander won't capture you while it's in the air :P	//hpoint ((atl_x << 14) + atl_x2, (atl_z << 14) + atl_z2);
			if (SQRT(drop_x*drop_x+drop_y*drop_y+drop_z*drop_z)<1600) {
				if (recover) {
					pos_x -= 0.125 * drop_x;
					pos_y -= 0.125 * drop_y;
					pos_z -= 0.125 * drop_z;
					opencapdelta = +1;
				}
			}
			else
				recover = 1;
			
			//Homing, by using atl_x2 and atl_y2. We've also added atl_y, but that isn't
			//saved in surface.bin. (SL)
			
			if (lifter_homing==1) {
				double height = hpoint(((atl_x << 14) + atl_x2), ((atl_z << 14) + atl_z2));
				double diff = (height-9000.0) - atl_y ;
				if (diff<.01 || (diff > .01 && !landerStuck)) {	//We want the lander to move down ONLY if it is NOT stuck, but it can move up anytime. (SL)
					Dword tmp=(Dword) (((double)atl_y)+diff*.1);
					//status("ASDF", 50); sprintf(fcs_status_extended, "1 %.3f %.3f %li %li", diff, height-9000.0, atl_y, tmp);	//TEMPORARY for debugging this height-correction stuff (SL)
					atl_y=tmp;
				}
				
				drop_x = pos_x - ((atl_x << 14) + atl_x2);
				drop_z = pos_z - ((atl_z << 14) + atl_z2);
				if (SQRT(drop_x*drop_x+drop_z*drop_z)<2048) {
					lifter_homing=2;
				} else {
					Dword newx = (Dword) (((atl_x << 14) + atl_x2) + drop_x*.025);
					Dword newz = (Dword) (((atl_z << 14) + atl_z2) + drop_z*.025);
					double nheight = hpoint(newx, newz);
					double diff = (nheight-2000.0) - atl_y ;
					//-1000 - 2000 = -3000. If height = -2000, diff = -1000. If height = -4000, diff = 1000
					if (diff < -90) {
						landerStuck=5;
						Dword tmp=(Dword) (((double)atl_y)+diff*.1);
						//status("ASDF", 50); sprintf(fcs_status_extended, "2 %.3f %.3f %li %li", diff, nheight-2000.0, atl_y, tmp);		//TEMPORARY for debugging this height-correction stuff (SL)
						atl_y = tmp;
					} else {
						if (diff<0) {
							landerStuck=5;
							atl_y=(Dword) (((double)atl_y)+diff);
							//status("ASDF", 50); sprintf(fcs_status_extended, "3 %.3f %.3f %li", diff, nheight-2000.0, atl_y);		//TEMPORARY for debugging this height-correction stuff (SL)
						}
						atl_x = newx >> 14;
						atl_z = newz >> 14;
						atl_x2 = newx - (atl_x<<14);
						atl_z2 = newz - (atl_z<<14);
					}
					liftx=newx;
					liftz=newz;
					//pos_y = hpoint(pos_x, pos_z);
				}
				
			} else if (lifter_homing==2) {
				double height = hpoint(((atl_x << 14) + atl_x2), ((atl_z << 14) + atl_z2));
				double diff = height - atl_y;
				if (abs(diff) > .01) {
					atl_y+=(diff*.05);
				} else {
					lifter_homing=0;
				}
			}
			if (landerStuck>0) {
				landerStuck--;
			}
		}
		// tracciamento onde in arrivo (onde del mare)
		from_user ();
		cam_x += sp_x;
		cam_y += sp_y + waving_y;
		cam_z += sp_z;
		if (waves_in) {
			// calcolo della distanza del player dal centro onde.
			dfc = SQRT (pos_x0 * pos_x0 + pos_z0 * pos_z0);
			// inizializzazione texture delle onde in arrivo.
			txtr = n_globes_map;
			for (ptr = 20480+256; ptr < 32768; ptr++)
				n_globes_map[ptr] = n_globes_map[ptr-256] >> 1;
			// usa i primi 32K, dove c'Š la sfumatura del mare...
			V_MATRIXS = 8; change_txm_repeating_mode();
			// ora attiva poligoni brillanti...
			setfx (2);
			// e un basso livello di dettaglio...
			culling_needed = 1;
			// ciclo di tracciamento delle onde in arrivo.
			// (normali onde del mare, prodotte dal vento)
			w = 10;
			while (w) {
				w--;
				if (wr[w] <= 0) {
					// questo produce nuove onde...
					wh[w] = 500 + wp * 100 + RANDOM(1500);
					wd[w] = (wp + 50) * -10;
					wr[w] = 15E5;
				}
				else {
					// questo invece succede quando
					// si "becca" un'onda in faccia...
					if (landed && !opencapdelta) {
						if (pos_y > -50 || waveblur) {
							if (waveblur) {
								pos_x = pos_x0 / (1 - (wd[w] / 2E6)) + 1E6;
								pos_z = pos_z0 / (1 - (wd[w] / 2E6)) + 1E6;
								user_alfa *= 1 + (float) RANDOM(5) * 0.002;
							}
							if (fabs (dfc - wr[w]) - 3*wl[w] <= fabs (2*wd[w]))
								waveblur = 1 + RANDOM (3);
						}
					}
				}
				if (fabs(pos_y)+fabs(dfc-wr[w]) > 0.5*wr[w])
					goto dontdo;
				drop_x = 0;
				yy[1] = wy[w];
				yy[0] = wy[w] - wh[w];
				yy[3] = wy[w] - wh[w];
				yy[2] = wy[w];
				drop_z = 18 * deg;
				cpos = 0;
			  redo:	while (drop_x<2*M_PI) {
					drop_y = wr[w] - wl[w];
					xx[1] = cos (drop_x) * wr[w]  + wx[w];
					zz[1] = sin (drop_x) * wr[w]  + wz[w];
					xx[0] = cos (drop_x) * drop_y + wx[w];
					zz[0] = sin (drop_x) * drop_y + wz[w];
					drop_x += drop_z;
					xx[3] = cos (drop_x) * drop_y + wx[w];
					zz[3] = sin (drop_x) * drop_y + wz[w];
					xx[2] = cos (drop_x) * wr[w]  + wx[w];
					zz[2] = sin (drop_x) * wr[w]  + wz[w];
					polymap (xx, yy, zz, 4, 128);
				}
				if (!cpos) {
					drop_x = 9*deg; cpos++;
					goto redo;
				}
			dontdo:	wr[w] += wd[w];
			}
			// reimpostazione dei normali parametri
			// per il texturing...
			setfx (0); // seleziona poligoni normali
			culling_needed = 0; // alto livello dettaglio
			V_MATRIXS = 16; change_txm_repeating_mode();
			txtr = p_background;
		}
		// qui disegna tutto il landscape.
		mirror = 0; // non Š un riflesso.
		ipfx = ((Dword)(cam_x)) >> 14;
		ipfz = ((Dword)(cam_z)) >> 14;
		if (landed)
			iperficie (1);
		else
			iperficie (4);
		// questo traccia la capsuletta mentre si scende...
		if (!landed) {
			H_MATRIXS = 0;
			V_MATRIXS = 0;
			change_txm_repeating_mode();
			txtr = n_globes_map;
			cam_x = 0;
			cam_z = 0;
			cam_y = 1030;
			polycupola (-1, 1);
			setfx (0); cupola (-1, 8);
			cam_y -= 1030;
			polycupola (+1, 1);
			setfx (0); cupola (+1, 8);
			cam_y = 0;
			// reimpostazione dei normali parametri
			// per il texturing...
			setfx (0); // seleziona poligoni normali
			culling_needed = 0; // alto livello dettaglio
			V_MATRIXS = 16; change_txm_repeating_mode();
			txtr = p_background;
		}
		// tracciamento onde in partenza (acqua smossa)
		if (waves_out) {
			// inizializzazione della texture per gli spruzzi
			// prodotti dal fatto che si sta nuotando, o comunque
			// annaspando da fermi, per rimanere a galla...
			txtr = n_globes_map;
			// usa i primi 32K, dove c'Š la sfumatura del mare...
			V_MATRIXS = 8; change_txm_repeating_mode();
			// ora attiva poligoni brillanti...
			setfx (2);
			// e un basso livello di dettaglio...
			culling_needed = 1;
			// e costruisci le sagome degli spruzzi,
			// quando si nuota rapidamente...
			if (fabs(step) > 200 && pos_y > -50) {
				for (ptr = 20480; ptr < 20480+256; ptr++)
					n_globes_map[ptr] = fast_random(63);
				for (ptr = 20480; ptr > 0; ptr--) {
					if (n_globes_map[ptr+256])
						n_globes_map[ptr] = n_globes_map[ptr+256] - 1;
					else
						n_globes_map[ptr] = 0;
				}
			}
			for (ptr = 20480+256; ptr < 32768; ptr++)
				n_globes_map[ptr] = n_globes_map[ptr-256] >> 1;
			// ciclo di tracciamento delle onde in partenza.
			// queste sono quelle prodotte dal protagonista,
			// e le differenze sono le seguenti:
			// - la cresta Š orientata verso l'esterno.
			// - l'onda si espande, non si restringe.
			// - l'onda si appiattisce sempre pi— e,
			//   dopo un po' di tempo, svanisce.
			w = now;
			while (w >= 10) {
				w--;
				if (wr[w] > 100 * wh[w]) wr[w] = 0;
				if (wr[w] == 0) goto prox;
				drop_x = 0;
				yy[1] = wy[w];
				yy[0] = wy[w] - wh[w];
				yy[3] = wy[w] - wh[w];
				yy[2] = wy[w];
				drop_z = 18 * deg;
				while (drop_x<2*M_PI) {
					drop_y = wr[w] + wl[w];
					xx[0] = cos (drop_x) * drop_y + wx[w];
					zz[0] = sin (drop_x) * drop_y + wz[w];
					xx[1] = cos (drop_x) * wr[w]  + wx[w];
					zz[1] = sin (drop_x) * wr[w]  + wz[w];
					drop_x += drop_z;
					if (hpoint (xx[0], zz[0]) == 0) {
						xx[2] = cos (drop_x) * wr[w]  + wx[w];
						zz[2] = sin (drop_x) * wr[w]  + wz[w];
						xx[3] = cos (drop_x) * drop_y + wx[w];
						zz[3] = sin (drop_x) * drop_y + wz[w];
						polymap (xx, yy, zz, 4, 128);
					}
				}
				wr[w] += wd[w];
				wh[w] /= 1.025;
				prox:
			}
			// reimpostazione dei normali parametri
			// per il texturing...
			setfx (0); // seleziona poligoni normali
			culling_needed = 0; // alto livello dettaglio
			V_MATRIXS = 16; change_txm_repeating_mode();
			txtr = p_background;
		}
		// tracciamento dell'alone del "sole", eventualmente.
		if (!nightzone && rainy < 1.2) {
			if (nearstar_class!=5&&nearstar_class!=6&&nearstar_class!=10) {
				if (nearstar_class!=11||gl_start<90) {
					if (dsd1<1000*nray1&&dsd1>=10*nray1) {
						alfa = user_alfa;
						beta = user_beta;
						change_angle_of_view();
						lens_flares_for (0, 0, 0, sun_x, sun_y, sun_z,
								 (10 * nray1) / dsd1, 1 + (0.002 * dsd1), hud_closed, 2, 1, 1);
					}
				}
			}
		}
		// tracciamento dell'alone del "sole" primario, se presente.
		if (secondarysun) {
		if (!pri_nightzone && rainy < 2.1) {
			if (dsd2<1000*nray2&&dsd2>=10*nray2) {
				alfa = user_alfa;
				beta = user_beta;
				change_angle_of_view();
				lens_flares_for (0, 0, 0, pri_x, pri_y, pri_z,
						 (10 * nray2) / dsd2, 1 + (0.002 * dsd2), hud_closed, 2, 1, 1);
			}
		}}
		// Variazioni ambientali.
		// Include: pioggia, vento, generazione delle onde, fulmini,
		//          effetti di un'atmosfera particolarmente densa.
		if (atmosphere) {
			// effetti del vento, che si fanno sentire quandunque
			// ci sia un'atmosfera, al di l… del fatto che essa
			// sia respirabile o meno.
			iwp  += (float)(RANDOM(albedo)) * 0.020;
			iwp  -= (float)(RANDOM(albedo)) * 0.020;
			if (iwp < -1) iwp = -1;
			if (iwp > 1) iwp = 1;
			wp   += ((iwp * rwp) - wp) * 0.05;
			wdir += flandom() * iwp * 0.1;
			wdir -= flandom() * iwp * 0.1;
		}

		if (nobrighten==2) {
			if (resolve>=63) {
				tavola_colori_brightness (surface_palette, 0, 256, 63, 63, 63, brightencnt);
			} else {
				tavola_colori_brightness (surface_palette, 0, 256, resolve, resolve, resolve, brightencnt);
			}
			nobrighten=0;
		} else if (nobrighten==1) {
			nobrighten=0;
		}
		if (crcy - pos_y == 0 && gravity >= 1500) {
			if (gravity >= 2501) gravity = 2500;
			fallingdmgcolor += (gravity - 1500) / 15.8730159;
			gravity = 1499;
		}
		if (fallingdmgcolor >= 64) fallingdmgcolor = 63;
		if (fallingdmgcolor!=0) {
			tavola_colori_brightness (surface_palette, 0, 256, resolve, 63 - fallingdmgcolor, 63 - fallingdmgcolor, brightencnt);
			fallingdmgcolor--;
		}

		if (nearstar_p_type[ip_targetted] == 2) {
//Visionmode:
//0 = Normal
//1 = Ultra
//2 = Infra
//3 = Ocean
//4 = Plant
			if (visionmode == 2) {  //Infra
				mask_pixels (adapted+2880, 64);
			}
			if (visionmode == 1) {  //Ultra
				mask_pixels (adapted+2880, 128);
			}
			if (visionmode == 4) {  //Plant
				mask_pixels (adapted+2880, 192);
			}
			if (visionmode != 2 && visionmode != 3 && visionmode != 4){   // != 2 != 3 != 4
				mask_pixels (adapted+2880, 0);
			}
			if (nofog == 0 && visionmode != 2 && visionmode != 3 && visionmode != 4) {
				psmooth_grays (adapted+2880);
			}
			goto ends;
		}
		if (nearstar_p_type[ip_targetted] != 2) {
			if (visionmode == 2) {
				mask_pixels (adapted+2880, 64);
			}
			if (visionmode == 1){
				mask_pixels (adapted+2880, 0);
			}
			if (visionmode == 3){
				mask_pixels (adapted+2880, 128);
			}
			if (visionmode == 4){
				mask_pixels (adapted+2880, 192);
			}
		}
		if (nearstar_p_type[ip_targetted] == 3) {
			if (rainy >= 2 || flashes > 5) {
				// quando piove...
				wdirsin = sin (wdir) * wp;
				wdircos = cos (wdir) * wp;
				wdirsin -= (pos_z - refz) * 0.333;
				wdircos -= (pos_x - refx) * 0.333;
				SRAND (CLOCK());
				fast_srand (CLOCK() % 18);
				if (rainy==0) {	//Maybe this'll fix the endless lightning bug, if it's being caused by rainy being set to 0 during a flash due to an update. (SL)
					flash=1;
				} else {
					ptr = RANDOM(3) + 1 ; while (ptr) {
						flash = RANDOM (150 / rainy);
						ptr--;
					}
				}
				if (rainy > 3) {
					setfx (1);
					Forward (-1000);
					ptr = RANDOM (25 * flashes) + 50;
					temp = (float)(CLOCK()%18) * 100;
					while (ptr) {
						drop_x = pos_x + fast_random (1023) - fast_random (1023);
						drop_z = pos_z + fast_random (1023) - fast_random (1023);
						drop_y = pos_y - fast_random (2047) + temp;
						if (pp_temp >= 5) {                         //RAIN
							stick3d (drop_x, drop_y, drop_z,
							 drop_x + wdircos, drop_y + 100, drop_z + wdirsin);
						} else { //if (pp_temp < 5) {							//HAIL (MEGA)
							stick3d (drop_x, drop_y - 1, drop_z,
							 drop_x + wdircos / 4, drop_y + 3, drop_z + wdirsin / 4);
							stick3d (drop_x, drop_y, drop_z,
							 drop_x + wdircos / 4, drop_y + 4, drop_z + wdirsin / 4);
						}
						ptr--;
					}
					setfx (0);
				}
			}
			if (pos_y>=0) {
				// Nuota a pelo d'acqua (ove possibile).
				// Quindi fa delle piccole onde...
				if (nearstar_p_type[ip_targetted] == 3
				&& (sctype == PLAINS || sctype == DESERT || sctype==FOREST || sctype==SHRUBLAND))
					goto ends; // non c'Š acqua su deserti e prati.
				waveratio = 10 - fabs(step) / 5;
				if (waveratio < 4) waveratio = 4;
				if (!(CLOCK()%waveratio)) {
					from_user ();
					SRAND (CLOCK());
					wr[lw] = 200;
					wh[lw] = RANDOM (100)    + fabs(3 * step);
					wy[lw] = 50 		 + fabs(3 * step);
					wd[lw] = RANDOM (5) + 12 + fabs(2 * step);
					wl[lw] = RANDOM (50)     + fabs(2 * step);
					wx[lw] = pos_x - step*opt_tsinbeta*opt_tcosalfa;
					wz[lw] = pos_z + step*opt_tcosbeta*opt_tcosalfa;
					lw++; if (lw>24) lw = 10;
				}
			}
		}
		// annebbiamento della vista (eventuale),
		// subito dopo che si Š stati bagnati da un'onda...
	  ends: 
		if (fcs_status_delay>0) {
			Word len = strlen(fcs_status_extended);
			len = len+len;
			wrouthud(160-len, 100, NULL, fcs_status_extended);
			fcs_status_delay--;
		}
		
		if (waveblur) {
			ptr = waveblur;
			while (ptr) {
				psmooth_64 (adapted, 160);
				ptr--;
			}
			waveblur--;
		}
		else {
			QUADWORDS = 160 + openhudcount * 80;
			psmooth_64 (adapted, 160);
			psmooth_64 (adapted, 160);
			QUADWORDS = pqw;
		}
		
		
		/*	//TEMPORARY (for testing the changes to the albedo formula) (SL)
		char temptmp[120];
		sprintf(temptmp, "RAW ALBEDO %i ALBEDO %i OLD ALBEDO %i RAINY %3.3f", raw_albedo, albedo, old_albedo, rainy);	//TEMPORARY
		wrouthud(0, 50, NULL, temptmp);
		*/
		
		ReadCommFile(1);
		if (force_update == 1) {
			mooses = 0;
		}
		if (mooses == 0 && portablegoes == 1) {
			Moose("..\\DATA\\goesfile.txt");
			mooses = 1;
		}
		/*if (portablegoes == 1 || helpison == 1) {
			if (portablegoesbgr == 1) {
				areaclear(adapted, 1, 1, 319, 199, 0, 0, 0);
			}
		}*/			
		if (portablegoes == 1) {
			moosepage = 0;
			ShowMoose(moosepage, 0, 0, portablegoesbgr);
			if (goesnet_command[0]!=NULL) {
				areaclear(adapted, 9, 179, 300, 186, 0, 0, 70);
				wrouthud (10, 180, NULL, goesnet_command);
			}
		}

		if (helpison) {
			ShowMoose(0, 1, 1, portablegoesbgr);
			//ShowMoose(0, 1, 0, portablegoesbgr); //use single text file
		}
		
		if (about) {								//F1 - about page & help page.
			ShowAboutPage(True);
		}

		/*sprintf (outhudbuffer, "%3i" , sky_brightness);	//random debug information regarding new night colours
		wrouthud (100, 181, NULL, outhudbuffer);
		sprintf (outhudbuffer, "%3i" , horiz_brt);
		wrouthud (150, 181, NULL, outhudbuffer);
		sprintf (outhudbuffer, "%3i" , sky_grn_filter);
		wrouthud (200, 181, NULL, outhudbuffer);*/

		if (advstat) {								//F2 - ADVANCED DATA
			ShowAdvStat(crcy, sctype, formalappr, sin(formalbob));
		}

		if (moviestat) {							//F3 - MOVIE STATUS
			ShowMovieSetup(moviefsec, movieflashoff, moviedeck);
		}
		CalculatemovieFPS(moviefscap, moviestime);

		if (binstat) {								//F4 - BINOCUSCOPE STATUS
			ShowBinStat();
		}

		
		//F5 - PORTABLE GOES

		
		//I used this to see if colormix was working: (SL)
		//char tmpc[20];
		//sprintf(tmpc, "COLORMIX %i", colorMix);
		//wrouthud (200, 100, NULL, tmpc);
		
		//More testing: (SL)
		//char temptmp[120];
		//sprintf(temptmp, "OCOT=%i CM=%i RESOLVE=%i TIME=%f", option_change_over_time, colorMix, resolve, secs-lsecs);
		//wrouthud(100, 100, NULL, temptmp);
		
		// il fotogramma Š finito. ora lo visualizza.
		surrounding (1, openhudcount);
		QUADWORDS = 16000;
		if (widesnapping==0) pcopy (adaptor, adapted);
		QUADWORDS = pqw;
		// effetto di apertura della capsula:
		// quando Š totalmente aperta, si pu• scendere.
		if (opencapdelta < 0) {
			opencapcount += opencapdelta;
			if (opencapcount <= 0) {
				opencapdelta = 0;
				opencapcount = 0;
			}
		}
		
		// effetto di chiusura della capsula:
		// quando Š totalmente sigillata, scotty beam me up.
		#if defined(ALL)
		if (!option_flying_lander) {
		#endif
		#if defined(ALL) || !defined(FLYING_LANDER)
			if (opencapdelta > 0) {
				opencapcount += opencapdelta;
				if (opencapcount > 32) {
					pos_y -= 20 * (opencapcount - 31);
					landed = 0;
					lifter_vertical = 1;
					recover=2;
					movie = 0;
				}
				if (opencapcount > 250)
					break;
			}
		#endif
		#if defined(ALL)
		} else
		#endif
		#if defined(ALL) || defined(FLYING_LANDER)
		if (landed || lifter_vertical==1) {	//Launching is done the same with flying-lander as before.
			if (opencapdelta > 0) {
				crcy = hpoint (pos_x, pos_z) - formalappr - ((sin(formalbob) + 1) * 10); //higher
				opencapcount += opencapdelta;
				if (opencapcount > 32) {
					pos_y += gravity;
					gravity -= 20;
					if (pos_y > crcy) {
						pos_y = crcy;
						if (gravity>0) {
							gravity = -(gravity);	//bounce
						}
					}
					landed = 0;
					lifter_vertical = 1;
					recover=2;
				}
				if (pos_y < crcy-473040)
					break;
			}
		} else if (!landed && option_flying_lander) {
			crcy = hpoint (pos_x, pos_z) - formalappr - ((sin(formalbob) + 1) * 10); //higher
			if (lifter_vertical==-1) {			//land
				if (pos_y >= crcy) {
					pos_y = crcy;
					//landed!
					atl_x	= ((long)pos_x) >> 14;
					atl_z	= ((long)pos_z) >> 14;
					atl_x2	= pos_x - (atl_x<<14);
					atl_z2	= pos_z - (atl_z<<14);
					pos_y   = hpoint (pos_x, pos_z);
					atl_y	= pos_y;
					liftx=float(((atl_x << 14) + atl_x2));
					liftz=float(((atl_z << 14) + atl_z2));
					gravity = 0;
					landed = 1;
					lifter_homing = 0;
					lifter_vertical = -1;
					opencapcount=180;
					opencapdelta=-2;
					recover=0;
				} else {
					liftx=pos_x;
					liftz=pos_z;
					double diff = crcy - pos_y;
					if (abs(diff) > 2) {
						gravity = gravity*.9 + diff*.0025;
					} else {
						gravity = diff;
					}
				}
			} else if (lifter_vertical==0) {	//hover
				crcy = hpoint (pos_x, pos_z) - formalappr - ((sin(formalbob) + 1) * 10); //higher
				double diff;
				if (pos_y > crcy) {
					diff = crcy-pos_y;
					pos_y = crcy;
					gravity = diff;	//-(gravity*.32);	//bounce
				}
				diff = (crcy-30000) - pos_y ;
				double surfdiff = (crcy - pos_y);
				if (abs(diff) > .01) {
					if (surfdiff<=5000) {						//Emergency boost!
						gravity = diff*.05;
						pos_y += gravity;
					} else if (surfdiff>=20000) { 				//Lethargic (Well, it's not bad, except you ram gently rolling hills at this rate :o )
						gravity = gravity*.9 + diff*.01;		//We want to move at diff*.025, but transition at a 10% rate.
					} else {
						//This encompasses a spectrum from 'emergency boost' to 'lethargic' :P
						double rate = (surfdiff+13750)/37500;
						//Alas, rate isn't the rate of change of our speed. It's the merging-level of gravity vs speed input.
						if (rate<0) rate=0;
						if (rate>.9) rate=.9;
						gravity = gravity*rate + diff*(.1*(1-rate));	
					}
				}
				if (!landed) {
					liftx=pos_x;
					liftz=pos_z;
				}
			}
			pos_y += gravity;
		}
		#endif
		/*
			opencapdelta=1; pos_y = surface_level;
			opencapcount=32; Y changes 218 times before we leave
				(technically 219, but after changing y the 219th time,
				we exit without redrawing, IIRC).
			20*2 + 20*3 + 20*4 + 20*5 ... 20*217
			sum of 20*x for x = 2 ... 217: 473040
			pos_y before departure = surface_y - 473040;
		
			On key:
			'q': lifter_vertical=1;
			'a': lifter_vertical=0;
			'z': lifter_vertical=-1;
				
		*/
		if (returnToStart) {
			break;
		}
		// effetto di apertura della visiera dell'HUD.
		if (openhuddelta < 0) {
			openhudcount += openhuddelta;
			if (openhudcount <= 0) {
				openhuddelta = 0;
				openhudcount = 0;
			}
		}
		// effetto di chiusura della visiera dell'HUD.
		if (openhuddelta > 0) {
			openhudcount += openhuddelta;
			if (openhudcount >= 180) {
				openhuddelta = 0;
				openhudcount = 180;
				hud_closed = 1;
			}
		}
		// consumi supplementari della navicella
		// (ovviamente continua a fare il suo lavoro anche
		// mentre si esplora la superficie, per cui consuma)
		//additional_consumes ();	//Disabled for now - will get taken care of back on the SD. (SL)
		// aggiornamento coordinate di stepping.
		add_height (pos_x, pos_z, 300);
		// fine sincronizzazione fotogrammi.
		sync_stop ();
		// controllo funzione widesnapping.
		if (widesnapping!=0) {
			if (widesnapping==-1) {
				snapshot (9997, 0);
				widesnapping=0;
			} else if (widesnapping == 1) {
				dzat_x = backup_dzat_x;
				dzat_y = backup_dzat_y;
				dzat_z = backup_dzat_z;
				snapshot (9997+widesnapping, 1);
				dzat_x = 0;
				dzat_y = 0;
				dzat_z = 0;
			} else {
				snapshot (9997+widesnapping, 0);
			}
			widesnapping++;
			if (widesnapping == 3) {
				char recycled;
				widesnapping = 0;
				user_beta += widesnappingangle;
				//
				ih = sa_open (header_bmp);
				if (ih==NOFILE) goto wserror;
				READFILE (ih, t, 54);
				t[18] = 0x94;
				t[19] = 0x03;
				CLOSEFILE (ih);
				prog = lastSnapshot;
				recycled=0;
				do {
					prog++; if (prog == 100000000) {	//Image limit increased to 99,999,999 (SL)
						if (recycled) {
							status("TOO MANY SNAPSHOTS", 300);
							goto wserror;
						} else {
							recycled=1;
							prog=0;
						}
					}
					sprintf (snapfilename, "..\\GALLERY\\%08d.BMP", prog);	//Image limit increased to 99,999,999 (SL)
					ih = OPENFILE (snapfilename, 0);
					if (ih != NOFILE) CLOSEFILE (ih);
				} while (ih != NOFILE);
				lastSnapshot = prog;
				
				//
				//Panoramic snapshots no longer overwrite pictures 9997-9999 if those happened to exist. (SL)
				i9997 = OPENFILE ("..\\GALLERY\\WIDE9997.BMP", OPEN_RB);
				i9998 = OPENFILE ("..\\GALLERY\\WIDE9998.BMP", OPEN_RB);
				i9999 = OPENFILE ("..\\GALLERY\\WIDE9999.BMP", OPEN_RB);
				if (i9997 == NOFILE || i9998 == NOFILE || i9999 == NOFILE) {
					if (i9997 != NOFILE) CLOSEFILE (i9997);
					if (i9998 != NOFILE) CLOSEFILE (i9998);
					if (i9999 != NOFILE) CLOSEFILE (i9999);
					goto wserror;
				}
				//
				oh = CREATEFILE (snapfilename);
				if (oh==NOFILE) goto wserror;
				WRITEFILE (oh, t, 54);
				//
				FILESEEK (i9997, 54L, SEEK_SET);
				READFILE (i9997, adapted, 1024);
				WRITEFILE (oh, adapted, 1024);
				//
				FILESEEK (i9997, 1078L, SEEK_SET);
				for (line = 0; line < 200; line++) {
					READFILE (i9997, adapted, 320);
					FILESEEK (oh, line*916L + 1078L + 309L, SEEK_SET);
					WRITEFILE (oh, adapted + 10, 299);
				}
				//
				FILESEEK (i9998, 1078L, SEEK_SET);
				for (line = 0; line < 200; line++) {
					READFILE (i9998, adapted, 320);
					FILESEEK (oh, line*916L + 1078L, SEEK_SET);
					WRITEFILE (oh, adapted, 309);
				}
				//
				FILESEEK (i9999, 1078L, SEEK_SET);
				for (line = 0; line < 200; line++) {
					READFILE (i9999, adapted, 320);
					FILESEEK (oh, line*916L + 1078L + 608L, SEEK_SET);
					WRITEFILE (oh, adapted + 10, 308);
				}
				//
				CLOSEFILE (oh);
				//
			    wserror:
				//Fixed the taking-panoramic-screenshots-b0rks-stuff bug. (SL)
				//(Alex forgot to close the original screenshot files before deleting them)
				if (i9997!=NOFILE) CLOSEFILE (i9997);
				if (i9998!=NOFILE) CLOSEFILE (i9998);
				if (i9999!=NOFILE) CLOSEFILE (i9999);
				remove ("..\\GALLERY\\WIDE9997.BMP");
				remove ("..\\GALLERY\\WIDE9998.BMP");
				remove ("..\\GALLERY\\WIDE9999.BMP");
				hopfind=-hopfind;
			}
		} else if (snapping) {
			dzat_x = backup_dzat_x;
			dzat_y = backup_dzat_y;
			dzat_z = backup_dzat_z;
			snapshot (0, 1);
			dzat_x = 0;
			dzat_y = 0;
			dzat_z = 0;
			snapping=0;
			hopfind=-hopfind;
		}
		

        //formal/nonformal approaches
	if (formalapprst == 1 & formalappr < formalheight) formalappr = formalappr + ((formalheight - formalappr) / 10) + 5;
	if (formalapprst == 1 & formalappr > formalheight)  formalappr = formalheight;
	if (formalapprst == 0 & formalappr > 0) formalappr = formalappr - (formalappr / 10) - 5;
	if (formalapprst == 0 & formalappr < 0) formalappr = 0;
	formalbob = formalbob + pp_pulse / 2000;
	if (formalbob > 6.28) formalbob = 0;

        if (supvision == 3) {
           goto supmoose;
        }



               /*tempi = 1000;
               while (tempi > 0) {
                  tempx=RANDOM(198) + 1;
                  tempy=RANDOM(198) + 1;
                  tempb=(tempy*200)+tempx;
                  //tempb=RANDOM(40000)+25534;
   	          p_surfacemap[tempb] += RANDOM(3) - 1;
  		  if (p_surfacemap[tempb] < 0) p_surfacemap[tempb] = 0;
  		  if (p_surfacemap[tempb] > 250) p_surfacemap[tempb] = 0;
                  tempi = tempi - 1;
                }*/

               /*
               //tempn = 1;
               while (tempn>0){
                tempi = 10;
                tempx=RANDOM(180) + 10;
                tempy=RANDOM(180) + 10;
                tempb=(tempy*200)+tempx;
                tempz=RANDOM(3) - 1;
  		  if (tempz < 0) tempz = 0;
		  if (tempz > 250) tempz = 0;
               
                while (tempi > 0) {
                  tempx=tempx+RANDOM(3)-1;
                  tempy=tempy+RANDOM(3)-1;
                  tempb=(tempy*200)+tempx;
                  //tempb=RANDOM(40000)+25534;
                  if (tempn > 500)
                  ruinschart[tempb] = AF4;
                  else ruinschart[tempb] = AF4;
   	          p_surfacemap[tempb] = tempz;
   	          p_surfacemap[tempb-1] = tempz;
   	          p_surfacemap[tempb+1] = tempz;
   	          p_surfacemap[tempb-200] = tempz;
   	          p_surfacemap[tempb+200] = tempz;
                  tempi = tempi - 1;
                }
                tempn--;
               }*/


               /*
               //tempn = 1;
               while (tempn>0){   //Volcano fluid! Yay! :D
                tempi = 500;
                tempx=100;
                tempy=100;
                tempb=(tempy*200)+tempx;
                //tempz=RANDOM(3) - 1;
  		  //if (tempz < 0) tempz = 0;
		  //if (tempz > 250) tempz = 0;
                while (tempi > 0) {
                  tempx=tempx+RANDOM(3)-1;
                  tempy=tempy+RANDOM(3)-1;
                  tempb=(tempy*200)+tempx;
                  ////tempb=RANDOM(40000)+25534;
                  //if (tempn > 500)
                  ruinschart[tempb] = AF6;
                  //else ruinschart[tempb] = AF4;
   	          p_surfacemap[tempb] = abs(p_surfacemap[tempb]-1);
   	          p_surfacemap[tempb-1] = abs(p_surfacemap[tempb-1]-1);
   	          p_surfacemap[tempb+1] = abs(p_surfacemap[tempb+1]-1);
   	          p_surfacemap[tempb-200] = abs(p_surfacemap[tempb-200]-1);
   	          p_surfacemap[tempb+200] = abs(p_surfacemap[tempb+200]-1);
                  tempi = tempi - 1;
                }
                tempn--;
               }

               while (tempi<40000 && nearstar_p_type[ip_targetted] == 0) {
                if (ruinschart[tempi] >=0x90 && p_surfacemap[tempi] >=100)
                ruinschart[tempi]=AF6;
                 tempi++;
               }
               tempi=0;*/

               while (tempi<40000 && nearstar_p_type[ip_targetted] == 0) { //Change everything to AF6 if it's got a high ruinschart index!
                if (ruinschart[tempi] >=0x90) // && p_surfacemap[tempi] >=100)
                ruinschart[tempi]=AF4;
                 tempi++;
               }
               tempi=0;

                // earthquake
		if (earthtime > 1 && pos_y > crcy - 10){
			Earthquake(&earthtime);
		}

		if (nearstar_p_type[ip_targetted] == 2 || nearstar_p_type[ip_targetted] == 3 || nearstar_p_type[ip_targetted] == 5 || nearstar_p_type[ip_targetted] == 7 || nearstar_p_type[ip_targetted] == 8){
			if (RANDOM (1000000) == 0 && landed && pos_y > crcy - 10){
				earthtime = 50 + RANDOM (250);
			}
		}   


		// end of earthquake

		// movie stuff
		if (movie) {
			moviedelay = moviedelay - 1;
			if (moviedelay <= 0) {
				widesnapping = 0;
				snapshot (0, 0);
				moviedelay = moviefsec;
			}
		}

		// controllo tastiera.
		while (tasto_premuto()) {
			w = attendi_pressione_tasto();
			if (!w) {
				w = attendi_pressione_tasto();
				if (w == 0x49) {	//pgup: 33/true in windows
					openhuddelta = -5;
					hud_closed = 0;
				}
				if (w == 0x51)		//pgdown: 34/true in windows
					openhuddelta = +5;
				if (w == 0x4B){	//left arrow
					//user_beta = user_beta + 1;
					slide-=10;
					if (slide<-1000) slide=-1000;
				}
				if (w == 0x4D){	//right arrow
					//user_beta = user_beta - 1;
					//slide=1;
					slide+=10;
					if (slide>1000) slide=1000;
				}
				if (w == 0x50){
					//user_alfa = user_alfa + 1;
					slide*=.9;
					if (slide<10 && slide>-10) slide=0;
				}
				if (w == 0x48){
					//user_alfa = user_alfa - 1;
					option_mouseLook++;
					if (option_mouseLook>2) option_mouseLook=0;
					if (option_mouseLook==0) {
						status("MOUSELOOK DISABLED", 50);
					} else if (option_mouseLook==1) {
						status("MOUSELOOK ENABLED", 50);
					} else {
						status("INVERTED Y AXIS", 50);
					}
				}
				if (w == 134){
					hopfind=-hopfind;
					user_beta = user_beta + 5;
					snapping=1;
				}
				if (w == 83){								// Delete - RAWSNAP  ( also "b")
					snapshot (0, 0);
				}
	
				if (w==0x3B){								// f1 - HELP & ABOUT
					if (about == 0){
						about = 1;
						advstat = 0;
						binstat = 0;
						moviestat = 0;
					}
					else {
						about = 0;
					}
				}
				if (w==0x3C){								// f2 - advstat
					if (advstat == 0){
						advstat = 1;
						about = 0;
					}
					else {
						advstat = 0;
					}
				}
				
				if (w==0x3D){								// f3 - moviestat
					if (moviestat == 0){
						moviestat = 1;
						about = 0;
					}
					else {
						moviestat = 0;
					}
				}
				if (w==0x44){								// F10 - show map
                                        if (showmapz == 0) {
                                                if (supvision == 0) {
						  memcpy(old_surface_palette, surface_palette, 768);
						}
						if (showmapcol == 1) {
						   shade(surface_palette, 0, 128, 0 , 0 , 0, 63 , 63 , 63);
						} else {
						   shade(surface_palette, 0, 128, 5 , 25 , 5, 40 , 63 , 12);
						   if (sctype == OCEAN)
							surface_palette[0] = 25; surface_palette[1] = 25; surface_palette[2] = 63;
						}
						   surface_palette [387] = 63; surface_palette [388] = 0;  surface_palette [389] = 0; 
						   surface_palette [390] = 0; surface_palette [391] = 0;  surface_palette [392] = 63;
						tavola_colori (surface_palette, 0, 256, 63,63,63);
						showmapz = 1;
						about = 0;
						moviestat = 0;
				    	//fd = fopen("surfdmp.dmp", "wb");		//(by ees33, this dumps a file which contains the height of the surface at various points)
        				//fwrite(p_surfacemap, 40000, 1, fd);
        				//fclose(fd);
        				////exit(0);
					}
					else {
                                                memcpy(surface_palette, old_surface_palette, 768);
                                                if (supvision == 1) {
                                                  supvision = 3;
                                                  showmapz=0;
                                                  goto supmoose;     //Yay for descriptive goto's! :D
                                                }
						tavola_colori (surface_palette, 0, 256, 63,63,63);
						showmapz=0;
					}
				}
				if (w==0x85){
                                  if (showdebug == 0) {
                                  showdebug = 1;
                                  status("SHOWING DEBUG STUFF",25); 
                                  } else {
                                    showdebug = 0;
                                    status("NOT SHOWING DEBUG STUFF",25);
                                  }
                                  }


				if (w==0x3F){								// f5 - portable GOES
					if (portablegoes == 1){
						portablegoes = 0;
					}
					else {
						portablegoes = 1;
						about = 0;
						helpison = 0;
					}
				}
				
				if (w==0x43){								// f9 - help(/textreader, in the future)
					if (helpison == 1){
						helpison = 0;
					}
					else {
						helpison = 1;
						if (helppage == 0) {
							Moose("..\\DOCS\\help1.txt");
							helppage = 1;
							//Moose("..\\DOCS\\help.txt",helppage); //use single text file
						}
						about = 0;
						portablegoes = 0;
					}
				}
				
				if (w==0x3E){								// f4 - BINOCUSTAT
					if (binstat == 0){
						binstat = 1;
						about = 0;
					}
					else {
						binstat = 0;
					}
				}
				
				if (w==144 && !moviestat && !showmapz){					//add 1 to brightness
					if (brightencnt < 113) {
						brightencnt = brightencnt + 1;
						nobrighten=2;
					}
				}
				if (w==142 && !moviestat && !showmapz){					//substract 1 from brightness
					if (brightencnt > 13) {
						brightencnt = brightencnt - 1;
						nobrighten=2;
					}
				}
				if (w==150 && !showmapz){								//reset brightness
					brightencnt = 63;
					nobrighten=2;
				}
				if (w==150 && showmapz && !moviestat){								//reset brightness
					mapcontr=1;
					mapmod=1;
				}
				
				if (w==144 && showmapz && !moviestat && mapcontr < 3) mapcontr+=0.1;
				if (w==142 && showmapz && !moviestat && mapcontr > 0) mapcontr-=0.1;
				
				if (w==144 && moviestat && !movie && !showmapz) {					//add 1 to moviedeck
					if (moviedeck < 999) {
						moviedeck++;
						/*sprintf (snapfilename, "..\\MOVIES\\%02i\\00000001.BMP", moviedeck);
						FILE * tmpFile = fopen(snapfilename, "r");
						if (tmpFile == NULL) {
							movieexists = 0;
						} else {
							movieexists = 1;
						}*/
						movieexists = 0;
						movienr = 0;
					}
				}
				if (w==142 && moviestat && !movie && !showmapz) {					//substract 1 from moviedeck
					if (moviedeck > 1) {
						moviedeck--;
						/*sprintf (snapfilename, "..\\MOVIES\\%02i\\00000001.BMP", moviedeck);
						FILE * tmpFile = fopen(snapfilename, "r");
						if (tmpFile == NULL) {
							movieexists = 0;
						} else {
							movieexists = 1;
						}*/	
						movieexists = 0;
						movienr = 0;
					}
				}





				/*if (w == 80) {
					latitude++;
					alfa = deg * (90 - latitude);
					beta = deg * exposure;
					sun_x = -dsd1 * cos(beta) * sun_x_factor;
					sun_y = -dsd1 * sin(beta) * sin(alfa);
					sun_z = +dsd1 * sin(beta) * cos(alfa);
					alfa = deg * (90 - latitude + pri_latitude);
					beta = deg * pri_exposure;
					pri_x = -dsd2 * cos(beta) * pri_sun_x_factor;
					pri_y = -dsd2 * sin(beta) * sin(alfa);
					pri_z = +dsd2 * sin(beta) * cos(alfa);
				}
				if (w == 72) {
					latitude--;
					alfa = deg * (90 - latitude);
					beta = deg * exposure;
					sun_x = -dsd1 * cos(beta) * sun_x_factor;
					sun_y = -dsd1 * sin(beta) * sin(alfa);
					sun_z = +dsd1 * sin(beta) * cos(alfa);
					alfa = deg * (90 - latitude + pri_latitude);
					beta = deg * pri_exposure;
					pri_x = -dsd2 * cos(beta) * pri_sun_x_factor;
					pri_y = -dsd2 * sin(beta) * sin(alfa);
					pri_z = +dsd2 * sin(beta) * cos(alfa);
				}*/
			}
			else {
				if (helpison == 1) {
					if (w=='+' || w=='-') {
						if (w=='+')
							helppage++;
						if (w=='-')
							helppage--;
						sprintf (filetouse, "..\\DOCS\\help%i.txt" , helppage);
						Moose(filetouse);
						ShowMoose(0, 1, 1, portablegoesbgr);
						
						//Moose("..\\DOCS\\help.txt",helppage);		//use single text file
						//ShowMoose(0, 1, 0 , portablegoesbgr);						//use single text file
						goto endtype;
					}
				}
				if (helpison == 1 || portablegoes == 1) {
					if (w==9) {
						if (portablegoesbgr==0) {
								portablegoesbgr = 1;
						} else {
							portablegoesbgr = 0;
						}
					}						
				}				
				if (portablegoes==1) {
					if (w>=97 && w<=122) {
						goesnet_command[gnc_pos]=w-32;
						goesnet_command[gnc_pos+1]='_';
						goesnet_command[gnc_pos+2]=NULL;
						gnc_pos++;
						goto endtype;	
					}
					if ((w>=32 && w<=96) && w!= 64) {
						goesnet_command[gnc_pos]=w;
						goesnet_command[gnc_pos+1]='_';
						goesnet_command[gnc_pos+2]=NULL;
						gnc_pos++;
						goto endtype;
					}

					if (w==13) {
						goesnet_command[gnc_pos]=NULL;
						RunCommand(NULL);
						force_update = 1;
						goesnet_command[0]=NULL;
						gnc_pos = 0;
						goto endtype;
					}
					if (w==8 && gnc_pos!=0) {
						if (gnc_pos > 1) {
							goesnet_command[gnc_pos-1]='_';
						} else {
							goesnet_command[gnc_pos-1]=NULL;
						}
						goesnet_command[gnc_pos]=NULL;
						gnc_pos--;
						goto endtype;
					}
				}
					
				if (w=='+' && surlight < 63 && !moviestat && !showmapz) surlight++;
				if (w=='-' && surlight > 10 && !moviestat && !showmapz) surlight--;

				if (w=='+' && moviestat && moviefsec < 999 && !movie && !showmapz) moviefsec++;
				if (w=='-' && moviestat && moviefsec > 1 && !movie && !showmapz) moviefsec--;
					
				if (w=='+' && showmapz && !moviestat && mapmod < 3) mapmod = mapmod + 0.1;
				if (w=='-' && showmapz && !moviestat && mapmod > 0) mapmod = mapmod - 0.1;
				if (w==13) {
					if (movie == 0 && moviestat) {
						movie = 1;
						moviefscap = 0;
						moviestime = gtime;
						moviestat = 0;
						movienr = 0;
					}
					else if (movie == 1) {
                                           movie = 0;
                                           movieexists = 2;
                                          }
				}
				if (w=='f' && moviestat && !movie) {
					if (movieflashoff == 1) movieflashoff = 0;
					else movieflashoff = 1;
				}


				if (w == 'Q' || w=='q') {
					if (!landed) {
						lifter_vertical = 1;
						opencapdelta=1;
						opencapcount=33;
						status("GOING BACK TO STARDRIFTER..", 25);
					}
				}
				if (w == 'A' || w=='a') {
					if (landed) {
						lifter_homing = 1;
						status("CALLING THE LANDING POD..", 25);
					} else {
						lifter_vertical = 0;
						status("HOVERING..", 25);
					}
				}
				if (w == 'Z' || w=='z') {
					if (landed) {
						lifter_homing = 2;
						status("LANDING POD STOPPING AND LANDING..", 25);
					} else {
						lifter_vertical = -1;
						status("LANDING..", 25);
					}
				}

				if (w == 'g') {
					if (degrass == 0) {
						degrass = 1;
						status("DEGRASSIFYING ON", 25);
					} else {
						degrass = 0;
						status("DEGRASSIFYING OFF", 25);
					}
				}
				if (w == 's') {
					if (formalapprst == 0) {
						formalapprst = 1;
						status("FORMAL APPROACH", 25);
					} else {
						formalapprst = 0;
						status("NORMAL APPROACH", 25);
					}
				}
				if (degrass == 1 && groundflares == 8) {
					groundflares = 16;
				}
				if (degrass == 0 && groundflares == 16) {
					groundflares = 8;
				}

				if ((w == '*' || (w=='m' && !showmapz) && widesnapping==0)) {
					hopfind=-hopfind;
					snapping=1;
				}
				if (w=='m' && showmapz) {
                                  showmaptype = showmaptype * -1;
                                  }
				if (w=='n' && showmapz) {
                                  showmapcol = showmapcol * -1;
						if (showmapcol == 1) {
						   shade(surface_palette, 0, 128, 0 , 0 , 0, 63 , 63 , 63);
						} else {
						   shade(surface_palette, 0, 128, 5 , 25 , 5, 40 , 63 , 12);
						   if (sctype == OCEAN)
							surface_palette[0] = 25; surface_palette[1] = 25; surface_palette[2] = 63;
						}
						   surface_palette [387] = 63; surface_palette [388] = 0;  surface_palette [389] = 0; 
						   surface_palette [390] = 0; surface_palette [391] = 0;  surface_palette [392] = 63;
						tavola_colori (surface_palette, 0, 256, 63,63,63);
                                  }
				if ((w == 'b') && widesnapping==0) {                // b - RAWSNAP (also 'delete')
					snapshot (0, 0);

				}

				if ((w == '/' || w=='n' && !showmapz) && widesnapping==0) {
					hopfind=-hopfind;
					//snapshot (9997, 0);
					widesnapping = -1;

				}
				
				if (w == 'c') {
					jetpack = 0;
				}
				
				if (w >= 48 && w <= 57) {
					w = w - 48;
					if (fixed_step == (w * 10))
						fixed_step = 0;
					else
						fixed_step = (w * 10);
					goto endtype;
				}
				/*
				if (w == '1') {
					if (fixed_step == 10)
						fixed_step = 0;
					else
						fixed_step = 10;
				}
				if (w == '2') {
					if (fixed_step == 20)
						fixed_step = 0;
					else
						fixed_step = 20;
				}
				if (w == '3') {
					if (fixed_step == 30)
						fixed_step = 0;
					else
						fixed_step = 30;
				}
				if (w == '4') {
					if (fixed_step == 40)
						fixed_step = 0;
					else
						fixed_step = 40;
				}
				if (w == '5') {
					if (fixed_step == 50)
						fixed_step = 0;
					else
						fixed_step = 50;
				}
				if (w == '6') {
					if (fixed_step == 60)
						fixed_step = 0;
					else
						fixed_step = 60;
				}
				if (w == '7') {
					if (fixed_step == 70)
						fixed_step = 0;
					else
						fixed_step = 70;
				}
				if (w == '8') {
					if (fixed_step == 80)
						fixed_step = 0;
					else
						fixed_step = 80;
				}
				if (w == '9') {
					if (fixed_step == 90)
						fixed_step = 0;
					else
						fixed_step = 90;
				}*/
				if (w ==  '.') {
					if (fixed_step == 500)
						fixed_step = 0;
					else
						fixed_step = 500;
				}
				if (w ==  ',') {
					if (fixed_step == 250)
						fixed_step = 0;
					else
						fixed_step = 250;
				}
				if (w == 'j') {
					if (pos_y > crcy - 10) {
					gravity -= gravity + 500;
					jumping = 1;
				}
				}
				if (w == 32) { //pressin spacebar? JETPACK THE HELL OUTTA HERE!!! :P (MEGA)
					if (landed) {	//Jetpack shouldn't work if you're in the lander (SL)
						blinkhudlights = 1;
						blinkhudlights_stay = 0;
						if (pos_y > crcy - 150 ) {
							gravity -=gravity + 500;
						} else {
							gravity = gravity - 50;
							jumping = 1;
							jetpack = 1;
						}
					}
				}
				if (w == 'l' && pos_y < crcy + 10) { //Mommy, can I return now to the surface? (MEGA)
					gravity = gravity + 400;
				}
				if (w == 'f' && !moviestat) {
					if (nofog == 0) {
						status("NO FOGGING ON", 25);
						nofog = 1;
						visionmode = 0;
					} else {
						nofog = 0;
						status("NO FOGGING OFF", 25);
					}
				}
				if (w == 'h') {
					if (!hopfind) {
						hopfind = 1; //Turn on bracket mode
						status("BRACKETS ON", 25);
					} else if (hopfind == 1) {
						hopfind = 2; //Turn on line mode
						status("LINES ON", 25);
					} else if (hopfind == 2) {
						hopfind = 3; //Turn on 'both' mode
						status("BRACKETS AND LINES ON", 25);
					} else {
						hopfind = 0; //Turn off
						status("HOPPER FINDER OFF", 25);
					}
				}
				if (w == 'v') {
					if (hidebeam == 0) {
						status("HIDING VERTICAL PODLOCATOR LINE", 25);
						hidebeam = 1;
					} else {
						status("SHOWING VERTICAL PODLOCATOR LINE", 25);
						hidebeam = 0;
					}
				}
				if (w == 'd') {
					if (hideplants) {
						hideplants = 0;
						status("SHOWING DEBRIS", 25);
					} else {
						hideplants = 1;
						status("HIDING DEBRIS", 25);
					}
				}
				if ((w=='o' && showmapz == 0) || supvision == 3) {
                                  supmoose:
                                  if (supvision == 0 || supvision == 3) {
                              		memcpy(old_surface_palette, surface_palette, 768);
                                        shade(surface_palette, 0, 64, 0 , 0 , 0, 0 , 0 , 63);
                                        shade(surface_palette, 64, 64, 0 , 0 , 0, 0 , 40 , 63);
                                        shade(surface_palette, 128, 64, 0 , 0 , 0, 63 , 0 , 0);
                                        shade(surface_palette, 192, 64, 0 , 0 , 0, 63 , 63 , 0);
                                        tavola_colori (surface_palette, 0, 256, 63,63,63);
                                        status("SUPERVISION ON", 25);
                                        supvision = 1;
                                  } else {
					memcpy(surface_palette, old_surface_palette, 768);
				        tavola_colori (surface_palette, 0, 256, 63,63,63);
				        status("SUPERVISION OFF", 25);
					supvision=0;
                                  }
                                }
				if (w == 'p') {
                                        if (visionmode == 0)
                                        status("ULTRACOLOUR", 25);
                                        if (visionmode == 1)
                                        status("INFRARED", 25);
                                        if (visionmode == 2)
                                        status("OCEANVISION", 25);
                                        if (visionmode == 3)
                                        status("PLANTVISION", 25);
                                        visionmode++;
                                        if (visionmode == 5) {
                                          status("NORMAL", 25);
                                          visionmode = 0;
                                        }
                                }
				
				/*if (w == '0')
					fixed_step = 0;*/
				if (about && w == 27) {
					w = 0;
					about=0;
					goto endpmain;
				}
				if (w == 27 && landed) {
					sfh = CREATEFILE (surface_file);
					if (sfh ISFILEVALID) {
						WRITEFILE (sfh, &landing_pt_lon, 2);
						WRITEFILE (sfh, &landing_pt_lat, 2);
						WRITEFILE (sfh, &atl_x, 4);
						WRITEFILE (sfh, &atl_z, 4);
						WRITEFILE (sfh, &atl_x2, 4);
						WRITEFILE (sfh, &atl_z2, 4);
						WRITEFILE (sfh, &pos_x, 4);
						WRITEFILE (sfh, &pos_y, 4);
						WRITEFILE (sfh, &pos_z, 4);
						WRITEFILE (sfh, &user_alfa, 4);
						WRITEFILE (sfh, &user_beta, 4);
						WRITEFILE (sfh, &openhuddelta, 2);
						WRITEFILE (sfh, &openhudcount, 2);
						WRITEFILE (sfh, &hud_closed, 1);
						CLOSEFILE (sfh);
						exitflag = 1;
						goto nodissolve;
					}
				}
			}
		}
		endtype:	
		endpmain:
		
		if (option_change_over_time && colorMix==-1 && resolve==67 && secs>lsecs) {
			returnToStart=2;
			entryflag=0;
			tempn=1000;
		} else if (secs>lsecs-0.25 && showdebug) {
			status("UPDATING WEATHER ETC IN 1/4 SECOND", 80);
		}
		if (returnToStart) {
			break;
		}
	} while (1);

	/* operazioni di recupero per ritornare al ciclo principale. */

	// Dissolvenza al nero (blank frame di ritorno).
	
	//These prevent two fadeouts in a row.
	if (returnToStart==0 && resolve<67) {
		tavola_colori_brightness (surface_palette, 0, 256,
		       63, 63, 63, brightencnt);
		resolve=67;
	} else if (returnToStart!=2 && resolve==67) {
		for (w=64; w>=0; w-=4) {
			tavola_colori_brightness (surface_palette, 0, 256, w, w, w, brightencnt);
			ll = CLOCK(); while (ll == CLOCK()) {}
		}
	}
    nodissolve:
	if (returnToStart!=2) {
		pclear (adapted, 0);
		pclear (adaptor, 0);
	}
	
	if (!returnToStart) {
		dzat_x = backup_dzat_x;
		dzat_y = backup_dzat_y;
		dzat_z = backup_dzat_z;
		field_amplificator = bfa;
		pos_x = 0; pos_y = 0; pos_z = -3100;
		user_alfa = 0; user_beta = 0;
		dlt_alfa = 0; dlt_beta = 0;
		step = 100; shift = 0;
	}
	RecalcPlanetStuff(1);
	
	if (returnToStart) {
		//showmapz = 0;
		goto begin;
	}
	
	unloadallpv ();
	loadpv (vehicle_handle, vehicle_ncc, 15, 15, 15, 0, 0, 0, 0, 1);
	loadpv (mini_vehicle_handle, vehicle_ncc, 1e-6, 1e-6, 1e-6, 0, 0, 3050e-6, 0, 1);
		
	load_QVRmaps ();
	load_starface ();
	load_digimap2 ();

	npcs = -12345;
	if (goesnetCommandWasBlank) {
		goesnet_command[0] = 0;
	}
}
