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

        T U D    H A U P T M O D U L


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

#include "tudinc.H"

// Gloabel Variablen s.h. Ende von tudinc.H
float deltati;

landschafttype *landscapeptr;
spieler_kettetype *spieler_ketteptr;
einheit_daten_kette_iqtype *einheit_daten_ketteptr;
objekt_daten_kette_iqtype *objekt_daten_ketteptr;
untergrundtabtype *untergrundtabptr=NULL;


// ********************************************* Globale Prozeduren
// ********************************************* Globale Prozeduren
// ********************************************* Globale Prozeduren

void chkdir(float *dir)
{
    if ((*dir)<=-M_PI)
	(*dir)+=2.0*M_PI;
    else
	if ((*dir)>M_PI)
	    (*dir)-=2.0*M_PI;
}


// Liefert die vergangene Zeit zw. 2 Zeitpunkten (in Sekunden)
// Achtung die Zeitpunkte duerfen nicht zu weit auseinanderliegen !

float getdeltatime(timeval *alte_zeit,timeval *neue_zeit)
{
    return ( (neue_zeit->tv_sec - alte_zeit->tv_sec) 
	     + ((float)(neue_zeit->tv_usec - alte_zeit->tv_usec) /1000000.0) );
}


// Untergrundtabelle ************************************************************
// Untergrundtabelle ************************************************************
// Untergrundtabelle ************************************************************
untergrundtabtype::untergrundtabtype(char *dateiname,int8 mode)
{
  iotype *ioptr=make_file_to_io_check(dateiname);
  change(ioptr,mode);
  delete ioptr;
}

void untergrundtabtype::change(iotype *ioptr,int8 mode)
{
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_marke_check("untergrundtabtype");
  cfgptr->change_int16_check(&anzahl);
  for (int16 akt=0;akt<anzahl;akt++)
    {
      cfgptr->change_int8_check(tab+akt);
    }
  cfgptr->change_marke_check("ende");
}


// Relationships ************************************************************
// Relationships ************************************************************
// Relationships ************************************************************

spieler_relation_zeigerelemtype::spieler_relation_zeigerelemtype()
{
}

void spieler_relation_zeigerelemtype::change(iotype *ioptr,int8 mode)
{
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_int32_check(&spielernummer);
  cfgptr->change_int8_check(&relation);
  delete cfgptr;
}


// Spielerdaten ***************************************************************
// Spielerdaten ***************************************************************
// Spielerdaten ***************************************************************

spieler_zeigerelemtype::spieler_zeigerelemtype()
{
  spielername="Unknown";
  flaggenname="spr_src/unknown.spr";
  spielernummer=0;
  akteinheitnr=-1;
  cout <<"New Player initialized.\n";
  dateiname="";
}

void spieler_zeigerelemtype::ladespieler(const char *name)
{
  iotype *ioptr=make_file_to_io_check(name);
  change_short(ioptr,CFG_TEXT_MODE);
  cout <<"Player \""<<spielername.c_str()<<"\" entered the game.\n";
  cout <<"His flag is \""<<flaggenname.c_str()<<"\"\n";
  dateiname=name;
}

void spieler_zeigerelemtype::change_short(iotype *ioptr,int8 mode)
{
    cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
    cfgptr->change_string_check(&spielername);
    cfgptr->change_string_check(&passwd);
    cfgptr->change_string_check(&flaggenname);
    spieler_relation_kette.change(ioptr,mode);
    cfgptr->change_marke_check("ende");
    delete cfgptr;
}

void spieler_zeigerelemtype::change(iotype *ioptr,int8 mode)
{
  change_short(ioptr,mode);
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_int32_check(&spielernummer);
  delete cfgptr;
}


// Objekttype **********************************************************************
// Objekttype **********************************************************************
// Objekttype **********************************************************************
// Objekttype **********************************************************************
// Objekttype **********************************************************************

const char *objekt_zeigerelemtype::headerstring="objekttype";
const char *objekt_zeigerelemtype::getheaderstring()
{
  return objekt_zeigerelemtype::headerstring;
}

objekt_zeigerelemtype::objekt_zeigerelemtype()
{
  objekt_datenptr=NULL;
}

objekt_zeigerelemtype::objekt_zeigerelemtype(const char *name,int32 _anzahl)
{
  objekt_datenptr=NULL;
  anzahl=_anzahl;
  objekt_datenname=name;
  init();
}

objekt_zeigerelemtype::~objekt_zeigerelemtype()
{
  deinit();
}

void objekt_zeigerelemtype::change(iotype *ioptr,int8 mode)
{
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_int32_check((int32 *)&anzahl);
  cfgptr->change_string_check(&objekt_datenname);
  // cout <<"objekt_z_type::change() aufgerufen mit: "<<objekt_datenname<<endl;
  if (ioptr->getmode()==IOTYPE_READ_MODE)
    {
      deinit();
      init();
    }
  delete cfgptr;
}

void objekt_zeigerelemtype::deinit()
{
  if (objekt_datenptr)
    objekt_daten_ketteptr->delete_elementadress(objekt_datenptr);
}

void objekt_zeigerelemtype::init()
{
  //  cout <<"objekt_z_type::init() aufgerufen mit: "<<objekt_datenname.c_str()<<endl;
  objekt_datenptr=objekt_daten_ketteptr->make_elementadress(objekt_datenname.c_str());
}

// objekt_kettetype **********************************************************************
// objekt_kettetype **********************************************************************
// objekt_kettetype **********************************************************************
// objekt_kettetype **********************************************************************
// objekt_kettetype **********************************************************************


objekt_zeigerelemtype *objekt_kettetype::get_or_create(const char* name)
{
  objekt_zeigerelemtype *erg=getobjekt(name);
  if (erg)
    return erg;
  // todo kommt bei nicht detailed gechangeten einheiten staendig !!cout << "ERSTELLE WEIL NICHT VORHANDEN !!!\n";
  erg=new objekt_zeigerelemtype;
  erg->objekt_datenname=name;
  erg->anzahl=0;
  // load static data
  erg->init();
  zeiger_push(erg);
  return erg;
}

ostream &operator<<(ostream &ost,const objekt_zeigerelemtype &z)
{
  cout <<"Objekt: name: "<<z.objekt_datenname<<" anzahl: "<<z.anzahl<<endl;
  return ost;
}

objekt_zeigerelemtype *objekt_kettetype::getobjekt(const char* name) const
{
  objekt_zeigerelemtype *erg;
  if (kette_search(this,name,erg))
    return erg;
  return NULL;
}
int32 objekt_kettetype::calc_newanz(int32 anz,objekt_datentype *obj_datenptr)
{
  if (maxvolume!=0.0)
    {
      int32 masse=obj_datenptr->volume*anz;
      int32 vol=volume();
      if (vol+masse>maxvolume)
	{
	  int32 erg=(maxvolume-vol)/obj_datenptr->volume;
	  if (erg<0) erg=0;
	  cout << "tudinc.C: objekt_kettetype::calc_newanz: maxvolume reached => give "<<erg<<" instead of "<<anz<<endl;
	  return erg;
	}
      return anz;
    }
  cout << "tudinc.C: objekt_kettetype::calc_newanz: WARNING ! maxvolume=0\n";
  return anz;
}

int32 objekt_kettetype::add(const char *name,int32 anz)
{
  objekt_zeigerelemtype *obj=getobjekt(name);
  if (!obj)
    {
      obj=new objekt_zeigerelemtype(name,anz);
      obj->anzahl=calc_newanz(anz,obj->objekt_datenptr);
      zeiger_push(obj);
      return obj->anzahl;
    }
  int32 erg=calc_newanz(anz,obj->objekt_datenptr);
  obj->anzahl+=erg;
  return erg;
}
void objekt_kettetype::give(const char *name,int32 togive,objekt_kettetype &otherkette)
{
  if (togive<0)
    {
      cout <<"objekt_kettetype::give: should give negative/nothing => should take => BAD BOY !!\n";
      return;
    }
  objekt_zeigerelemtype *obj=getobjekt(name);
  if (!obj)
    cout <<"objekt_kettetype::give: should give an objekt that i doesn't have\n";
  else
    {
      if (togive>obj->anzahl)
	{
	  cout <<"objekt_kettetype::give: should give more than i have\n";
	  togive=obj->anzahl;
	}
      obj->anzahl-=otherkette.add(name,togive);
    }
}
void objekt_kettetype::giveuntil(const char *name,int32 giveuntil,objekt_kettetype &otherkette)
{
  objekt_zeigerelemtype *obj=getobjekt(name);
  if (!obj)
    cout <<"objekt_kettetype::giveuntil: should give an objekt that i doesn't have\n";
  else
    give(name,obj->anzahl-giveuntil,otherkette);
}

void objekt_kettetype::check()
{
  objekt_zeigerelemtype *akt=anfang->next;
  while (akt!=ende)
    {
      if ((strcmp(akt->objekt_datenname.c_str(),"object/ammo.obj"))&&(strcmp(akt->objekt_datenname.c_str(),"object/fuel.obj")))
	   cout << "Warning: wrong objectname :\"" << akt->objekt_datenname << "\"\n";
      akt=akt->next;
    };
}

int32 objekt_kettetype::volume() const
{
  int32 erg=0;
  objekt_zeigerelemtype *akt=anfang->next;
  while(akt!=ende)
    {
      erg+=akt->anzahl*akt->objekt_datenptr->volume;
      akt=akt->next;
    }
  return erg;
}


// product_datentype *********************************************************************
// product_datentype *********************************************************************
// product_datentype *********************************************************************
// product_datentype *********************************************************************
// product_datentype *********************************************************************

const char *product_datentype::headerstring="product_datentype";
const char *product_datentype::getheaderstring()
{
  return product_datentype::headerstring;
}


void product_datentype::change(iotype *ioptr,int8 mode)
{
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_marke_check(getheaderstring());
  delete cfgptr;
  change_intern(ioptr,mode);
}

void product_datentype::change_intern(iotype *ioptr,int8 mode)
{
  check_or_save_header(this,ioptr,mode);
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  if (ioptr->getmode()==IOTYPE_WRITE_MODE)
    reltime_tobuild*=100.0;
  else
    deinit();
  cfgptr->change_float_check(&reltime_tobuild);
  reltime_tobuild/=100.0;
  needed_objekt_kette.change(ioptr,mode);
  cfgptr->change_string_check(&spritename);
  delete cfgptr;
  if (ioptr->getmode()==IOTYPE_READ_MODE)
    init();
}


// objekt_datentype *****************************************************************
// objekt_datentype *****************************************************************
// objekt_datentype *****************************************************************
// objekt_datentype *****************************************************************
// objekt_datentype *****************************************************************

const char *objekt_datentype::headerstring="objekt_datentype";
const char *objekt_datentype::getheaderstring()
{
  return objekt_datentype::headerstring;
}

ammo_datentype *objekt_datentype::cast_ammo_datentype()
{
  if (!strcmp(getheaderstring(),ammo_datentype::headerstring))
    return ((ammo_datentype *)this);
  cout <<"I am of type: \""<<getheaderstring()<<"\" and should be of \""<<ammo_datentype::headerstring<<"\"\n";
  fatalfehler("objekt_datentype::cast_ammo_datentype(): this cast is not allowed\n");
  return NULL;
}

objekt_datentype *objekt_datentype::create(iotype *ioptr,int8 mode)
{
  if (ioptr->getmode()!=IOTYPE_READ_MODE)
    fatalfehler("object_datentype::create\n"
		"iotype is not in read mode");
  int32 oldseek=ioptr->getpos();
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  string _headerstring;
  cfgptr->read_string_check(&_headerstring);
  delete cfgptr;
  ioptr->seekset(oldseek);
  objekt_datentype *erg=NULL;
  if (_headerstring==objekt_datentype::headerstring)
    erg=new objekt_datentype;
  else if (_headerstring==ammo_datentype::headerstring)
    erg=new ammo_datentype;
  else
    fatalfehler("object_datentype::create(...): Illegal headerstring");
  erg->change(ioptr,mode);
  return erg;
}

void objekt_datentype::change_intern(iotype *ioptr,int8 mode)
{
  product_datentype::change_intern(ioptr,mode);
  check_or_save_header(this,ioptr,mode);
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_int32_check(&volume);
  cfgptr->change_int32_check(&unit);
  cfgptr->change_marke_check("end");
  delete cfgptr;
}
objekt_datentype::~objekt_datentype()
{
}

// ammo_datentype *****************************************************************
// ammo_datentype *****************************************************************
// ammo_datentype *****************************************************************

const char *ammo_datentype::headerstring="ammo_datentype";
const char *ammo_datentype::getheaderstring()
{
  return ammo_datentype::headerstring;
}

void ammo_datentype::change_intern(iotype *ioptr,int8 mode)
{
  objekt_datentype::change_intern(ioptr,mode);
  check_or_save_header(this,ioptr,mode);
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_float_check(&muehexplosion);
  cfgptr->change_float_check(&explosionsradius);
  explosionsradius*=landscapeptr->massstab;
  explosionsradiusint=ftoi(explosionsradius);
  cfgptr->change_string_check(&sound);
  cfgptr->change_marke_check("end");
  delete cfgptr;
}
ammo_datentype::~ammo_datentype()
{
}



// Statische Einheitdaten *****************************************************
// Statische Einheitdaten *****************************************************
// Statische Einheitdaten *****************************************************

// Type checking
const char *einheit_datentype::headerstring="einheit_datentype";
const char *einheit_datentype::getheaderstring()
{
  return einheit_datentype::headerstring;
}

einheit_datentype::einheit_datentype()
{
}

einheit_datentype::~einheit_datentype()
{
  //  deinit(); einheit_datentype hat gerade keine eigene init und deinit routine
}

einheit_datentype *einheit_datentype::create(iotype *ioptr,int8 mode)
{
  if (ioptr->getmode()!=IOTYPE_READ_MODE)
    fatalfehler("einheit_datentype::create\n"
		"iotype is not in read mode");
  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(),panzer_datentype::headerstring))
    {
      panzer_datentype *neues=new panzer_datentype;
      neues->change(ioptr,mode);
      return neues;
    }
  else if (!strcmp(_headerstring.c_str(),firma_datentype::headerstring))
    {
      firma_datentype *neues=new firma_datentype;
      neues->change(ioptr,mode);
      return neues;
    }
  fatalfehler("einheit_datentype::create: Illegaler headerstring !");
  return(NULL); // spaeter 
}

void einheit_datentype::change_intern(iotype *ioptr,int8 mode)
{
  if (ioptr->getmode()==IOTYPE_WRITE_MODE)
    fatalfehler("tudinc.H: einheit_datentype::change :\n"
		"leider wird _*NOCH*_ kein save unterstuetzt !");
  
  product_datentype::change_intern(ioptr,mode);
  check_or_save_header(this,ioptr,mode);  

  // Wenn ein Panzer ueber einen anderen geladen wird !! (nur beim lesen !!!)
  //  deinit();

  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);

  // Randlinienlader
  randlinien_kette.change(ioptr,mode);

  cfgptr->change_int32_check(&sichtradius);
  sichtradius=ftoi((float)sichtradius*landscapeptr->massstab);
  
  // Schutz
  int32 einheitradiusint;
  cfgptr->change_int32_check(&einheitradiusint);
  einheitradius=(float)einheitradiusint;
  cfgptr->change_float_check(&muehmine);
  cfgptr->change_float_check(&muehgranate);
  muehmine/=100.0;
  muehgranate/=100.0;
  cfgptr->change_string_check(&fuelname);
  cfgptr->change_float_check(&fuelpersec);
  cfgptr->change_float_check(&capacity);
  cfgptr->change_marke_check("end einheit_datentype");
  delete cfgptr;

  // Nur beim Lesen !!!!
  //  init();
}

void einheit_datentype::convert(panzer_datentype **result)
{
  if (!strcmp(panzer_datentype::headerstring,getheaderstring()))
    {
      *result=(panzer_datentype *)this;
      return;
    }      
  cerr << panzer_datentype::headerstring <<" *"<<headerstring<<"::convert():\n"
       <<"illegal type conversation\n";
  fatalfehler("see above");
}
 
void einheit_datentype::convert(firma_datentype **result)
{
  if (!strcmp(firma_datentype::headerstring,getheaderstring()))
    {
      *result=(firma_datentype *)this;
      return;
    }
  cerr << firma_datentype::headerstring <<" *"<<headerstring<<"::convert():\n"
       <<"Unzulaessige Typkonvertierung\n";
  fatalfehler("s.h. oben");
}


// Statische Firmendaten **************************************************
// Statische Firmendaten **************************************************
// Statische Firmendaten **************************************************

const char *firma_datentype::headerstring="firma_datentype";
const char *firma_datentype::getheaderstring()
{
  return firma_datentype::headerstring;
}

firma_datentype::firma_datentype()
{
  firma_offen_spriteptr=NULL;
}

// Einheit entfernen
firma_datentype::~firma_datentype()
{
  deinit();
}

void firma_datentype::init()
{
  firma_offen_spriteptr=allsprites_ketteptr->make_elementadress(firma_offen_spritename.c_str());
}

void firma_datentype::deinit()
{
  if (firma_offen_spriteptr)
    allsprites_ketteptr->delete_elementadress(firma_offen_spriteptr);  
}

void firma_datentype::change_intern(iotype *ioptr,int8 mode)
{
    einheit_datentype::change_intern(ioptr,mode);
    check_or_save_header(this,ioptr,mode);

    if (ioptr->getmode()==IOTYPE_WRITE_MODE)
	fatalfehler("tudinc.H: firma_datentype::change :\n"
		    "leider wird _*NOCH*_ kein save unterstuetzt !");

    // Wenn ein Panzer ueber einen anderen geladen wird !! (nur beim lesen !!!)
    deinit();

    cfgtype *cfgptr=choose_cfgtype(ioptr,mode);

    cfgptr->change_string_check(&firma_offen_spritename);
    cfgptr->change_float_check(&time_tobuild_tiger);
    //    cout <<"Firma geladen time_tobuld_tiger: "<<time_tobuild_tiger<<endl;
    buildable_objekt_kette.change(ioptr,mode);
    buildable_vehicle_kette.change(ioptr,mode);
    cfgptr->change_marke_check("end firma_datentype");
    delete cfgptr;

    // Nur beim Lesen !!!!
    init();
}

// StatischeCanondaten  ******************************************************
// StatischeCanondaten  ******************************************************
// StatischeCanondaten  ******************************************************

const char *canon_datentype::headerstring="canon_datentype";
const char *canon_datentype::getheaderstring()
{
  return panzer_datentype::headerstring;
}

void canon_datentype::change(iotype *ioptr,int8 mode)
{
  check_or_save_header(this,ioptr,mode);
  if (ioptr->getmode()==IOTYPE_WRITE_MODE)
    fatalfehler("tudinc.H: panzer_datentype::change :\n"
		"leider wird _*NOCH*_ kein save unterstuetzt !");
  
  // Wenn eine canon ueber einen anderen geladen wird !! (nur beim lesen !!!)
  deinit();
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_string_check(&turm_spritename);
  // Turmpos.
  turmpos.change(ioptr,mode);
  cfgptr->change_float_check(&vturmdreh);    
  cfgptr->change_float_check(&vturmdrehhand);    
  cfgptr->change_float_check(&vturmfahr);
  cfgptr->change_float_check(&vturmfahrhand);
  
  vturmdreh*=M_PI/180.0;
  vturmdrehhand*=M_PI/180.0;
  vturmfahr*=M_PI/180.0;
  vturmfahrhand*=M_PI/180.0;
  
  // Turmbereiche
  cfgptr->change_float_check(&relturmdirlinksmax);
  relturmdirlinksmax*=M_PI/180.0;
  cfgptr->change_float_check(&relturmdirrechtsmax);
  relturmdirrechtsmax*=M_PI/180.0;
  cfgptr->change_float_check(&turmfahrmax);
  turmfahrmax*=M_PI/180.0;
  cfgptr->change_float_check(&turmfahrmin);
  turmfahrmin*=M_PI/180.0;
  cfgptr->change_float_check(&fuelpersec);

  // KILL
  cfgptr->change_float_check(&ladedauer);
  cfgptr->change_float_check(&richtzeit);
  cfgptr->change_string_check(&ammoname);
  cfgptr->change_float_check(&vschuss);
  vschuss*=landscapeptr->massstab;
  cfgptr->change_marke_check("end canon_datentype");
  delete cfgptr;
  init();
}



// StatischePanzerdaten  ******************************************************
// StatischePanzerdaten  ******************************************************
// StatischePanzerdaten  ******************************************************
// StatischePanzerdaten  ******************************************************
// spaeter
/*
ostream& operator<<(ostream& os, panzer_datentype pd)
{
  return os<<"Das ist der Panzerdatentyp mit dem Sprite: "<<pd.turm_spritename.c_str();
}*/

const char *panzer_datentype::headerstring="panzer_datentype";
const char *panzer_datentype::getheaderstring()
{
  return panzer_datentype::headerstring;
}


panzer_datentype::panzer_datentype()
{
}

// Einheit entfernen
panzer_datentype::~panzer_datentype()
{
  deinit();
}

void panzer_datentype::init()
{
  //  turm_spriteptr=allsprites_ketteptr->make_elementadress(turm_spritename.c_str());
}

void panzer_datentype::deinit()
{
  //  if (turm_spriteptr)
  //    allsprites_ketteptr->delete_elementadress(turm_spriteptr);  
}

void panzer_datentype::change_intern(iotype *ioptr,int8 mode)
{
  einheit_datentype::change_intern(ioptr,mode);
  check_or_save_header(this,ioptr,mode);

  if (ioptr->getmode()==IOTYPE_WRITE_MODE)
    fatalfehler("tudinc.H: panzer_datentype::change :\n"
		"leider wird _*NOCH*_ kein save unterstuetzt !");
  
  // Wenn ein Panzer ueber einen anderen geladen wird !! (nur beim lesen !!!)
  deinit();
  
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  
  cfgptr->change_string_check(&vehiclename);
  
  // Vektorteil *******************************
  cfgptr->change_marke_check("vektorteil");
  // Raddotslader
  raddots_kette.change(ioptr,mode);
  
  // Untergrundcheckdaten !!!
  cfgptr->change_marke_check("untergrundcheck");
  // Speed
  int feld;
  for (feld=0;feld<anzunter;feld++)
    {
      cfgptr->change_float_check(&(speedfaktor[feld]));
      speedfaktor[feld]/=100.0;
    }
  for (feld=0;feld<anzunter;feld++)
    {
      cfgptr->change_float_check(&(destroyfaktor[feld]));
      destroyfaktor[feld]=100.0/destroyfaktor[feld];
    }
  for (feld=0;feld<anzunter;feld++)
    {
      cfgptr->change_int8_check(&(verbotenezone[feld]));
    }
  cfgptr->change_marke_check("fahrzeugdaten");
  
  cfgptr->change_float_check(&vpanzvor);
  vpanzvor*=landscapeptr->massstab;
  cfgptr->change_float_check(&vpanzback);
  vpanzback*=landscapeptr->massstab;
  
  cfgptr->change_float_check(&vdreh);    
  cfgptr->change_float_check(&vdrehstand);    
  vdreh*=M_PI/180.0;
  vdrehstand*=M_PI/180.0;
  cfgptr->change_float_check(&minelegdauer);
  cfgptr->change_marke_check("canon_daten_kettetype");  
  canon_daten_kette.change(ioptr,mode);
  cfgptr->change_marke_check("end panzer_datentype");  
  delete cfgptr;
  // Nur beim Lesen !!!!
  init();
}


// Der allgemeine Einheittype ************************************************************
// Der allgemeine Einheittype ************************************************************
// Der allgemeine Einheittype ************************************************************

// Type checking
const char *einheittype::headerstring="einheittype";
const char *einheittype::getheaderstring()
{
  return einheittype::headerstring;
}

int einheittype::friendship(einheittype *akt)
{
  if (akt->spielernummer==spielernummer)
    return REL_FRIEND;
  spieler_zeigerelemtype *ichspielerptr;
  if (!kette_search(spieler_ketteptr,spielernummer,ichspielerptr))
    // "Besitzerlose" Einheiten !! bzw. Abwesenheit des Besitzers !!! => Krieg !! todo ?
    return REL_ENEMY;
  spieler_relation_zeigerelemtype *sprelptr;
  if (kette_search(&(ichspielerptr->spieler_relation_kette),akt->spielernummer,sprelptr))
    return (sprelptr->relation);
  return REL_ENEMY;
}

int einheittype::near(einheittype *akt,float dist)
{
  float deltax=pos.x-akt->pos.x;
  float deltay=pos.y-akt->pos.y;
  float abstand=deltax*deltax+deltay*deltay;
  float minabstand=dist + akt->einheit_datenptr->einheitradius;
  minabstand=minabstand*minabstand;
  return (abstand<=minabstand);
}

int einheittype::near(einheittype *akt)
{
  return near(akt,einheit_datenptr->einheitradius);
}

void einheittype::change(iotype *ioptr,int8 mode)
{
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_marke_check(getheaderstring());
  if (ioptr->getmode()==IOTYPE_READ_MODE)
    {
      // lesen
      string aktmode;
      cfgptr->read_string_check(&aktmode);
      if (aktmode=="detailed")
	setmode(detailed_mode);
      else if (aktmode=="short")
	setmode(short_mode);
      else
	fatalfehler("tudinc.C: einheittype::change(...): wrong mode - i expect detialed_mode or short_mode");
    }
  else if (ioptr->getmode()==IOTYPE_WRITE_MODE )
    {
      // schreiben
      if (getmode()==detailed_mode)
	{
	  cfgptr->write_string("detailed");
	}
      else if (getmode()==short_mode)
	{
	  cfgptr->write_string("short");
	}
      else // falls jemals mehr modis auch unten hinzufuegen !!
	fatalfehler("tudinc.C: einheittype::change(...) wrong changemode\n");
    }
  else
    fatalfehler("tudinc.C: einheittype::change(...): iotype in unknown mode");
  delete cfgptr;

  change_intern(ioptr,mode);
}

void einheittype::change_intern(iotype *ioptr,int8 mode)
{
  check_or_save_header(this,ioptr,mode);
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_int32_check(&spielernummer);
  change_container(ioptr,mode,lendlist);
  cfgptr->change_int32_check(&einheitnummer);
  pos.change(ioptr,mode);
  cfgptr->change_float_check(&einheitdir);
  cfgptr->change_string_check(&einheit_daten_dateiname);

  if (getmode()==detailed_mode)
    {
      //  cout <<"einheittype::change_detailed(...): ...\n";
      cfgptr->change_float_check(&substanz);
      objekt_kette.change(ioptr,mode);
      cfgptr->change_marke_check("ende");
    }

  if (ioptr->getmode()==IOTYPE_READ_MODE)
    // Achtung laedt einheit_daten nur neu wenn noch keine geladen wurden !
    // todo total scheisse was soll das ??
    init();

  delete cfgptr;
}

einheittype::einheittype()
{
  einheit_datenptr=NULL;
  setmode(detailed_mode);
  fuel=0.0;
}

einheittype::einheittype
(const char *_einheit_daten_dateiname,vektor2_koordtype *_pos, int32 _spielernummer,
 float _einheitdir,int32 _einheitnummer)
{
  //  cout <<"einheittype::einheittype(,,,,) aufgerufen\n";
  einheit_datenptr=NULL;
  pos=*_pos;
  spielernummer=_spielernummer;
  einheitdir=_einheitdir;
  einheitnummer=_einheitnummer;
  einheit_daten_dateiname=_einheit_daten_dateiname;
  substanz=100;
  init();
}

einheittype::~einheittype()
{
  deinit();
}

// todo ich glaub nicht dass das funktioniert
void einheittype::init()
{
  if (!einheit_datenptr)
    einheit_datenptr=einheit_daten_ketteptr->make_elementadress(einheit_daten_dateiname.c_str());
  // todo nicht jede einheit muss nen fuel haben !!
  fuelptr=objekt_kette.get_or_create(einheit_datenptr->fuelname.c_str());

  // Darf nicht zu hoch sein evtl eine checkbereich routine
  if (substanz>100)
    substanz=100;

  objekt_kette.set_maxvolume(einheit_datenptr->capacity);
}

void einheittype::deinit()
{
  if (einheit_datenptr)
    einheit_daten_ketteptr->delete_elementadress(einheit_datenptr);
  einheit_datenptr=NULL;
}





// Die dynamischen Firmendaten **********************************************************************
// Die dynamischen Firmendaten **********************************************************************
// Die dynamischen Firmendaten **********************************************************************
// Die dynamischen Firmendaten **********************************************************************

// Type checking
const char *firmatype::headerstring="firmatype";
const char *firmatype::getheaderstring()
{
  return firmatype::headerstring;
}

firmatype::firmatype()
{
  firma_datenptr=NULL;
  typeof_tobuild="none";
}

firmatype::firmatype
(const char *_panzer_daten_dateiname,vektor2_koordtype *_pos,
 int32 _spielernummer,float _einheitdir,int32 _einheitnummer)
  : einheittype(_panzer_daten_dateiname,_pos,_spielernummer,_einheitdir,_einheitnummer)
{
  einheit_datenptr_to_firma_datenptr();
  typeof_tobuild="none";
}


void firmatype::einheit_datenptr_to_firma_datenptr()
{
  if (einheit_datenptr)
    einheit_datenptr->convert(&firma_datenptr);
  else
    fatalfehler("firmatype::einheit_datenptr_to_firma_datenptr():\n"
		"einheit_datenptr ist NULL !");
}

void firmatype::change_intern(iotype *ioptr,int8 mode)
{
  einheittype::change_intern(ioptr,mode);
  check_or_save_header(this,ioptr,mode);
  if ((ioptr->getmode()==IOTYPE_READ_MODE)&&(!firma_datenptr))
    {
      einheit_datenptr_to_firma_datenptr();
    }
  if (getmode()==detailed_mode)
    {
      cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
      cfgptr->change_marke_check("begin firmatype");
      cfgptr->change_float_check(&countdown);
      cfgptr->change_string_check(&tobuild);
      cfgptr->change_string_check(&typeof_tobuild);
      cfgptr->change_marke_check("end firmatype");
      delete cfgptr;
    }
}

float firmatype::time_tobuild()
{
  // todo evtl. eleganter machen
  float erg;
#ifdef kickwarn
  erg=0.0;
#endif
  if (typeof_tobuild=="vehicle")
    {
      einheit_datentype *ablage=einheit_daten_ketteptr->make_elementadress(tobuild.c_str());
      //    cout <<"ablage: reltobuild "<<ablage->reltime_tobuild<<" firma time to build tiger "<<firma_datenptr->time_tobuild_tiger<<endl;
      erg=ablage->reltime_tobuild*firma_datenptr->time_tobuild_tiger;
      einheit_daten_ketteptr->delete_elementadress(ablage);
    }
  else if (typeof_tobuild=="object")
    {
      objekt_datentype *ablage=objekt_daten_ketteptr->make_elementadress(tobuild.c_str());
      //    cout <<"ablage: reltobuild "<<ablage->reltime_tobuild<<" firma time to build tiger "<<firma_datenptr->time_tobuild_tiger<<endl;
      erg=ablage->reltime_tobuild*firma_datenptr->time_tobuild_tiger;
      objekt_daten_ketteptr->delete_elementadress(ablage);
    }
  else
    fatalfehler("firmatype::time_tobuild(): should build something strange (impossible;-)\n");
  //cout <<"time_tobuild: "<<erg<< "seconds\n";
  return erg;
}

// todo really ugly exactly the same twice
kettetype<string_zeigerelemtype> *firmatype::akt_buildable_objekts()
{
  kettetype<string_zeigerelemtype> *erg=new kettetype<string_zeigerelemtype>;
  string_zeigerelemtype *akt=firma_datenptr->buildable_objekt_kette.anfang->next;
  while (akt!=firma_datenptr->buildable_objekt_kette.ende)
    {
      objekt_datentype *aktprdaten=objekt_daten_ketteptr->make_elementadress(akt->c_str());	  
      objekt_kettetype *missing=aktprdaten->missing_objects(objekt_kette);
      if (!(missing->anzzeigerelem))
	{
	  string_zeigerelemtype *newone=new string_zeigerelemtype(akt->c_str());
	  erg->zeiger_push(newone);
	}
      delete missing;
      objekt_daten_ketteptr->delete_elementadress(aktprdaten);
      akt=akt->next;
    }
  return erg;
}

kettetype<string_zeigerelemtype> *firmatype::akt_buildable_vehicles()
{
  kettetype<string_zeigerelemtype> *erg=new kettetype<string_zeigerelemtype>;
  string_zeigerelemtype *akt=firma_datenptr->buildable_vehicle_kette.anfang->next;
  while (akt!=firma_datenptr->buildable_vehicle_kette.ende)
    {
      einheit_datentype *aktprdaten=einheit_daten_ketteptr->make_elementadress(akt->c_str());	  
      objekt_kettetype *missing=aktprdaten->missing_objects(objekt_kette);
      if (!(missing->anzzeigerelem))
	{
	  string_zeigerelemtype *newone=new string_zeigerelemtype(akt->c_str());
	  erg->zeiger_push(newone);
	}
      delete missing;
      einheit_daten_ketteptr->delete_elementadress(aktprdaten);
      akt=akt->next;
    }
  return erg;
}


// Eingabedaten ***************************************************************
// Eingabedaten ***************************************************************
// Eingabedaten ***************************************************************

void eingabetype::change(iotype *ioptr,int8 mode)
{
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_float_check(&gas);
  cfgptr->change_float_check(&drehen);
  cfgptr->change_int16_check(&autodrive);
  autodriveto_kette.change(ioptr,mode);
  cfgptr->change_int32_check(&autofollow_number);
  cfgptr->change_float_check(&autofollow_distance);
  autofollow_relto.change(ioptr,mode);
  cfgptr->change_int32_check(&follower);
  delete cfgptr;

  if (ioptr->getmode()==IOTYPE_READ_MODE)
    if (checkbereich())
      cout <<"eingabetype::change: incorrect input!\n";
}

int eingabetype::checkbereich()
{
    int ret=0;
    if (gas>1.0)
	{
	    gas=1.0;
	    ret=1;
	}
    else if (gas<-1.0)
	{
	    gas=-1.0;
	    ret=1;
	}
    if (drehen>1.0)
	{
	    drehen=1.0;
	    ret=1;
	}
    else if (drehen<-1.0)
	{
	    drehen=-1.0;
	    ret=1;
	}
    return(ret);
}

void eingabetype::init()
{
  gas=0;
  drehen=0;
  autodrive=0;
  autofollow_distance=60;
  autodrivetoptr=autodriveto_kette.anfang;
  follower=-1;
  autofollow_number=-1;
}

// Die Daten, die nur der Besitzer kennt ! ************************************
// Die Daten, die nur der Besitzer kennt ! ************************************
// Die Daten, die nur der Besitzer kennt ! ************************************

void besitzerdatentype::change(iotype *ioptr,int8 mode)
{
    cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
    cfgptr->change_string_check(&fahrzeug_name);
    eingabe.change(ioptr,mode);
    cfgptr->change_float_check(&standzeit);
    cfgptr->change_float_check(&restminelegdauer);
    cfgptr->change_marke_check("ende");
    delete cfgptr;
}

void besitzerdatentype::init()
{
  // todo alles kack - nee net so schlecht aber fahrzeug_name muss man noch setzen koennen
  fahrzeug_name="Noname";
  eingabe.init();
}








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

void canontype::change(iotype *ioptr,int8 mode)
{
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_float_check(&relturmdir);

  if (einheitptr->getmode()==einheitptr->detailed_mode)
    {
      cfgptr->change_float_check(&dirhorizon);
      cfgptr->change_float_check(&restladedauer);
      cfgptr->change_float_check(&turmdrehen);
      cfgptr->change_float_check(&turmfahren);
      cfgptr->change_int16_check(&schiessen);
      cfgptr->change_marke_check("ende");
    }
  delete cfgptr;
}

void canontype::chkturmdirbereich()
{
  if (relturmdir<canon_datenptr->relturmdirlinksmax)
    {
      // Über linken Rand hinaus
      relturmdir=canon_datenptr->relturmdirlinksmax;
      turmdrehen=0;
      return;
    }
  if (relturmdir>canon_datenptr->relturmdirrechtsmax)
    {
      // Über rechten Rand hinaus
      relturmdir=canon_datenptr->relturmdirrechtsmax;
      turmdrehen=0;
      return;
    }
  chkdir(&(relturmdir));
  if (dirhorizon<canon_datenptr->turmfahrmin)
    {
      dirhorizon=canon_datenptr->turmfahrmin;
      turmfahren=0;
    }
  else
    if (dirhorizon>canon_datenptr->turmfahrmax)
      {
	dirhorizon=canon_datenptr->turmfahrmax;
	turmfahren=0;
      }
}

int canontype::checkbereich()
{
  if (restladedauer>canon_datenptr->ladedauer)
    {
      restladedauer=canon_datenptr->ladedauer;
      return 1;
    }
  if (turmdrehen>1.0)
    {
      turmdrehen=1.0;
      return 1;
    }
  else if (turmdrehen<-1.0)
    {
      turmdrehen=-1.0;
      return 1;
    }
  if (turmfahren>1.0)
    {
      turmfahren=1.0;
      return 1;
    }
  else if (turmfahren<-1.0)
    {
      turmfahren=-1.0;
      return 1;
    }
  return 1;
}

void canontype::calc_aktturmpos(vektor2_koordtype &erg)
{
  vektor2_koordtype aktpos(&(canon_datenptr->turmpos));
  aktpos.rotate(einheitptr->einheitdir);
  erg.import(&aktpos);
}

float canontype::maxreichweite()
{
  // todo was wenn M_PI_4 nicht einstellbar
  // s= V * t *1.1
  return (cos(M_PI_4)*canon_datenptr->vschuss
	  *2*sin(M_PI_4)*canon_datenptr->vschuss/landscapeptr->gravity
	  *1.1);
}




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

// Type checking
const char *panzertype::headerstring="panzertype";
const char *panzertype::getheaderstring()
{
  return panzertype::headerstring;
}

panzertype::panzertype()
{
  panzer_datenptr=NULL;
}

panzertype::panzertype
(const char *_panzer_daten_dateiname,vektor2_koordtype *_pos,
 int32 _spielernummer,float _einheitdir,int32 _einheitnummer)
  : einheittype(_panzer_daten_dateiname,_pos,_spielernummer,_einheitdir,_einheitnummer)
{
  einheit_datenptr_to_panzer_datenptr();
}

panzertype::~panzertype()
{
}

void panzertype::change_intern(iotype *ioptr,int8 mode)
{
  einheittype::change_intern(ioptr,mode);

  check_or_save_header(this,ioptr,mode);
  //  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);

  // todo gehoert hier eigentlich auch net hin !! vielleicht aber auch doch :-)
  if ((ioptr->getmode()==IOTYPE_READ_MODE)&&(!panzer_datenptr))
    einheit_datenptr_to_panzer_datenptr();
  
  // Detailed ??
  if (getmode()==detailed_mode)
    {
      besitz.change(ioptr,mode);
    }
  //  delete cfgptr;
}

void panzertype::einheit_datenptr_to_panzer_datenptr()
{
  if (einheit_datenptr)
    einheit_datenptr->convert(&panzer_datenptr);
  else
    fatalfehler("panzertype::einheit_datenptr_to_panzer_datenptr():\neinheit_datenptr ist NULL !");
}


// Schussobjekt **************************************************************
// Schussobjekt **************************************************************
// Schussobjekt **************************************************************

schusstype::schusstype()
{}

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

void schusstype::change(iotype *ioptr,int8 mode)
{
  pos.change(ioptr,mode);
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_float_check(&dir);
  cfgptr->change_float_check(&speed);
  cfgptr->change_float_check(&restzeit);
  cfgptr->change_float_check(&muehexplosion);
  cfgptr->change_float_check(&explosionsradius);
  cfgptr->change_string_check(&sound);
  delete cfgptr;
  return;
}


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

explosionstype::explosionstype()
{}

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

void explosionstype::change(iotype *ioptr,int8 mode)
{
  pos.change(ioptr,mode);
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_float_check(&muehexplosion);
  cfgptr->change_float_check(&explosionsradius);
  cfgptr->change_string_check(&sound);
  delete cfgptr;
  return;
}



// ****************************************************************************
// *************************************************************     Landschaft
// *************************************************************     Landschaft
// *************************************************************     Landschaft
// ****************************************************************************

landschafttype::landschafttype(const char *n)
{
    name=n;
    iotype *ioptr=make_file_to_io_check(n);
    change(ioptr,CFG_TEXT_MODE);
    landspriteptr=allsprites_ketteptr->make_elementadress(spritename.c_str());
    delete ioptr;
};


landschafttype::~landschafttype()
{
    allsprites_ketteptr->delete_elementadress(landspriteptr);
};

void landschafttype::change(iotype *ioptr,int8 mode)
{
    cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
    cfgptr->change_float_check(&massstab);
    cfgptr->change_float_check(&gravity);
    cfgptr->change_string_check(&spritename);
    delete cfgptr;
}



// Kommunikation *****************************************************************************
// Kommunikation *****************************************************************************
// Kommunikation *****************************************************************************
// Kommunikation *****************************************************************************

eventmasktype::eventmasktype()
{
  explosions=0;
  playerlist=0;
}

void eventmasktype::change(iotype *ioptr,int8 mode)
{
    cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
    cfgptr->change_int16_check(&explosions);
    cfgptr->change_int16_check(&playerlist);
    delete cfgptr;
}

void tud_streamtype::send_stream_msg(const string& st)
{
  sendmsg(st.c_str(),st.length()+1,SEND_STREAM_MSG); //todo fragwuerdig !!
}

void tud_streamtype::verarbeite_stream_msg(char *msg,int32)
{
  cout <<msg<<endl;
  delete msg;
}







