 /*****************************************************************************
 **  This is part of the SpaceZero program
 **  Copyright(C) 2006-2011  M.Revenga
 **
 **  This program is free software; you can redistribute it and/or modify
 **  it under the terms of the GNU General Public License (version 3), or
 **  (at your option) any later version, as published by the Free Software 
 **  Foundation.
 **
 **  This program is distributed in the hope that it will be useful,
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 **  GNU General Public License for more details.
 **
 **  You should have received a copy of the GNU General Public License
 **  along with this program; if not, write to the Free Software
 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 ******************************************************************************/

/*************  SpaceZero  M.R.H. 2006-2011 ******************
		Author: M.Revenga
		E-mail: mrevenga at users.sourceforge.net
		version 0.80 May 2011
****/

#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include "general.h"
#include "spacezero.h"
#include "objects.h"
#include "ai.h"
#include "save.h"
#include "shell.h"
#include "help.h"
#include "planetnames.h"
#include "spacecomm.h"
#include "sound.h"
#include "graphics.h"
#include "functions.h"


extern int g_objid;  /* id of the objects */
extern struct Global gremote,glocal;
extern GtkWidget *win_main;
extern GdkFont *gfont;
extern GdkPixmap *pixmap;
extern GdkGC *gcolors[];
extern GdkGC *penRed;
extern GdkGC *penGreen;
extern GdkGC *penLightGreen;
extern GdkGC *penBlue;
extern GdkGC *penYellow;
extern GdkGC *penWhite;
extern GdkGC *penBlack;
extern GdkGC *penOrange;
extern GdkGC *penViolet;
extern GdkGC *penPink;
extern GdkGC *penCyan;
extern GdkGC *penSoftRed;

extern Point mouse_pos;

struct Player *players;
struct CCDATA *ccdatap;
int actual_player,actual_player0;

int record=0;
int nav_mode=RELATIVE;

int p_time=0;
int g_nobjsend=0;
int g_nshotsend=0;
int g_nobjmaxsend=0;
int g_nobjtype[6]={0,0,0,0,0,0};
int g_memused=0;
int gameover=FALSE;
int observeenemies=FALSE;

char version[64]={"0.80.06"};
char copyleft[]="";
char TITLE[64]="SpaceZero  ";
char last_revision[]={"Sep. 2011"};


Object *ship_c; /* ship controled by keyboard */
Object *cv;     /* coordinates center */
int fobj[4];
sem_t sem_barrier,sem_barrier1;


int g_cont;
time_t time0,time1;

int order2thread;

int *cell;


extern struct Keys keys;
extern struct Buffer buffer1,buffer2; /* buffers used in comm. */

struct HeadObjList listheadobjs;       /* list of all objects */
struct HeadObjList listheadplanets;    /* list of all planets */
struct HeadObjList *listheadcontainer; /* lists of objects that contain objects: free space and planets*/
struct HeadObjList *listheadkplanets;  /* lists of planets known by players */
struct HeadObjList listheadplayer;     /* list of objects of each player */
struct HeadObjList listheadnearobjs;   /* list of near enemies objects of actual player. only used in draw map function. */


struct TextMessageList listheadtext;
struct Parametres param;
Vector r_rel;

struct Habitat habitat;

char recordfile0[128]="";
char *savefile;
char optionsfile[128]="";
char savefile0[128]=""; /* server */
char savefile1[128]=""; /* client */
char savefiletmp[128]=""; /* tmp save file */

char clientname[PLAYERNAMEMAXLEN];

/*  sound */
int soundenabled=TRUE;
/* -- sound */

int loadsw =0;
int gcrash=0;

void signal_handler(int ,siginfo_t *,void *);
void int_handler(int);
void segfault_handler(int);

void PrintGameOptions(void);

int main(int argc,char *argv[]){

  GtkWidget *drawing_area;
  FILE *fprecord;
  char title[64]="";
  int i,j;
  int sw;
  int state;
  struct sigaction sa;
  sigset_t wait_response; 
  int width,height;
  int npcs,npcc;
  int nteam=1;


  srand(time(NULL));

  Keystrokes(RESET,NULL);

  strcat(optionsfile,getenv("HOME"));
  strcat(optionsfile,"/");
  strcat(optionsfile,SAVEDIR);

  /* Test if the configuration directory exists */
  if(CreateDir(optionsfile)!=0){
    printf("Cant create directory: %s\n",optionsfile);
    exit(-1);
  }
  /* --Test if the directory exists */

  strcat(optionsfile,OPTIONSFILE);

  state=Arguments(argc,argv,&param,optionsfile);
  if(state){
    Usage(version,last_revision);
    exit(-1);
  }

  if(sizeof(int)<4){
    fprintf(stderr,"**************************************************************\n");
    fprintf(stderr,"WARNING: size of int %ld bytes\n, maybe SpaceZero doesnt work properly\n",(unsigned long)sizeof(int));
    fprintf(stderr,"**************************************************************\n");
  }

  fprintf(stderr,"**************************************************************\n");
  fprintf(stderr,"WARNING: Communication between 64 and 32 bits machines not tested,\nmaybe SpaceZero doesnt work properly\n");
  fprintf(stderr,"**************************************************************\n");

  if(param.nplayers==-1){
    if(param.server==FALSE && param.client==FALSE){
      param.nplayers=NUMPLAYERS;
    }
    if(param.server==TRUE){
      param.nplayers=NUMPLAYERS;
    }
    if(param.client==TRUE){
      param.nplayers=1;
    }
  }

  if(CheckArgs(param)){
    fprintf(stderr,"ERROR in arguments, exiting...\n");
    exit(-1);
  }

  printf("Game arguments:\n");
  printf("\tNUM GALAXIES: %d\n",param.ngalaxies);
  printf("\tNUM PLANETS: %d\n",param.nplanets);
  printf("\tNUM PLAYERS: %d\n",param.nplayers);
  if(param.kplanets){
    printf("\tPlanets are known by all the players.\n");
  }
  printf("\tplayer name: %s\n",param.playername);
  printf("\tknown planets: %d\n",param.kplanets);
  printf("\tsound: %d\n",param.sound);
  printf("\tmusic: %d\n",param.music);
  printf("\tcooperative mode: %d\n",param.cooperative);
  printf("\tcomputer cooperative mode: %d\n",param.compcooperative);
  printf("\tQueen mode: %d\n",param.queen);
  printf("\tpirates: %d\n",param.pirates);

  printf("\tUniverse size: %d\n",param.ul);
  printf("\tSERVER: %d\n",param.server);
  printf("\tCLIENT: %d\n",param.client);
  printf("\tIP: %s\n",param.IP);
  printf("\tPORT: %d\n",param.port);
  printf("\tfont type: %s\n",param.font);
  printf("\twindow geometry: %s\n",param.geom);
  
  strcat(recordfile0,getenv("HOME"));
  strcat(recordfile0,"/");
  fprintf(stdout,"HOME: %s\n",recordfile0);
  strcat(recordfile0,SAVEDIR);
  strcat(recordfile0,RECORDFILE0);
  fprintf(stdout,"record file:%s\n",recordfile0);

  strcat(savefile0,getenv("HOME"));
  strcat(savefile0,"/");
  strcat(savefile0,SAVEDIR);
  if(param.server==TRUE){
    strcat(savefile0,SAVEFILENET);
  }
  else{
    strcat(savefile0,SAVEFILE0);
  }

  printf("savefile0:%s\n",savefile0);

  strcat(savefile1,getenv("HOME"));
  strcat(savefile1,"/");
  strcat(savefile1,SAVEDIR);
  strcat(savefile1,SAVEFILE1);

#if TESTSAVE
  strcat(savefiletmp,"/tmp/tmpsavespacezero");
#endif


  printf("savefile1:%s\n",savefile1);
  savefile=savefile0;

  if(param.client==TRUE){
    savefile=savefile1;
  }
  if(param.server==TRUE){
    savefile=savefile0;
  }
  fprintf(stdout,"save file:%s\n",savefile);

  fprintf(stdout,"options file:%s\n",optionsfile);
  

  sw=0;
  if((fprecord=fopen(recordfile0,"rt"))==NULL){

    if((fprecord=fopen(recordfile0,"wt"))==NULL){
      fprintf(stdout,"No puede abrirse el archivo: %s", recordfile0);
      exit(-1);
    }
    fprintf(fprecord,"%d\n",0);
    fclose(fprecord);

    if((fprecord=fopen(recordfile0,"rt"))==NULL){
      fprintf(stdout,"No puede abrirse el archivo: %s", recordfile0);
      exit(-1);
    }
  }
  if(fscanf(fprecord,"%d",&record)!=1){
    fprintf(stderr,"Setting record to 0\n");
    record=0;
  }

  fclose(fprecord);
  printf("Record: %d\n",record);

  GameParametres(SET,DEFAULT,0);   /* defaults game values */

  if(param.server==TRUE||param.client==TRUE){
    GameParametres(SET,GNET,TRUE);
  }

  if(param.server==TRUE){
    GameParametres(SET,GMODE,SERVER);
  }
  if(param.client==TRUE){
    GameParametres(SET,GMODE,CLIENT);
  }

  /* process identifier */

  SetProc(0);
  SetNProc(1);

  if(GameParametres(GET,GMODE,0)==CLIENT){
    SetProc(1);
  }
  if(GameParametres(GET,GNET,0)==TRUE){
    SetNProc(2);
  }


  /* --process identifier */

  listheadobjs.next=NULL;
  listheadobjs.n=0;
  listheadplanets.next=NULL;
  listheadplanets.n=0;

  listheadtext.next=NULL;
  listheadtext.info.n=0;

  listheadnearobjs.next=NULL;
  listheadnearobjs.n=0;

  GameParametres(SET,GNGALAXIES,param.ngalaxies);
  GameParametres(SET,GNPLANETS,param.nplanets);
  GameParametres(SET,GNPLAYERS,param.nplayers);  /*+1 system +1 pirates */

  if(param.kplanets==TRUE){
    GameParametres(SET,GKPLANETS,TRUE);
  }
  if(param.pirates==FALSE){
    GameParametres(SET,GPIRATES,FALSE);
  }

  GameParametres(SET,GULX,param.ul);
  GameParametres(SET,GULY,param.ul);

  GameParametres(SET,GCOOPERATIVE,param.cooperative);
  GameParametres(SET,GCOMPCOOPERATIVE,param.compcooperative);

  SetDefaultKeyValues(&keys,1);

  for(i=0;i<4;i++)fobj[i]=0;
  
  strcat(title,TITLE);
  if(param.server==TRUE)
    strcat(title,"(server)  ");
  if(param.client==TRUE)
    strcat(title,"(client)  ");
  strcat(title,version);
  strcat(title,"  ");
  strcat(title,copyleft);
  /* strcat(title,"  "); */
  /* strcat(title,last_revision); */
  


  time0=0;
  sem_init(&sem_barrier,1,0);
  sem_init(&sem_barrier1,1,0);


  sigemptyset(&wait_response);
  sa.sa_sigaction=signal_handler;
  sigemptyset(&sa.sa_mask);
  sa.sa_flags=SA_SIGINFO;
  if(sigaction(SIGNAL0,&sa,NULL)){
    perror("sigaction");
    exit(-1);
  }

  sa.sa_handler=int_handler;
  sigemptyset(&sa.sa_mask);
  sa.sa_flags=0;
  if(sigaction(SIGINT,&sa,NULL)){
    perror("sigaction");
    exit(-1);
  }

  sa.sa_handler=segfault_handler;
  sigemptyset(&sa.sa_mask);
  sa.sa_flags=0;
  if(sigaction(SIGSEGV,&sa,NULL)){
    perror("sigaction");
    exit(-1);
  }

  npcc=0;
  npcs=GameParametres(GET,GNPLAYERS,0);


  /* Graphics initialization */


  gtk_init(&argc,&argv);


  GameParametres(SET,GWIDTH,WIDTH);
  GameParametres(SET,GHEIGHT,HEIGHT);

  if(GetGeom(param.geom,&width,&height)<0){
    fprintf(stderr,"Warning: -geom option bad formed. Using default values.\n");
  }
  else{
    GameParametres(SET,GWIDTH,width);
    GameParametres(SET,GHEIGHT,height);
  }

  printf("Width: %d Height: %d\n",width,height);

  gfont=InitFonts(param.font);

  drawing_area=InitGraphics(title,optionsfile,
			    GameParametres(GET,GWIDTH,0),
			    GameParametres(GET,GHEIGHT,0));

  if(gfont==NULL){
    GameParametres(SET,GPANEL,PANEL_HEIGHT);
  }
  else{
    GameParametres(SET,GPANEL,2*gdk_text_height(gfont,"pL",2));
  }


  GameParametres(SET,GHEIGHT,height-GameParametres(GET,GPANEL,0));


  /* --Graphics initialization */

  gcolors[0]=penWhite;
  gcolors[1]=penYellow;
  gcolors[2]=penRed;
  gcolors[3]=penGreen;
  gcolors[4]=penBlue;
  gcolors[5]=penOrange;
  gcolors[6]=penViolet;
  gcolors[7]=penPink;
  gcolors[8]=penCyan;
  gcolors[9]=penLightGreen; /* penWhite */
  gcolors[10]=penSoftRed;


  if(GameParametres(GET,GNET,0)==TRUE){
    if(param.server==TRUE){
      printf("SERVER\n");
      OpenComm(0,param);
    }
    if(param.client==TRUE){
      printf("CLIENT\n");
      OpenComm(1,param);
    }  
    printf("conexion established\n");
    
    /* synchronization with comm threads  */
    sem_wait(&sem_barrier);
  }
  
  printf("MAIN:\n nplayers: %d\n",GameParametres(GET,GNPLAYERS,0));
  printf("nproc: %d  proc: %d\n",GetNProc(),GetProc());

  players=malloc((GameParametres(GET,GNPLAYERS,0)+2)*sizeof(struct Player)); /* +1 system +1 pirates*/ 
  if(players==NULL){ 
    fprintf(stderr,"ERROR in malloc (players)\n"); 
    exit(-1); 
  } 
  g_memused+=(GameParametres(GET,GNPLAYERS,0)+2)*sizeof(struct Player);

  ccdatap=malloc((GameParametres(GET,GNPLAYERS,0)+2)*sizeof(struct CCDATA)); /* +1 system +1 pirates*/
  if(ccdatap==NULL){ 
    fprintf(stderr,"ERROR in malloc (ccdatap)\n"); 
    exit(-1); 
  } 
  g_memused+=(GameParametres(GET,GNPLAYERS,0)+2)*sizeof(struct CCDATA);



  for(i=0;i<GameParametres(GET,GNPLAYERS,0)+2;i++){
    snprintf(players[i].playername,PLAYERNAMEMAXLEN,"player%d",i);
    players[i].id=i;
    players[i].pid=GameParametres(GET,GNPLANETS,0)+1;
    players[i].proc=0;
    players[i].control=COMPUTER;
    players[i].team=i+1;
    players[i].profile=PLAYERPROFDEFAULT;
    players[i].strategy=PLAYERSTRATRANDOM;
    /* strategy is random weight choosed at WarCCPlanets() */
    players[i].strategy=(int)(NUMPLAYERSTRAT*Random(-1));
    players[i].maxlevel=0;
    players[i].cv=0;
    players[i].color=i;
    players[i].nplanets=0;
    players[i].nships=0;
    players[i].nbuildships=0;
    players[i].gold=10000*RESOURCEFACTOR;
    players[i].lastaction=0;
    players[i].ndeaths=0;
    players[i].nkills=0;
    players[i].points=0;
    players[i].ttl=2000;
    players[i].modified=SENDOBJUNMOD;
    players[i].kplanets=NULL;
    players[i].ksectors.n=0;
    players[i].ksectors.n0=0;
    players[i].ksectors.list=NULL;
    for(j=0;j<NINDEXILIST;j++){
      players[i].ksectors.index[j]=NULL;
    }

    /* player control and assigment of processors */
    players[i].control=COMPUTER;
    players[i].proc=0;
    if(i==1){
      players[i].control=HUMAN;
    }
    if(GameParametres(GET,GNET,0)==TRUE){
      if(i==1){
	players[i].proc=1;
	if(strlen(clientname)>0){
	  snprintf(players[i].playername,PLAYERNAMEMAXLEN,"%s",clientname);	
	}
      }
      if(i==2){
	players[i].control=HUMAN;
	if(strlen(param.playername)>0){
	  snprintf(players[i].playername,PLAYERNAMEMAXLEN,"%s",param.playername);
	}
      }
    }
    else{
      if(i==1){
	players[i].control=HUMAN;
	if(strlen(param.playername)>0){
	  snprintf(players[i].playername,PLAYERNAMEMAXLEN,"%s",param.playername);
	}
      }
    }
  }
  snprintf(players[GameParametres(GET,GNPLAYERS,0)+1].playername,PLAYERNAMEMAXLEN,"%s","pirates");

  for(i=0;i<GameParametres(GET,GNPLAYERS,0)+2;i++){ /* HERE TODO include ccdata in player*/
    ccdatap[i].player=i;
    ccdatap[i].planetinfo=NULL;
    ccdatap[i].nkplanets=0;
    ccdatap[i].nplanets=0;
    ccdatap[i].time=0;
    ccdatap[i].ninexplore=0;
    ccdatap[i].nenemy=0;
    
    ccdatap[i].nexplorer=0;
    ccdatap[i].nfighter=0;
    ccdatap[i].ntower=0;
    ccdatap[i].ncargo=0;
    
    ccdatap[i].sw=0;
    ccdatap[i].war=0;
    
    ccdatap[i].planetlowdefense=NULL;
    ccdatap[i].planetweak=NULL;
    ccdatap[i].planet2meet=NULL;
    ccdatap[i].planet2attack=NULL;
  }
  
  /* teams */
  players[0].team=1;   /* Universe objects */

  /* default mode:  All against all */
  
  for(i=0;i<GameParametres(GET,GNPLAYERS,0)+2;i++){
    players[i].team=i+1; 
  }
  nteam=2; 

  /* human players */
  for(i=1;i<GameParametres(GET,GNPLAYERS,0)+2;i++){
    if(players[i].control==HUMAN){
      players[i].team=nteam;
      if(param.cooperative==FALSE){
	nteam++;
      }
    }
  }
  if(param.cooperative==TRUE){
    nteam++;
  }

  /* computer players */
  for(i=1;i<GameParametres(GET,GNPLAYERS,0)+1;i++){
    if(players[i].control==COMPUTER){
      players[i].team=nteam;
      if(param.compcooperative==FALSE){
	nteam++;
      }
    }
  }
  if(param.compcooperative==TRUE){
    nteam++;
  }

  /* pirate player*/
  i=GameParametres(GET,GNPLAYERS,0)+1;
  players[i].team=nteam;

  /* --teams */

  if(param.queen){
    fprintf(stderr,"WARNING: Queen mode set to ON.\n");
    GameParametres(SET,GQUEEN,TRUE);
  }

  if(param.client==FALSE){
    printf("CreateUniverse()...");
    CreateUniverse(GameParametres(GET,GULX,0),GameParametres(GET,GULY,0),&listheadobjs,planetnames);
    CreatePlanetList(listheadobjs,&listheadplanets);
    printf("...done\n");
    printf("CreateShips()..."); 
    CreateShips(&listheadobjs); 
    printf("...done\n"); 
  }


  listheadcontainer=malloc((GameParametres(GET,GNPLANETS,0)+1)*sizeof(struct HeadObjList));
  g_memused+=(GameParametres(GET,GNPLANETS,0)+1)*sizeof(struct HeadObjList);
  if(listheadcontainer==NULL){
    printf("ERROR in malloc main()\n");
    exit(-1);
  }
  for(i=0;i<GameParametres(GET,GNPLANETS,0)+1;i++){
    listheadcontainer[i].next=NULL;
    listheadcontainer[i].n=0;
  }

  listheadkplanets=malloc((GameParametres(GET,GNPLAYERS,0)+2)*sizeof(struct HeadObjList));
  g_memused+=(GameParametres(GET,GNPLAYERS,0)+2)*sizeof(struct HeadObjList);
  if(listheadkplanets==NULL){
    printf("ERROR in malloc main()\n");
    exit(-1);
  }
  for(i=0;i<GameParametres(GET,GNPLAYERS,0)+2;i++){
    listheadkplanets[i].next=NULL;
    listheadkplanets[i].n=0;
  }

  /************************************************************/

  if(param.server==TRUE){
    
    if(ExecSave(listheadobjs,SAVETMPFILE)!=0){
      fprintf(stderr,"Error in main(): I cant open %s\n",SAVETMPFILE);
      exit(-1);
    }
    printf("gid: %d\n",g_objid);
    SetModifiedAll(&listheadobjs,ALLOBJS,SENDOBJUNMOD,TRUE);
    p_time=GetTime();
  }
  
  if(GameParametres(GET,GNET,0)==TRUE){
    sem_post(&sem_barrier1);
    sem_wait(&sem_barrier);
  }

  if(param.client==TRUE){

    GetUniverse();

    g_objid=glocal.g_objid;

    SetModifiedAll(&listheadobjs,ALLOBJS,SENDOBJUNMOD,TRUE);
    CreatePlanetList(listheadobjs,&listheadplanets);
  }

  actual_player=1;
  if(GameParametres(GET,GMODE,0)==SERVER){ /* only two human players, by now*/ 
    actual_player=2;
  }
  actual_player0=actual_player;
  players[actual_player].control=HUMAN;

  printf("Actual Player: %d\n",actual_player);

  DestroyObjList(&listheadplayer); 
  listheadplayer.n=0; 
  listheadplayer.next=NULL; 
  CreatePlayerList(listheadobjs,&listheadplayer,actual_player);


  cv=NextCv(&listheadplayer,cv,actual_player);
  if(cv!=NULL){
    habitat.type=cv->habitat;
    habitat.obj=cv->in;
    cv->selected=TRUE;
  }
  
   
  {     /* Adding planets to players list */
    struct ObjList *ls;
    ls=listheadobjs.next;
    while(ls!=NULL){
      if(ls->obj->type==PLANET){      
	/* pirates known some planets */
	/* players[GameParametres(GET,GNPLAYERS,0)+1].kplanets= */
	/*   Add2IntList((players[GameParametres(GET,GNPLAYERS,0)+1].kplanets),ls->obj->id); */
	/* rest of players */
	for(i=0;i<GameParametres(GET,GNPLAYERS,0)+1;i++){
	  if(GameParametres(GET,GKPLANETS,0)==TRUE ||
	     players[ls->obj->player].team==players[i].team ||
	     (ENEMIESKNOWN==TRUE && players[ls->obj->player].team > 1) ){
	    players[i].kplanets=Add2IntList((players[i].kplanets),ls->obj->id);
	  }
	}
      }
      ls=ls->next;
    }
  }

#if SOUND
  /* sound initialization*/ 
  
  GameParametres(SET,GMUSIC,param.music);
  GameParametres(SET,GSOUND,param.sound);
  state=InitSound();
  if(state!=0){
    printf("Error initializing sound, sound disabled Error id:%d\n",state);
    soundenabled=FALSE;
    param.sound=FALSE;
    param.music=FALSE;
    GameParametres(SET,GMUSIC,param.sound);
    GameParametres(SET,GSOUND,param.music);
    Play(NULL,-1,0); /* disable sound */
  }

  if(soundenabled==TRUE){
    PlaySound(MUSIC,SLOOP,0.75);
    if(param.music){
      printf("Music is on (%d)\n",param.music);
    }
    else{
      Sound(SSTOP,MUSIC);
      printf("Music is off\n");
    }
  }


  /*--sound initialization*/ 
#endif


  /* printf teams */

  for(i=1;i<GameParametres(GET,GNPLAYERS,0)+2;i++){
    printf("PLAYER %d TEAM %d ",i,players[i].team);
    if(players[i].control==HUMAN)printf("HUMAN");
    if(players[i].control==COMPUTER)printf("COMPUTER");
    printf(" name: \"%s\"",players[i].playername);
    printf("\n");
  }

#if CELLON
  {
    int nx,ny;
    nx=GameParametres(GET,GULX,0)/2000;
    ny=GameParametres(GET,GULY,0)/2000;

    cell=malloc(nx*ny*sizeof(int));
    if(cell==NULL){ 
      fprintf(stderr,"ERROR in malloc (creating cell)\n"); 
      exit(-1); 
    }
    for(i=0;i<nx*ny;i++){
      cell[i]=0;
    }
  } 
#endif    


  PrintGameOptions();



  gtk_timeout_add((int)(DT*100),MainLoop,(gpointer)drawing_area);  /* 42 DT=0.42 in general.h*/

  gtk_main();

  printf("\ntotal points: %d record: %d\n",players[1].points,record);



  printf("******************************************************\n");
  g_print("%sversion %s  %s\n",TITLE,version,last_revision);
  g_print("Please, send bugs and suggestions to: mrevenga at users dot sourceforge dot net\n");
  g_print("Homepage:  http://spacezero.sourceforge.net/\n");


  j=-1;
  for(i=0;i<GameParametres(GET,GNPLAYERS,0);i++){
    if(players[i].points>=record){
      j=i;
      record=players[i].points;
    }
  }
  if(j!=-1){
    if((fprecord=fopen(recordfile0,"wt"))==NULL){
      fprintf(stdout,"No puede abrirse el archivo: %s", recordfile0);
      exit(-1);
    }
    fprintf(fprecord,"%d",record);
    fclose(fprecord);
  }

  return 0;
} /*  main */


gint MainLoop(gpointer data){
  /*
    Main gtk loop. executed 24 times by second.

*/
  int i;
  int drawmap;
  static int cont=0;
  float x0,y0;
  static int lasttimepirates=2000;
  static int lasttimeasteroids=0;
  Object *cv0;     /* coordinates center */
  GtkWidget *drawing_area=(GtkWidget *) data;
  GdkRectangle update_rect;
  static int paused=0;
  static int swpaused=0;
  int gwidth,gheight;
  static int ulx,uly;
  int proc;
  int swcomm=0; /* TRUE if in time step has communication */ 
  int swmess=0; /* show a message */
  char point[128];
  char pointmess[128];
  Rectangle wininfo,wingame;


  if(time0==0){
    time0=time(NULL);
  }
  
  
  ulx=GameParametres(GET,GULX,0);
  uly=GameParametres(GET,GULY,0);

  gwidth=GameParametres(GET,GWIDTH,0);
  gheight=GameParametres(GET,GHEIGHT,0);


  wininfo.x=0;
  wininfo.y=0;
  wininfo.width=150;
  wininfo.height=gheight;

  wingame.x=wininfo.width;
  wingame.y=0;
  wingame.width=gwidth-wininfo.width;
  wingame.height=gheight;



  proc=GetProc();

#if CELLON
  {
    int nx,ny;
    nx=GameParametres(GET,GULX,0)/2000;
    ny=GameParametres(GET,GULY,0)/2000;
    for(i=0;i<nx*ny;i++){
      cell[i]=0;
    }
    UpdateCell(&listheadobjs,cell);
  } 
#endif
  for(i=0;i<GameParametres(GET,GNPLANETS,0)+1;i++){
    DestroyObjList(&listheadcontainer[i]);
    listheadcontainer[i].next=NULL;
    listheadcontainer[i].n=0;
  }
  for(i=0;i<GameParametres(GET,GNPLAYERS,0)+2;i++){
    DestroyObjList(&listheadkplanets[i]);
    listheadkplanets[i].next=NULL;
    listheadkplanets[i].n=0;
  }

  key_eval(&keys);

  if(GameParametres(GET,GPAUSED,0)==FALSE){
      DestroyObjList(&listheadplayer);
      listheadplayer.next=NULL;
      listheadplayer.n=0;
      
      CreatePlayerList(listheadobjs,&listheadplayer,actual_player);
      CreateContainerLists(&listheadobjs,listheadcontainer);
      CreatekplanetsLists(&listheadobjs,listheadkplanets);
  }


  /* messages */
  swmess=0;


  /* GAME OVER */
  if(actual_player==actual_player0){
    
    static int n=1;
    static int player=0;
    if(player!=actual_player){
      n=0;
      player=actual_player;
    }
    if(GameParametres(GET,GPAUSED,0)==FALSE){
      if(n<=0){
	n=CountObjs(&listheadplayer,-1,SHIP,-1);
	n*=10;
      }
      
      if(n<=0){
	gameover=TRUE;
	observeenemies=TRUE;
      }
      n--;
    }
  }

  if(gameover==TRUE){
    sprintf(pointmess,"GAME OVER");
    swmess++;
  }
  /* game paused */
  if(GameParametres(GET,GPAUSED,0)==TRUE){
    sprintf(pointmess,"PAUSED    (press p to continue)");
    swmess++;
  }
  /* game quit */
  if(GameParametres(GET,GQUIT,0)==1){
    sprintf(pointmess,"Really QUIT?  ( y/n )");
    swmess++;
  }

  if(swmess){
    DrawMessageBox(drawing_area,pixmap,gfont,pointmess,gwidth/2,0.3*gheight);
  }

  if(GameParametres(GET,GPAUSED,0)==TRUE){
    if(swpaused>=NETSTEP){
      return(TRUE);
    }
    if(GameParametres(GET,GNET,0)==TRUE){
      sprintf(point,"Game PAUSED");
      SendTextMessage(point);   
    }
    swpaused++;
  }
  else{
    swpaused=0;
  }


  drawmap=FALSE;
  if(!(cont%2))drawmap=TRUE;

  /* ai */

  for(i=1;i<GameParametres(GET,GNPLAYERS,0)+2;i++){
    if(players[i].control==COMPUTER && proc==players[i].proc){
      ControlCenter(&listheadobjs,players[i]);
    }
  }

  CheckGame("");
  UpdateObjs();                     /* new positions */

  for(i=1;i<GameParametres(GET,GNPLAYERS,0)+2;i++){
    if(proc==players[i].proc){
      players[i].ttl--;
      if(players[i].ttl<=0)players[i].modified=SENDPLAYERMOD;
    }
  }
  
  if(drawmap==TRUE){
    if(!(cont%10)){
      DestroyObjList(&listheadnearobjs);
      listheadnearobjs.n=0;
      listheadnearobjs.next=NULL;
      CreateNearObjsList(&listheadobjs,&listheadnearobjs,actual_player);
    }
  }


  for(i=0;i<GameParametres(GET,GNPLANETS,0)+1;i++){
    Collision(&listheadcontainer[i]);         /* interact among objects */
  }
  GetGold();     
  if(GameParametres(GET,GPIRATES,0)==TRUE && (players[GameParametres(GET,GNPLAYERS,0)+1].nplanets<5)){
    if(proc==players[GameParametres(GET,GNPLAYERS,0)+1].proc){/*  Send TO ai */
      if(GetTime()-lasttimepirates>2000){
	if(((20000.0*rand())/RAND_MAX)<=1){
	  char text[TEXTMENMAXLEN];
	  lasttimepirates=GetTime();
	  x0=ulx*Random(-1)-ulx/2;
	  y0=uly*Random(-1)-uly/2;
	  CreatePirates(&listheadobjs,4,x0,y0);
	  snprintf(text,TEXTMENMAXLEN,"PIRATES!!! at sector: %d %d",(int)(x0/SECTORSIZE),(int)(y0/SECTORSIZE));
	  Add2TextMessageList(&listheadtext,text,0,-1,0,100,0);
	  if(GameParametres(GET,GNET,0)==TRUE){
	    SendTextMessage(text);
	  }
	}
      }
    }
  }

  if(proc==players[GameParametres(GET,GNPLAYERS,0)+1].proc){/*  Send TO ai */
    if(GetTime()-lasttimeasteroids>3000){
      if(((11000.0*rand())/RAND_MAX)<=1){ /* every 10 minutes */
	char text[TEXTMENMAXLEN];
	float factor;

	factor=(float)GameParametres(GET,GULX,0)/100000.0;
	factor*=factor;
	factor=2*(factor+1);
	lasttimeasteroids=GetTime();
	for(i=0;i<factor;i++){
	  x0=ulx*Random(-1)-ulx/2;
	  y0=uly*Random(-1)-uly/2;
	  CreateAsteroids(&listheadobjs,6,x0,y0);
	  
	  snprintf(text,TEXTMENMAXLEN,"ASTEROIDS!!! at sector: %d %d",(int)(x0/SECTORSIZE),(int)(y0/SECTORSIZE));
	  Add2TextMessageList(&listheadtext,text,0,-1,0,100,0);
	  if(GameParametres(GET,GNET,0)==TRUE){
	    SendTextMessage(text);   
	  }
	}
      }
    }
  }
  
  if(swpaused==TRUE){
    printf("PAUSED\n");
    fflush(NULL);
  }
  
  /* synchronization with comm threads */


  swcomm=FALSE;
  if(GameParametres(GET,GNET,0)==TRUE){
    CheckModifiedPre(&listheadobjs,proc);
    Setttl0(&listheadobjs);
    if( !(cont%NETSTEP)){  
      NetComm();     /* net communication */
      CheckModifiedPost(&listheadobjs,proc);
      swcomm=TRUE;
    }
    Setttl(&listheadobjs,-1);
  }
  else{
    swcomm=TRUE;
  }


  GetPoints(listheadobjs,proc,players);/* points and experience */

  if(GameParametres(GET,GKPLANETS,0)==FALSE){
    UpdateSectors(listheadobjs);
  }
  
  if(keys.load==TRUE && swcomm==TRUE){
    keys.load=FALSE;
    keys.save=FALSE;

    DestroyObjList(&listheadplayer);  /* HERE verificar con DestroyAllObjs() in execload() */
    listheadplayer.n=0;  
    listheadplayer.next=NULL;  

    if(ExecLoad(savefile)==0){
      loadsw=1;
      p_time=GetTime();
      observeenemies=FALSE;
      gameover=FALSE;
      CreatePlanetList(listheadobjs,&listheadplanets);
      
      { /* deleting the message list */
	struct TextMessageList *lh;
	lh=&listheadtext;
	while(lh->next!=NULL){
	  lh->next->info.duration=0;
	  lh=lh->next;
	}
      }
      SetDefaultKeyValues(&keys,0);
      CheckGame("Checking game after load...");
      printf("done\n");
    }
    CreatePlayerList(listheadobjs,&listheadplayer,actual_player);
  }


  if(keys.save==TRUE && swcomm==TRUE){
    char text[TEXTMENMAXLEN];
    keys.load=FALSE;
    keys.save=FALSE;


    if(ExecSave(listheadobjs,savefile)==0){    
      snprintf(text,TEXTMENMAXLEN,"GAME SAVED.");
      Add2TextMessageList(&listheadtext,text,0,-1,0,100,0);
      if(GameParametres(GET,GNET,0)==TRUE){
	SendTextMessage(text);   
      }
    }
    else{
      fprintf(stderr,"Error in MainLoop(): I cant open %s\n",savefile);
    }
  }
  
  if(cv!=NULL){
    if(nav_mode==RELATIVE){
      r_rel.x=cv->x;
      r_rel.y=cv->y;
    }
    else{
      if(cv->x - r_rel.x>gwidth/2)
	r_rel.x+=gwidth;
      if(cv->x - r_rel.x <-gwidth/2)
	r_rel.x-=gwidth;
      
      if(cv->y - r_rel.y>gheight/2)
	r_rel.y+=gheight;
      if(cv->y - r_rel.y <-gheight/2)
	r_rel.y-=gheight;
    }
  }

  /* Drawing window */

  /* game window*/
  if(paused==0){

    /* clear window */

    if(keys.m==TRUE){
      if(drawmap){ 
	gdk_draw_rectangle(pixmap,   
			   drawing_area->style->black_gc,   
			   TRUE, 
			   0,0,   
			   drawing_area->allocation.width,   
			   drawing_area->allocation.height);  
      } 
    } 
    else{ 
      if(gcrash){ 
	gdk_draw_rectangle(pixmap,   
			   drawing_area->style->white_gc,   
			   TRUE,  
			   0,0,   
			   drawing_area->allocation.width,   
			   drawing_area->allocation.height);  
	gcrash=0; 
      } 
      else{  
	
 	gdk_draw_rectangle(pixmap,     
 			   drawing_area->style->black_gc,     
 			   TRUE,    
 			   0,0,     
 			   drawing_area->allocation.width,     
 			   drawing_area->allocation.height); 
      }  
    }
    
    
    /* --clear window */

       
    if(keys.m==TRUE){
      if(drawmap){
	DrawMap(pixmap,actual_player,listheadobjs,cv,ulx);
      }
      if(keys.f5==TRUE){
	DrawPlayerList(pixmap,&listheadplayer,cv,loadsw || !(GetTime()%20));
      }
      DrawInfo(pixmap,cv);
    }
    else{  
      if(habitat.type==H_SPACE && cv!=NULL)DrawStars(pixmap,nav_mode,r_rel.x,r_rel.y);
      {int n;
      n=DrawObjs(pixmap,&listheadobjs,habitat,cv,r_rel); 
      }
      if(cv!=NULL && (habitat.type==H_SPACE)){
	DrawRadar(pixmap,cv,&listheadobjs);
      }
      
      if(habitat.type==H_PLANET && cv!=NULL){
	DrawPlanetSurface(pixmap,habitat.obj->planet,gcolors[players[habitat.obj->player].color]); 
      }
      if(keys.f5==TRUE){
	DrawPlayerList(pixmap,&listheadplayer,cv,loadsw || !(GetTime()%20));
      }
      DrawInfo(pixmap,cv);
      if(cv!=NULL){
	if(cv->accel>0){
	  Play(cv,THRUST,cv->accel/cv->engine.a_max);
	}
      }
    }
  }/* if(paused==0) */

    if(keys.f6==TRUE){
      DrawGameStatistics(pixmap,players);
    }
    
    if(swmess){ 
      DrawMessageBox(drawing_area,pixmap,gfont,pointmess,gwidth/2,0.3*gheight);
    } 


  /* Draw Shell */
  
  if(keys.o==TRUE){/* QWERTY */
    gdk_draw_line(pixmap,penWhite,
		  0,gheight,
		  gwidth,gheight);
    
    cv0=cv;     /* coordinates center */

    Shell(pixmap,gfont,penGreen,&listheadobjs,players,&keys,&cv);

    if(cv!=NULL){
      if(cv->state==-1){ /* Object just selled*/
	cv=SelectObjInObj(&listheadplayer,cv->in->id,cv->player);
	if(cv!=NULL){
	  cv->selected=TRUE;
	  if(cv->in==cv0->in){
	    habitat.type=cv->habitat;
	    habitat.obj=cv->in;
	  }
	  else{
	    cv=cv0;
	  }
	}
      }
      
      if(cv0!=cv){ /* if center coordinates changes */
	if(cv!=NULL){
	  habitat.type=cv->habitat;
	  habitat.obj=cv->in;
	  if(cv->type==PLANET){
	    habitat.type=H_PLANET;
	    habitat.obj=cv;
	  }
	}
      }
    }
  }
  else{
    gdk_draw_line(pixmap,penRed,
		  0,gheight,
		  gwidth,gheight);
  }
  
  /* --Draw Shell */


  /* Draw selection box */
  DrawSelectionBox(&cv,0);
  /* --Draw selection box */



  /* show window */
 
  if(keys.m==TRUE){ 
    if(drawmap){ 
      update_rect.x=0;
      update_rect.y=0;
      update_rect.width=drawing_area->allocation.width;
      update_rect.height=drawing_area->allocation.height;
    }
  }
  else{
    update_rect.x=0;
    update_rect.y=0;
    update_rect.width=drawing_area->allocation.width;
    update_rect.height=drawing_area->allocation.height;
  }

  /* PRODUCTION */
  gtk_widget_draw(drawing_area,&update_rect); /*  deprecated */
    
  if(GameParametres(GET,GPAUSED,0)==TRUE){
    paused=1;
  }
  else{
    paused=0;
  }
  
  /* --Drawing window */  
  

  if(GameParametres(GET,GPAUSED,0)==FALSE){
    IncTime();
  }

  loadsw=0;

  if(GameParametres(GET,GQUIT,0)==2 && swcomm==TRUE){
    Quit(NULL,NULL); 
  }
  
  if(RemoveDeadObjs(&listheadobjs,cv)==NULL){
    cv=NULL;
  }

  if(IsInObjList(&listheadobjs,ship_c)==0){  
    ship_c=NULL;  
  }  

  cont++;
  return(TRUE);

  } /* MainLoop */

gint Quit(GtkWidget *widget,gpointer gdata){
  /*
    
   */

  sem_close(&sem_barrier);
  sem_close(&sem_barrier1);

#if SOUND
  printf("Sound Closed\n");
  ExitSound();
  printf("Sound Closed\n");
#endif

  DestroyAllObj(&listheadobjs);
  listheadobjs.next=NULL;
  listheadobjs.n=0;
  ship_c=NULL;
  cv=NULL;


  QuitGraphics(widget,gdata);
  printf("Graphics Closed\n");
  return FALSE;
}



void key_eval(struct Keys *key){
  /*
    version 01 13May11
    Evaluate all the key and mouse press 

   */
  Object *obj;
  static int swtab=0;
  static int swtab0=0;
  int gulx,guly;
  int proc;
  int mode;  /* nav mode, order mode */
  int keyf=-1;

  proc=GetProc();
  gulx=GameParametres(GET,GULX,0);
  guly=GameParametres(GET,GULY,0);
  

  /* QUIT game */
  if(key->ctrl==TRUE && key->q==TRUE){
    GameParametres(SET,GQUIT,1);  /*  ask: Really Quit? */
  }

  if(GameParametres(GET,GQUIT,0)==1){
    if(key->n==TRUE || key->esc==TRUE){
      GameParametres(SET,GQUIT,0);
      key->ctrl=FALSE;
      key->q=FALSE;
      key->n=FALSE;
    }
    if(key->y==TRUE){ 
      GameParametres(SET,GQUIT,2);  /* Quit game */
      GameParametres(SET,GPAUSED,FALSE);
    }
    return;
  }

  /* game paused */
  if( key->p==TRUE && GameParametres(GET,GPAUSED,0)==TRUE){
    GameParametres(SET,GPAUSED,FALSE);
    key->p=FALSE;
    Sound(SPLAY,MUSIC);
  }
  // dont pause in order mode
  if(key->o==FALSE && key->p==TRUE && GameParametres(GET,GPAUSED,0)==FALSE){
    GameParametres(SET,GPAUSED,TRUE);
    key->p=FALSE;
    Sound(SPAUSE,MUSIC);
  }

  mode=0;
  if(key->o==TRUE)mode=1;
  switch(mode){
  case 0: /* Nav mode */
    /* f1 f2 f3 f4 */    
    keyf=-1;
    if(key->f1)keyf=0;
    if(key->f2)keyf=1;
    if(key->f3)keyf=2;
    if(key->f4)keyf=3;
    key->f1=key->f2=key->f3=key->f4=FALSE;
    
    if(keyf>=0) {
      if(key->ctrl==TRUE){
	key->ctrl=FALSE;
	if(cv!=NULL)
	  fobj[keyf]=cv->id;
      }
      else{
	if((obj=SelectObj(&listheadobjs,fobj[keyf]))!=NULL){
	  if(cv!=NULL)cv->selected=FALSE;
	  cv=obj;
	  habitat.type=cv->habitat;
	  habitat.obj=cv->in;
	  DrawSelectionBox(&cv,1);
	  cv->selected=TRUE;
	}
      }
    }  
    /*-- f1 f2 f3 f4 */    

    /* observe enemies */
    if(observeenemies==TRUE){
      if(key->f7==TRUE || key->f8==TRUE){
	if(cv!=NULL){
	  players[actual_player].cv=cv->id;
	}
	else{
	  players[actual_player].cv=0;
	}
	if(key->f7==TRUE){
	  key->f7=FALSE;
	  actual_player--;
	  if(actual_player<1){
	    actual_player=GameParametres(GET,GNPLAYERS,0)+1;
	  }
	}
	if(key->f8==TRUE){
	  key->f8=FALSE;
	  actual_player++;
	  if(actual_player>GameParametres(GET,GNPLAYERS,0)+1){
	    actual_player=1;
	  }
	}

	DestroyObjList(&listheadplayer);
	listheadplayer.n=0;
	listheadplayer.next=NULL;
	CreatePlayerList(listheadobjs,&listheadplayer,actual_player);
	
	cv=SelectObj(&listheadplayer,players[actual_player].cv);
	if(cv==NULL){
	  cv=NextCv(&listheadplayer,cv,actual_player);
	}
	if(cv!=NULL){
	  habitat.type=cv->habitat;
	  habitat.obj=cv->in;
	  DrawSelectionBox(&cv,1);
	}
      }
    }
    /*-- observe enemies */

    if(ship_c!=NULL){
      if(ship_c->type!=SHIP){
	key->trace=FALSE;
      ship_c->trace=FALSE;
      }
      if(ship_c->subtype!=EXPLORER &&
	 ship_c->subtype!=FIGHTER &&
	 ship_c->subtype!=QUEEN){
	key->trace=FALSE;
	ship_c->trace=FALSE;
      }
      
      if(key->trace==TRUE){
	/* if(ship_c->trace==TRUE) */
	/*   ship_c->trace=FALSE; */
	/* else */
	/*   ship_c->trace=TRUE; */
	key->trace=FALSE;
      }
      
      if(ship_c->ai == 0 && proc==players[ship_c->player].proc){
	
	if(key->down==TRUE){
	  ship_c->accel-=.08;
	  if(ship_c->accel<0)ship_c->accel=0;
	}
	if(cv==ship_c){ 
	  if(ship_c->gas>0 && key->m==FALSE){
	    if(key->up==TRUE){
	      ship_c->accel+=ship_c->engine.a;
	      if(ship_c->accel>ship_c->engine.a_max)ship_c->accel=ship_c->engine.a_max;
	      
	      if(ship_c->mode==LANDED && ship_c->vy>0){ship_c->mode=NAV;} 
	    }
	    else{
	      ship_c->accel=0;
	    }
	    if(key->left==TRUE && ship_c->gas > ship_c->engine.gascost){
	      ship_c->ang_a+=ship_c->engine.ang_a;
	      if(ship_c->ang_a > ship_c->engine.ang_a_max) 
		ship_c->ang_a=ship_c->engine.ang_a_max; 
	    }
	    if(key->right==TRUE && ship_c->gas>ship_c->engine.gascost){
	      ship_c->ang_a-=ship_c->engine.ang_a;
	      if(ship_c->ang_a < -ship_c->engine.ang_a_max) 
		ship_c->ang_a = -ship_c->engine.ang_a_max; 
	    }
	    if(key->left==FALSE  && key->right==FALSE){
	      ship_c->ang_a=0;
	    }
	    if(key->space==TRUE && ship_c->gas > 2){
	      if (!ship_c->weapon->cont1){
		ChooseWeapon(ship_c);
		if(proc==players[ship_c->player].proc){
		  if(FireCannon(&listheadobjs,ship_c,NULL)==0){
		    Play(ship_c,FIRE0,1);
		  }
		}
	      }
	    }
	  }
	}
      }    
    }/* if(ship_c!=NULL) */
    
    if(cv!=NULL){
      if(key->n==TRUE){
	if(nav_mode==RELATIVE){
	  nav_mode=ABSOLUTE;
	  r_rel.x=cv->x;
	  r_rel.y=cv->y;
	}
	else{
	  nav_mode=RELATIVE;
	}
	key->n=FALSE;
      }
      
      if(actual_player==actual_player0){
	
	if(key->i==TRUE){
	  ship_c=cv;
	  ship_c->ai=1;
	  key->a=FALSE;
	  key->i=FALSE;
	}
	
	if(key->a==TRUE){
	  ship_c=cv;
	  ship_c->ai=0;
	  key->a=FALSE;
	  key->i=FALSE;
	}
	
	if(key->number[1]==TRUE){
	  if(cv->weapon0.type!=CANNON0)
	    cv->weapon=&cv->weapon0;    
	  key->number[1]=FALSE;
	}
	if(key->number[2]==TRUE){
	  if(cv->weapon1.type!=CANNON0)
	    cv->weapon=&cv->weapon1;    
	  key->number[2]=FALSE;
	}
	if(key->number[3]==TRUE){
	  if(cv->weapon1.type!=CANNON0)
	    cv->weapon=&cv->weapon2;    
	  key->number[3]=FALSE;
	}
      }
    }
    
    break;
  case 1: /* order mode */
    break;
  default:
    break;
  }

  if(!(key->Avpag | key->Repag | key->home | key->tab)){
    swtab=0;
    swtab0=0;
  }

  if(key->Avpag|key->Repag|key->home|key->tab){
    Shell(NULL,NULL,NULL,NULL,NULL,NULL,NULL); /* reset shell() */
    key->o=FALSE; /*get out of order mode */
    key->p=FALSE;
    if(key->tab==TRUE){
      if(swtab==0){
	if(cv!=NULL)cv->selected=FALSE;
	if(key->ctrl==TRUE){
	  cv=PrevCv(&listheadplayer,cv,actual_player);
	}
	else{
	  cv=NextCv(&listheadplayer,cv,actual_player);
	}
      }
      swtab++;
      if(swtab0)if(swtab>1)swtab=0;  
      if(swtab>6){swtab=0;swtab0=1;}  
    }
  
    if(key->Avpag|key->Repag|key->home){
      if(swtab==0){
	if(cv!=NULL)cv->selected=FALSE;
	if(key->Avpag==TRUE){
	  cv=NextPlanetCv(&listheadplayer,cv,actual_player);
	  key->Avpag=FALSE;
	}
	if(key->Repag==TRUE){
	  cv=PrevPlanetCv(&listheadplayer,cv,actual_player);
	  key->Repag=FALSE;
	}
	if(key->home==TRUE){
	  key->home=FALSE;
	  cv=FirstShip(&listheadplayer,cv,actual_player);
	}
      }
      swtab++;
      if(swtab0)if(swtab>1)swtab=0;  
      if(swtab>6){swtab=0;swtab0=1;}  
    }

    if(cv!=NULL){
      habitat.type=cv->habitat;
      habitat.obj=cv->in;
      DrawSelectionBox(&cv,1);
      cv->selected=TRUE;
      
      if(nav_mode==ABSOLUTE){
	while(cv->x - r_rel.x>GameParametres(GET,GWIDTH,0)/2){
	  r_rel.x+=GameParametres(GET,GWIDTH,0);
	}
	while(cv->x - r_rel.x <-GameParametres(GET,GWIDTH,0)/2){
	  r_rel.x-=GameParametres(GET,GWIDTH,0);
	}
	while(cv->y - r_rel.y>GameParametres(GET,GHEIGHT,0)/2){
	  r_rel.y+=GameParametres(GET,GHEIGHT,0);
	}
	while(cv->y - r_rel.y <-GameParametres(GET,GHEIGHT,0)/2){
	  r_rel.y-=GameParametres(GET,GHEIGHT,0);
	}
      }
    }
  }

  /* save and load game */
  if(key->ctrl==TRUE && key->s==TRUE){
    if(GameParametres(GET,GMODE,0)==CLIENT){
      key->save=FALSE;
    }
    else{
      key->save=TRUE;
      key->s=FALSE;
    }
  }

  if(key->ctrl==TRUE && key->l==TRUE){

    if(GameParametres(GET,GMODE,0)==CLIENT){
      key->load=FALSE;
    }
    else{
      key->load=TRUE;
      key->l=FALSE;  
    }
  }
  /*-- save and load game */
}




void UpdateShip(Object *obj){
  /* 
     Calculate the new coordinates of the ship *obj

  */
  float vx,vy,vmax2;
  float cosa,sina;
  float rx,ry;
  float vr,vo;
  float fx,fy;
  float fx0,fy0;
  float dtim;
  float a,factor;
  float g=1.2/250000;
  float U;
  int time;
  int n;

  int proc,gwidth;


  proc=GetProc();

  vx=obj->vx;
  vy=obj->vy;
  dtim=DT/obj->mass;
  
  fx0=fy0=0;

  if(obj->habitat==H_SPACE){
    U=PlanetAtraction(&fx0,&fy0,obj->x,obj->y,obj->mass);

    if(obj->subtype==SATELLITE){
      if(fx0>0.0000001){
	obj->life=2400;
      }
    }
  }
  else{
      if(obj->in!=NULL){
	fy0=-g*obj->mass*(float)obj->in->mass;
      }
      else{
	printf("in = NULL in id: %d\n",obj->id);
	return;
      }
  }

  obj->x0=obj->x;
  obj->y0=obj->y;

  if(obj->mode==NAV){
    obj->x+=obj->vx*DT+.5*(fx0)*DT*dtim;
    obj->y+=obj->vy*DT+.5*(fy0)*DT*dtim;
  }

  fx=fy=0;
  if(obj->habitat==H_SPACE){
    PlanetAtraction(&fx,&fy,obj->x,obj->y,obj->mass);
  }
  else{
      fy=-g*obj->mass*(float)obj->in->mass;
  }

  if(proc==players[obj->player].proc){
    if(obj->engine.a_max && obj->accel>0){
      obj->gas-=10*obj->engine.gascost*obj->accel/obj->engine.a_max;
      if(obj->gas<0){
	obj->gas=0;
	obj->accel=0;
      }
    }
    if(obj->engine.ang_a_max && obj->ang_a!=0){
      obj->gas-=fabs(obj->engine.gascost*obj->ang_a/obj->engine.ang_a_max);
      if(obj->gas<0){
	obj->gas=0;
	obj->ang_a=0;
      }
    }
  }
  if(obj->accel){
    vx+=(.5*(fx+fx0)+cos(obj->a)*obj->accel)*dtim;
    vy+=(.5*(fy+fy0)+sin(obj->a)*obj->accel)*dtim;
  }
  else{
    vx+=(.5*(fx+fx0))*dtim;
    vy+=(.5*(fy+fy0))*dtim;
  }

  if(obj->mode==LANDED && vy>0){
    obj->mode=NAV;
  } 
  if(obj->mode==LANDED && vy<0){
    vy=0;
    vx=0;
  } 


  /* if max vel is reached, reescaling */

  if(obj->type==SHIP){
    vmax2=obj->engine.v2_max*(1-0.4375*(obj->state<25));
  }
  else{
    vmax2=obj->engine.v2_max;
  }
  if(vx*vx+vy*vy>vmax2){
    factor=sqrt(vmax2/(vx*vx+vy*vy));
    if(factor>1){
      printf("ERROR factor>1\n");
      printf("\tobj_enginev2max: %d %d\n",obj->engine.v2_max,(obj->state<25));
    }
    vx*=factor;
    vy*=factor;
  }
  
  if(obj->ang_a!=0){
    obj->ang_v+=obj->ang_a*100.*dtim;
    if(obj->ang_v > obj->engine.ang_v_max)obj->ang_v=obj->engine.ang_v_max;
    if(obj->ang_v < -obj->engine.ang_v_max)obj->ang_v=-obj->engine.ang_v_max;
  }
  else{
    obj->ang_v*=0.5;
  }
  
  obj->a+=(obj->ang_v+0.5*obj->ang_a*100.*dtim)*DT; 
  
  if(obj->a > PI)obj->a-=2*PI;
  if(obj->a < -PI)obj->a+=2*PI;


  obj->vx=vx;
  obj->vy=vy;
  obj->fx0=obj->fx;
  obj->fy0=obj->fy;
  
  if(obj->weapon0.cont1)obj->weapon0.cont1--;
  if(obj->weapon1.cont1)obj->weapon1.cont1--;
  if(obj->weapon2.cont1)obj->weapon2.cont1--;

  if(proc==players[obj->player].proc){
    
    if(obj->type==SHIP && obj->habitat==H_SPACE){

      obj->gas+=0.05;

      if(obj->gas > obj->gas_max)obj->gas=obj->gas_max; 
      if(obj->state>0 && obj->state<25){
	obj->state+=0.005;
      }
    }


    if(obj->type==SHIP && obj->mode==LANDED){
      time=GetTime();
      /* repair and refuel  */
      if(players[obj->player].gold<5){
	n=5*Random(-1);
      }
      else{
	n=0;
      }

      if(players[obj->player].gold>0 && n==0){
	if(obj->state<100){
	  if(obj->state>0){
	    obj->state+=0.05;
	  }
	  if(obj->state>100)obj->state=100;
	  players[obj->player].gold-=.125; /* total cost 250  */
	  
	}
	if(obj->gas < obj->gas_max){
	  obj->gas+=2;
	  if(obj->gas>obj->gas_max)obj->gas=obj->gas_max;
	  players[obj->player].gold-=.2; /* total cost 100 */
	  
	}

	if(!(time%4)){
	  if(obj->weapon0.n<obj->weapon0.max_n){
	    if(players[obj->player].gold>obj->weapon0.projectile.unitcost){
	      obj->weapon0.n++;
	      players[obj->player].gold-=obj->weapon0.projectile.unitcost;
	    }
	  }
	}
	if(!(time%240)){
	  if(obj->weapon1.n<obj->weapon1.max_n){
	    if(players[obj->player].gold>obj->weapon1.projectile.unitcost){
	      players[obj->player].gold-=obj->weapon1.projectile.unitcost;
	      obj->weapon1.n++;
	    }
	  }
	}
	if(!(time%14)){
	  if(obj->weapon2.n<obj->weapon2.max_n){
	    if(players[obj->player].gold>obj->weapon2.projectile.unitcost){
	      players[obj->player].gold-=obj->weapon2.projectile.unitcost;
	      obj->weapon2.n++;
	    }
	  }
	}
      }
      /* Learning Experience */
      
      if(time - obj->cdata->tmlevel>50){
	int mlevel=0;
	mlevel=NearMaxLevelObj(obj,&listheadcontainer[obj->in->id]);

	obj->cdata->tmlevel=time;
	obj->cdata->mlevel=mlevel;
      }
      if(obj->cdata->mlevel - obj->level > 2){
	float factor=0.02;
	Experience(obj,(obj->cdata->mlevel - obj->level)*factor);
      }

    }  /*if(obj->mode==LANDED) */

  }
  if(obj->habitat==H_PLANET){
    gwidth=GameParametres(GET,GWIDTH,0);

    if(obj->x<0)obj->x+=gwidth;
    if(obj->x>gwidth)obj->x-=gwidth;

    if(obj->y>GameParametres(GET,GHEIGHT,0)){ /* its out of planet */
      if(proc==players[obj->player].proc){
	a=obj->x*(2*PI)/gwidth-PI;
	cosa=cos(a);
	sina=sin(a);
	obj->x=obj->in->planet->x+2*obj->in->planet->r*cosa;
	obj->y=obj->in->planet->y+2*obj->in->planet->r*sina;
	
	vo=-obj->vx;
	vr=obj->vy;
	obj->vx=vr*cosa-vo*sina;
	obj->vy=vr*sina+vo*cosa;
	
	rx=obj->x - obj->in->planet->x;
	ry=obj->y - obj->in->planet->y;
	
	a=atan2(ry,rx);
	
	/*      obj->a=obj->a-a+PI/2;  */
	obj->a=a-PI/2+obj->a;
	
	obj->habitat=H_SPACE;
	obj->planet=NULL;
	obj->in=NULL;
	if(GameParametres(GET,GNET,0)==TRUE){
	  SetModified(obj,SENDOBJAALL);  /*on getting out of planet */
	  obj->ttl=0;
	}
	if(obj==cv){
	  habitat.type=H_SPACE;
	  habitat.obj=NULL;
	}
      }
    }
  }
  
  return;
}

void UpdateAsteroid(Object *obj){
  /* 
     Calculate the new coordinates of the asteroid *obj
     Only gravitational forces.
  */

  float vx,vy,vmax2;
  float fx,fy;
  float fx0,fy0;
  float dtim;
  float factor;
  float g=1.2/250000;
  float U;
  int proc,gwidth;


  if(obj->type!=ASTEROID)return;

  proc=GetProc();

  vx=obj->vx;
  vy=obj->vy;
  dtim=DT/obj->mass;
  
  fx0=fy0=0;

  if(obj->habitat==H_SPACE){
    U=PlanetAtraction(&fx0,&fy0,obj->x,obj->y,obj->mass);
  }
  else{
    if(obj->mode==NAV){
      if(obj->in!=NULL){
	fy0=-g*obj->mass*(float)obj->in->mass;
      }
      else{
	printf("in = NULL in id: %d\n",obj->id);
	return;
      }
    }
  }

  obj->x0=obj->x;
  obj->y0=obj->y;
 
  obj->x+=obj->vx*DT+.5*fx0*DT*dtim;
  obj->y+=obj->vy*DT+.5*fy0*DT*dtim;
  
  fx=fy=0;
  if(obj->habitat==H_SPACE){
    PlanetAtraction(&fx,&fy,obj->x,obj->y,obj->mass);
  }
  else{
    fy=-g*obj->mass*(float)obj->in->mass;
  }

  vx+=.5*(fx+fx0)*dtim;
  vy+=.5*(fy+fy0)*dtim;

  /* if max vel is reached, reescaling */
  
  vmax2=(VELMAX*VELMAX/16.0);

  if(vx*vx+vy*vy>vmax2){
    factor=sqrt(vmax2/(vx*vx+vy*vy));
    if(factor>1){
      printf("ERROR factor>1\n");
      printf("\tobj_enginev2max: %d %d\n",obj->engine.v2_max,(obj->state<25));
    }
    vx*=factor;
    vy*=factor;
  }

  obj->a+=DT*obj->ang_v; 

  if(obj->a > PI)obj->a-=2*PI;
  if(obj->a < -PI)obj->a+=2*PI;

  obj->vx=vx;
  obj->vy=vy;
  obj->fx0=obj->fx;
  obj->fy0=obj->fy;

  if(obj->habitat==H_PLANET){
    gwidth=GameParametres(GET,GWIDTH,0);

    if(obj->x<0)obj->x+=gwidth;
    if(obj->x>gwidth)obj->x-=gwidth;
  }
  
  return;
}


void Collision(struct HeadObjList *lh){
  /*
    version 02.(200211) without CollisionList
    Calculate the collision between objects 
  */  

  struct ObjList *ls1,*ls2;
  Object *obj1,*obj2,*objt1,*objt2;
  Object *obj,*pnt,*shot;
  Object *nobj;
  struct Planet *planet;
  Segment s;
  float radio2,r,r2,rx,ry;
  float radar1,radar2;
  float r02,r0x,r0y;
  float damage;
  float v;
  float a,b;
  char text[TEXTMENMAXLEN];  
  int i,j;
  int gwidth,gheight,gkplanets,gnet,gnplayers;
  int proc;
  int crashsw=0;
  static int cont=0;


  gwidth=GameParametres(GET,GWIDTH,0);
  gheight=GameParametres(GET,GHEIGHT,0);
  gkplanets=GameParametres(GET,GKPLANETS,0);
  gnet=GameParametres(GET,GNET,0);
  gnplayers=GameParametres(GET,GNPLAYERS,0);

  proc=GetProc();

  /* among objs and ship */
  ls1=lh->next;

  /* among objs */
  while(ls1!=NULL){ 

    obj1=ls1->obj;

    if(obj1->state<=0){
      ls1=ls1->next;
      continue;
    }

    switch(obj1->type){
    case SHIP:
      
      if(gnet==TRUE && obj1->ttl<MINTTL){ls1=ls1->next;continue;}

      break;
    case PROJECTILE:
      if(obj1->subtype==EXPLOSION){ 
	ls1=ls1->next;continue; 
      }
      break;
    case TRACKPOINT:
    case TRACE:
      ls1=ls1->next;
      continue;
      break;
    default:
      break;
    }
    
    radar1=obj1->radar;

    ls2=ls1->next;

    if(obj1->type==PLANET){
      while(ls2!=NULL && ls2->obj->type==PLANET){
	ls2=ls2->next;
      }
    }
    while(ls2!=NULL){  /* double loop */
      if(obj1->state<=0){
	ls2=ls2->next;
	continue;
      }
      obj2=ls2->obj;

      switch(obj2->type){
      case SHIP:
	if(gnet==TRUE){
	  if(obj2->ttl<MINTTL){ls2=ls2->next;continue;}
	}

	break;
      case PROJECTILE:
	if(obj1->type==PROJECTILE){
	  /* missiles collides with the others projectiles */ 
	  if(obj1->subtype!=MISSILE && obj2->subtype!=MISSILE){
	    ls2=ls2->next;continue;
	  }
	}
	break;
      case PLANET:
	if(obj1->type==PLANET){
	  ls2=ls2->next;continue;
	}
	break;
      case ASTEROID:
	if(obj1->type==ASTEROID){
	  ls2=ls2->next;continue;
	}
	break;
      case TRACKPOINT:
      case TRACE:
	ls2=ls2->next;continue;
	break;
      default:
	break;
      }

      if(obj1->player==obj2->player){ /* same player, two ships or shots */
	if((obj1->type!=PLANET && obj2->type!=PLANET)){
	  ls2=ls2->next;
	  continue;
	}
      }

      if(obj2->state<=0){
	ls2=ls2->next;
	continue;
      }

      if(obj1->in!=obj2->in){
	ls2=ls2->next;
	continue;
      }
      if(obj1->parent==obj2 || obj2->parent==obj1){
	ls2=ls2->next;
	continue;
      }
      if(gnet==TRUE){
	if(players[obj1->player].proc==players[obj2->player].proc){
	  if(proc!=players[obj1->player].proc){
	    ls2=ls2->next;
	    continue;
	  }
	}
      }

      if(players[obj1->player].team==players[obj2->player].team){
	if(!(obj1->type==PLANET || obj2->type==PLANET)){
	  ls2=ls2->next;
	  continue;
	}
      }

      radar2=obj2->radar;
      radio2=(obj1->radio+obj2->radio)*(obj1->radio+obj2->radio);
      
      rx=obj2->x - obj1->x;
      ry=obj2->y - obj1->y;
      r2=rx*rx+ry*ry;
      
      r0x=obj2->x0 - obj1->x0;
      r0y=obj2->y0 - obj1->y0;
      r02=0.25*((rx+r0x)*(rx+r0x)+(ry+r0y)*(ry+r0y));


      /* Experience in combat, among SHIPS */
      if(r2<1000000){      
	if(obj1->type==SHIP && obj2->type==SHIP){
	  if(players[obj2->player].team!=players[obj1->player].team){
	    if(obj1->habitat==obj1->habitat){
	      int il;
	      float factor,points;
	      /* obj1 */
	      if(proc==players[obj1->player].proc){
		il=obj2->level-obj1->level;
		factor=0.001;
		if(il==-1)factor/=2;
		if(il<-1)factor=0;
		if(factor>0){
		  points=(il+2)*(il+2)*factor*(obj2->level+1);
		  Experience(obj1,points);
		}
	      }
	      /* obj2 */
	      if(proc==players[obj2->player].proc){
		il=obj1->level-obj2->level;
		factor=0.001;
		if(il==-1)factor/=2;
		if(il<-1)factor=0;
		if(factor>0){
		  points=(il+2)*(il+2)*factor*(obj1->level+1);
		  Experience(obj2,points);
		}
	      }
	    }
	  }
	}
      }
    /* --Experience in combat */

      /* planets and SHIPS */
      if(gkplanets==FALSE){
	/*	if(r2<RADAR_RANGE2){  planet  discovered  */
	if((obj1->type==PLANET && obj2->type==SHIP) ||
	   (obj2->type==PLANET && obj1->type==SHIP)){

	  if(r2<radar1*radar1 || r2<radar2*radar2){ /* planet  discovered */	    
	    if(obj1->type==PLANET){
	      obj=obj2;
	      pnt=obj1;
	    }
	    else{
	      obj=obj1;
	      pnt=obj2;
	    }
	    
	    if(!((cont+obj->id)%20)){
	      if(r2<obj->radar*obj->radar){

		if(IsInIntList((players[obj->player].kplanets),pnt->id)==0){
		  for(i=0;i<=gnplayers+1;i++){
		    if(players[obj->player].team==players[i].team){
		      players[i].kplanets=Add2IntList((players[i].kplanets),pnt->id);;
		      snprintf(text,TEXTMENMAXLEN,"(%d) PLANET %d discovered",obj->pid,pnt->id);
		      Add2TextMessageList(&listheadtext,text,obj->id,obj->player,0,100,0);
		    }
		  }
		}
	      }
	    }
	  }
	}
      }
      /* --planets and SHIPS */


      if(r2<radio2 || r02<radio2){
	if(obj1->type==PROJECTILE || obj2->type==PROJECTILE){
	  if(obj1->subtype==LASER || obj2->subtype==LASER){
	    if(obj1->subtype==LASER){
	      obj=obj2;
	      shot=obj1;
	    }
	    else{
	      obj=obj1;
	      shot=obj2;
	    }
	    r=(obj->x-shot->x)*sin(shot->a)-(obj->y-shot->y)*cos(shot->a);
	    r2=r*r;
	    if(r2>obj->radio*obj->radio){
	      ls2=ls2->next;
	      continue;
	    }
	  }
	}

	/*
	   objects and planets 
	*/

	if((obj1->type==PLANET && obj2->type!=PLANET) ||
	   (obj2->type==PLANET && obj1->type!=PLANET)){

	  /* inner planet */
	  if(obj1->type==PLANET){
	    obj=obj2;
	    pnt=obj1;
	  }
	  else{
	    obj=obj1;
	    pnt=obj2;
	  }
	  if(proc==players[obj->player].proc){
	    obj->habitat=H_PLANET;
	    obj->planet=NULL;
	    obj->in=pnt;
	    
	    /*entering planet */
	    if(gnet==TRUE){
	      if(proc==players[obj->player].proc){
		SetModified(obj,SENDOBJAALL);
		obj->ttl=0;
	      }
	    }
	    if(obj==cv){
	      habitat.type=H_PLANET;
	      habitat.obj=pnt;
	    }
	    /* initial conditions at planet */
	    a=atan2(-pnt->y+obj->y,-pnt->x+obj->x);
	    b=atan2(obj->vy,obj->vx)-a;
	    obj->x=(a+PI)/(2*PI)*gwidth;
	    obj->y=gheight;
	    v=sqrt(obj->vx*obj->vx+obj->vy*obj->vy);
	    
	    obj->vx=-v*sin(b);
	    obj->vy=v*cos(b);
	    
	    obj->a=obj->a-a+PI/2;
	    if(obj->a > PI)obj->a-=2*PI;
	    if(obj->a < -PI)obj->a+=2*PI;
	    if(obj->actorder.id!=-1)obj->actorder.time=0;
	  }
	}

	/*  --objects and planets */


	/* among ships and projectiles */
	if((obj1->type!=PLANET && obj2->type!=PLANET)){

	  for(i=0;i<2;i++){
	    if(i==0){
	      objt1=obj1;
	      objt2=obj2;
	    }
	    if(i==1){
	      objt1=obj2;
	      objt2=obj1;
	    }

	    damage=objt2->damage*(1-objt1->shield);
	    
	    objt1->state-=damage;
	    
	    Play(objt1,CRASH,1);
	    if(objt1==cv)gcrash=1;
	    if(objt1->type==SHIP){
	      /*receive an impact */
	      if(objt1->state>0){
		if(proc==players[objt1->player].proc){
		  Experience(objt1,damage/2); /* experience for receive an impact*/
		}
		
		if(objt1->player==actual_player && cv!=objt1){
		  snprintf(text,TEXTMENMAXLEN,"(%c %d) HELP",Type(objt1),objt1->pid);
		  Add2TextMessageList(&listheadtext,text,objt1->id,objt1->player,0,100,2);
		}
	      }
	    }
	    if(objt1->type==SHIP || objt1->type==ASTEROID || objt1->subtype==MISSILE){/* HERE */
	      if(gnet==TRUE){
		if(proc==players[objt1->player].proc){
		  SetModified(objt1,SENDOBJAALL);
		  objt1->ttl=0;
		}
	      }
	    }
	    
	    if(objt1->state<=0){
	      if(obj1->in!=NULL && objt1->type==SHIP){
		float price;
		
		price=0.025*GetPrice(objt1,0,0,0);
		if(price>0){
		  objt1->in->planet->gold+=price;
		}
	      }


	      if(objt2->type==SHIP){
		objt1->sw=objt2->id;
	      }
	      if(objt2->type==PROJECTILE){
		if(objt2->parent!=NULL){
		  objt1->sw=objt2->parent->id;
		}
	      }

		
	      if(gnet==TRUE){
		if(proc==players[objt1->player].proc){
		  SetModified(objt1,SENDOBJKILL);
		  objt1->ttl=0;
		}
	      }
	      switch(objt1->type){
	      case SHIP:
		break;
	      case ASTEROID:
/* 		if(objt1->in!=NULL){ */
/* 		  objt1->in->planet->gold+=(4-objt1->subtype)*200; */
/* 		} */
		if(objt1->subtype<ASTEROID3){
		  if(proc==players[objt1->player].proc){
		    for(j=0;j<3;j++){
		      nobj=NewObj(&listheadobjs,ASTEROID,objt1->subtype+1, 
				  objt1->x,objt1->y,objt1->vx+10.0*rand()/RAND_MAX-5,objt1->vy+10.0*rand()/RAND_MAX-5, 
				  CANNON0,ENGINE0,0,NULL,objt1->in); 
		      nobj->a=PI/2;
		      nobj->ai=0;
		      nobj->in=objt1->in;
		      nobj->habitat=objt1->habitat;
		      nobj->mode=NAV;
		      Add2ObjList(&listheadobjs,nobj);
		    }
		  }
		}
		break;
	      default:
		break;
	      }
	    }
	  } /* for(i=0;i<2;i++){ */
	}
	/* --among ships and projectiles */
      }     /*  if(r2<radio2 || r02<radio2){ */
      else{
	if(r2<4*radio2 && 0){
	  /* Avoid collision */ /* TODO */

	}
      }

      ls2=ls2->next;
    } /* while ls2!=NULL */ /* --double loop*/ 

    /* collision with planet terrain */
    if(obj1->mode!=LANDED && obj1->habitat==H_PLANET){
      if(proc==players[obj1->player].proc || obj1->type==PROJECTILE){
	planet=obj1->in->planet;
	crashsw=0;
	if(!GetSegment(&s,obj1)){
	  if(obj1->y - obj1->radio +1< s.y0 && obj1->y - obj1->radio +1< s.y1){
	    if(obj1->type!=SHIP){ /* destroy object */
	      obj1->state=0;
	      obj1->sw=0;
	      
	      if(obj1->type==ASTEROID){
		planet->gold+=100*pow(2,5-obj1->subtype);
	      }
	      if(gnet==TRUE){
		if(proc==players[obj1->player].proc){
		  SetModified(obj1,SENDOBJKILL);
		  SetModified(obj1->in,SENDOBJPLANET); /* HERE */
		  obj1->ttl=0;
		}
	      }
	    }
	    if(obj1->type==SHIP){
	      switch(s.type){
	      case TERRAIN:  /* destroy ship */
		crashsw=1;
		break;
	      case LANDZONE:
		if(fabs(obj1->vx)>2 || /* ship crashed */
		   fabs(obj1->vy)>5 ||
		   fabs(obj1->a-PI/2)>.35){
		  crashsw=1;
		}
		else{ /* ship has landed */
		  if(obj1->vy<0){
		    obj1->mode=LANDED;
		    if(gnet==TRUE){
		      if(proc==players[obj1->player].proc){
			SetModified(obj1,SENDOBJAALL);
			obj1->ttl=0;
		      }
		    }
		    obj1->vx=0;
		    obj1->vy=0;
		    obj1->ang_a=0;
		    obj1->ang_v=0;
		    obj1->y=obj1->y0=s.y0+obj1->radio+1;
		  }
		  
		  if(players[obj1->in->player].team!=players[obj1->player].team){
		    char text[TEXTMENMAXLEN];
		    if(players[obj1->in->player].team != 1){
		      GetInformation(&players[obj1->player],&players[obj1->in->player],obj1);
		    }
		    Experience(obj1,50);  /* Experience for conquest a planet */
		    
		    snprintf(text,TEXTMENMAXLEN,"Planet %d LOST",obj1->in->id);
		    Add2TextMessageList(&listheadtext,text,obj1->in->id,obj1->in->player,0,100,2);
		    
		    obj1->in->player=obj1->player;
		    if(gnet==TRUE){
		      if(proc==players[obj1->player].proc){
			SetModified(obj1->in,SENDOBJPLANET);
			players[obj1->player].modified=SENDPLAYERMOD;
			obj1->ttl=0;
		      }
		    }
		  }
		  else{
		    if(PlanetEmpty(obj1->in,obj1)){
		      obj1->in->player=obj1->player;
		      if(gnet==TRUE){
			if(proc==players[obj1->player].proc){
			  SetModified(obj1->in,SENDOBJPLANET);
			  players[obj1->player].modified=SENDPLAYERMOD;
			  obj1->ttl=0;
			}
		      }
		    }
		  }
		}
		break;
	      default:
		break;
	      }
	      
	      if(crashsw){
		float price,factor;

		factor=0.01*obj1->state*0.25;
		if(factor<.1)factor=.1;  /* at least an 10 percent*/
		price=factor*GetPrice(obj1,0,0,0);
		if(price>0){
		  planet->gold+=price;
		}
		
		obj1->state=0;
		obj1->sw=0;
		
		if(gnet==TRUE){
		  if(proc==players[obj1->player].proc){
		    SetModified(obj1,SENDOBJKILL);
		    SetModified(obj1->in,SENDOBJPLANET);
		    obj1->ttl=0;
		  }
		}
		crashsw=0;
	      }
	    }/* if SHIP*/
	  } /* if(obj1->y - obj1->radio < s.y0 && obj1->y - obj1->radio < s.y1){ */
	} /* if GetSegment()*/
      } /*      if(obj1->mode!=LANDED && obj1->habitat==H_PLANET ) */
    }
    /* --collision with planet terrain */
    
    ls1=ls1->next;
  } /* while(ls1!=NULL) */

  cont++;
  if(cont>10000)cont=0;
  return;
}





int UpdateObjs(void){
  /*
    Update the coordinates of the objects.
  */  
  
  int n=0;
  struct ObjList *ls;
  Object *obj,*nobj,*ship_enemy;
  float d2;
  float rx,ry,b,ib;  
  int gnet;
  int proc;

#if CLOSEDUNIVERSE 
  int gulx,guly;
  gulx=GameParametres(GET,GULX,0);
  guly=GameParametres(GET,GULY,0);

#endif

  
  gnet=GameParametres(GET,GNET,0);
  proc=GetProc();

  ls=listheadobjs.next;
  
  if(listheadobjs.n==0)return(0);
  
  while(ls!=NULL){
    obj=ls->obj;
    
    if(obj->durable==TRUE){
      
      obj->life--;
      if(obj->life<=0){
	obj->life=0;
	obj->state=0;
	obj->sw=0;
      }
    }
    
    if(obj->life>0){/* && proc==players[obj->player].proc){ */
      
      switch(obj->type){
      case PROJECTILE:
	switch(obj->subtype){
	case MISSILE:
	  ship_enemy=NearestObj(&listheadobjs,obj,SHIP,PENEMY,&d2);
	  if(ship_enemy!=NULL){
	    if(ship_enemy->habitat!=obj->habitat)ship_enemy=NULL;
	    if(d2>obj->radar*obj->radar)ship_enemy=NULL;
	  }

	  if(ship_enemy==NULL){
	    obj->ang_a=obj->ang_v=0;
	    
	    obj->accel+=obj->engine.a;
	    if(obj->accel > obj->engine.a_max)
	      obj->accel=obj->engine.a_max;	    
	    
	  }
	  else{
	    rx=ship_enemy->x - obj->x;
	    ry=ship_enemy->y - obj->y;
	    b=atan2(ry,rx);
	    ib=b - obj->a;
	    
	    if(ib>0){
	      obj->ang_a+=obj->engine.ang_a;
	      if(obj->ang_a<0)obj->ang_a=0;
	    }
	    if(ib<0){
	      obj->ang_a-=obj->engine.ang_a;
	      if(obj->ang_a>0)obj->ang_a=0;
	    }
	    obj->accel+=obj->engine.a;
	    if(obj->accel > obj->engine.a_max)
	      obj->accel=obj->engine.a_max;	    
	  }
	  UpdateShip(obj);	  
	  break;
	default:
	  obj->x0 = obj->x;
	  obj->y0 = obj->y;
	  
	  obj->x += obj->vx*DT;
	  obj->y += obj->vy*DT;
	  break;
	}
	break;
      case SHIP:
	if(obj->trace==TRUE && habitat.type==H_SPACE){
	  nobj=NewObj(&listheadobjs,TRACE,NULO,
		 obj->x,obj->y,
		 0,0,
		      CANNON0,ENGINE0,obj->player,obj,obj->in);
	  Add2ObjList(&listheadobjs,nobj);
	}

	switch(obj->subtype){
	case SHIP1:
	case SHIP2:
	case SHIP3:
	case SHIP4:
	case SATELLITE:
	case TOWER:
	  if(proc==players[obj->player].proc){
	    ai(&listheadobjs,obj,actual_player);
	  }
	  UpdateShip(obj);
	  break;
	  
	default:
	  g_print("ERROR (UpdateObjs 1)\n");
	  exit(-1);
	  break;
	}
	break;
      case ASTEROID:
	UpdateAsteroid(obj);
	break;
	
      case TRACKPOINT:
      case TRACE:
	break;
      case PLANET:
	/* planets create some gold */
	obj->planet->A=obj->planet->reggold;
	break;
	
      default:
	g_print("ERROR (UpdateObjs 2) %d\n",obj->type);
	exit(-1);
	break;
	
      }
#if CLOSEDUNIVERSE 
      if(obj->x>gulx)obj->x-=gulx;
      if(obj->x<0)obj->x+=gulx;
      if(obj->y>guly)obj->y-=guly;
      if(obj->y<0)obj->y+=guly;
#endif
    } /* if (obj->life>0) */
    
    if(obj->life<=0){
      obj->state=0;obj->sw=0;
    }
    
    if(gnet==TRUE){
      obj->ttl--;
      if(obj->life<=0){
	if(GetProc()==players[obj->player].proc){
	  SetModified(obj,SENDOBJKILL);
	  obj->ttl=0;
	}
      }
    }
    
    ls=ls->next;
    n++;
    if (n>listheadobjs.n){
      g_print("ERROR: n: %d  N: %d\n",n,listheadobjs.n);
      return(-1);
    }
  } /* while(ls!=NULL) */
  return (n);
}

gint TimerCreateObj(gpointer data){
  Object *nobj;

  nobj=NewObj(&listheadobjs,SHIP,SHIP1, 
	 GameParametres(GET,GWIDTH,0)*Random(-1), 
	 GameParametres(GET,GHEIGHT,0)*Random(-1), 
	 0,0,
	 /*level_vel*(2*VELMAX*(Random(-1))-VELMAX),  */
	 /*level_vel*(2*VELMAX*(Random(-1))-VELMAX),  */
	      CANNON0,ENGINE2,0,NULL,NULL);
  Add2ObjList(&listheadobjs,nobj);
  return 1000;
}

int IsValidPosition(float x,float y,float r){
  /*
    Not used
  */

  struct ObjList *ls;
  float rx,ry,r2,radio2;

  ls=listheadobjs.next;
  while(ls!=NULL){
    rx=ls->obj->x-x;
    ry=ls->obj->y-y;
    
    rx+= LX*(-(rx > LX/2) + ((-rx) > LX/2));
    ry+= LY*(-(ry > LY/2) + ((-ry) > LY/2));
    
      r2=rx*rx+ry*ry;
      
      radio2=(ls->obj->radio+r)*(ls->obj->radio+r);
      
      if (r2<radio2){
	g_print("no valid\n");
	return(0);
      }
      ls=ls->next;
  }
 
  g_print("valid\n");
  return 1;
}


int CheckPlanetDistance(struct HeadObjList *lh,float x,float y){
  /*
    The distance between two planets must be greater than 600
  */

  struct ObjList *ls;

  ls=lh->next;
  while(ls!=NULL){
    if(ls->obj->type==PLANET){      
      if((ls->obj->x-x)*(ls->obj->x-x)+(ls->obj->y-y)*(ls->obj->y-y)<600*600 ){
	return(1);
      }
    }
    ls=ls->next;
  }
  
  return(0);

}

void CreateUniverse(int ulx,int uly,struct HeadObjList *lheadobjs,char **ptnames){
  /*
    Create Galaxies and planets.
   */


  int i,j;
  float x,y;
  float x0,y0;
  float rg;
  Object *obj;
  int n,np=0;
  int nplanetpergalaxie=1;
  int nplanets;
  int ngalaxies=1;


  ngalaxies=GameParametres(GET,GNGALAXIES,0);

  if(ngalaxies==1)rg=ulx;
  else
    rg=ulx/(2*ngalaxies);

  nplanets=GameParametres(GET,GNPLANETS,0);
  nplanetpergalaxie=(int)((float)nplanets/ngalaxies+0.5);


  printf("\n\tnumber of galaxies: %d\n",ngalaxies);
  printf("\tnumber of planets per galaxy: %d\n",nplanetpergalaxie);
  printf("\tgalaxy radius: %.0f\n",rg);

  for(j=0;j<ngalaxies;j++){
    if(np>=nplanets)break;
    x0=(ulx-2*rg)*Random(-1)-(ulx-2*rg)/2;
    y0=(uly-2*rg)*Random(-1)-(uly-2*rg)/2;
    if(ngalaxies==1){
      x0=0;
      y0=0;
    }
    for(i=0;i<nplanetpergalaxie;i++){
      if(np>=nplanets)break;
      n=0;
      do{
	x=x0+rg*Random(-1)-rg/2;
	y=y0+rg*Random(-1)-rg/2;
	n++;
	if(n>100){
	  fprintf(stderr,"ERROR: Universe size too small or too much planets. Exiting...\n");
	  exit(-1);
	}
      }
      while(CheckPlanetDistance(lheadobjs,x,y));

      if(x<-ulx/2||x>ulx/2||y<-uly/2||y>uly/2){
	printf("WARNING CreateUniverse(): planet out of limits: %f %f\n",x,y); 
      }	

      obj=NewObj(lheadobjs,PLANET,NULO,x,y,0,0,CANNON0,ENGINE0,0,NULL,NULL);
      if(obj!=NULL){
      
	if(i<NUMPLANETNAMES-1 && j==0){
	  strncpy(obj->name,ptnames[i+1],OBJNAMESMAXLEN);
	}
	else{
	  strncpy(obj->name,ptnames[0],OBJNAMESMAXLEN);
	}
	Add2ObjList(lheadobjs,obj);
	np++;
      }
    }
  }
  if(np<nplanets){
    int m=nplanets-np;
    //    printf("WARNING CreateUniverse(): number of planets incorrect: %d\n",np);
    for(i=0;i<m;i++){
      x=ulx*Random(-1)-ulx/2;
      y=uly*Random(-1)-uly/2;

      obj=NewObj(lheadobjs,PLANET,NULO,x,y,0,0,CANNON0,ENGINE0,0,NULL,NULL);
      if(obj!=NULL){
	
	if(i<NUMPLANETNAMES-1 && j==0){
	  strncpy(obj->name,ptnames[i+1],OBJNAMESMAXLEN);
	}
	else{
	  strncpy(obj->name,ptnames[0],OBJNAMESMAXLEN);
	}
	Add2ObjList(lheadobjs,obj);
	np++;
      }
    } 
  }
  printf("\tnumber of planets created: %d\n",np);
}

float PlanetAtraction(float *fx,float *fy,float x,float y,float m){
  /*
    calculates the atraction forces betwwen ships and planets
    returns:
    the force in fx,fy arguments.
    the potential energy.
  */

  struct ObjList *ls;
  float rx,ry,r,r2,ir2r;
  float U; /* potential*/
  float GM;
  
  ls=listheadplanets.next;
  U=0;

  while (ls!=NULL){
    rx=ls->obj->x-x;
    ry=ls->obj->y-y;
    r2=rx*rx+ry*ry;

    if(r2<GRAVITATION_RANGE2){
      GM=G*ls->obj->mass;
      r=sqrt(r2);
      ir2r=1./(r2*r);
      *fx+=GM*rx*ir2r;
      *fy+=GM*ry*ir2r;
      U-=GM/r;
    }

    ls=ls->next;
  }
 
  *fx*=m;
  *fy*=m;
  U*=m;

  return(U);
}


int PrintfObjInfo(FILE *fp,Object *obj){
  /*
    printf obj info
    used only for debug.
   */

  int in,dest,parent,planet;
  fprintf(fp,"time: %d\n id:%d durable:%d visible:%d\n \
points:%d habitat:%d mode:%d \nmodified: %d \n	       \
x:%g y:%g x0:%g y0:%g \nvx:%g vy:%g \n		       \
fx0:%g fy0:%g fx:%g fy:%g\n a:%g ang_v:%g accel:%g \n  \
gas:%g gas_max:%g life:%g shield:%g state:%g\n",
	  GetTime(),
	  obj->id,obj->durable,obj->visible,
	  obj->kills,obj->habitat,obj->mode,
	  obj->modified,
	  obj->x,obj->y,obj->x0,obj->y0,
	  obj->vx,obj->vy,
	  obj->fx0,obj->fy0,obj->fx,obj->fy,
	  obj->a,obj->ang_v,obj->accel,
	  obj->gas,obj->gas_max,
	  obj->life,obj->shield,obj->state);

  fprintf(fp,"dest_r2:%g mass:%d radio:%d \ntype:%d subtype:%d\n\
 damage:%d player:%d player:%d\nai:%d trace:%d norder:%d\n",
	  obj->dest_r2,obj->mass,obj->radio,
	  obj->type,obj->subtype,
	  obj->damage,obj->player,obj->player,
	  obj->ai,obj->trace,obj->norder);
  
  in=0;
  dest=0;
  planet=0;
  parent=0;

  if(obj->in!=NULL)in=obj->in->id;
  if(obj->dest!=NULL)dest=obj->dest->id;
  if(obj->parent!=NULL)parent=obj->parent->id;
  if(obj->planet!=NULL)planet=obj->id;
  
  fprintf(fp,"parent:%d dest:%d in:%d planet:%d\n weapon:%d engine:%d\n ",
	  parent,dest,in,planet,
	  obj->weapon->type,obj->engine.type);
  

  fprintf(fp,"parent:%p dest:%p in:%p planet:%p\n",
	  obj->parent,obj->dest,obj->in,obj->planet);

  return(0);
}

Object *ChooseInitPlanet(struct HeadObjList lheadobjs){
  /*
    returns:
    a pointer to a free planet.
   */

  struct ObjList *ls;
  int cont=0;
  int nplanets=0;
  int rplanet;

  /* counting planets */
  ls=lheadobjs.next;
  while(ls!=NULL){
    if(ls->obj->type==PLANET){
      cont++;
    }
    ls=ls->next;
  }

  nplanets=cont;
  rplanet=(int)(nplanets*Random(-1));

  ls=lheadobjs.next;
  cont=0;
  while(ls!=NULL){
    if(ls->obj->type==PLANET){
      if(ls->obj->player==0 && cont==rplanet){  /* a random planet */
	return(ls->obj);
      }
    }
    ls=ls->next;
    cont++;
  }

  cont=0;
  ls=lheadobjs.next;
  while(ls!=NULL){
    if(ls->obj->type==PLANET ){
      if(ls->obj->player==0){  /* the first free planet */
	return(ls->obj);
      }
    }
    ls=ls->next;
    cont++;
  }

  printf("ERROR ChooseInitPlanet(): Too many players or too few planets\n");
  return(NULL);
}

void CreateShips(struct HeadObjList *lheadobjs){
  /*
    Choose initial planet.
    Create the initial player ships
   */
  Object *obj,*planet;
  Segment *s;
  int i;

  
  for(i=1;i<=GameParametres(GET,GNPLAYERS,0);i++){
    planet=ChooseInitPlanet(*lheadobjs);
    if(planet==NULL){
      fprintf(stderr,"ERROR CreateShips(): obj==NULL\n");
      exit(-1);
    }
    s=LandZone(planet->planet);
    if(s==NULL){
      fprintf(stderr,"ERROR CreateShips(): Segment==NULL\n");
      exit(-1);
    }

    obj=NewObj(lheadobjs,SHIP,QUEEN,
	       0,0,0,0,
	       CANNON5,ENGINE5,i,NULL,planet);
    obj->x=obj->x0=.5*(s->x0+s->x1);
    obj->y=obj->y0=s->y0+obj->radio+1;
    obj->a=PI/2;
    obj->ai=1;
    obj->habitat=H_PLANET;
    obj->mode=LANDED;


      
    Add2ObjList(lheadobjs,obj);
    players[obj->player].nbuildships++;

    planet->player=obj->player;

    if(GameParametres(GET,GNET,0)==TRUE){
      if(GetProc()==players[planet->player].proc){
	SetModified(planet,SENDOBJPLANET);
	planet->ttl=0;
      }
    }

    players[obj->player].kplanets=Add2IntList((players[obj->player].kplanets),planet->id);
    players[obj->player].nplanets++;

    if(GameParametres(GET,GKPLANETS,0)==FALSE){
      int j,k;
      
      for(j=-2;j<3;j++){
	for(k=-2;k<3;k++){
	  if(j*j+k*k<8){  
	    Add2IntIList(&(players[obj->player].ksectors),
			 Cuadrante(planet->x+j*SECTORSIZE,planet->y+k*SECTORSIZE));
	  }
	}
      }
    }
    if(i==actual_player){
      cv=obj;
      ship_c=obj;
      habitat.type=H_PLANET;
      habitat.obj=planet;
      /*      obj->in->mass*=5; */
    }
  }
  return;
}


int CheckGame(char *cad){
  /*
    Check some game consistence.
    Used every step (!!HERE check this)
    Used after load a game.
  */

  struct ObjList *ls;
  struct ListOrder *lo;
  Object *obj;
  int nord;
  int i;
  int n=0;
  int types[20];
  int type;
  int proc;


  proc=GetProc();

  /* Checking Orders */

  for(i=0;i<20;i++){
    types[i]=0;
  }


  printf("%s",cad);
 
  ls=listheadobjs.next;
  while(ls!=NULL){
    obj=ls->obj;

    type=obj->type+1;
    if(type>19)type=19;
    types[type]++;


    if(proc==players[obj->player].proc){
      nord=obj->norder;
      n=0;
      lo=obj->lorder;
      while(lo!=NULL){
	n++;
	lo=lo->next;
      }
      if(n!=obj->norder){
	printf("ERROR CheckGame():norder incorrect\n");
	printf("\tObj: %d, type: %d norder=%d , size of list: %d\n",
	     obj->id,obj->type,obj->norder,n);
	printf("\tDeleting all the orders of object %d\n",obj->id);
	DelAllOrder(obj);
      } 

      /* if planet dont belongs to a landed ship */
      if(obj->mode==LANDED && obj->in==NULL){
	fprintf(stderr,"\tError CheckGame() obj %d landed and in NULL\n",obj->id);
	ls=ls->next;continue;
      }
      if(obj->mode==LANDED && obj->in!=NULL){
	if(obj->in->planet==NULL){
	  fprintf(stderr,"\tError CheckGame() obj %d planet not assigned\n",obj->id);
	  ls=ls->next;continue;
	}
      }
      if(obj->mode==LANDED && players[obj->in->player].team!=players[obj->player].team){ 
	/* 
	   this is posible if two ships of different players are landed in the same planet.
	 */
	obj->in->player=obj->player;
      }
    }
    ls=ls->next;
  }
  return(0);
}


void Density(void){
  /*
    
    Not used by now

   */
  struct ObjList *ls;
  int i,j;
  int den[10][10];
  float x,y;

  for(i=0;i<10;i++)
    for(j=0;j<10;j++)
      den[i][j]=0;

  ls=listheadobjs.next;
  while(ls!=NULL){
    if(ls->obj->type==PLANET){
      
      if(ls->obj->in!=NULL){
	x=ls->obj->in->planet->x;
	y=ls->obj->in->planet->y;
      }
      else{
	x=ls->obj->x;
	y=ls->obj->y;
      }


      i=10.*x/(float)GameParametres(GET,GULX,0);
      j=10.*y/(float)GameParametres(GET,GULY,0);
      i+=5;
      j+=5;
      if(i<0)i=0;
      if(j<0)j=0;
      if(i>9)i=9;
      if(j>9)j=9;
      den[i][j]++;
    }
    ls=ls->next;
  }

  for(i=0;i<10;i++){
    for(j=0;j<10;j++){

    }
  }
}

void GetUniverse(void){

  /*ExecLoad("kk"); */
  if(ExecLoad(savefile)!=0){
    exit(-1);
  }

  p_time=GetTime();
  CheckGame("Checking game after load...");
  printf("done\n");

}

void NetComm(void){
   /* net gamming */

  /* orders to  thread:
     OTSENDOBJS: send modified objects.
     OTSENDALLOBJS save: send all the objects.
     OTSENDLOAD load: load all the objects.
     OTSENDKILL to finish: quit the program.
  */
  int mode;  
  int fd;

  mode=GameParametres(GET,GMODE,0);

  order2thread=OTSENDOBJS;

  if(mode==SERVER){
    if(keys.save==TRUE){
      order2thread=OTSENDSAVE;
    }
    
    if(keys.load==TRUE){
      /* check if is possible open the dir */ 
      /* checking the file */
      if((fd=open(savefile,O_RDONLY))==-1){
	fprintf(stdout,"CommServer()[OTSENDLOAD]:No puede abrirse el archivo %s\n",savefile);
      }
      else{
	order2thread=OTSENDLOAD;
      }
      close(fd);
    }
  }

  if(GameParametres(GET,GQUIT,0)==2){
    order2thread=OTSENDKILL;
  }

  switch(mode){
  case SERVER:
    LoadBuffer(order2thread,&buffer1,SERVER);
    sem_post(&sem_barrier1); /* run comm. thread*/
    break;
  case CLIENT:
    sem_post(&sem_barrier1); /* run comm. thread*/
    break;
  default:
    break;
  }
  
  sem_wait(&sem_barrier); /* HERE send this far away in code */
}


void signal_handler(int signo,siginfo_t *info,void *ignored){
  g_cont++;
  printf("sig: %d cont:%d\n",signo,g_cont);
}

void int_handler(int signo){
  fprintf(stderr,"signal n %d received (SIGINT)\n",signo);
  Quit(NULL,NULL);
}

void segfault_handler(int signo){
  fprintf(stderr,"signal n %d received (SEGFAULT)\n",signo);
  if(ExecSave(listheadobjs,SAVETMPFILE)!=0){
    fprintf(stderr,"Error in main(): I cant open %s\n",SAVETMPFILE);
    exit(-1);
  }
  fprintf(stderr,"game saved in %s\n",SAVETMPFILE);
  exit(-1);
  /*  Quit(NULL,NULL); */
}


void DrawInfo(GdkPixmap *pixmap,Object *obj){
  /*
    Show info of the player and actual ship.
  */  

  static GdkGC *gc;
  static GdkGC *gcframe;
  static int charw=10;
  static int charh=10;
  static int swgmess=0;
  static int glen=0;

  GdkGC *gcmessage;
  int textw;
  Object *planet;
  Object *objt;
  float d2;
  char point[TEXTMENMAXLEN];
  char tmpcad[16];
  int x,y;
  int h,m,s;
  int i;
  static int sw=0;
  int lsw;
  struct TextMessageList *lh;
  int time;
  int gwidth,gwidth2,gheight;
  int incy;

  if(sw==0){
    gc=penGreen;
    gcframe=penGreen;
    sw=1;
  }
  gwidth=GameParametres(GET,GWIDTH,0);
  gheight=GameParametres(GET,GHEIGHT,0);
  gwidth2=gwidth/2;

  time=GetTime();

  /* 
   *    General info
   */
  if(gfont!=NULL){
    charh=gdk_text_height(gfont,"pL",2);
    charw=gdk_text_width(gfont,"O",1);
  }
  else{
    charh=12;
    charw=12;
  }
  incy=charh;
  y=incy;
  x=gwidth2-7*charw;
  sprintf(point,"record: %d",record);
  DrawString(pixmap,gfont,penGreen,x,y,point);

  y+=incy;
  h=(int)(time/(20*60*60));
  m=(int)(time/(20*60))-h*60;
  s=(int)(time/(20))-h*3600-m*60;
  
  sprintf(point,"time: %d:",h);
  if(m<10){
    sprintf(tmpcad,"0%d:",m);
  }
  else{
    sprintf(tmpcad,"%d:",m);
  }
  strcat(point,tmpcad);

  if(s<10){
    sprintf(tmpcad,"0%d",s);
  }
  else{
    sprintf(tmpcad,"%d",s);
  }
  strcat(point,tmpcad);
  x=gwidth2-7*charw;
  DrawString(pixmap,gfont,penGreen,x,y,point);

  
  /* 
   *      order info 
   */

  if(keys.o==FALSE) 

    DrawString(pixmap,gfont,penRed,10,gheight+GameParametres(GET,GPANEL,0)/2+4, 
 		    "O: Introduce command"); 
    /*
     *    Ship info
     */
  if(obj!=NULL){
    if(obj->type==SHIP && keys.f5==FALSE){  
      y=DrawShipInfo(pixmap,gfont,penGreen,obj,0,0);

      sprintf(point,"============");
      DrawString(pixmap,gfont,penGreen,10,y,point);
      y+=incy;

    }
  }

  /*
   *  Player info
   */
  if(keys.f5==FALSE){
    y=DrawPlayerInfo(pixmap,gfont,penCyan,&players[actual_player],10,y);
    sprintf(point,"============");
    DrawString(pixmap,gfont,penGreen,10,y,point);
    y+=incy;
  
    
    /*
     *   Planet info
     */
    if(obj!=NULL){
      if(obj->type==PLANET)planet=obj;
      else planet=obj->in;
      
      if(planet!=NULL){

	y=DrawPlanetInfo(pixmap,gfont,penGreen,planet,10,y);
	sprintf(point,"============");
	DrawString(pixmap,gfont,penGreen,10,y,point);
	y+=incy;
      }
    }
  }
  /* Enemy info */
  objt=NearestObj(&listheadobjs,cv,SHIP,PENEMY,&d2);
  if(cv!=NULL && objt!=NULL){
    if(d2 < (cv->radar*cv->radar)){
      DrawEnemyShipInfo(pixmap,gfont,penGreen,objt,gwidth,0);
    }
  }
  
  
  /* text messages */

 /* net message */  
  if(PendingTextMessage()){
    GetTextMessage(point);
    DrawString(pixmap,gfont,gcframe,gwidth2-incy*6,.25*gheight,point);
  }

  /* game messages */

  lh=listheadtext.next;
  i=0;
  lsw=0;
  if(swgmess){
    gdk_draw_rectangle(pixmap,    
		       penBlack,
		       TRUE,   
		       10,
		       gheight-incy*swgmess-10,
		       glen+15,
		       incy*swgmess+10);

    gdk_draw_rectangle(pixmap,    
		       penRed,
		       FALSE,   
		       10,
		       gheight-incy*swgmess-10,
		       glen+15,
		       incy*swgmess+10);
  }
  glen=0;
  while(lh!=NULL){
    strncpy(point,lh->info.text,TEXTMENMAXLEN);
    if(lh->info.dest!=actual_player && lh->info.dest !=-1){
      lh->info.duration=0;
      lsw=1;
    }
    else{
      
      switch(lh->info.value){
      case 0:
	gcmessage=penRed;
	break;
      default:
	gcmessage=penWhite;
	break;
      }

      DrawString(pixmap,gfont,gcmessage,20,gheight-incy*swgmess+incy*i+5,point);
      textw=gdk_text_width(gfont,point,strlen(point));      
      if(textw>glen)glen=textw;
      if(lh->info.print==0){
	fprintf(stdout,"%s\n",point);
	lh->info.print=1;
      }
      /*      DrawString(pixmap,gfont,gcframe,350,120+15*i,point); */
      if(i<3){
	lh->info.duration--;
	if(lh->info.duration<=0)lsw=1;
      }
      i++;
    }
    if(i>9)break;

    lh=lh->next;
  }
  swgmess=i;  
  if(lsw){ /* cleaning the message list */
    struct TextMessageList *freels;
    lh=&listheadtext;
    while(lh->next!=NULL){
      if(lh->next->info.duration<=0){
	freels=lh->next;
	lh->next=lh->next->next;
	free(freels);
	g_memused-=sizeof(struct TextMessageList);
	freels=NULL;
	listheadtext.info.n--;
	continue;
      }
      lh=lh->next;
    }
  }
}

void GetGold(void){
  /*
    version 03 21Dic2010
    Count the number of planets that belongs to each player    
    Increase players gold 
   */


  struct ObjList *ls;
  int nplayers;
  int i;
  int proc;
  float inctower;
  float levelfactor;
 

  proc=GetProc();
  nplayers=GameParametres(GET,GNPLAYERS,0);


  for(i=0;i<nplayers+2;i++){
    players[i].nplanets=0;
    players[i].nships=0;
    players[i].balance=0;
  }

  ls=listheadobjs.next;
  while(ls!=NULL){
    switch(ls->obj->type){
    case PLANET:
      players[ls->obj->player].nplanets++;
      break;
    case SHIP:
      players[ls->obj->player].nships++;
      break;
    default:
      ls=ls->next;continue;
      break;
    }

    if(proc!=players[ls->obj->player].proc){
      ls=ls->next;continue;
    }
    if(ls->obj->player==0){
      ls=ls->next;continue;
    }

    switch(ls->obj->type){
    case PLANET:
      /*gold for each planet*/
      players[ls->obj->player].balance+=.01*RESOURCEFACTOR; 
      break;
    case SHIP:
      players[ls->obj->player].balance-=ls->obj->cost;

      switch(ls->obj->subtype){
      case TOWER:
	levelfactor=(1.0+1.0*ls->obj->level);
	
	if(ls->obj->in->planet->gold>0){
	  inctower=(.4+0.1*levelfactor)*RESOURCEFACTOR;
	  if(ls->obj->in->planet->gold>inctower){
	    players[ls->obj->player].balance+=inctower; 
	    ls->obj->in->planet->gold-=inctower;
	    
	  }
	  else{
	    players[ls->obj->player].balance+=ls->obj->in->planet->gold;
	    ls->obj->in->planet->gold=0;
	  }
	}
	else{
	  ls->obj->in->planet->gold=0;
	  if(ls->obj->in->planet->A > 0.015){
	    players[ls->obj->player].balance+=0.015*levelfactor;
	    ls->obj->in->planet->A-=0.015;
	  }
	  else{
	    players[ls->obj->player].balance+=ls->obj->in->planet->A*levelfactor;
	    ls->obj->in->planet->A=0.0;
	  }
	}
	break;
	
      default:
	break;
      }
      break;
    default:
      break;
    }
    ls=ls->next;
  }
  
  for(i=0;i<nplayers+2;i++){
    if(proc==players[i].proc){
      players[i].gold+=players[i].balance;
    }
  }
}

void GetPoints(struct HeadObjList hol,int proc,struct Player *p){
  /* 
     version 0.3    12Dic2010

     if state is 0 sum points and experience
  */
  
  struct ObjList *ls;
  Object *obj;   /* dead object */
  Object *obj2;  /* killer */
  Object *obj3;  /* who receive points */
  int il;
  float factor,points;
  int sw=0;
  int gnet;
  

  ls=hol.next;
  gnet=GameParametres(GET,GNET,0);

  while(ls!=NULL){
    obj=ls->obj;
    obj2=obj3=NULL;
    sw=0;
    if(gnet==TRUE){
      if(obj->modified==SENDOBJDEAD)sw=1;
    }
    else{
      if(obj->state<=0)sw=1;
    }

    if(sw){
      switch(obj->type){
      case PROJECTILE:
	/* points to nobody */

	break;
      case SHIP:
	p[obj->player].ndeaths++;
	/* points to the killer */
	if(obj->sw!=0){
	  obj2=SelectObj(&listheadobjs,(obj->sw));
	  if(obj2!=NULL){
	    obj3=NULL;
	    if(obj2->type==SHIP)obj3=obj2;
	    if(obj3!=NULL){
	      /* must be a SHIP */
	      obj3->kills++;
	      p[obj3->player].nkills++;

	      /* Experience for kill an enemy */
	      il=obj->level-obj3->level;
	      factor=50;
	      if(il<0)factor/=2;
	      if(il<-1)factor/=2;
	      if(il<-2)factor/=2;
	      if(factor>0){
		points=factor*pow(2,obj->level);
		if(points<10)points=10;
		Experience(obj3,points);
	      }
	      /* --Experience for kill an enemy */
	    }
	  }
	}
	break;
      case ASTEROID:
	if(obj->sw!=0){
	  obj2=SelectObj(&listheadobjs,(obj->sw));
	  if(obj2!=NULL){
	    obj3=NULL;
/* 	    if(obj2->type==PROJECTILE){ */
/* 	      obj3=SelectObj(&listheadobjs,obj2->parent->id); */
/* 	    } */
	    if(obj2->type==SHIP)obj3=obj2;
	    if(obj3!=NULL){
	      /* must be a SHIP */

	      switch(obj->subtype){
	      case ASTEROID1:
		p[obj3->player].gold+=50;
		break;
	      case ASTEROID2:
		p[obj3->player].gold+=100;
		break;
	      case ASTEROID3:
		p[obj3->player].gold+=200;
		break;
	      default:
		fprintf(stderr,"ERROR in GetGold():asteroid subtype unknown\n");
		exit(-1);
		break;
	      }
	    }
	  }
	}
	break;
      default:
	break;
      }
    } /*  if(sw) */
    ls=ls->next;    
  }
  return;
}

void PrintGameOptions(void){

  printf("actual game options:\n");
  printf("\tUniverse size: %d\n",GameParametres(GET,GULX,0));
  printf("\tNUM GALAXIES: %d\n",GameParametres(GET,GNGALAXIES,0));
  printf("\tNUM PLANETS: %d\n",GameParametres(GET,GNPLANETS,0));
  printf("\tNUM PLAYERS: %d\n",GameParametres(GET,GNPLAYERS,0));
  if(GameParametres(GET,GKPLANETS,0)==TRUE){
    printf("\tPlanets are known by all the players.\n");
  }
  printf("\tknown planets: %d\n",GameParametres(GET,GKPLANETS,0));
  printf("\tcooperative mode: %d\n",GameParametres(GET,GCOOPERATIVE,0));
  printf("\tcomputer cooperative mode: %d\n",GameParametres(GET,GCOMPCOOPERATIVE,0));
  printf("\tQueen mode: %d\n",GameParametres(GET,GQUEEN,0));
  printf("\tpirates: %d\n",GameParametres(GET,GPIRATES,0));
  

}
