#include <stdio.h>
#include <osbind.h>
#include <obdefs.h>

/* Celestial Caesarism  - Sept., 1986 - Jack B. Hardy */

int contrl[12],intin[128],ptsin[128],intout[128],ptsout[128],
	numships[9][20];
int handle,planets,explored,score,drive,
	port_state,hi_mask=0xF00,lo_mask=0x00FF,ch_enable=7,
	wr_command=128,rd_command=0,volume=1,
	cha_lo=0,cha_hi=1,chb_lo=2,chb_hi=3,cha_vol=8,chb_vol=9;
short contrl_grid[9][20],area_kn[9][20],a_grid[9][20],
	  industry[9][20],atari_xy[2];
short numplayers,bit_player,turn_num,maxturns,vis_ships,limit_pro,atari;
long f_length=3600;
char player[4][16],buffer[3600],
	 message1[]="Show Area Known and Controlled by Fleet Admiral ",
	 a_orders[]="Orders From Fleet Admiral ",
	 alert0[]="[3][ Celestial Caesarism | Requires Medium Resolution | ]\
[ RESTART ]",
	 path[]="A:\*.GAM\0",io_file[]="CELESTIA.GAM\0";
struct record{
	int eta;
	int owner;
	int shipsent;
	int xs;
	int ys;
	int xf;
	int yf;
	};
struct record orders[300];
extern double giaccess();

main()
{
	int dum,dum2,rez;

	appl_init();
	handle=graf_handle(&dum,&dum2,&dum,&dum2);
	init_vwk();
	color_reg(1,1000,900,0);
	color_reg(0,100,100,300);
	v_hide_c(handle);
	v_clrwk(handle);
	rez=Getrez();
	if (rez!=1)
		end_prg();
	else
		start_prg();
	color_reg(0,1000,1000,1000);
	color_reg(1,0,0,0);
	v_clsvwk(handle);
	appl_exit();
}

/* Open work station */

init_vwk()
{
	int i,l_intin[11],l_intout[57];

	for (i=0; i<10;l_intin[i++]=1);
	l_intin[10]=2;
	i=v_opnvwk(l_intin,&handle,l_intout);

	Giaccess(volume,cha_vol+wr_command);
	Giaccess(volume,chb_vol+wr_command);
	port_state=Giaccess(port_state,ch_enable+rd_command);
	Giaccess(60,ch_enable+wr_command);
	Giaccess(port_state,ch_enable+wr_command);
}

/* Change color register */

color_reg(reg,r,g,b)
int reg,r,g,b;
{
	int rgb_in[3];

	rgb_in[0]=r;
	rgb_in[1]=g;
	rgb_in[2]=b;
	vs_color(handle,reg,rgb_in);
}

/* End program if not medium resolution */

end_prg()
{
	v_show_c(handle,0);
	form_alert(1,alert0);
}

/* Delay loop */

wait(time)
long time;
{
	long length=0L;

	while(length<time) ++length;
}

/* The main program loop */

start_prg()
{
	int i,x,y,stat,tot_ships,tot_planets,a_ct,save_stat,load_stat,but=0;
	short t=0,quit=0;
	char message[70];

	save_stat= -1;
	atari= -1;
	title();
	load_stat=load_game();
	if(load_stat == -1)
	{
		get_info();
		load_grid();
	}
	color_reg(0,0,0,300);
	while(turn_num<maxturns)
	{
		for(i=0; i<=numplayers; i++)
		{
			v_hide_c(handle);
			v_clrwk(handle);
			draw_grid();
			draw_but(10,0,629,14);
			strcpy(message,message1);
			strcat(message,player[i]);
			graf_mouse(3,0);
			v_show_c(handle,0);
			a_ct=30;
			but=0;
			while(but==0)
			{
				text1(message,t);
				vq_mouse(handle,&stat,&x,&y);
				if(y<14) but=stat;
				wait(1000L);
				t=t^1;
				a_ct--;
				if((atari==i)&&(a_ct==0)) but=1;
			}
			if(atari==i) a_play(i); /* Let Atari play automatically */
			else	 /* Else collect information from human player */
			{
				v_hide_c(handle);
				vsl_color(handle,WHITE);
				draw_but(10,0,629,14);
				vsl_color(handle,BLACK);
				display_grid(i);
				vs_curaddress(handle,1,9);
  printf("  	Status Report For Fleet Admiral %s. 			  ",player[i]);
				count(&tot_ships,&tot_planets);
				vs_curaddress(handle,2,2);
  printf("Total Ships = %3d ~~ Total Planets = %2d ~~ ",tot_ships,tot_planets);
  printf("Known Area = %3d  ~~ Score = %5d",explored,score);
				if(tot_ships==0) /* If player lost all ships skip turn */
				{
					vs_curaddress(handle,23,30);
					puts("\007");
					puts("No Ships Available!!");
					wait(400000);
					break;
				}
				draw_l_box(1,1,10,166,630,176);
				find_orders();
				v_rvoff(handle);
			}
		}
		v_hide_c(handle);
		v_clrwk(handle);
		draw_grid();
		draw_but(10,0,629,14);
		vst_effects(handle,0);
v_gtext(handle,128,10,"Movement and Battle Phase - Press Button to Begin");
		vs_curaddress(handle,24,36);
		turn_num++;
		printf("Turn # %d",turn_num);
		but=0;
		while(but==0) vq_mouse(handle,&but,&x,&y);
		erase_line();
		move_players();
		pack_orders();
		add_industry();
		if(turn_num%5==0) show_status();
		vs_curaddress(handle,24,9);
		v_rvon(handle);
		puts("Press Left Button to Continue - Right Button to Save/Quit Game");
		v_rvoff(handle);
		but=0;
		while(but==0) vq_mouse(handle,&but,&x,&y);
		if(turn_num%5==0)
		{
		color_reg(0,0,0,300);
		color_reg(1,1000,900,0);
		}
		if(but==2)
		{
			save_stat=save_game();
			if(save_stat>-1) turn_num=maxturns;
		}
	}
	if(save_stat== -1) final_show();
}

/* Count players Ships / Planets */

count(tot_ships,tot_planets)
int *tot_ships,*tot_planets;
{
	int row,column,ships,planets;

	explored=0;
	score=0;
	ships=0;
	planets=0;

	for(row=0; row<=8; row++)
		for(column=0; column<=19; column++)
			if((area_kn[row][column]&bit_player)==bit_player)
			{
				explored++;
				score+=50;
				if((contrl_grid[row][column]&bit_player)==bit_player)
				{
					score+=numships[row][column]*10;
					ships+=numships[row][column];
					if((contrl_grid[row][column]&16)==16)
					{
						score+=500;
						planets++;
					}
				}
			}
	*tot_ships=ships;
	*tot_planets=planets;
}

/* Display message in form specified */

text1(message,t)
char message[70];
short int t;
{
	vst_effects(handle,t);
	vst_color(handle,GREEN);
	v_gtext(handle,80,10,message);
}

/* Display title screen */

title()
{
	int i;

	vst_effects(handle,16);
	char_height(24);
	vst_color(handle,BLACK);
	v_gtext(handle,156,56,"Celestial Caesarism");
	vst_effects(handle,0);
	vst_color(handle,RED);
	char_height(12);
	for(i=432; i>=216; i-=8) v_gtext(handle,i,80,"by Jack Hardy ");
	vst_color(handle,BLACK);
	char_height(6);
	for(i=0; i<=280; i+=4) v_gtext(handle,i,96," \275 1986");
}

/* Get player names - etc. */

get_info()
{
	char number,yn,ch,name[140];
	int i,in,fill,xy[2];

	while(yn!='Y' && yn!='y')
	{
		vst_color(handle,GREEN);
		vs_curaddress(handle,14,1);
		v_eeos(handle);
		v_gtext(handle,208,110," How many players?  (1 - 4)  ");
		vsin_mode(handle,4,1);
		number='0';
		while(number<'1' || number>'4') vrq_string(handle,1,0,xy,&number);
		vs_curaddress(handle,14,55);
		printf("%c",number);
		vst_color(handle,BLACK);
		numplayers=number-49;
		vs_curaddress(handle,16,1);
		v_rvon(handle);
		puts(" Please limit name to 15 characters ");
		v_rvoff(handle);
		for (i=0; i<=numplayers; i++)
		{
			in=0;
			for(fill=0; fill<=139; fill++) name[fill]='\000';
			printf("Enter name of player #%d => ",i+1);
			while((vrq_string(handle,1,0,xy,&ch))!=0)
			{
				if(ch=='\010')
				{
					in--;
					vs_curaddress(handle,17+i,28+in);
					v_eeol(handle);
				}
				else if(ch=='\177')
				{
					in=0;
					for(fill=0; fill<=139; fill++) name[fill]='\000';
					vs_curaddress(handle,17+i,28);
					v_eeol(handle);
				}
				else if((ch>'\37')&&(ch<'\173'))
				{
					putchar(ch);
					name[in]=ch;
					in++;
				}
			}
			puts("\007");
			name[15]='\000';
			strcpy(player[i],name);
		}
		if(numplayers<3) /* Let atari player if less than 4 humans */
		{
			if(numplayers==0) add_atari(); /* Atari plays if only one human */
			else
			{
				printf("Do you want Atari ST to play? [Y/N] ");
				yn=yes_no();
				if((yn=='y') || (yn=='Y')) add_atari();
			}
		}
		maxturns=0;
		while(maxturns<10 || maxturns>25) /* Set maximun number of turns */
		{
			vs_curaddress(handle,16,1);
			v_eeos(handle);
			puts("Press space bar to terminate input.");
			printf("How many turns would you like to play? [10-25] ");
			scanf("%2d",&maxturns);
			putchar('\n');
		}
		vis_ships=0;
		printf("Show enemy ships? [Y/N] ");
		yn=yes_no();
		if((yn=='y') || (yn=='Y')) vis_ships=1;
		limit_pro=0;
		printf("Limit neutral planet ship production? [Y/N] ");
		yn=yes_no();
		if((yn=='y') || (yn=='Y')) limit_pro=1;
		vs_curaddress(handle,16,1);
		v_eeos(handle);
		for(i=0; i<=numplayers; i++)
			printf("Player #%d is %s.\n",i+1,player[i]);
		printf("The number of turns = %d.\n",maxturns);
		printf("See enemy ships = ");
		if(vis_ships==1) puts("YES ");
		else puts("NO ");
		printf("Limit neutral planet ship production = ");
		if(limit_pro==1) puts("YES ");
		else puts("NO ");
		printf("\nAll entries correct? [Y/N] ");
		yn=yes_no();
	}
}

/* Change size of printed characters */

char_height(height)
int height;
{
int char_width,char_height,cell_width,cell_height;

vst_height(handle,height,&char_width,&char_height,&cell_width,&cell_height);
}

/* Increase players and let Atari enter name */

add_atari()
{
	int i;
	static char at_string[]="Atari ST\0";

	numplayers++;
	atari=numplayers;
	strcpy(player[numplayers],at_string);
	printf("Enter name of player #%d => ",numplayers+1);
	for(i=0;i<=7;i++)
	{
		printf("%c",at_string[i]);
		wait(8000L);
	}
	putchar('\n');
	wait(270000L);
}

/* Wait for Y or N keys to be pressed */

yes_no()
{
	int xy[2];
	char yn='x';

	while((yn!='Y') && (yn!='y') && (yn!='N') && (yn!='n'))
		vrq_string(handle,1,0,xy,&yn);
	printf("%c\n",yn);
	return(yn);
}

/* Draw grid to screen  */

draw_grid()
{
	int pxyarray[4],x,y,i;
	x=0;
	y=16;

	fill_area();
	vsl_color(handle,BLACK);
	pxyarray[0]=x;
	pxyarray[2]=x+639;
	for (i=y; i<y+145; i=i+16) /* draw lines across */
	{
		pxyarray[1]=i;
		pxyarray[3]=i;
		v_pline(handle,2,pxyarray);
	}

	pxyarray[1]=y;     /* draw lines down */
	pxyarray[3]=y+144;
	for (i=x; i<x+640; i=i+32)
	{
		pxyarray[0]=i;
		pxyarray[2]=i;
		v_pline(handle,2,pxyarray);
	}
draw_line();
}

/* Draw line down right edge of screen */

draw_line()
{
	int pxyarray[4];

	pxyarray[0]=639;
	pxyarray[1]=16;
	pxyarray[2]=639;
	pxyarray[3]=160;
	v_pline(handle,2,pxyarray);
}

/* Draw and fill area with color red */

fill_area()
{
	vsf_style(handle,3);
	draw_l_box(3,RED,0,16,639,160);
}

/* Make square transparent or solid */

shade_area(x,y,mode)
int x,y,mode;
{
	v_hide_c(handle);
	vsf_style(handle,1);
	vswr_mode(handle,mode);
	draw_l_box(2,BLACK,x*32+1,y*16+17,x*32+31,y*16+31);
	vswr_mode(handle,1);
	v_show_c(handle);
}

/* Draw button in area, size, and color passed */

draw_l_box(index,color,x,y,x2,y2)
int index,color,x,y,x2,y2;
{
	int pxy[4];

	vsf_interior(handle,index);
	vsf_color(handle,color);
	pxy[0]=x;
	pxy[1]=y;
	pxy[2]=x2;
	pxy[3]=y2;
	v_bar(handle,pxy);
}

/* Set up initial board with planets and player positions */

load_grid()
{
	int i,row,column,player;

	player=1;
	for(i=0; i<=numplayers; i++)
	{
		selec_rc(&row,&column);
		contrl_grid[row][column]=player+16;
		area_kn[row][column]=player;
		numships[row][column]=60;   /* Add ships if player at edge */
		if(column<9) numships[row][column]+=36-(column*4);
		if(column>10) numships[row][column]+=4*column-40;
		if(row<4) numships[row][column]+=16-(row*4);
		if(row>4) numships[row][column]+=4*row-16;
		industry[row][column]=15;
		player*=2;
		if(atari==i)
		{
			atari_xy[0]=column;
			atari_xy[1]=row;
			a_grid[row][column]=1;
		}
	}
	planets=(Random() & 15)+30;  /* Number of neutral planets 30-45 */
	for(i=0; i<=planets; i++)
	{
		selec_rc(&row,&column);
		contrl_grid[row][column]=16;
		industry[row][column]=(Random() & 3)+3;
		numships[row][column]=industry[row][column];
	}
}

/* Choose row and column from grid */

selec_rc(row,column)
int *row,*column;
{
	int num1,num2;

	do  	 /* Choose random number within grid */
	{
		num1=9;
		while (num1>8) num1=Random() & 15;
		num2=20;
		while(num2>19) num2=Random() & 31;
	}
	while(contrl_grid[num1][num2]>0);  /* If occupied, choose another */

	*row=num1;
	*column=num2;
}

/* Draw box for button */

draw_but(x,y,x2,y2)
int x,y,x2,y2;
{
	int xyarray[4];

	xyarray[0]=x;
	xyarray[1]=y;
	xyarray[2]=x2;
	xyarray[3]=y2;
	v_rbox(handle,xyarray);
}

/* Show player area known and controlled */

display_grid(player)
int player;
{
	int row,column,pxy[4],x,y,color;

	bit_player=num_player(player);
	for(row=0; row<=8; row++)   /* player control checked by bits */
		for(column=0; column<=19; column++)
			if((area_kn[row][column]&bit_player)==bit_player)
			{
				vsf_interior(handle,1);
				vsf_color(handle,WHITE);
				pxy[0]=column*32+1;
				pxy[1]=row*16+17;
				pxy[2]=column*32+31;
				pxy[3]=row*16+30;
				v_bar(handle,pxy);
				x=column*32+15;
				y=row*16+23;
				if((contrl_grid[row][column]&bit_player)==bit_player)
				{   /* Show planets and ships */
					vst_color(handle,GREEN);
					if(numships[row][column] != 0)
						v_gtext(handle,x-3,y+3,"\177");
					if((contrl_grid[row][column] & 16)==16)
							draw_planet(x,y,GREEN);
				}
				else if((contrl_grid[row][column] & 31)!=0)
				{   /* If enemy, show in red - neutral planet yellow */
					vst_color(handle,RED);
					if((numships[row][column]>0)&&(vis_ships>0))
						v_gtext(handle,x-3,y+3,"\177");
					if((contrl_grid[row][column]&16)==16)
					{
						color=1;
						if((contrl_grid[row][column] & 15)!=0)
							color=RED;
						draw_planet(x,y,color);
					}
				}
			}
	vst_color(handle,GREEN);
	draw_line();
}

/* Find bit that controls each player */

num_player(player)
int player;
{
	int i=0,num=1;

	while(i!=player)
	{
		num*=2;
		i++;
	}
	return(num);
}

/* Draw planet in color passed to procedure */

draw_planet(x,y,color)
int x,y,color;
{
	vsf_color(handle,color);
	vsf_interior(handle,2);
	vsf_style(handle,14);
	v_circle(handle,x,y,8);
	v_contourfill(handle,x,y,color);
}

/* Accept player input from mouse */

find_orders()
{
	int x,y,ox,oy,i,stat,but,numsh,fleet,empty,end=0;
	int lt_rt,up_dn,moves,equal_moves,total_moves;

	empty=find_start();
	but=0;
	while(but!=2)
	{
		v_rvon(handle);
		vs_curaddress(handle,22,24);
		puts(" ARMADA = ?    ");
		vs_curaddress(handle,22,45);
		puts(" DESTINATION ");
		vs_curaddress(handle,22,64);
		puts(" ETA = ?   ");
		numsh=0;
		while(numsh==0)
		{
			vs_curaddress(handle,24,22);
			v_rvoff(handle);
			puts("- Push Right Mouse Button To End Turn -");
			graf_mouse(7,0);  /* Change mouse to crosshairs */
			v_show_c(handle,0);
			but=0;
			while(but==0)
			{
				v_rvoff(handle);
				flash_text(10,"ORIGIN");
				v_rvon(handle);
				flash_text(10,"ORIGIN");
				vq_mouse(handle,&stat,&x,&y);
				if(y>16 && y<160) but=stat;
				if(stat==2)
				{
					but=2;
					vs_curaddress(handle,24,16);
		   puts("\007 Continue - Left Button / End Turn - Right Button ");
					while(but!=0) vq_mouse(handle,&but,&x,&y);
					while(but==0) vq_mouse(handle,&but,&x,&y);
					erase_line();
					wait(1000L);
					if(but==1) but=0;
					if(but==2) end=2;
				}
			}
			if(end==2) break;
			erase_line();
			x/=32;y-=16;y/=16;ox=x;oy=y;
			if((contrl_grid[y][x] & bit_player)!=bit_player)
			{
				vs_curaddress(handle,24,21);
				puts("\007 That Sector Is Not Controlled By You!!");
				wait(150000);
				erase_line();
			}
			else
			{
				shade_area(x,y,2);
				if(industry[y][x]>0)
				{
					vs_curaddress(handle,24,22);
			printf("Planet Manufactures %d Ships Per Turn.",industry[y][x]);
				}
				if(numships[y][x]>0)
				{
					numsh=numships[y][x];
					vs_curaddress(handle,22,34);
					v_rvon(handle);
					printf(" %d",numsh);
				}
				else
				{
					v_rvoff(handle);
					vs_curaddress(handle,24,22);
				puts("\007 No Ships Available In This Sector!!  	");
					wait(150000);
					erase_line();
					shade_area(x,y,3);
					if(x==19) draw_line();
				}
			}
		}
		if(end==2) break;
		while(but!=0) vq_mouse(handle,&but,&x,&y);
		while(but==0)
		{
			v_rvoff(handle);
			flash_text(45,"DESTINATION");
			v_rvon(handle);
			flash_text(45,"DESTINATION");
			vq_mouse(handle,&stat,&x,&y);
			if(y>16 && y<160) but=stat;
		}
		erase_line();
		x/=32;y-=16;y/=16;
		if(x==ox && y==oy)
		{
			shade_area(x,y,3);
			if(x==19) draw_line();
		}
		else
		{
			lt_rt=0;
			up_dn=0;
			shade_area(x,y,2);
			lt_rt=(x<ox) ? ox-x : x-ox;
			up_dn=(y<oy) ? oy-y : y-oy;
			moves=(up_dn<lt_rt) ? lt_rt-up_dn : up_dn-lt_rt;
			equal_moves=(up_dn<lt_rt) ? lt_rt-moves : up_dn-moves;
			total_moves=equal_moves+moves;
			if(total_moves>1) total_moves/=2;
			v_rvon(handle);
			vs_curaddress(handle,22,70);
			printf(" %d",total_moves);
			fleet=send_ships(numsh);
			vs_curaddress(handle,23,1);
			v_hide_c(handle);
			v_eeos(handle);
			if(fleet>0)
			{
				numships[oy][ox]-=fleet;
				orders[empty].eta=total_moves;
				orders[empty].owner=bit_player;
				orders[empty].shipsent=fleet;
				orders[empty].xs=x;
				orders[empty].ys=y;
				orders[empty].xf=ox;
				orders[empty].yf=oy;
				empty++;
			}
		}
		shade_area(x,y,3);
		shade_area(ox,oy,3);
		if((x==19)||(ox==19)) draw_line();
	}
}

/* Erase text line from bottom of screen */

erase_line()
{
	vs_curaddress(handle,24,10);
	v_rvoff(handle);
	printf("														 ");
}

/* Display text in inverse or standard */

flash_text(x,text)
int x;
char text[12];
{
	vs_curaddress(handle,22,x);
	printf(" %s ",text);
	wait(6000L);
}

/* Find number of ships to send */

send_ships(total)
int total;
{
	int num=0,send=0,button=0,stat,x,y;

	graf_mouse(3,0);
	while(send==0)
	{
		v_hide_c(handle);
		draw_l_box(0,RED,204,180,356,194);
		v_rvoff(handle);
		vs_curaddress(handle,24,28);
		printf("Send %3d Ship(s)",num);
		draw_l_box(0,RED,384,180,402,194);
		v_gtext(handle,390,190,"\001");
		draw_l_box(0,RED,408,180,426,194);
		v_gtext(handle,414,190,"\002");
		v_show_c(handle,0);
		while(button!=1)
		{
			vq_mouse(handle,&stat,&x,&y);
			if(y>180 && y<194)
				button=stat;
		}
		v_hide_c(handle);
		if(x>204 && x<356)
		{
			send=1;
			draw_l_box(1,1,205,181,355,193);
			v_rvon(handle);
			vs_curaddress(handle,24,28);
			printf("Send %3d Ship(s)",num);
			v_rvoff(handle);
			v_show_c(handle,0);
			while(button==1)
				vq_mouse(handle,&button,&x,&y);
		}
		if(x>384 && x<402)
		{
			draw_l_box(1,1,385,181,401,193);
			v_gtext(handle,390,190,"\001");
			v_show_c(handle,0);
			while(button==1)
			{
				num+=1;
				if(num>total) num=total;
				vs_curaddress(handle,24,33);
				printf("%3d",num);
				wait(5000L);
				vq_mouse(handle,&button,&x,&y);
			}
		}
		if(x>408 && x<426)
		{
			draw_l_box(1,1,409,181,425,193);
			v_gtext(handle,414,190,"\002");
			v_show_c(handle,0);
			while(button==1)
			{
				num-=1;
				if(num<0) num=0;
				vs_curaddress(handle,24,33);
				printf("%3d",num);
				wait(5000L);
				vq_mouse(handle,&button,&x,&y);
			}
		}
		v_show_c(handle,0);
		button=0;
	}
	return(num);
}

/* Find empty spot in structured array to store orders */

find_start()
{
	int i=0;

	while(orders[i].eta != 0) i++;
	return(i);
}

/* Read orders and execute */

move_players()
{
	int i=0,x,y,results,planet,num;
	short temp;
	char message[60];

	while(orders[i].eta != 0)
	{
		orders[i].eta--;
		if(orders[i].eta==0)
		{
			num=find_admiral(orders[i].owner);
			strcpy(message,a_orders);
			strcat(message,player[num]);
			vs_curaddress(handle,1,1);
			puts("\007");
			vst_color(handle,WHITE);
			v_gtext(handle,40,10,"000000000000000000000000000000000000000000");
			v_gtext(handle,320,10,"00000000000000000000000000000000000");
			vst_color(handle,RED);
			v_gtext(handle,136,10,message);
			x=orders[i].xs;
			y=orders[i].ys;
			temp=(area_kn[y][x]&15);
			temp=(temp | orders[i].owner);
			area_kn[y][x]=temp;
			shade_area(x,y,2);
			if(numships[y][x] != 0) /* If other ships occupy grid - fight */
			{
				results=battle(x,y,i);
				vs_curaddress(handle,24,23);
				switch(results)
				{
					case 0:
						printf("**  Attacker Was Defeated!!  **");
						break;
					case 1:
						printf("	Attacker Was Suscessful!!");
						numships[y][x]=orders[i].shipsent;
						planet=(contrl_grid[y][x]&16);
						contrl_grid[y][x]=orders[i].owner+planet;
						break;
					case 2:
				printf("Area reinforced with %d ship(s).",orders[i].shipsent);
						numships[y][x]+=orders[i].shipsent;
						break;
					case 3:
						printf(" ~~  Attacker Retreated!!  ~~");
						orders[i].eta=(Random() & 3)+1;
						orders[i].xs=orders[i].xf;
						orders[i].ys=orders[i].yf;
						orders[i].xf=Random()&15;
						orders[i].yf=Random()&7;
						break;
				}
			}
			else
			{
				vs_curaddress(handle,24,27);
				printf(" ^^^ %d Ship(s) Arriving. ^^^",orders[i].shipsent);
				planet=(contrl_grid[y][x]&16);
				contrl_grid[y][x]=orders[i].owner+planet;
				numships[y][x]=orders[i].shipsent;
			}
			wait(250000);
			shade_area(x,y,3);
			if(x==19) draw_line();
			erase_line();
			vs_curaddress(handle,22,1);
			v_hide_c(handle);
			v_eeos(handle);
			v_show_c(handle);
		}
		i++;
	}
}

/* Execute battle and return results */

battle(x,y,ord)
int x,y,ord;
{
	int num,dshots,ashots,achance,dchance,attships,player,maxshots;
	int quit=1,i,mx,my,hit,won_lost,button,stop=0,shields=1,dshields=0;

	if((contrl_grid[y][x]&orders[ord].owner)==orders[ord].owner)
		won_lost=2;
	else
	{
		draw_l_box(1,1,2,166,637,176);
		achance=(Random()&31)+69;
		dchance=(Random()&31)+69;
		v_rvon(handle);
		vs_curaddress(handle,22,2);
		attships=orders[ord].shipsent;
		printf("Attacker has %3d ships -%3d%% accuracy --",attships,achance);
		vs_curaddress(handle,22,43);
	 printf("Defender has %3d ships -%3d%% accuracy",numships[y][x],dchance);
		vs_curaddress(handle,24,12);
		printf(" Press left button to attack - right button to retreat! ");
		player=find_admiral(orders[ord].owner);
		if(player==atari)
		{
			wait(30000L);
			if((numships[y][x]/attships)>2) quit=0;
		}
		else
		{
			while(button!=0) vq_mouse(handle,&button,&mx,&my);
			while(button==0) vq_mouse(handle,&button,&mx,&my);
			if(button==2) quit=0;
			while(button!=0) vq_mouse(handle,&button,&mx,&my);
		}
		erase_line();
		while(orders[ord].shipsent>0 && numships[y][x]>0 && quit>0)
		{
			v_rvon(handle);
			dshots=numships[y][x];
			if((contrl_grid[y][x]&15)!=0)
			{
				dshots+=numships[y][x]/2;
				if((contrl_grid[y][x]&16)==16)
				{
					dshots+=numships[y][x]/2;
					shields=2;
					dshields=1;
				}
			}
			ashots=orders[ord].shipsent;
			maxshots=(ashots>dshots) ? ashots : dshots;
			for(i=1; i<=maxshots; i++)
			{
				if(ashots>0)
				{
					ashots--;
					fire(170);
					hit=odds(achance);
					if(hit==1)
					{
						if(dshields==0)
						{
							numships[y][x]--;
							vs_curaddress(handle,22,55);
							printf("%4d",numships[y][x]);
							dshields=shields;
						}
						hit_sound();
						dshields--;
					}
					sound_off();
					if(numships[y][x]==0)
					{
						stop=1;
						break;
					}
				}
				if(dshots>0)
				{
					dshots--;
					fire(480);
					hit=odds(dchance);
					if(hit==1)
					{
						orders[ord].shipsent--;
						vs_curaddress(handle,22,14);
						printf("%4d",orders[ord].shipsent);
						hit_sound();
					}
					sound_off();
					if(orders[ord].shipsent==0)
					{
						stop=1;
						break;
					 }
				}
				vq_mouse(handle,&button,&mx,&my);
				if(button!=0)
				{
					vs_curaddress(handle,24,12);
					v_rvoff(handle);
			printf("Left button to continue attack - Right button to retreat");
					while(button!=0) vq_mouse(handle,&button,&mx,&my);
					while(button==0) vq_mouse(handle,&button,&mx,&my);
					erase_line();
					v_rvon(handle);
					if(button==2) quit=0;
				}
				if(quit==0) break;
				if(stop==1) break;
			}
		}
		won_lost=(orders[ord].shipsent>numships[y][x])? 1 : 0;
	}
	if(quit==0)
	{
		won_lost=3;
		if(orders[ord].shipsent>10)
			orders[ord].shipsent-=orders[ord].shipsent/10;
	}
	v_rvoff(handle);
	return(won_lost);
}

/* Move orders in array to fill empty spaces */

pack_orders()
{
	int i,start,empty;

	empty=find_start();
	start=empty;
	for(i=start; i<=300; i++)
		if(orders[i].eta != 0)
		{
			orders[empty].eta=orders[i].eta;
			orders[i].eta=0;
			orders[empty].owner=orders[i].owner;
			orders[empty].shipsent=orders[i].shipsent;
			orders[empty].xs=orders[i].xs;
			orders[empty].ys=orders[i].ys;
			orders[empty].xf=orders[i].xf;
			orders[empty].yf=orders[i].yf;
			empty++;
		}
}

/* Draw expanding red box and create sound */

fire(side)
int side;
{
	char note_hi,note_lo;
	int i,tone1=202,tone2=304;

	volume=10;

	Giaccess(volume,cha_vol+wr_command);
	Giaccess(volume,chb_vol+wr_command);
	for(i=4; i<=152; i+=4)
	{
		draw_l_box(1,RED,side-i,182,side+i,196);
		tone1-=4;
		note_hi=(tone1&hi_mask)>>8;
		note_lo=(tone1&lo_mask);
		Giaccess(note_lo,cha_lo+wr_command);
		Giaccess(note_hi,cha_hi+wr_command);
		tone2-=4;
		note_hi=(tone2&hi_mask)>>8;
		note_lo=(tone2&lo_mask);
		Giaccess(note_lo,chb_lo+wr_command);
		Giaccess(note_hi,chb_hi+wr_command);
		wait(100L);
	}
	draw_l_box(0,0,side-i,182,side+i,196);
}

/* Calulate chance of miss or hit */

odds(chance)
int chance;
{
	int shot,results;

	do
		shot=Random() & 127;
	while(shot>100);

	results=(shot>chance)? 0:1;
	return(results);
}

/* Build ships for each planet */

add_industry()
{
	int r,c;

	for(r=0; r<=8; r++)
		for(c=0; c<=19; c++)
		{
			numships[r][c]+=industry[r][c];
		if((limit_pro==1)&&((contrl_grid[r][c]&15)==0)&&(numships[r][c]>30))
				numships[r][c]=30;
		}
}

/* Find player number */

find_admiral(i)
int i;
{
	int results;
	results=i;

	if(i<4) results-=1;
	else results/=2;
	if(results==4) results-=1;

	return(results);
}

/* BANG */

hit_sound()
{
	char note_hi,note_lo;
	int tone1,tone2;

	volume=15;

	Giaccess(volume,cha_vol+wr_command);
	Giaccess(volume,chb_vol+wr_command);
	for(tone1=1280; tone1<=2580; tone1+=10)
	{
		tone2=tone1+640;
		note_hi=(tone1&hi_mask)>>8;
		note_lo=(tone1&lo_mask);
		Giaccess(note_lo,cha_lo+wr_command);
		Giaccess(note_hi,cha_hi+wr_command);
		note_hi=(tone2&hi_mask)>>8;
		note_lo=(tone2&lo_mask);
		Giaccess(note_lo,chb_lo+wr_command);
		Giaccess(note_hi,chb_hi+wr_command);
		wait(120L);
	}
}

/* Show status of all players each 5 turns */

show_status()
{
	int i,but,x,y,tot_ships,tot_planets,admiral=1;

	v_hide_c(handle);
	color_reg(1,0,0,0);
	color_reg(0,1000,1000,1000);
	v_clrwk(handle);
	v_rvon(handle);
	vs_curaddress(handle,1,32);
	printf(" Turn # %d ",turn_num);
	if(turn_num==maxturns) puts("  GAME OVER! ");
	for(i=0; i<=numplayers; i++)
	{
		v_rvon(handle);
		vs_curaddress(handle,i*5+3,15);
		printf("~~~~~~~ Status of Fleet Admiral %s ~~~~~~~",player[i]);
		v_rvoff(handle);
		bit_player=admiral;
		admiral*=2;
		count(&tot_ships,&tot_planets);
		vs_curaddress(handle,i*5+4,30);
		printf("Total Ships = %d",tot_ships);
		vs_curaddress(handle,i*5+5,30);
		printf("Total Planets = %d",tot_planets);
		vs_curaddress(handle,i*5+6,30);
		printf("Known Area = %d",explored);
		vs_curaddress(handle,i*5+7,30);
		printf("Score = %d",score);
	}
}

/* Kill sound */

sound_off()
{
	Giaccess(0,cha_vol+wr_command);
	Giaccess(0,chb_vol+wr_command);
}

/* Show final grid for all players */

final_show()
{
	int i,tot_ships,tot_planets,but,x,y;

	v_hide_c(handle);
	vst_color(handle,GREEN);
	for(i=0; i<=numplayers; i++)
	{
		v_clrwk(handle);
		draw_grid();
		display_grid(i);
		vs_curaddress(handle,1,9);
		printf("  Final Status Report For Fleet Admiral %s. ",player[i]);
		count(&tot_ships,&tot_planets);
		vs_curaddress(handle,2,2);
  printf("Total Ships = %3d ~~ Total Planets = %2d ~~ ",tot_ships,tot_planets);
		printf("Known Area = %3d  ~~ Score = %5d",explored,score);
		vs_curaddress(handle,24,26);
		v_rvon(handle);
		puts("  Press Button to Continue  ");
		v_rvoff(handle);
		but=0;
		while(but==0) vq_mouse(handle,&but,&x,&y);
	}
	v_show_c(handle,0);
}

/* Atari's turn to play */

a_play(player) /*  Check for Atari control */
int player;
{
	int r,c,p;

	bit_player=num_player(player);
	p=bit_player;

	for(r=0;r<=8;r++)
		for(c=0;c<=19;c++)
			if(((contrl_grid[r][c]&p)==p)&&(numships[r][c]>0)) search(r,c);
}

/* Search for unexplored territory and planets to attack */

search(r,c)  /* Four search patterns for orders */
int r,c;
{
	int x,y,pattern,flag=0;

	pattern=Random()&3;
	switch(pattern)  /* Primary orders search and attack */
	{
	case 0:
		for(y=r-3;y<=r+3;y++)
			for(x=c-3;x<=c+3;x++)
				if((x>-1)&&(x<20)&&(y>-1)&&(y<9)&&(numships[r][c]>0))
					flag=primary_orders(r,c,y,x);
		break;
	case 1:
		for(x=c-3;x<=c+3;x++)
			for(y=r-3;y<=r+3;y++)
				if((x>-1)&&(x<20)&&(y>-1)&&(y<9)&&(numships[r][c]>0))
					flag=primary_orders(r,c,y,x);
		break;
	case 2:
		for(y=r+3;y>=r-3;y--)
			for(x=c+3;x>=c-3;x--)
				if((x>-1)&&(x<20)&&(y>-1)&&(y<9)&&(numships[r][c]>0))
					flag=primary_orders(r,c,y,x);
		break;
	case 3:
		for(x=c+3;x>=c-3;x--)
			for(y=r+3;y>=r-3;y--)
				if((x>-1)&&(x<20)&&(y>-1)&&(y<9)&&(numships[r][c]>0))
					flag=primary_orders(r,c,y,x);
		break;
	}
	if(flag==0)
	{
	switch(pattern) /* Secondary orders re-inforce planet */
	{
	case 0:
		for(y=r-3;y<=r+3;y++)
			for(x=c-3;x<=c+3;x++)
				if((x>-1)&&(x<20)&&(y>-1)&&(y<9)&&(numships[r][c]>0))
					flag=secondary_orders(r,c,y,x);
		break;
	case 1:
		for(x=c-3;x<=c+3;x++)
			for(y=r-3;y<=r+3;y++)
				if((x>-1)&&(x<20)&&(y>-1)&&(y<9)&&(numships[r][c]>0))
					flag=secondary_orders(r,c,y,x);
		break;
	case 2:
		for(y=r+3;y>=r-3;y--)
			for(x=c+3;x>=c-3;x--)
				if((x>-1)&&(x<20)&&(y>-1)&&(y<9)&&(numships[r][c]>0))
					flag=secondary_orders(r,c,y,x);
		break;
	case 3:
		for(x=c+3;x>=c-3;x--)
			for(y=r+3;y>=r-3;y--)
				if((x>-1)&&(x<20)&&(y>-1)&&(y<9)&&(numships[r][c]>0))
					flag=secondary_orders(r,c,y,x);
		break;
	}
	}
	if((flag==0)&&((contrl_grid[r][c]&16)!=16)) go_home(r,c);
}

/* Explore and attack */

primary_orders(r,c,y,x)
int r,c,y,x;
{
	int flag=0;

	if((contrl_grid[r][c]&16)==16)
	{
		if(numships[r][c]>15)
		{
			if(a_grid[y][x]==0)
			{
				if(turn_num==0) store_a_orders(r,c,y,x,5);
				else store_a_orders(r,c,y,x,1);
				a_grid[y][x]=1;
			}
			if((area_kn[y][x]&bit_player)==bit_player)
			{
				if((contrl_grid[y][x]&31)==16)
					s_a_fleet(r,c,y,x);
				if(((contrl_grid[y][x]&31)>16)&&(numships[y][x]<10))
					s_a_fleet(r,c,y,x);
			}
		}
		flag=1;
	}
	else if(a_grid[y][x]==0)
	{
		store_a_orders(r,c,y,x,1);
		a_grid[y][x]=1;
		flag=1;
	}
	return(flag);
}

/* Re-inforce planets */

secondary_orders(r,c,y,x)
int r,c,y,x;
{
	int ct,fleet,flag=0;

	ct=bit_player+16;
	if((contrl_grid[y][x]&ct)==ct)
	{
		if(((contrl_grid[r][c]&16)==16)&&(numships[r][c]>20))
		{
			fleet=numships[r][c]-15;
			store_a_orders(r,c,y,x,fleet);
		}
		else store_a_orders(r,c,y,x,numships[r][c]);
		flag=1;
	}
	return(flag);
}

/* Send a fleet to conquer */

s_a_fleet(r,c,y,x)
int r,c,y,x;
{
	int fleet;

	if(numships[r][c]>25)
	{
		fleet=numships[r][c]-12;
		if(fleet>(6*turn_num+6))
		{
			fleet=6*turn_num+6;
			store_a_orders(r,c,y,x,fleet);
		}
		else if((limit_pro==1)&&(turn_num>4)&&(fleet>35))
		{
			fleet=35;
			store_a_orders(r,c,y,x,fleet);
		}
	}
}

/* Unable to explore or conquer - go to home planet */

go_home(r,c)
int r,c;
{
	int x,y;

	x=atari_xy[0];
	y=atari_xy[1];
	store_a_orders(r,c,y,x,numships[r][c]);
}

/* Place Atari orders in array */

store_a_orders(r,c,y,x,fleet)
int r,c,y,x,fleet;
{
	int empty;

	empty=find_start();
	numships[r][c]-=fleet;
	orders[empty].eta=1;
	orders[empty].owner=bit_player;
	orders[empty].shipsent=fleet;
	orders[empty].xs=x;
	orders[empty].ys=y;
	orders[empty].xf=c;
	orders[empty].yf=r;
}

/* Save for a later date */

save_game()
{
	int button,wr_handle,i,j,ct;

	wr_handle= -1;
	for(i=0;i<=8;i++)
		for(j=0;j<=19;j++)
		{
			buffer[j+(i*20)]=contrl_grid[i][j];
			buffer[j+180+(i*20)]=area_kn[i][j];
			buffer[j+360+(i*20)]=numships[i][j];
			buffer[j+540+(i*20)]=industry[i][j];
			buffer[j+720+(i*20)]=a_grid[i][j];
		}
	for(i=0;i<=3;i++)
		for(j=0;j<=20;j++)
			buffer[j+900+(i*21)]=player[i][j];
	buffer[1000]=numplayers;
	buffer[1001]=turn_num;
	buffer[1002]=maxturns;
	buffer[1003]=vis_ships;
	buffer[1004]=limit_pro;
	buffer[1005]=atari;
	buffer[1006]=atari_xy[0];
	buffer[1007]=atari_xy[1];
	ct=find_start();
	buffer[1008]=ct;
	for(i=0;i<=ct;i++)
	{
		buffer[1010+(i*7)]=orders[i].eta;
		buffer[1011+(i*7)]=orders[i].owner;
		buffer[1012+(i*7)]=orders[i].shipsent;
		buffer[1013+(i*7)]=orders[i].xs;
		buffer[1014+(i*7)]=orders[i].ys;
		buffer[1015+(i*7)]=orders[i].xf;
		buffer[1016+(i*7)]=orders[i].yf;
	}
	v_show_c(handle,0);
	drive=Dgetdrv();
	path[0]=(drive+'A');

	fsel_input(path,io_file,&button);
	if(button!=0)
	{
		wr_handle=Fcreate(io_file,0);
		if(wr_handle> -1)
			Fwrite(wr_handle,f_length,buffer);
		Fclose(wr_handle);
	}
	v_hide_c(handle);
	return(wr_handle);
}

/* Restore old game */

load_game()
{
	int button,rd_handle,i,j,ct;
	char rn;

	rd_handle= -1;
	rn=question();
	if(rn=='R' || rn=='r')
	{
		v_show_c(handle,0);
		drive=Dgetdrv();
		path[0]=(drive+'A');

		fsel_input(path,io_file,&button);
		if(button!=0)
		{
			rd_handle=Fopen(io_file,0);
			if(rd_handle>-1)
				Fread(rd_handle,f_length,buffer);
			Fclose(rd_handle);
			for(i=0;i<=8;i++)
				for(j=0;j<=19;j++)
				{
					contrl_grid[i][j]=buffer[j+(i*20)];
					area_kn[i][j]=buffer[j+180+(i*20)];
					numships[i][j]=buffer[j+360+(i*20)];
					industry[i][j]=buffer[j+540+(i*20)];
					a_grid[i][j]=buffer[j+720+(i*20)];
				}
			for(i=0;i<=3;i++)
				for(j=0;j<=20;j++)
					player[i][j]=buffer[j+900+(i*21)];
			numplayers=buffer[1000];
			turn_num=buffer[1001];
			maxturns=buffer[1002];
			vis_ships=buffer[1003];
			limit_pro=buffer[1004];
			atari=buffer[1005];
			atari_xy[0]=buffer[1006];
			atari_xy[1]=buffer[1007];
			ct=buffer[1008];
			for(i=0;i<=ct;i++)
			{
				orders[i].eta=buffer[1010+(i*7)];
				orders[i].owner=buffer[1011+(i*7)];
				orders[i].shipsent=buffer[1012+(i*7)];
				orders[i].xs=buffer[1013+(i*7)];
				orders[i].ys=buffer[1014+(i*7)];
				orders[i].xf=buffer[1015+(i*7)];
				orders[i].yf=buffer[1016+(i*7)];
			}
		}
		v_hide_c(handle);
	}
	return(rd_handle);
}

/* New game or old */

question()
{
	char rn;
	int xy[2];

	vs_curaddress(handle,14,27);
	v_rvon(handle);
	printf("N");
	v_rvoff(handle);
	printf("ew game - ");
	v_rvon(handle);
	printf("R");
	v_rvoff(handle);
	printf("estore old game");
	while((rn!='r')&&(rn!='R')&&(rn!='n')&&(rn!='N'))
		vrq_string(handle,1,0,xy,&rn);
	return(rn);
}
