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

             T U D    S E R V E R    M O D U L


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

#include "tudinc_server.H"

// Globale Variablen siehe Ende von tudinc_server.H

int32 maxspieler; 
string levelname;
float wunschti;
float muehmineexplosion;
float mineexplosionsradius;
servermsg_kettetype *servermsg_ketteptr;
leveltype *levelptr;
einheit_server_kettetype *einheit_server_ketteptr;
schuss_server_kettetype *schuss_server_ketteptr;
explosions_server_kettetype *explosions_server_ketteptr;












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

                K L A S S E N  -  F U N K T I O N E N

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


einheit_server_zeigerelemtype *einheit_server_zeigerelemtype::create(iotype *ioptr,int8 mode)
{
  if (ioptr->getmode()!=IOTYPE_READ_MODE)
    fatalfehler("einheit_server_zeigerelemtype::create\n"
		"iotype befindet sich nicht im Lesemodus");
  int32 oldseek=ioptr->getpos();
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  string _headerstring;
  cfgptr->read_string_check(&_headerstring);
  delete cfgptr;
  ioptr->seekset(oldseek);

  // Welchen Einheittyp muss ich initen *****************************************
  if (!strcmp(_headerstring.c_str(),panzertype::headerstring))
    {
      panzer_server_zeigerelemtype *neues=new panzer_server_zeigerelemtype();
      neues->change(ioptr,mode);
      return neues;
    }
  else if (!strcmp(_headerstring.c_str(),firmatype::headerstring))
    {
      firma_server_zeigerelemtype *neues=new firma_server_zeigerelemtype;
      neues->change(ioptr,mode);
      return neues;
    }
  cerr <<"I don't know this einheittype: "<<_headerstring<<endl;
  fatalfehler("einheit_server_zeigerelemtype::create: Illegaler headerstring !");
  return(NULL); // spaeter 
}

int einheit_server_zeigerelemtype::crashcheck()
{
  einheit_server_zeigerelemtype *laufzeiger
    = einheit_server_ketteptr->anfang->next;
  while(laufzeiger!=einheit_server_ketteptr->ende){
    if (einheitnummer!=laufzeiger->einheitnummer){
      if (near(laufzeiger))
	{
	  // Vektorcheck !!
	  linie2_polpunkt_poldir_zeigerelemtype *rls=get_randlinien_kette()->anfang->next;
	  linie2_polpunkt_poldirtype akt_pol_rls;
	  linie2_koordpunkt_koorddirtype akt_koord_rls;
	  linie2_polpunkt_poldir_zeigerelemtype *rld;
	  linie2_polpunkt_poldirtype akt_pol_rld;
	  linie2_koordpunkt_koorddirtype akt_koord_rld;
	  vektor2_koordtype sp;
	  while (rls!=get_randlinien_kette()->ende)
	    {
	      rld=laufzeiger->get_randlinien_kette()->anfang->next;
	      akt_pol_rls.import((linie2_polpunkt_poldirtype *)rls);
	      akt_pol_rls.rotate(einheitdir);
	      akt_koord_rls.import(&akt_pol_rls);
	      akt_koord_rls.startp.add(&(pos));
	      while (rld!=laufzeiger->get_randlinien_kette()->ende)
		{
		  akt_pol_rld.import((linie2_polpunkt_poldirtype *)rld);
		  akt_pol_rld.rotate(laufzeiger->einheitdir);
		  akt_koord_rld.import(&akt_pol_rld);
		  akt_koord_rld.startp.add(&(laufzeiger->pos));
		  if (akt_koord_rls.schneide(akt_koord_rld,&sp))
		    return(1);
		  rld=rld->next;
		}
	      rls=rls->next;
	    }
	}
    }
    laufzeiger=laufzeiger->next;
  }
  return(0);
}

void einheit_server_zeigerelemtype::shotat
(vektor2_koordtype _pos,float _muehexplosion,float _explosionsradius)
{
  vektor2_koordtype dif=pos;
  dif.sub(&_pos);
  float abstand=dif.betrag();
  if (abstand>einheit_datenptr->einheitradius+_explosionsradius)
    // Daneben
    return;
  abstand-=einheit_datenptr->einheitradius;
  if (abstand<0)
    {
      // Volltreffer
      substanz-=_muehexplosion*einheit_datenptr->muehgranate;
      //      cout << "Volltreffer !\n";
    }
  else
    {
      float ablage=(_muehexplosion-abstand*_muehexplosion/_explosionsradius)*einheit_datenptr->muehgranate;
      substanz-=ablage;
      //      cout << "Treffer Schadenspunkte: "<<ablage<<endl;
    }
}

void einheit_server_zeigerelemtype::verarbeite_stream_msg(istream& ist)
{
  // todo maybe a bug !!!
  streampos oldpos=ist.tellg();
  string befehl;
  ist>>befehl;
  if (befehl=="giveuntil")
    {
      int32 otnr;
      ist >>otnr;
      einheit_server_zeigerelemtype *other;
      if (kette_search(einheit_server_ketteptr,otnr,other))
	{
	  if (near(other))
	    {
	      string objektname;
	      ist >>objektname;
	      // todo 	      objektname="object/"+objektname+".obj";
	      float giveuntil;
	      ist >>giveuntil;
	      objekt_kette.giveuntil(objektname.c_str(),giveuntil,other->objekt_kette);
	    }
	  else
	    cout <<"Vehicle No. : "<<einheitnummer<<" should give something to vehicle No."<<otnr
		 <<"\nBut it is to far away.\n";
	}
      else
	cout <<"Vehicle No. : "<<einheitnummer<<" should give something to a nonexisting vehicle\n";
      return;
    }
  if (befehl=="newowner")
    {
      int32 sp;
      if (ist >>sp)
	newowner(sp);
      return; 
    }
  if (befehl=="lend")
    {
      int sp;
      if (ist>>sp)
	lend(sp);
      return;
    }
  if (befehl=="giveback")
    {
      giveback();
    }
  ist.seekg(oldpos);
}

void einheit_server_zeigerelemtype::verarbeite_stream_msg_foreigner(istream& ist,int32 foreigner)
{
  // todo maybe a bug !!!
  streampos oldpos=ist.tellg();
  string befehl;
  ist>>befehl;
  if (befehl=="takeback")
    {
      takeback(foreigner);
      return;
    }
  ist.seekg(oldpos);
  cout << "tudinc_server.C: einheit_server_zeigerelemtype::verarbeite_stream_msg_foreigner(): Player "<<foreigner<<" tried to use  player "<<spielernummer<<"'s vehicle\n";
}


// einheit_server_kettetype ************************************************************
// einheit_server_kettetype ************************************************************
// einheit_server_kettetype ************************************************************

void einheit_server_kettetype::create(const char *_panzer_daten_dateiname,
				      vektor2_koordtype *_pos,
				      int32 _spielernummer,float _einheitdir)
{
  // Search free number could be improved - todo
  einheit_server_zeigerelemtype *akt;
  int32 _einheitnummer=0;
  int32 max=0;
  akt=anfang->next;
  while(akt!=ende)
    {
      if (akt->einheitnummer>max)
	max=akt->einheitnummer;
      if (akt->einheitnummer==_einheitnummer)
	_einheitnummer=max+1;
      akt=akt->next;
    }
  
  // Decide which object to create 
  // this should be at one point but is also at tudinc.C
  iotype *ioptr=make_file_to_io_check(_panzer_daten_dateiname);
  cfgtype *cfgptr=choose_cfgtype(ioptr,CFG_TEXT_MODE);
  string header;
  cfgptr->read_string_check(&header);
  delete cfgptr;
  delete ioptr;
  // create einheit and insert it at the correct position
  // perhaps i will have to change the sort criteria
  if (header==firma_datentype::headerstring)
    zeiger_push(new firma_server_zeigerelemtype(_panzer_daten_dateiname,_pos,_spielernummer,
						_einheitdir,_einheitnummer));
  else if (header==panzer_datentype::headerstring)
    zeiger_addafter(anfang,new panzer_server_zeigerelemtype(_panzer_daten_dateiname,_pos,
							    _spielernummer,_einheitdir,
							    _einheitnummer));
  else
    fatalfehler("einheit_server_kettetype::create(char *_panze...): Illegal headerstring\n");
}

// Einheit sichtbar ?  Achtung kein Unterschied zw. eigener und feindlicher Einheit !!
// (eigene Einheiten sind aber eigentlich immer sichtbar :-)
int einheit_server_kettetype::visible(einheit_server_zeigerelemtype *einheitptr,int32 spnr)
{
  einheit_server_zeigerelemtype *akt2=anfang->next;
  while (akt2!=ende)
    {
      if (akt2->spielernummer==spnr)
	if (akt2->near(einheitptr,akt2->einheit_datenptr->sichtradius))
	  return 1;
      akt2=akt2->next;
    }
  return 0;
}

void einheit_server_kettetype::setmode(einheittype::changemodetype _changemode)
{
  einheit_server_zeigerelemtype *akt2=anfang->next;
  while (akt2!=ende)
    {
      akt2->setmode(_changemode);
      akt2=akt2->next;
    }
}



// Dynamische Firmendaten  ****************************************************
// Dynamische Firmendaten  ****************************************************
// Dynamische Firmendaten  ****************************************************

firma_server_zeigerelemtype::firma_server_zeigerelemtype()
{
}

firma_server_zeigerelemtype::firma_server_zeigerelemtype
(const char *_panzer_daten_dateiname,vektor2_koordtype *_pos,int32 _spielernummer,
 float _einheitdir,int32 _einheitnummer) 
  : einheittype(_panzer_daten_dateiname,_pos,_spielernummer,_einheitdir,_einheitnummer),
    firmatype(_panzer_daten_dateiname,_pos,_spielernummer,_einheitdir,_einheitnummer) 
{
}

void firma_server_zeigerelemtype::verarbeite_stream_msg(istream& ist)
{
  einheit_server_zeigerelemtype::verarbeite_stream_msg(ist);
  string befehl;
  while(1)
    {
      if (ist>>befehl)
	{
	  if (befehl=="build")
	    {
	      string btype;
	      ist>>typeof_tobuild;
	      if (building())
		{
		  if ((typeof_tobuild=="object")||(typeof_tobuild=="vehicle"))
		    {
		      string einheitname;
		      ist>>einheitname;
		      tobuild=einheitname;
		      string_zeigerelemtype n(einheitname);
		      string_zeigerelemtype *akt;
		      kettetype<string_zeigerelemtype> *aktb=akt_buildable_objekts();
		      if (kette_search(aktb,n,akt))
			{
			  // Is a buildable object
			  if (readable(einheitname.c_str()))
			    countdown=time_tobuild();
			  else 
			    stop_building();
			}
		      else
			{
			  delete aktb;
			  aktb=akt_buildable_vehicles();
			  if (kette_search(aktb,n,akt))
			    {
			      // Is a buildable vehicle
			      if (readable(einheitname.c_str()))
				countdown=time_tobuild();
			      else
				stop_building();
			    }
			  else
			    stop_building();
			}
		      delete aktb;
		    }
		  else
		    {
		      cerr<<"firma_server_zeigerelemtype::verarbeite_stream_msg:\n"
			"Unknown type to build (must be object or vehicle)\n";	      
		      stop_building();
		    }
		}
	    }
	  else if (befehl!="")
	    {
	      cout<<"firma_server_zeigerelemtype::verarbeite_stream_msg:\n"
		"Got a unknown message: \""<<befehl<<"\""<<endl;
	    }
	  if (!ist)
	    {
	      cout <<"firma_server_zeigerelemtype::verarbeite_stream_msg:\n"
		"Got a wrong message\n";
	    }
	}
      else
	break;
    }
}

int firma_server_zeigerelemtype::neuerbesitzer(int *neuer)
{
  int32 gefundenerspieler=0;
  int anzgefunden=0;

  einheit_server_zeigerelemtype *laufzeiger
    = einheit_server_ketteptr->anfang->next;
  while(laufzeiger!=einheit_server_ketteptr->ende)
    {
      if (einheitnummer!=laufzeiger->einheitnummer)
	{
	  if (near(laufzeiger))
	    {
	      // Vektorcheck !! ??? soll ich richtig gucken ob in der firma ne einheit steht ?
	      if (laufzeiger->spielernummer)
		{
		  if (laufzeiger->spielernummer!=gefundenerspieler)
		    {
		      anzgefunden++;
		      gefundenerspieler=laufzeiger->spielernummer;
		      if ((gefundenerspieler==spielernummer)||(anzgefunden>1))
			break;
		    }
		}
	    }	
	}
      laufzeiger=laufzeiger->next;
    }
  if (anzgefunden==1)
    *neuer=gefundenerspieler;
  else
    *neuer=0;
  return anzgefunden;
}

int firma_server_zeigerelemtype::calc()
{
  // Besitzer wechseln ?
  // todo eigentlich wie crashcheck !! evtl. bei crashcheck einbauen
  // nur alle paar sekunden testen ?

  int neuer;
  int leer=(!neuerbesitzer(&neuer));
  if (neuer)
    // Besitzer gewechselt
    spielernummer=neuer;
  if ((leer)&&(building())||(typeof_tobuild=="object")) // todo evtl. boolean 
    {
      // Baue Einheit todo ist natuerlich noch schlecht schoener film oder .....
      if (countdown<0)
	{
	  countdown=time_tobuild();
	  if (typeof_tobuild=="vehicle")
	    {
	      einheit_server_ketteptr->create(tobuild.c_str(),&pos,spielernummer,einheitdir);
	    }
	  else if (typeof_tobuild=="object")
	    {
	      if (objekt_kette.add(tobuild.c_str(),1)!=1)
		stop_building();
	    }
	  else
	    cerr <<"firma_server_zeigerelemtype::calc(): should build unknown object type :\""<<typeof_tobuild<<"\"\n";
	}
      else
	countdown-=deltati;
    }
  if (substanz>0)
    return 0;
  //else  Firma kaputt
  return 1;
}

// Dynamische canondaten  ****************************************************
// Dynamische canondaten  ****************************************************
// Dynamische canondaten  ****************************************************

int canon_servertype::calc_autoshot()
{
  // todo speedup this (don't always search the lists) sort it or remember old results

  einheit_server_zeigerelemtype *akt;
  if ((shotat_number!=einheitptr->einheitnummer)
      &&
      (kette_search(einheit_server_ketteptr,shotat_number,akt)))
    {
      // Friend or enemy ? visible ?
      if ((!einheitptr->friendship(akt))&&(einheit_server_ketteptr->visible(akt,einheitptr->spielernummer)))
	{
	  // Horizontalen Winkel einstellen
	  // todo winkel beschraenkungen beruecksichtigen !!!
	  vektor2_koordtype dif(akt->pos);
	  vektor2_koordtype aktturmpos;
	  calc_aktturmpos(aktturmpos);
	  dif.sub(&(einheitptr->pos));
	  dif.sub(&aktturmpos);
	  if (dif.betrag()<=maxreichweite())
	    {
	      vektor2_poltype peil(&dif);
	      float aktpeil=einheitptr->einheitdir+relturmdir;
	      chkdir(&aktpeil);
	      float difpeil=peil.dir-aktpeil;
	      chkdir(&difpeil);
	      if (fabs(difpeil)<0.1*M_PI_2)
		// Abweichung <9°
		turmdrehen=difpeil;
	      else
		if (difpeil<0)
		  turmdrehen=-1;
		else
		  turmdrehen=1;
	      
	      // Vertikalen Winkel einstellen
	      // Vorlaeufig immer winkel<45 grad !!!
	      // todo auch andere Winkel falls z.Bsp. Tank nur ueber 45 oder so
	      float schussweite=canon_datenptr->vschuss*canon_datenptr->vschuss*2
		*sin(dirhorizon)*cos(dirhorizon)/landscapeptr->gravity;
	      if (dirhorizon>M_PI/4)
		turmfahren=-1;
	      else
		{
		  if (schussweite>peil.betrag)
		    turmfahren=-1;
		  else
		    turmfahren=1;
		}
	      // Schiessen wenn ein Treffer moeglich ist !
	      vektor2_poltype shot(schussweite,aktpeil);
	      vektor2_koordtype shotat(&shot);
	      vektor2_koordtype aktturmpos;
	      calc_aktturmpos(aktturmpos);
	      shotat.add(&einheitptr->pos);
	      shotat.add(&aktturmpos);
	      dif=akt->pos;
	      dif.sub(&shotat);
	      
	      if (dif.betrag()<=akt->einheit_datenptr->einheitradius*0.8)
		schiessen=1;
	      else
		schiessen=0;
	      return 1;
	    }
	  // Einheit existiert ist aber nicht in Reichweite
	  schiessen=0;
	  turmfahren=0;
	  turmdrehen=0;
	  return -1;
	}
    }
  // Einheit existiert nicht od. ist ein freund od ist nicht sichtbar !
  schiessen=0;
  turmfahren=0;
  turmdrehen=0;
  return 0;
}

void canon_servertype::calc_autoaim()
{
  if ((!autoshot)||(calc_autoshot()!=1))
    {
      // Neues Ziel suchen  spaeter nicht in jeder Runde ein Ziel suchen !!
      float nearest=maxreichweite();
      vektor2_koordtype aktturmpos;
      calc_aktturmpos(aktturmpos);
      einheit_server_zeigerelemtype *gefunden=NULL;
      einheit_server_zeigerelemtype *akt=einheit_server_ketteptr->anfang->next;
      while (akt!=einheit_server_ketteptr->ende)
	{
	  vektor2_koordtype dif(akt->pos);
	  dif.sub(&einheitptr->pos);
	  dif.sub(&aktturmpos);
	  if ((dif.betrag()<nearest)&&(!einheitptr->friendship(akt))
	      &&(einheit_server_ketteptr->visible(akt,einheitptr->spielernummer)))
	    {
	      nearest=dif.betrag();
	      gefunden=akt;
	    }
	  akt=akt->next;
	}
      if (gefunden)
	{
	  autoshot=2;
	  shotat_number=gefunden->einheitnummer;
	}
      else
	{
	  autoshot=0;
	}
    }	
}

int canon_servertype::calc()
{
  // Prioritiver Autoschuss
  // Nachladen !!
  restladedauer-=deltati;

  if (autoshot==1)
    {
      if (!calc_autoshot())
	autoshot=0;
    }
  else
    if (canon_kette_baseptr->autoaim)
      calc_autoaim();

  if (turmdrehen)
    {
      // Drehwinkel bestimmen
      float deltadreh;
      if (einheitptr->fuel_avail())
	{
	  deltadreh=canon_datenptr->vturmdreh*deltati;
	  einheitptr->fuel_sub(deltati*canon_datenptr->fuelpersec);
	}
      else
	deltadreh=canon_datenptr->vturmdrehhand*deltati;
      
      deltadreh*=turmdrehen;
      relturmdir+=deltadreh;
    }

  if (turmfahren)
    {
      float deltafahr;
      if (einheitptr->fuel_avail())
	{
	  deltafahr=canon_datenptr->vturmfahr*deltati;
	  einheitptr->fuel_sub(deltati*canon_datenptr->fuelpersec);
	}
      else
	deltafahr=canon_datenptr->vturmfahrhand*deltati;
      deltafahr*=turmfahren;
      dirhorizon+=deltafahr;
    }
  chkturmdirbereich();


  // SCHIESSEN !!!
  if ((schiessen)&&(einheitptr->get_standzeit()>=canon_datenptr->richtzeit)&&(restladedauer<=0.0)
      &&(ammoptr->anzahl>0))
    {
      // Einen Schuß initialisieren 
      //	    cout <<"Panzer hat geschossen !\n";
      restladedauer=canon_datenptr->ladedauer;

      ammoptr->anzahl--;
      float speed=cos(dirhorizon)*canon_datenptr->vschuss;
      float restzeit=2*sin(dirhorizon)*canon_datenptr->vschuss/landscapeptr->gravity;
      vektor2_koordtype shotpos;
      calc_aktturmpos(shotpos);
      shotpos.add(&einheitptr->pos);
      schuss_server_zeigerelemtype *schuss=
	new schuss_server_zeigerelemtype(shotpos,einheitptr->einheitdir+relturmdir,
					 speed,restzeit,ammo_datenptr->muehexplosion,
					 ammo_datenptr->explosionsradius,ammo_datenptr->sound.c_str());
      schuss_server_ketteptr->zeiger_push(schuss);
    }
  return 0;
}

// Dynamische Panzerdaten  ****************************************************
// Dynamische Panzerdaten  ****************************************************
// Dynamische Panzerdaten  ****************************************************


void panzer_server_zeigerelemtype::checkbereich()
{
  if (besitz.restminelegdauer>panzer_datenptr->minelegdauer)
    besitz.restminelegdauer=panzer_datenptr->minelegdauer;
  untergrundcheck(&server.aktspeedfaktor,&server.aktdestroyfaktor);
}

void panzer_server_zeigerelemtype::setmaxbereich()
{
  besitz.restminelegdauer=0;

  canon_datentype *akt=panzer_datenptr->canon_daten_kette.anfang->next;
  while (akt!=panzer_datenptr->canon_daten_kette.ende)
    {
      canon_servertype *neues=new canon_servertype(akt,&canon_kette_server,this);
      neues->setmaxbereich();
      canon_kette_server.zeiger_push(neues);
      akt=akt->next;
    }
  untergrundcheck(&server.aktspeedfaktor,&server.aktdestroyfaktor);
}

// Rueckgabewert ==-1 => ausserhalb der Landschaft ! 
int panzer_server_zeigerelemtype::untergrundcheck
(float *speedfaktor,float *destroyfaktor)
{
    *speedfaktor=0.0;
    *destroyfaktor=0.0;
    vektor2_poltype aktpoldot;
    vektor2_koordtype aktdot;
    uchar farbe;

    vektor2_pol_zeigerelemtype *laufzeiger
	= panzer_datenptr->raddots_kette.anfang->next;

    while(laufzeiger!=panzer_datenptr->raddots_kette.ende)
      {
	aktpoldot.import((vektor2_poltype *)laufzeiger);
	aktpoldot.rotate(einheitdir);
	aktdot.import(&aktpoldot);
	if (landscapeptr->landspriteptr->getpixel_clip(
						       ftoi(aktdot.x+pos.x),
						       ftoi(aktdot.y+pos.y),(char *)&farbe))
	  {
#ifdef DEBUG
	    printf("Landschaftsgrenze erreicht: POSx:%f POSy:%f "
		   "DOTx:%f DOTy:%f\n",pos.x,pos.y,
		   aktdot.x+pos.x,aktdot.y+pos.y);
#endif
	    return(-1);
	  }
	(*speedfaktor)+=panzer_datenptr->speedfaktor[untergrundtabptr->tab[farbe]];
	// spater auf fahren fragen net so kompliziert !
	if (( (fuel_avail())&&((besitz.eingabe.gas)||(besitz.eingabe.drehen)))
	    ||(panzer_datenptr->verbotenezone[untergrundtabptr->tab[farbe]]) )
	  (*destroyfaktor)+=panzer_datenptr->destroyfaktor[untergrundtabptr->tab[farbe]];
	
	laufzeiger=laufzeiger->next;
      }
    (*speedfaktor)/=(float)(panzer_datenptr->raddots_kette.anzzeigerelem);
    (*destroyfaktor)/=(float)(panzer_datenptr->raddots_kette.anzzeigerelem);
    return(0);
}


int panzer_server_zeigerelemtype::calc_driveto(const vektor2_koordtype &topos)
{
  vektor2_koordtype dif(topos);
  dif.sub(&pos);
  if (dif.betrag()>3)
    {
      vektor2_poltype peil(&dif);
      float difpeil=peil.dir-einheitdir;
      chkdir(&difpeil);
      if (difpeil<0.02)
	// Ziel befindet sich links !!
	besitz.eingabe.drehen=-1;
      else if (difpeil>0.02)
	besitz.eingabe.drehen=1;
      else 
	besitz.eingabe.drehen=0;
      if ((fabs(difpeil)>3*M_PI_4)&&(dif.betrag()<4*einheit_datenptr->einheitradius))
	// Rückwärts fahren !!
	besitz.eingabe.gas=-1;
      else
	besitz.eingabe.gas=1;
      return 1;
    }
  //  else
  /*  besitz.eingabe.gas=0;
  besitz.eingabe.drehen=0; */
  return 0;
}

int panzer_server_zeigerelemtype::calc_autofollow()
{      
  // todo nicht immer liste durchrennen und nach nr suchen sondern per index !!!
  // evtl. liste mit index !!! naja
  einheit_server_zeigerelemtype *akt;
  if (kette_search(einheit_server_ketteptr,besitz.eingabe.autofollow_number,akt))
    {
      vektor2_koordtype dif;
      if (besitz.eingabe.autodrive==2)
	dif=akt->pos;
      else // autodrive==3
	dif=akt->pos+besitz.eingabe.autofollow_relto;
      dif.sub(&pos);
      if (dif.betrag()>besitz.eingabe.autofollow_distance)
	{
	  if (besitz.eingabe.autodrive==2)
	    {
	      //	      cout <<"p..type:calc_autofollow(): distance to "<<besitz.eingabe.autofollow_number<<" "<<dif.betrag()<<endl;
	      calc_waypointdrive();
	    }
	  else
	    // todo say to autofollow_number that he should slow down
	    calc_driveto(akt->pos+besitz.eingabe.autofollow_relto);
	}
      else if (besitz.eingabe.autodrive==3)
	calc_driveto(akt->pos+besitz.eingabe.autofollow_relto);
      else
	{
	  besitz.eingabe.gas=0;
	  besitz.eingabe.drehen=0;
	}
      return besitz.eingabe.autodrive;
    }
  //  else autofollow_number doesn't exist anymore
  // todo send a mesg to client
  if (besitz.eingabe.autodrive==3)
    {
      besitz.eingabe.gas=0;
      besitz.eingabe.drehen=0;
      return 0;
    }
  // autodrive==2 => switch into waypoint mode
  return 1;
}

void panzer_server_zeigerelemtype::calc_waypointdrive()
{
  bool nowaypoints=false;
  if (besitz.eingabe.autodrivetoptr==besitz.eingabe.autodriveto_kette.anfang)
    if (besitz.eingabe.autodriveto_kette.anzzeigerelem)
      besitz.eingabe.autodrivetoptr=besitz.eingabe.autodrivetoptr->next;
    else
      nowaypoints=true;
 
  if (!calc_driveto(*besitz.eingabe.autodrivetoptr))
    {
      // Waypoint reached 
      besitz.eingabe.autodrivetoptr=besitz.eingabe.autodrivetoptr->next;
      besitz.eingabe.autodriveto_kette.delbefore(besitz.eingabe.autodrivetoptr);
      if (besitz.eingabe.autodrivetoptr==besitz.eingabe.autodriveto_kette.ende)
	besitz.eingabe.autodrivetoptr=besitz.eingabe.autodriveto_kette.anfang;
      else
	nowaypoints=true;
    }
  if (nowaypoints)
    {
      besitz.eingabe.gas=0;
      besitz.eingabe.drehen=0;
    }
}

// Berechnet Einheit
int panzer_server_zeigerelemtype::calc()
{
    if (substanz>0)
      {
	// Panzer lebt !

	// Autofollow
	if (besitz.eingabe.autodrive>1)
	  besitz.eingabe.autodrive=calc_autofollow();
	
	// Autodrive
	if (besitz.eingabe.autodrive==1)
	  calc_waypointdrive();

	kette_calc(&canon_kette_server);

	server.inbewegung=((fuel_avail())&&((besitz.eingabe.drehen)||(besitz.eingabe.gas)));

	if (!server.inbewegung)
	  {
	    besitz.standzeit+=deltati;
	  }
	else
	  {
	    besitz.standzeit=0.0;
	    // Eigentliches Fahren
	    if (besitz.eingabe.drehen)
	      {
		float deltadreh;
		if (!besitz.eingabe.gas) //nur 1mal benzin abziehen
		  {
		    if (panzer_datenptr->vdrehstand>0.0)
		      {
			fuel_sub(deltati*panzer_datenptr->fuelpersec);
			deltadreh=panzer_datenptr->vdrehstand*deltati;
		      }
		    else
		      deltadreh=0.0;
		  }else
		    {
		      deltadreh=panzer_datenptr->vdreh*deltati;
		      if (besitz.eingabe.gas<0.0)
			deltadreh=-deltadreh;
		    }
		deltadreh*=besitz.eingabe.drehen;
		deltadreh*=server.aktspeedfaktor;
		einheitdir+=deltadreh;
		chkdir(&einheitdir);
	      }
	    if (besitz.eingabe.gas)
	      {
		fuel_sub(deltati*panzer_datenptr->fuelpersec);
		float deltafahr;
		if (besitz.eingabe.gas>0)
		  deltafahr=panzer_datenptr->vpanzvor*deltati;
		else
		  deltafahr=panzer_datenptr->vpanzback*deltati;
		deltafahr*=besitz.eingabe.gas;
		deltafahr*=server.aktspeedfaktor;
		
		pos.x+=cos(einheitdir)*deltafahr;
		pos.y+=sin(einheitdir)*deltafahr;
	      }
	
	    // Gefahren => Neuen Untergrund feststellen (Landschaftsgrenze)
	    // und crashcheck !
	    if (crashcheck()
		|| untergrundcheck(&server.aktspeedfaktor,&server.aktdestroyfaktor))
	      {
		pos.x=server.oldposx;
		pos.y=server.oldposy;
		einheitdir=server.oldpanzdir;
		besitz.eingabe.gas=0;
		besitz.eingabe.drehen=0;
	      }else{
		server.oldposx=pos.x;
		server.oldposy=pos.y;
		server.oldpanzdir=einheitdir;
	      }
	
	    // Materialermüdung !!
	    substanz-=server.aktdestroyfaktor*deltati;
	  }
	return(0);
      }
    //    else

    //ammotodo
    /*
    if (besitz.anzshot)
      {
	server.todtimer+=deltati;
	int con=RAND_MAX/ftoi(panzer_datenptr->einheitradius);
	// Lasse alle restlichen schuesse im Abstand von 0.15 sec explodieren
	while ((server.todtimer>0.15)&&(besitz.anzshot))
	  {
	    int relx=random()/con-ftoi(panzer_datenptr->einheitradius)/2;
	    int rely=random()/con-ftoi(panzer_datenptr->einheitradius)/2;
	    vektor2_koordtype apos(pos);
	    apos.x+=relx;
	    apos.y+=rely;
	    explosions_server_zeigerelemtype *explosionsptr=
	      new explosions_server_zeigerelemtype(apos,panzer_datenptr->muehexplosion,
						   panzer_datenptr->explosionsradius);
	    explosions_server_ketteptr->zeiger_push(explosionsptr);
	    server.todtimer-=0.15;
	    besitz.anzshot--;
	  }
	return(0);
      }
      */

    // else
    // Wirklich am Ende letzte Explosion
    // ammotodo
    /*
    explosions_server_zeigerelemtype *explosionsptr=
      new explosions_server_zeigerelemtype(pos,panzer_datenptr->muehexplosion,
					   panzer_datenptr->explosionsradius);
    explosions_server_ketteptr->zeiger_push(explosionsptr);
    */
    return(1);
}

void panzer_server_zeigerelemtype::change(iotype *ioptr,int8 mode)
{
  panzertype::change(ioptr,mode);
  canon_kette_server.change(ioptr,mode,&panzer_datenptr->canon_daten_kette,this);
  // todo warum ist das hier ?
  if (ioptr->getmode()==IOTYPE_READ_MODE)
    checkbereich();
}

void panzer_server_zeigerelemtype::verarbeite_stream_msg(istream& ist)
{
  einheit_server_zeigerelemtype::verarbeite_stream_msg(ist);
  string befehl;
  while ((ist>>befehl))
    {
      if (befehl=="canon")
	canon_kette_server.verarbeite_stream_msg(ist);
      else if (befehl=="autodrive")
	{
	  // switch autodrive mode
	  int n;
	  ist >> n;
	  if (n!=besitz.eingabe.autodrive)
	    {
	      if (n!=2) // (!n)||(n==3)||(n==1)
		{
		  // switch waypoint drive off => clear all waypoints => clear parent
		  clearwaypoints();
		  removeparent();
		}
	      besitz.eingabe.autodrive=n;
	    }
	}
      else if (befehl=="autodriveto")
	{		
	  vektor2_koordtype newwaypoint;
	  ist >> newwaypoint.x;
	  ist >> newwaypoint.y;
	  addwaypoint(newwaypoint);
	}
      else if (befehl=="autofollow")
	{
	  int no;
	  ist >> no;
	  newparent(no);
	}
      else if (befehl=="stop")
	{
	  besitz.eingabe.gas=0;
	  besitz.eingabe.drehen=0;
	  /*
	  besitz.eingabe.turmdrehen=0;
	  besitz.eingabe.turmfahren=0;*/
	  //	  cout <<"Stoped vehicle.\n";
	}
      else if (befehl!="")
	{
	  cout<<"panzer_server_zeigerelemtype::verarbeite_stream_msg:\n"
	    "Got a unknown message1: \""<<befehl<<"\""<<" Laenge: "<<befehl.size()<<endl;
	  cout <<"Befehl[letztes]="<<int(befehl[befehl.size()-1])<<endl;
	}

      if (!ist)
	{
	  cout <<"panzer_server_zeigerelemtype::verarbeite_stream_msg:\n"
	    "Got a wrong message2\n";
	}
      befehl="";
    }
  ist.clear();
}

void panzer_server_zeigerelemtype::clearwaypoints()
{
  //  cout <<"p..type::clearwaypoints: I("<<einheitnummer<<" clear my waypoints\n";
  besitz.eingabe.autodriveto_kette.clear();
  besitz.eingabe.autodrivetoptr=besitz.eingabe.autodriveto_kette.anfang;
  if (besitz.eingabe.follower>=0)
    {
      //      cout << "I tell it my childs\n";
      einheit_server_zeigerelemtype *unit=einheit_server_ketteptr->get_unit(besitz.eingabe.follower);
      if (unit)
	unit->clearwaypoints();
      else
	// child died
	besitz.eingabe.follower=-1;
    }
}

// add a waypoint and tell it my child if i have one
void panzer_server_zeigerelemtype::addwaypoint(const vektor2_koordtype &v)
{
  //  cout <<"p..type::addwaypoint(): I("<<einheitnummer<<") add waypoint "<<v<<endl;
  vektor2_koord_zeigerelemtype *n=new vektor2_koord_zeigerelemtype();
  n->x=v.x;
  n->y=v.y;
  besitz.eingabe.autodriveto_kette.zeiger_push(n);
  if (besitz.eingabe.follower>=0)
    {
      //      cout <<"I tell it my child\n";
      einheit_server_zeigerelemtype *unit=einheit_server_ketteptr->get_unit(besitz.eingabe.follower);
      if (unit)
	unit->addwaypoint(v);
      else
	// child died
	besitz.eingabe.follower=-1;
    }
}
// Is this a child of me ?
bool panzer_server_zeigerelemtype::is_child(int32 no)
{
  //  cout <<"pa..type::is_child(): Is "<<no<<" a child of "<<einheitnummer<<" ?\n";
  // Don't have childs
  if (besitz.eingabe.follower==-1)
    {
      //      cout <<"No I don't have childs\n";
      return false;
    }
  // Yes it is
  if (besitz.eingabe.follower==no)
    {
      //      cout <<"Yes it is\n";
      return true;
    }
  einheit_server_zeigerelemtype *unit=einheit_server_ketteptr->get_unit(besitz.eingabe.follower);
  if (unit)
    {
      // Ask my child if he has such a child
      //      cout <<"Not mine but perhaps one of my child\n";
      return unit->is_child(no);
    }
  // Oh - my child died ;-)
  //  cout <<"No my child died\n";
  besitz.eingabe.follower=-1;
  return false;
}

void panzer_server_zeigerelemtype::removeparent()
{
  // disable old parent (if i have one)
  if (besitz.eingabe.autofollow_number>=0)
    {
      //      cout <<"panz..type::removeparent()\n";
      einheit_server_zeigerelemtype *unit=einheit_server_ketteptr->get_unit(besitz.eingabe.autofollow_number);
      if (unit)
	{
	  unit->removechild();
	}
      besitz.eingabe.autofollow_number=-1;
    }
}

// i want to a have another parent 
void panzer_server_zeigerelemtype::newparent(int32 no)
{
  //  cout << "panzer..type::newparent: I("<<einheitnummer<<") should take "<<no<<" as parent with distance "<<dist<<endl;
  if ((no==einheitnummer)||(no==besitz.eingabe.autofollow_number)||(no<0))
    {
      cout << "panz..type::newparent(): Illegal No (meself old parent or none (<0)\n";
      return;
    }
  // remove old parent if i have one
  removeparent();


  // new parent musn't be child of me
  if (is_child(no)) 
    {
      //      cout << "This is my child => so it can't be my parent\n";
      return;
    }
  // todo if this is a unit which can't have childs drive to this unit ?
  einheit_server_zeigerelemtype *unit=einheit_server_ketteptr->get_unit(no);
  if (unit)
    {
      unit=unit->newchild(einheitnummer);
      if (!unit)
	{
	  // this unit hates childs ! => no parent
	  return;
	}
      besitz.eingabe.autofollow_number=unit->einheitnummer;
      besitz.eingabe.autofollow_distance=unit->einheit_datenptr->einheitradius+einheit_datenptr->einheitradius;
      // set follow mode
      besitz.eingabe.autodrive=2;
      addwaypoint(unit->pos); // todo calc dist
      //      cout <<"Yes - accepted this parent\n";
      return;
    }
  cout <<"tudinc_server.C::panzer_server_zeigerelemtype::newparent(): this parent not found\n";
}

void panzer_server_zeigerelemtype::removechild()
{
  besitz.eingabe.follower=-1;
  //  cout << "panzer...type::removechild(): my child left me\n";
}


// no wants to become a child of me , I return the parent it gets
einheit_server_zeigerelemtype *panzer_server_zeigerelemtype::newchild(int32 no)
{
  if (no==-1)
    {
      fatalfehler("newchild(-1) aufgerufen !!\n");
    }
  //  cout << "panzer...type::newchild(): I ("<<einheitnummer<<") Should take "<<no<<" as child\n";
  // don't have a child yet
  if (!havechild())
    {
      //      cout << "Didn't have a child => i take it\n";
      besitz.eingabe.follower=no;
      return this;
    }
  einheit_server_zeigerelemtype *unit=einheit_server_ketteptr->get_unit(besitz.eingabe.follower);
  if (unit)
    {
      // i have a child => the child will probably be the parent 
      // no rings  => no deadlock because parents never become childs of their childs
      //  cout << "I already have a child ! Perhaps my child wants to have it\n";
      return unit->newchild(no);
    }
  // my child died => i need to take a new one
  //  cout << "my child died => i need to take a new one\n";
  besitz.eingabe.follower=no;
  return this;
}

void panzer_server_zeigerelemtype::init()
{
  // init
  server.oldposx=pos.x;
  server.oldposy=pos.y;
  server.oldpanzdir=einheitdir;
  server.todtimer=0;
}

// Einheit erstellen
panzer_server_zeigerelemtype::panzer_server_zeigerelemtype()
{
  init();
}

panzer_server_zeigerelemtype::panzer_server_zeigerelemtype
(const char *_panzer_daten_dateiname,vektor2_koordtype *_pos,int32 _spielernummer,
 float _einheitdir,int32 _einheitnummer) 
  : einheittype(_panzer_daten_dateiname,_pos,_spielernummer,_einheitdir,_einheitnummer),
    panzertype(_panzer_daten_dateiname,_pos,_spielernummer,_einheitdir,_einheitnummer) 
{
  init();
  besitz.init();
  setmaxbereich();
}



panzer_server_zeigerelemtype::~panzer_server_zeigerelemtype()
{
#ifdef DEBUG
    cout <<"panzer_server_zeigerelemtype Destruktor des Servers aufgerufen !\n";
#endif
}


// Schussobjekt (Server)   ****************************************************
// Schussobjekt (Server)   ****************************************************
// Schussobjekt (Server)   ****************************************************

/*
schuss_server_zeigerelemtype::schuss_server_zeigerelemtype(iotype *ioptr,int8 mode) 
  : schusstype(ioptr,mode)
{}
*/

schuss_server_zeigerelemtype::schuss_server_zeigerelemtype
(vektor2_koordtype _pos,float _dir,float _speed,float _restzeit,
 float _muehexplosion,float _explosionsradius, const char *_sound) 
{
  pos=_pos;
  dir=_dir;
  speed=_speed;
  restzeit=_restzeit;
  muehexplosion=_muehexplosion;
  explosionsradius=_explosionsradius;
  sound=_sound;
}

int schuss_server_zeigerelemtype::calc()
{
  pos.x+=cos(dir)*speed*deltati;
  pos.y+=sin(dir)*speed*deltati;
  restzeit-=deltati;
  if (restzeit>0)
    return(0);
  else
    {
      //      cout <<"Schuss Explodiert!  Pos: "<<pos.x<<" ; "<<pos.y<<"\n";
      explosions_server_zeigerelemtype *explosionsptr=
	new explosions_server_zeigerelemtype(pos,muehexplosion,explosionsradius,sound.c_str());
      explosions_server_ketteptr->zeiger_push(explosionsptr);
      return(1);
    }
}

// Explosionsobjekt **********************************************************
// Explosionsobjekt **********************************************************
// Explosionsobjekt **********************************************************

/*
explosions_server_zeigerelemtype::explosions_server_zeigerelemtype(iotype *ioptr,int8 mode)
  :explosionstype(ioptr,mode)
{}
*/

explosions_server_zeigerelemtype::explosions_server_zeigerelemtype
(vektor2_koordtype _pos,float _muehexplosion,float _explosionsradius,const char *_sound)
{
  pos=_pos;
  muehexplosion=_muehexplosion;
  explosionsradius=_explosionsradius;
  sound=_sound;
  // Schaden berechnen !!
  einheit_server_zeigerelemtype *akt=einheit_server_ketteptr->anfang->next;
  while (akt!=einheit_server_ketteptr->ende)
    {
      akt->shotat(pos,muehexplosion,explosionsradius);
      akt=akt->next;
    }
}


// ****************************************************************************
// ****************************************************************************
//                     K O M M U N I K A T I O N 
// ****************************************************************************
// ****************************************************************************

servermsg_zeigerelemtype::servermsg_zeigerelemtype(verbindungstype *verbindung) 
    : tud_streamtype (verbindung)
{
    cout <<"New Client connected.\n";
    spielerptr=new spieler_zeigerelemtype;
    spieler_ketteptr->zeiger_push(spielerptr);
}

servermsg_zeigerelemtype::~servermsg_zeigerelemtype()
{
  cout <<"Client "<<spielerptr->spielernummer<<" ("<<spielerptr->spielername<<") left game.\n";
  spieler_ketteptr->del(spielerptr);
  send_event_spieler_kette_msg();
}

/*
void servermsg_zeigerelemtype::change(iotype *ioptr,int8 mode)
{
  spieler.change(ioptr,mode);
  //  eventmask.change(ioptr,mode); spaeter vielleicht
}
*/

void servermsg_zeigerelemtype::verarbeitemsg(char *msg,int32 laenge,int32 msgart)
{
  switch(msgart)
    {
//___ LOGIN __ MSGS ______________________________________
    case REQ_SPIELERANZ_MSG:
      send_spieleranz_msg();
      break;
    case REQ_SPIELERDATEI_MSG:
      verarbeite_req_spielerdatei_msg(msg);
      break;
    case REQ_FREESPIELERDATEI_MSG:
      verarbeite_req_freespielerdatei_msg();
      break;
    case REQ_FREESPIELERPLATZ_MSG:
      verarbeite_req_freespielerplatz_msg();
      break;
    case REQ_SPIELERPLATZ_MSG:
      verarbeite_req_spielerplatz_msg(msg,laenge);
      break;
    case REQ_LANDSNAME_MSG:
      send_landsname_msg();
      break;
    case REQ_SPIELER_KETTE_MSG:
      send_spielerkette_msg();
      break;
      //___ Spiel __ MSGS ______________________________________
    case REQ_PANZER_KETTE_MSG:
      verarbeite_req_panzer_kette_msg(msg,laenge);
      break;
    case SEND_EINGABE_MSG:
      verarbeite_eingabe_msg(msg,laenge);
      break;
    case SEND_EVENTMASK_MSG:
      verarbeite_eventmask_msg(msg,laenge);
      break;
    case SEND_STREAM_MSG:
      verarbeite_stream_msg(msg,laenge);
      break;
    default:
      fatalfehler("servermsg_zeigerelemtype::verarbeitemsg:  Unbekannte MSG empfangen");
    }
}

float servermsg_zeigerelemtype::send_ping_msg()
{
    timeval oldzeit;
    timeval zeit;    
    char *buffer;
    int32 laenge;
    int32 msgart;
    gettimeofday(&oldzeit,NULL);
    sendmsg(NULL,0,SEND_PING_MSG);
    recvmsg(&buffer,&laenge,&msgart,RECVMSG_UNENDLICH);
    gettimeofday(&zeit,NULL);
    if (msgart==SEND_PING_MSG)
	return( getdeltatime(&oldzeit,&zeit) );
    verarbeitemsg(buffer,laenge,msgart);
    return(-1);
}

void servermsg_zeigerelemtype::send_spieleranz_msg()
{    
    sendmsg((char *)(&maxspieler),sizeof(maxspieler),SEND_SPIELERANZ_MSG);
}

void servermsg_zeigerelemtype::verarbeite_req_spielerdatei_msg
(char *dateiname)
{
    // todo
    // spaeter muss hier geguckt werden ob die Datei existiert !
    // bzw. ob es die neueste Version ist !!!
    // Und wenn sie nicht existiert muss sie ueber das Netz koppiert werden !
    // bzw. ein neuer User angelegt werden !
    string datei("users/");
    datei+=dateiname;
    datei+=".usr";
    delete dateiname;
    cout << "Player wants to use userfile: \""<<datei<<"\"\n";
    spielerptr->ladespieler(datei.c_str());
}

void servermsg_zeigerelemtype::verarbeite_req_spielerplatz_msg(char *msg,int32 laenge)
{
  if (laenge!=sizeof(int32))
    fatalfehler("servermsg_zeigerelemtype::verarbeite_req_spielerplatz_msg\n"
		"(char *msg,int32 laenge): Fehlerhafter Request !");
  int32 platz=*((int32 *)msg);
  
  if ((platz<=0)||(platz>maxspieler))
    {
      sendmsg(NULL,0,DENY_SPIELERPLATZ_MSG);
    }
  else
    {
      spieler_zeigerelemtype *laufzeiger;
      if (kette_search(spieler_ketteptr,platz,laufzeiger))
	{
	  sendmsg(NULL,0,DENY_SPIELERPLATZ_MSG);
	}
      else
	{
	  sendmsg(NULL,0,GIVE_SPIELERPLATZ_MSG);
	  spielerptr->spielernummer=platz;
	  send_event_spieler_kette_msg();
	}
    }
}

void servermsg_zeigerelemtype::send_event_spieler_kette_msg()
{
  //  cout <<"Sende Event (SEND_SPIELER_KETTE_MSG) an Clients...\n";
  servermsg_zeigerelemtype *akt=servermsg_ketteptr->anfang->next;
  while (akt!=servermsg_ketteptr->ende)
    {
      if (akt->eventmask.playerlist)
	akt->send_spielerkette_msg();
      akt=akt->next;
    }
}


void servermsg_zeigerelemtype::verarbeite_req_freespielerdatei_msg()
{
  int gefunden=0;
  string userfile;
  for (int32 aktspieler=1;aktspieler<=maxspieler;aktspieler++)
    {
      userfile="users/player";
      userfile+=any_to_string(aktspieler);
      userfile+=".usr";

      gefunden=0;
      servermsg_zeigerelemtype *akt=servermsg_ketteptr->anfang->next;
      while (akt!=servermsg_ketteptr->ende)
	{
	  if (!strcmp(akt->spielerptr->dateiname.c_str(),userfile.c_str()))
	    {
	      gefunden=1;
	      break;
	    }
	  akt=akt->next;
	}
      if (!gefunden) break;
    }
  if (!gefunden)
    {
      spielerptr->ladespieler(userfile.c_str());
      cout << "I told Player to use userfile: \""<<userfile<<"\"\n";
      sendmsg(userfile.c_str(),userfile.length()+1,SEND_FREESPIELERDATEI_MSG);
    }
  else
    {
      // Leider kein Spieler frei => ????
      // todo
      cout << "I told Player that i am sorry but there is no free userfile.\n";
      sendmsg(NULL,0,SEND_FREESPIELERDATEI_MSG);
    }
}

void servermsg_zeigerelemtype::verarbeite_req_freespielerplatz_msg()
{
  int32 freespieler=0;
  for (int32 aktspieler=1;aktspieler<=maxspieler;aktspieler++)
    {
      servermsg_zeigerelemtype *found;
      if (!kette_search(servermsg_ketteptr,aktspieler,found))
	{
	  // Diese nummer ist frei !!
	  freespieler=aktspieler;
	  break;
	}
    }
  if (freespieler)
    {
      spielerptr->spielernummer=freespieler;
      cout << "I told Player to use number: \""<<freespieler<<"\"\n";
      iotype out;
      cfgtype *cfgptr=choose_cfgtype(&out,CFG_TEXT_MODE);
      cfgptr->write_int32(freespieler);
      delete cfgptr;
      sendmsg(out.get_buffer(),out.get_buffersize(),SEND_FREESPIELERPLATZ_MSG);
      send_event_spieler_kette_msg();
    }
  else
    {
      cout << "I told Player that i am sorry but there is no free playernumber.\n";
      sendmsg(NULL,0,SEND_FREESPIELERPLATZ_MSG);
    }
}


void servermsg_zeigerelemtype::verarbeite_req_panzer_kette_msg(char *msg,int32 laenge)
{
  if (laenge)
    {
      iotype io(msg,laenge);
      cfgtype *cfgptr=choose_cfgtype(&io,CFG_TEXT_MODE);
      int32 x1,y1,x2,y2;
      cfgptr->read_int32_check(&x1);
      cfgptr->read_int32_check(&y1);
      cfgptr->read_int32_check(&x2);
      cfgptr->read_int32_check(&y2);
      delete cfgptr;
      send_panzer_kette_msg(x1,y1,x2,y2);
      x1_old=x1;
      y1_old=y1;
      x2_old=x2;
      y2_old=y2;
    }
  else
    send_panzer_kette_msg(x1_old,y1_old,x2_old,y2_old);
}

void servermsg_zeigerelemtype::send_landsname_msg()
{
    iotype io;
    cfgtype *cfgptr=choose_cfgtype(&io,CFG_BINAER_MODE);
    cfgptr->change_string_check(&(landscapeptr->name));
    sendmsg(io.get_buffer(),io.get_buffersize(),LANDSNAME_MSG);
    delete cfgptr;
}

void servermsg_zeigerelemtype::send_spielerkette_msg()
{
  //  spaeter sollte der servermsg_zeigerelemtype einen pointer auf seine liste haben ?
  iotype io;
  spieler_ketteptr->change(&io,CFG_TEXT_MODE);
  sendmsg(io.get_buffer(),io.get_buffersize(),SEND_SPIELER_KETTE_MSG);
  cout << "Send player list event with "<<spieler_ketteptr->anzzeigerelem<<" players.\n";
}

void servermsg_zeigerelemtype::send_panzer_kette_msg()
{
  // todo
  cout <<"tudinc_server.C: Warning !! Report this to karme@unforgettable.com\n";
  iotype io;
  einheit_server_ketteptr->change(&io,CFG_BINAER_MODE);
  schuss_server_ketteptr->change(&io,CFG_BINAER_MODE);
  sendmsg(io.get_buffer(),io.get_buffersize(),SEND_PANZER_KETTE_MSG);
}

void servermsg_zeigerelemtype::send_panzer_kette_msg(int32 x1,int32 y1,int32 x2,int32 y2)
{
  char *marklist=new char[einheit_server_ketteptr->anzzeigerelem];
  einheit_server_zeigerelemtype *akt=einheit_server_ketteptr->anfang->next;
  uint32 anzmarked=0;
  // todo muss ich besser machen !!!
  for (int32 aktnr=0;aktnr<einheit_server_ketteptr->anzzeigerelem;aktnr++)
    {
      // Alle eigenen Einheiten muessen verschickt werden todo evtl. auf Wunsch anders !!
      // z.Bsp nur wenn sichtradius Auswirkungen auf scrollscreen !!
      if (akt->spielernummer==spielerptr->spielernummer)
	{
	  // Eigene Einheit 
	  marklist[aktnr]=1;
	  anzmarked++;
	  if (akt->einheitnummer!=spielerptr->akteinheitnr)
	    akt->setmode(einheittype::short_mode);
	  else
	    akt->setmode(einheittype::detailed_mode);
	}
      else
	{
	  int32 r=(int)(akt->einheit_datenptr->einheitradius);
	  int32 ex1=(int)(akt->pos.x)-r;
	  int32 ex2=(int)(akt->pos.x)+r;
	  int32 ey1=(int)(akt->pos.y)-r;
	  int32 ey2=(int)(akt->pos.y)+r;
	  // Einheit ist im "Bildbereich" ?
	  if((ex1>x2)||(ey1>y2)||(ex2<x1)||(ey2<y1)
	     ||(!einheit_server_ketteptr->visible(akt,spielerptr->spielernummer)))
	    // Nein
	    marklist[aktnr]=0;	    
	  else
	    {
	      marklist[aktnr]=1;
	      anzmarked++;
	      akt->setmode(einheittype::short_mode);
	    }
	}
      akt=akt->next;
    }
  iotype io;
  cfgtype *cfgptr=choose_cfgtype(&io,CFG_BINAER_MODE);
  cfgptr->write_int32(anzmarked);
  delete cfgptr;

  //  cout <<"Verschicke an Client "<<anzmarked<<" Einheiten\n";  // todo

  akt=einheit_server_ketteptr->anfang->next;
  for (int32 aktnr=0;aktnr<einheit_server_ketteptr->anzzeigerelem;aktnr++)
  {
    if (marklist[aktnr])
      akt->change(&io,CFG_BINAER_MODE);
    akt=akt->next;
  }
  delete marklist;
  schuss_server_ketteptr->change(&io,CFG_BINAER_MODE);
  sendmsg(io.get_buffer(),io.get_buffersize(),SEND_PANZER_KETTE_MSG);
}

void servermsg_zeigerelemtype::send_explosion_kette_msg()
{
    iotype io;
    explosions_server_ketteptr->change(&io,CFG_BINAER_MODE);
    sendmsg(io.get_buffer(),io.get_buffersize(),SEND_EXPLOSION_KETTE_MSG);
}


void servermsg_zeigerelemtype::verarbeite_eingabe_msg(char *msg,int32 laenge)
{
  cout << "tudinc_server.C: verarbeite_eingabe_msg() WARNING: obsolette call\n";
  iotype io(msg,laenge);
  cfgtype *cfgptr=choose_cfgtype(&io,CFG_BINAER_MODE);
  int32 einheitnummer;
  cfgptr->change_int32_check(&einheitnummer);
  delete cfgptr;
  
  einheit_server_zeigerelemtype *laufzeiger;
  if (kette_search(einheit_server_ketteptr,einheitnummer,laufzeiger))
    {
      if (spielerptr->spielernummer==laufzeiger->spielernummer)
	laufzeiger->eingabechange(&io,CFG_BINAER_MODE);
      else
	cout <<"A client tried to use a vehicle of another player!\n";
      return;
    }
  cout <<"void servermsg_zeigerelemtype::verarbeite_eingabe_msg:\n"
    "A Client tried to use a nonexisting vehicle !\n";
}

void servermsg_zeigerelemtype::verarbeite_eventmask_msg(char *msg,int32 laenge)
{
  iotype io(msg,laenge);
  eventmask.change(&io,CFG_BINAER_MODE);
}

void servermsg_zeigerelemtype::verarbeite_stream_msg(char *msg,int32 laenge)
{
  streambuf *buf=new strstreambuf(msg,laenge);
  istream ist(buf);
  string str;
  if (ist>>str)
    {
      if (str=="vehicle")
	{
	  int32 vehnr;
	  if (ist>>vehnr)
	    {
	      einheit_server_zeigerelemtype *akt;
	      if (kette_search(einheit_server_ketteptr,vehnr,akt))
		{
		  if (akt->spielernummer==spielerptr->spielernummer)
		    {
		      akt->verarbeite_stream_msg(ist);
		    }
		  else
		    akt->verarbeite_stream_msg_foreigner(ist,spielerptr->spielernummer);
		}
	      else 
		cout <<"Vehicle No.: "<<vehnr<<" not found\n";
	    }
	}
      else if (str=="player")
	{
	  int32 playernr;
	  if (ist>>playernr)
	    {
	      //todo
	      cout <<"I should send the following to Player "<<playernr<<endl;
	      string z;
	      getline(ist,z);
	      cout <<z<<endl;
	    }
	}
      else if (str=="relationship")
	{
	  int32 playernr;
	  string rlstr;
	  if ((ist>>playernr)&&(ist>>rlstr))
	    {
	      int8 new_relation;
	      if (rlstr=="friend")
		new_relation=REL_FRIEND;
	      else 
		if (rlstr=="enemy")
		  new_relation=REL_ENEMY;
		else
		  {
		    cerr << "Unknown relationship: '"<<rlstr<<"' => I think it is an enemy\n";
		    new_relation=REL_ENEMY;
		  }
	      spieler_relation_zeigerelemtype *nr;
	      if (!kette_search(&spielerptr->spieler_relation_kette,playernr,nr))
		{
		  cout <<"New relationship between player "
		       <<spielerptr->spielernummer<<" and "<<playernr<<endl;
		  nr=new spieler_relation_zeigerelemtype();
		  spielerptr->spieler_relation_kette.zeiger_push(nr);
		  nr->spielernummer=playernr;
		}
	      cout <<"Changed relationship between player "
		   <<spielerptr->spielernummer<<" and "<<playernr<<endl;
	      nr->relation=new_relation;
	    }	    
	  else
	    cerr <<"Error in relationship message from client.\n";
	}
      else if (str=="select")
	{
	  // todo
	  if (!(ist>>spielerptr->akteinheitnr))
	    cerr <<"Error in select msg from client\n";
	}
      else
	{
	  cout <<"Unknown message form Client No."<<spielerptr->spielernummer<<" ("<<spielerptr->spielername<<")\n";
	  tud_streamtype::verarbeite_stream_msg(msg,laenge);
	  return;
	}
    }
  else
    {
      cerr <<"Error in Message from Client.\n";
    }
  delete msg;
}



leveltype::leveltype()
{
  landscapeptr=NULL;
  einheit_server_ketteptr=new einheit_server_kettetype;
  schuss_server_ketteptr=new schuss_server_kettetype;
  explosions_server_ketteptr=new explosions_server_kettetype;
  servermsg_ketteptr=new servermsg_kettetype(4000);
}

leveltype::~leveltype()
{
  
  delete servermsg_ketteptr;
  delete explosions_server_ketteptr;
  delete schuss_server_ketteptr;
  delete einheit_server_ketteptr;
  delete landscapeptr;
}

void leveltype::change(iotype *ioptr,int8 mode)
{
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  // Landschaftsname
  cfgptr->change_string_check(&landsname);
  if (ioptr->getmode()==IOTYPE_READ_MODE)
    landscapeptr=new landschafttype(landsname.c_str());
  // Maxspieler
  cfgptr->change_int32_check(&maxspieler);
  // Einheitenliste changen naturlich im detailed mode !!
  einheit_server_ketteptr->setmode(einheittype::detailed_mode);
  einheit_server_ketteptr->change(ioptr,mode);
  // Schussliste changen
  schuss_server_ketteptr->change(ioptr,mode);
  delete cfgptr;    
}

int leveltype::calc()
{
  // Bearbeite neue MSGS
  kette_calc(servermsg_ketteptr);

  // Neue Connections ??
  while(servermsg_zeigerelemtype *neues
	=servermsg_ketteptr->managenewconnects()) 
    {
      cout <<"Speedtest ....\n";
      float pingtime=neues->send_ping_msg();
      if (pingtime!=-1)
	cout <<"Ping time: "<<pingtime<<endl;
      else
	cout <<"Ping has been aborted !\n";
    };
  
  // PANZER FAHREN
  allsprites_ketteptr->test();
  kette_calc(einheit_server_ketteptr);
  allsprites_ketteptr->test();
  
  // Schuesse berechnen
  //  schuss_server_ketteptr->calc();
  kette_calc(schuss_server_ketteptr);
  
  // Alle Explosionen an alle Clients verschicken !! natuerlich nur wenn es auch Explosionen gibt !!
  if (explosions_server_ketteptr->anzzeigerelem)
    {
      servermsg_zeigerelemtype *akt=servermsg_ketteptr->anfang->next;
      while (akt!=servermsg_ketteptr->ende)
	{
	  if (akt->eventmask.explosions)
	    akt->send_explosion_kette_msg();
	  akt=akt->next;
	}
      explosions_server_ketteptr->clear();
    }
  return 0;
}

void leveltype::ladelevel(const char *name)
{
  string levelname(name);
  cout <<"Load Level... "<<levelname<<endl;
  iotype *ioptr=make_file_to_io_check(levelname.c_str());
  change(ioptr,CFG_TEXT_MODE);
  delete ioptr;
}

void leveltype::savelevel(const char *name)
{
  cout <<"Save Level... "<<name<<endl;
  iotype io;
  change(&io,CFG_TEXT_MODE);
  make_io_to_file_check(&io,name,S_IWRITE|S_IRUSR|S_IRGRP|S_IROTH|S_IFREG);
}


