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

                    T U D    C L I E N T  -  M O D U L

		    H E A D E R D A T E I

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

#include <unistd.h> // for usleep()
#include "tudinc_client.H"
// todo muss eh weg !!
#include "terminal.H"


// Globale Variablen s.h. Ende von tudinc_client.H
// Anzahl rausgeschickter koordinaten requests
int16 reqcoords;
// transformtype transform; now in scrollscreentype
einheit_client_kettetype *einheit_client_ketteptr;
schuss_client_kettetype *schuss_client_ketteptr;
explosions_client_kettetype *explosions_client_ketteptr;
tudscreentype *tudscreenptr=NULL;
scrollscreentype *scrollscreenptr=NULL;
int showflags=0;
gametype *gameptr=NULL;
yyysound_client_noexception *soundptr;





// Hat hier eigentlich nix verloren !!! spaeter todo
transformtype::transformtype(spieler_zeigerelemtype *_ich)
{
  einheit_client_zeigerelemtype *myfirst=einheit_client_ketteptr->find_first_of(_ich->spielernummer);
  if (!myfirst)
    {
      //      cout << "Sorry but you don't have any vehicle\n";
      vtx=0;
      vty=0;
    }
  else
    {
      vtx=ftoi(myfirst->pos.x);
      vty=ftoi(myfirst->pos.y);
    }
  akttx=vtx;
  aktty=vty;
  tx_to=ftoi(akttx);
  ty_to=ftoi(aktty);
  vwinkel=3.14;
  vzoom=0.2;
  winkel_to=0.0;
  zoom_to=1.0;
}

void transformtype::scr_to_spr(int32 scrx,int32 scry,int32 *sprx,int32 *spry)
{
  vektor2_koordtype spr(scrx+scrollscreenptr->mx-scrollscreenptr->sx/2,scry+scrollscreenptr->my-scrollscreenptr->sy/2);
  spr.x/=vzoom;
  spr.y/=vzoom;
  spr.rotate(-vwinkel);
  *sprx=ftoi(spr.x)+vtx;
  *spry=ftoi(spr.y)+vty;
}

void transformtype::spr_to_scr(int32 sprx,int32 spry,int32 *scrx,int32 *scry)
{
  vektor2_koordtype scr(sprx-vtx,spry-vty);
  scr.rotate(vwinkel);
  scr.x*=vzoom;
  scr.y*=vzoom;
  *scrx=ftoi(scr.x)-scrollscreenptr->mx+scrollscreenptr->sx/2;
  *scry=ftoi(scr.y)-scrollscreenptr->my+scrollscreenptr->sy/2;
}

void transformtype::calc()
{
  transformed=totransform();
  if (transformed)
    {
      if (zoom_to>4)
	zoom_to=4;
      if (zoom_to<0.1)
	zoom_to=0.1;
      incfloat(vzoom,zoom_to,0.25);
      incfloat(vwinkel,winkel_to,0.5);
      incfloat(akttx,tx_to,fabs(akttx-tx_to)+1);
      vtx=ftoi(akttx);
      incfloat(aktty,ty_to,fabs(aktty-ty_to)+1);
      vty=ftoi(aktty);
    }
}

int transformtype::transforming()
{
  return transformed;
}

int transformtype::totransform()
{
  return ((vzoom!=zoom_to)||(vwinkel!=winkel_to)||(tx_to!=vtx)||(ty_to!=vty));
}

void transformtype::incfloat(float &aktvalue,const float incvalue,const float incspeed) const
{
  if (incvalue>aktvalue)
    {
      aktvalue+=incspeed*deltati;
      if (aktvalue>incvalue)
	aktvalue=incvalue;
    }
  else if (incvalue<aktvalue)
    {
      aktvalue-=incspeed*deltati;
      if (aktvalue<incvalue)
	aktvalue=incvalue;
    }
}
// Contentscreentype

const char *contentscreentype::headerstring="contentscreentype";

contentscreentype::contentscreentype()
{
  //  cout <<"contentscreentype() called\n";
  zahlen=NULL;
  oldother=NULL;
  anzz=0;
  mx=283;
  my=263;
  sx=150;
  sy=120;
  cout << rechtecktype(*this)<<endl;
}
contentscreentype::~contentscreentype()
{
  if(zahlen) 
    delete zahlen;
}

void contentscreentype::paint(einheit_client_zeigerelemtype *unit)
{
  if (calc_iconmap(unit))
    {
      killmenus();
      rechtecktype oldr=(*this);
      if (!anzz)
	sy=2;
      else
	{
	  // calculate new pushbuttons
	  strstreambuf buffer;
	  ostream o_order(&buffer);
	  istream i_order(&buffer);
	  o_order << "send vehicle "<<unit->einheitnummer<<" giveuntil ";
	  // Naeheste Einheit finden !!
	  einheit_client_zeigerelemtype *other=tudscreenptr->getnearestptr();
	  string first;
	  if (other)
	    {
	      o_order << other->einheitnummer<<" \n";
	      getline(i_order,first);
	      //	      cout << "First: "<<first<<endl;
	    }
	  /*	  else
	    {
	      	      cout << "contentscreen::paint():"
	      		   << "in the moment i have no contacts\n";
			   }      */
	  int32 akty=-my;
	  objekt_zeigerelemtype *oakt=unit->objekt_kette.anfang->next;
	  for (int no=0;no<anzz;no++)
	    {
	      objekt_datentype *aktobj=oakt->objekt_datenptr;
	      string second;
	      if (other)
		{
		  second=oakt->objekt_datenname;
		  second+=" ";
		}
	      int32 anz=zahlen[no];
	      if (anz)
		{
		  int32 left=-mx;
		  int32 aktx=left;
		  spritetype *sprptr=aktobj->spriteptr;
		  int32 nextline=sprptr->sy;
		  while (anz)
		    {
		      string third;
		      if (other)
			{
			  strstream ord3;
			  float abl=float(zahlen[no])-float(anz)*aktobj->unit;
			  if (abl<0) abl=0;
			  ord3 << abl;
			  ord3 >> third;
			  third=first+second+third;
			  //		  cout <<"Command is: \""<<third<<"\"\n";
			}
		      buttontype *newbutton=new buttontype(sprptr,third.c_str(),aktx+sprptr->mx,akty+sprptr->my);
		      addmenu(newbutton);
		      //		      cout << "Rechteck nach addmenu:"<<rechtecktype(*this)<<endl;
		      
		      aktx+=sprptr->sx;
		      if ((anz>1)&&(aktx+sprptr->sx>left+oldr.sx))
			{
			  akty+=nextline;
			  aktx=left;
			}
		      anz--;
		    }
		  // todo what happens if there is not eneough room for all tiles ?
		  akty+=nextline;
		}
	      oakt=oakt->next;
	    }
	}
      sx=oldr.sx;
      rechtecktype clip;
      if (oldr.sy<sy)
	// window enlarged
	clip=*this;
      else
	// window shrinked
	clip=oldr;
      paintparent(clip);
      //      parentspriteptr->malerechteck_clip(-mx,-my,sx,sy,32);
      parentspriteptr->map(clip);
      if ((unit)&&(unit->is_active()))
	unit->update_displays_depend_contents();
    }
}

bool contentscreentype::calc_iconmap(einheit_client_zeigerelemtype *unit)
{
  bool changed=false;
  int32 neuanz;
  if ((unit)&&(unit->getmode()==einheittype::detailed_mode))
    {
      neuanz=unit->objekt_kette.anzzeigerelem;
      einheit_client_zeigerelemtype *n=tudscreenptr->getnearestptr();
      if (oldother!=n)
	{
	  oldother=n;
	  changed=true;
	}
    }
  else
    neuanz=0;
  if (neuanz!=anzz)
    {
      if (zahlen)
	delete zahlen;
      anzz=neuanz;
      if (anzz)
	zahlen=new int[anzz];
      else
	zahlen=NULL;
      //      cout << "calc_iconmap:"<<anzz<<endl;
      changed=true;
    }
  if (anzz)
    {
      objekt_zeigerelemtype *akt=unit->objekt_kette.anfang->next;
      for (int no=0;no<anzz;no++)
	{
	  int32 anz=ftoi(akt->anzahl/akt->objekt_datenptr->unit);
	  if (!changed)
	    {
	      if (zahlen[no]!=anz)
		{
		  changed=true;
		  zahlen[no]=anz;
		}
	    }
	  else 
	    {
	      zahlen[no]=anz;
	    }
	  akt=akt->next;
	}
    }
  return changed;
}

// Scrollscreen **************************************************************************
// Scrollscreen **************************************************************************
// Scrollscreen **************************************************************************
// Scrollscreen **************************************************************************
// Scrollscreen **************************************************************************
// Scrollscreen **************************************************************************



int scrollscreentype::calc()
{
  // normally it should be painted here
  // but this is a special menu which must be calculated without input (every deltati seconds)
  return 0;
}
void scrollscreentype::paint() // see above
{
  // Naeheste Einheit finden !!
  tudscreenptr->newnearest(einheit_client_ketteptr->best_near(tudscreenptr->geteinheitptr()));

  transform.calc();
  // todo why did i do this ? perhaps i have to do a clear_box on parentsprite  clearsprite(1);
  int32 scrx,scry;
  transform.spr_to_scr(0,0,&scrx,&scry);
  landscapeptr->landspriteptr->copysprite_rotate_clip_to(scrx,scry,
							 transform.winkel(),transform.zoom(),
							 parentspriteptr,rechtecktype(*this),ftoi(deltati*1000));
  kette_calc(einheit_client_ketteptr);
  kette_calc(schuss_client_ketteptr);
  kette_calc(explosions_client_ketteptr);
  
  // todo in the moment much to slow
  if ((gameptr->maskmode==2)||((gameptr->maskmode==1)&&(gameptr->getavgti()<=gameptr->getwunschti()*1.4)))
    {
      calc_masksprite();
      paint_masksprite();
    }
  else
    {
      einheit_client_zeigerelemtype *akt=einheit_client_ketteptr->anfang->next;
      while (akt!=einheit_client_ketteptr->ende)
	{
	  if (akt->spielernummer==ichptr->spielernummer)
	    {
	      int32 scrx,scry;
	      transform.spr_to_scr(ftoi(akt->pos.x),ftoi(akt->pos.y),&scrx,&scry);
	      // todo need kreis_clip_to kreis_clip(scrx,scry,ftoi(akt->einheit_datenptr->sichtradius*transform.zoom()),allsprites_ketteptr->paletteptr->white());
	    }
	  akt=akt->next;
	}
    }
  if (painting)
    {
      //      cout <<"Painting scrollscreen\n";
      //      cout <<"Coords: "<<rechtecktype(*this)<<endl;
      parentspriteptr->map(rechtecktype(*this));
    }
}

void scrollscreentype::paintsprite(float x,float y,spritetype *sprite)
{
  int32 scrx,scry;
  transform.spr_to_scr(ftoi(x),ftoi(y),&scrx,&scry);
  sprite->copysprite_clip_to(scrx,scry,tudscreenptr,rechtecktype(*this));
}

int scrollscreentype::verarbeite_input(istream *ist)
{
  int x,y,button;
  if (verarbeite_mausclick_input(ist,&x,&y,&button))
    {
      cout << "scrollscreentype::verarbeite_event: Received illegal Event\n";
      // todo sollte vielleicht net unbedingt so sein
      delete ist;
      return 0;
    }	  
  int32 sprx,spry;
  transform.scr_to_spr((int32)x,(int32)y,&sprx,&spry);
  if (button==Button1)
    {
      // Einheit auswaehlen
      einheit_client_zeigerelemtype *akt=choose_tank(sprx,spry);
      if (akt)
	{
	  if (akt->spielernummer==ichptr->spielernummer)
	    *ausgabe <<"tank "<<akt->einheitnummer<<endl;
	  else if (akt->is_owner(ichptr->spielernummer))
	      // special select (I lent this unit to someone)
	      tudscreenptr->new_special_select(akt);
	}
      else
	{
	  *ausgabe <<"tank -1\n";
	}
    }
  else if (button==Button2)
    *ausgabe << "scroll "<<sprx<<" "<<spry<<endl;
  else if ((button==Button3))
    {
      // mouse klick with right button
      if (tudscreenptr->geteinheitnummer()!=-1)
	{
	  // a unit is selected
	  *ausgabe << "send vehicle "<<tudscreenptr->geteinheitnummer()<<" ";
	  einheit_client_zeigerelemtype *akt;
	  if ((akt=choose_tank(sprx,spry)))
	    {
	      // you clicked on a unit
	      if (akt->einheitnummer!=tudscreenptr->geteinheitnummer())
		{
		  // this was not the selected unit
		  if (!tudscreenptr->geteinheitptr()->friendship(akt))
		    {
		      // this is an enemy 
		      *ausgabe << "autoshotat "<<akt->einheitnummer<<" autoshot 1\n";
		      // Drive to X,Y
		      *ausgabe << "autodrive 1 autodriveto "<<sprx<<" "<<spry<<endl;
		    }
		  else 
		    {
		      *ausgabe << "autofollow "<<akt->einheitnummer<<endl;
		    }

		}
	      else
		{
		  // deactivate autopilots and stop
		  *ausgabe <<"autodrive 0 stop\n";
		}
	    }
	  else
	    {
	      // Drive to X,Y
	      *ausgabe << "autodrive 1 autodriveto "<<sprx<<" "<<spry<<endl;
	    }
	}
      else
	{
	  cout << "Sorry but you have to choose the vehicle that you wanna order.\n";
	}
    }
  else
    cout << "This Game uses only 3 Buttons !\n";
  return 0;
}

/* todo this function is totally useless (in the moment
void scrollscreentype::resize(int32 x,int32 y)
{
  cout << "scrollscreentype::resize\n";
  sprite_linear_nontransparent_screentype::resize(x,y);
  delete maskspriteptr;
  maskspriteptr=new sprite_linear_transparenttype(sx,sy,mx,my,255);
  calc_masksprite();
}
*/

void scrollscreentype::calc_masksprite()
{
  //  if (transform.transforming())

    {
      //      maskspriteptr->clearsprite(allsprites_ketteptr->paletteptr->black());
      // todo
      char black=allsprites_ketteptr->paletteptr->black();
	
      // Waagrechte Variante
      //      int32 y2=-my+sy;
      //      int32 x1=-mx;
      //      int32 x2=-mx+sx-1;
      //      char transcolor=maskspriteptr->transcolor;

      //	 senkrechte Variante !
	 uint32 transcolor=(uint8)maskspriteptr->transcolor;
	 uint32 farbe=(transcolor<<24)+(uint32(black)<<16)+(transcolor<<8)+uint32(black);
	 maskspriteptr->raster(farbe);
      
      /*
      // Geht weil 4fach !
      for (int32 akty=-my;akty<y2;akty+=2)
	{
	  maskspriteptr->hline(x1,x2,akty,black);
	  maskspriteptr->hline(x1,x2,akty+1,transcolor);
	}
	*/

      einheit_client_zeigerelemtype *akt=einheit_client_ketteptr->anfang->next;
      while (akt!=einheit_client_ketteptr->ende)
	{
	  if (akt->spielernummer==ichptr->spielernummer)
	    {
	      int32 scrx,scry;
	      transform.spr_to_scr(ftoi(akt->pos.x),ftoi(akt->pos.y),&scrx,&scry);
	      if (!maskspriteptr->kreis_flaeche_clip(scrx,scry,
						     ftoi(akt->einheit_datenptr->sichtradius*transform.zoom()),
						     maskspriteptr->transcolor))
		return;
	    }
	  akt=akt->next;
	}
    }
}

void scrollscreentype::paint_masksprite()
{
  /* Darkdown Variante !
     for (int32 akty=-my;akty<-my+sy;akty+=2)  
    for (int32 aktx=-mx;aktx<-mx+sx;aktx+=2)
      {
	if (maskspriteptr->getpixel(aktx,akty)!=maskspriteptr->transcolor)
	  darkdownpixel(aktx,akty);
      }*/
  maskspriteptr->copysprite_clip_to(0,0,parentspriteptr,rechtecktype(*this));
}

// Wählt einen Panzer aus
// gibt 0 zurueck wenn an der pos x y kein panzer ist ansonsten einen pointer auf die einheit!
einheit_client_zeigerelemtype *scrollscreentype::choose_tank(int32 x,int32 y)
{
  vektor2_koordtype click((float)x,(float)y);
  vektor2_koordtype abstand;
  float lastabstand=999999;
  einheit_client_zeigerelemtype *gefunden=NULL;
  einheit_client_zeigerelemtype *akt=einheit_client_ketteptr->anfang->next;
  while (akt!=einheit_client_ketteptr->ende)
    {
      abstand=click;
      abstand.sub(&(akt->pos));
      if ((abstand.betrag()<=akt->einheit_datenptr->einheitradius)&&(abstand.betrag()<lastabstand))
	{
	  if ((strcmp(akt->getheaderstring(),"firmatype"))||(!gefunden))
	    {
	      lastabstand=abstand.betrag();
	      gefunden=akt;
	    }
	  else
	    break;
	}
      akt=akt->next;
    }
  /*  if (gefunden)
    {
      cout <<"Typ der ausgewählten Einheit: "<<gefunden->getheaderstring()<<endl;
      return(gefunden);
    }*/
  return(gefunden);
}







/// The Tud Main Screen 

tudscreentype::tudscreentype(spieler_zeigerelemtype *_ichptr,int _x,int _y,int _sx,int _sy,
			     char *_palette=NULL,char *_scrname=NULL,char *_dpyname=NULL) 
  : sprite_linear_nontransparent_screentype(_x,_y,_sx,_sy,_sx/2-1,_sy/2-1,
					    _palette,_scrname,_dpyname) , selection_rect(374,202,79,52), special_rect(383,131,95,28)
{
  ichptr=_ichptr;
  special_select_menuptr=NULL;
  // This screen is divided into pieces
  // Load the menu configfile
  menuptr=new menutype();
  menuptr->set_parentspriteptr(this);
  iotype *ioptr=make_file_to_io_check("misc/screen.menu");
  menuptr->change(ioptr,CFG_TEXT_MODE);
  delete ioptr;
  
  // The scrollscreen is a submenu => add it to the menu
  scrollscreenptr=new scrollscreentype(ichptr,-18,271,360,360);
  //  cout <<"Nach init also noch in tudscreentype(...)\n";
  //  cout <<rechtecktype(*scrollscreenptr)<<endl;
  menuptr->addmenu(scrollscreenptr);

  // The Contentsscreen 
  contentscreenptr=new contentscreentype();
  menuptr->addmenu(contentscreenptr);

  spieler_menuptr=new menutype();
  menuptr->addmenu(spieler_menuptr);
  update_spielermenu();
    
  einheitptr=NULL;
  nearestptr=NULL;
  activeplayer=0;

  //todo this is verry ugly because global
  //::scrollscreenptr=scrollscreenptr;
  //cout <<"Nach init also noch in tudscreentype(...) aber die Globale variante\n";
  //cout <<rechtecktype(*(::scrollscreenptr))<<endl;
}
tudscreentype::~tudscreentype()
{
  // the scrollscreenptr is deleted by the menu ! delete scrollscreenptr;
  scrollscreenptr=NULL;
  contentscreenptr=NULL;
  delete menuptr;
}

int tudscreentype::calc()
{
  int erg=sprite_linear_nontransparent_screentype::calc();
  scrollscreenptr->paint();
  contentscreenptr->paint(einheitptr);
  if ((einheitptr)&&(einheitptr->getmode()==einheittype::detailed_mode))
    einheitptr->update_displays();
  return erg;
}

int tudscreentype::verarbeite_input(istream *ist)
{
  if (sprite_linear_nontransparent_screentype::verarbeite_input(ist))
    {
      menuptr->verarbeite_input(ist);
      char c;
      while (menuptr->get_output().get(c))
	ausgabe->put(c);
      menuptr->get_output().clear();
    }
  //else
  return 0;
}

void tudscreentype::update_spielermenu()
{
  spieler_menuptr->killmenus();
  spieler_menuptr->mx=-10;
  spieler_menuptr->sx=366;
  spieler_menuptr->my=-147;
  spieler_menuptr->sy=62;
  menuptr->calc(*spieler_menuptr);
  spieler_zeigerelemtype *akt=spieler_ketteptr->anfang->next;
  int32 aktx=-73;
  while(akt!=spieler_ketteptr->ende)
    {
      if (ichptr->compare(akt->spielernummer))
	{
	  // This is me
	  rechtecktype rect(-10,-147,39,40);
	  buttontype *newb=new buttontype(ichptr->flaggenname,"",rect);
	  spieler_menuptr->addmenu(newb);
	}
      else
	{
	  rechtecktype rect(aktx,-148,39,40);
	  string msg="selectplayer "+any_to_string(akt->spielernummer);
	  buttontype *newb=new buttontype(akt->flaggenname,msg.c_str(),rect);
	  spieler_menuptr->addmenu(newb);
	  string cmd="send relationship "+any_to_string(akt->spielernummer)+" ";
	  modified_pushbuttontype *newpb=new modified_pushbuttontype("misc/relation.menu",cmd.c_str(),-aktx+20,197);
	  int _index=0; //enemy
	  spieler_relation_zeigerelemtype *rel;
	  if (kette_search(&ichptr->spieler_relation_kette,akt->spielernummer,rel))
	    {
	      if (rel->relation==REL_FRIEND)
		_index=1;
	    }
	  newpb->setindex(_index);
	  spieler_menuptr->addmenu(newpb);
	  aktx-=53;
	}
      akt=akt->next;
    }
  menuptr->calc(*spieler_menuptr);
  menuptr->get_parentspriteptr()->map(*spieler_menuptr);
  //  cout << "tudscreentype::update_spielermenu(): updated\n";
}

void tudscreentype::neweinheit(int32 _einheitnummer)
{
  delete_special_select();
  einheit_client_zeigerelemtype *akt;
  if (einheitptr) 
    einheitptr->status_deactivate();
  //  cout << "tudscreentype::neweinheit: "<<_einheitnummer<<endl;
  *ausgabe<<"send select "<<_einheitnummer<<endl;
  menuptr->calc(selection_rect);      
  if ((kette_search(einheit_client_ketteptr,_einheitnummer,akt))&&(_einheitnummer!=-1))
    {
      einheitptr=akt;
      akt->paintto(tudscreenptr,selection_rect);
      einheitptr->status_activate(menuptr);
    }
  else
    {
      if (_einheitnummer!=-1)
	cerr << "tudscreentype:: WARNING: einheit "<<_einheitnummer<<" not found !\n";
      einheitptr=NULL;
    }
  ((sprite_lineartype *)tudscreenptr)->map(selection_rect);
}

void tudscreentype::new_special_select(einheit_client_zeigerelemtype *unit)
{
  neweinheit(-1);
  specialselect_einheitno=unit->einheitnummer;
  // paint unit
  unit->paintto(tudscreenptr,selection_rect);

  // insert takeback menu
  string no=any_to_string(unit->einheitnummer);
  string msg="tank -1 send vehicle "+no+" takeback\n tank "+no;
  special_select_menuptr=new buttontype("spr_src/takeback.spr",msg.c_str(),special_rect);
  menuptr->addmenu(special_select_menuptr);
  menuptr->calc(*special_select_menuptr);
  menuptr->get_parentspriteptr()->map(*special_select_menuptr);
  // paint player sprite  todo if you lend a unit it could be lend again should i always update this ?
  spieler_zeigerelemtype *akt;
  if (kette_search(spieler_ketteptr,unit->spielernummer,akt))
    {
      spritetype *spr=allsprites_ketteptr->make_elementadress(akt->flaggenname.c_str());
      spr->copysprite_maxpect_to(menuptr->get_parentspriteptr(),einheit_client_zeigerelemtype::actplayer_rect);
      menuptr->get_parentspriteptr()->map(einheit_client_zeigerelemtype::actplayer_rect);
    }
}

einheit_client_zeigerelemtype *tudscreentype::get_specialselect_einheitptr()
{
  einheit_client_zeigerelemtype *erg;
  if (kette_search(einheit_client_ketteptr,specialselect_einheitno,erg))
    return erg;
  return NULL;
}

void tudscreentype::delete_special_select()
{
  if (special_select_menuptr)
    {
      menuptr->killmenu(special_select_menuptr);
      special_select_menuptr=NULL;
      menuptr->get_parentspriteptr()->map(special_rect);
      // restore background of player window
      menuptr->calc(einheit_client_zeigerelemtype::actplayer_rect);
      menuptr->get_parentspriteptr()->map(einheit_client_zeigerelemtype::actplayer_rect);
    }
}

void tudscreentype::newnearest(einheit_client_zeigerelemtype *near)
{
  int32 nearnr=-1;
  if (near)
    nearnr=near->einheitnummer;
  if (nearnr!=getnearest())
    {
      rechtecktype r(100,265,79,53);
      menuptr->calc(r);      
      if (near)
	near->paintto(tudscreenptr,r);
      nearestptr=near;
      //      ((sprite_lineartype *)tudscreenptr)->malerechteck_clip(-r.mx,-r.my,r.sx,r.sy,32);
      ((sprite_lineartype *)tudscreenptr)->map(r);
    }
}

void tudscreentype::set_activeplayer(int32 pl)
{
  activeplayer=pl;
  if ((einheitptr)&&(einheitptr->is_active()))
    einheitptr->update_lend_give();
}

// Landscreen **********************************************************************
// Landscreen **********************************************************************
// Landscreen **********************************************************************
// Landscreen **********************************************************************
// Landscreen **********************************************************************

landscreentype::landscreentype
(int _x,int _y,int _sx,int _sy,char *_palette=NULL,char *_scrname=NULL,char *_dpyname=NULL) 
  : sprite_linear_nontransparent_screentype(_x,_y,_sx,_sy,_sx/2-1,_sy/2-1,
					    _palette,_scrname,_dpyname)
{
  zoom=2;
  winkel=M_PI_4;
  tx=cos(winkel);
  ty=sin(winkel); 
  calc_paint();
  paint();
}

void landscreentype::transform_to_land(int32 scrx,int32 scry,int32 &lx,int32 &ly)
{
  ly=int(float(scry)/ty*zoom);
  lx=int(float(scrx)*zoom)+int(tx*ly);
}

void landscreentype::transform_to_scr(int32 lx,int32 ly,int32 &scrx,int32 &scry)
{
  scrx=int(float(lx)/zoom)-int(tx*ly/zoom);
  scry=int(ty*float(ly)/zoom);
}


int landscreentype::verarbeite_input(istream *ist)
{
  if (sprite_linear_nontransparent_screentype::verarbeite_input(ist))
    {
      // Event übrig
      paint();
    }
  return 0;
}

void landscreentype::calc_paint()
{
  clearsprite(allsprites_ketteptr->paletteptr->black());
  spritetype *land=landscapeptr->landspriteptr;
  uint8 aktfarbe;
  int32 x1,y1,x2,y2;

  /* Kompletter screen !!  
  // OL => x1 und y1
  transform_to_land(-mx,-my,x1,y1);
  // UR=> x2 und y2
  transform_to_land(mx,my,x2,y2); */
  // UL => kleines x1
  transform_to_land(-mx,my,x1,y2);
  // OR => kleines x2
  transform_to_land(mx,-my,x2,y1);
  int32 dmid=(y2-y1)/2;
  y1+=dmid/4;
  y2-=dmid/4;
  cout <<"Land: "<<x1<<","<<y1<<","<<x2<<","<<y2<<endl;
  int32 x,y;
  int32 intzoom=ftoi(zoom);
  for (int32 akty=y1;akty<y2;akty+=intzoom)
    for (int32 aktx=x1;aktx<x2;aktx+=intzoom)
      {
	transform_to_scr(aktx,akty,x,y);
	if (!land->getpixel_clip(aktx,akty,(char *)&aktfarbe))
	  vline_clip(x,y,y-40+untergrundtabptr->tab[aktfarbe]*5,aktfarbe);
      }
}

void landscreentype::paint()  
{
  map();
}


// einheit_client_zeigerelemtype **************************************************
// einheit_client_zeigerelemtype **************************************************
// einheit_client_zeigerelemtype **************************************************
// einheit_client_zeigerelemtype **************************************************
// einheit_client_zeigerelemtype **************************************************
// einheit_client_zeigerelemtype **************************************************


einheit_client_zeigerelemtype *einheit_client_zeigerelemtype::create(iotype *ioptr,int8 mode)
{
  if (ioptr->getmode()!=IOTYPE_READ_MODE)
    fatalfehler("einheit_client_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_client_zeigerelemtype *neues=new panzer_client_zeigerelemtype();
      neues->change(ioptr,mode);
      return neues;
    }
  else if (!strcmp(_headerstring.c_str(),firmatype::headerstring))
    {
      firma_client_zeigerelemtype *neues=new firma_client_zeigerelemtype();
      neues->change(ioptr,mode);
      return neues;
    }
  fatalfehler("panzer_client_zeigerelemtype::create: Illegaler headerstring !");
  return(NULL); // spaeter 
}

void einheit_client_zeigerelemtype::calcsprite()
{
  if ((einheitdir+scrollscreenptr->transform.winkel()!=oldwinkel)||(oldzoom!=scrollscreenptr->transform.zoom())||(!oldsprite))
    {
      delete oldsprite;
      oldsprite=einheit_datenptr->spriteptr->rotate(einheitdir+scrollscreenptr->transform.winkel(),scrollscreenptr->transform.zoom());
      oldwinkel=einheitdir+scrollscreenptr->transform.winkel();
    }
  scrollscreenptr->paintsprite(pos.x,pos.y,oldsprite);
}

void einheit_client_zeigerelemtype::calcflag()
{
  // todo Total beschissen unbedingt schneller machen !!
  if (showflags)
    {
      spieler_zeigerelemtype *akt;
      if (kette_search(spieler_ketteptr,spielernummer,akt))
	{
	  spritetype *flaggen_spriteptr=
	    allsprites_ketteptr->make_elementadress(akt->flaggenname.c_str());
	  scrollscreenptr->paintsprite(pos.x,pos.y,flaggen_spriteptr);
	}
    }
}

int einheit_client_zeigerelemtype::calc()
{
  calcsprite();
  calcflag();
  objekt_kette.check();
  return 0;
}

void einheit_client_zeigerelemtype::update_displays()
{
  paint_substanz();
}

void einheit_client_zeigerelemtype::update_displays_depend_contents()
{
  paint_volume();
}

void einheit_client_zeigerelemtype::paint_substanz()
{
  if (box)
    box->setvalue(substanz/100.0);
}

void einheit_client_zeigerelemtype::paint_volume()
{
  if (volume_box)
    volume_box->setvalue(objekt_kette.volume()/einheit_datenptr->capacity);
}

void einheit_client_zeigerelemtype::paint_lendfrom()
{
  if (!lendlist.empty())
    {
      list<int32>::reverse_iterator pos;
      pos=lendlist.rbegin();
      int32 lendfrom=*pos;
      spieler_zeigerelemtype *akt;
      if (kette_search(spieler_ketteptr,lendfrom,akt))
	{
	  string msg="tank -1 send vehicle "+any_to_string(einheitnummer)+" giveback";
	  lendfrom_menuptr=new buttontype(akt->flaggenname,msg.c_str(),lendfrom_rect);
	  tud_menuptr->addmenu(lendfrom_menuptr);
	  tud_menuptr->calc(lendfrom_rect);
	  tud_menuptr->get_parentspriteptr()->map(lendfrom_rect);
	}
    }
}

void einheit_client_zeigerelemtype::update_lend_give()
{
  if (!lendto_menuptr)
    {
      rechtecktype rect(332,125,34,19);
      lendto_menuptr=new buttontype("","",rect);
      tud_menuptr->addmenu(lendto_menuptr);
    }
  if (!give_menuptr)
    {
      rechtecktype rect(373,125,34,19);
      give_menuptr=new buttontype("","",rect);
      tud_menuptr->addmenu(give_menuptr);
    }
  // restore background
  tud_menuptr->calc(actplayer_rect);
  // search act player
  spieler_zeigerelemtype *akt;
  string msg1,msg2;
  if (kette_search(spieler_ketteptr,tudscreenptr->get_activeplayer(),akt))
    {
      // paint sprite
      spritetype *spr=allsprites_ketteptr->make_elementadress(akt->flaggenname.c_str());
      spr->copysprite_maxpect_to(tud_menuptr->get_parentspriteptr(),actplayer_rect);
      tud_menuptr->get_parentspriteptr()->map(actplayer_rect);
      allsprites_ketteptr->delete_elementadress(spr);
      msg1="tank -1 send vehicle "+any_to_string(einheitnummer)+" lend "+any_to_string(tudscreenptr->get_activeplayer());
      msg2="tank -1 send vehicle "+any_to_string(einheitnummer)+" newowner "+any_to_string(tudscreenptr->get_activeplayer());
    }
  // set button msgs
  lendto_menuptr->set_msg(msg1);
  give_menuptr->set_msg(msg2);
}


void einheit_client_zeigerelemtype::status_activate(menutype *_tud_menuptr)
{
  if (active)
    fatalfehler("einheit_client_zeigerelemtype::status_activate: Allready active");
  active=true;
  tud_menuptr=_tud_menuptr;
  status_menuptr=new menutype();
  status_menuptr->mx=377;
  status_menuptr->my=-8;
  status_menuptr->sx=200;
  status_menuptr->sy=110;
  tud_menuptr->addmenu(status_menuptr);
  box=new bardiag_type(369,144,66,9,32,allsprites_ketteptr->paletteptr->black(),tudscreenptr);
  volume_box=new bardiag_type(274,31,128,9,32,allsprites_ketteptr->paletteptr->black(),tudscreenptr);
  paint_lendfrom();
  update_lend_give();
  update_displays_depend_contents();
}

void einheit_client_zeigerelemtype::status_deactivate()
{
  if (active)
    {
      rechtecktype olds=*((rechtecktype *)status_menuptr);
      tud_menuptr->killmenu(status_menuptr);
      status_menuptr=NULL;
      tud_menuptr->get_parentspriteptr()->map(olds);
      tud_menuptr->calc(*box);
      tud_menuptr->get_parentspriteptr()->map(*box);
      delete box;
      box=NULL;
      tud_menuptr->calc(*volume_box);
      tud_menuptr->get_parentspriteptr()->map(*volume_box);
      delete volume_box;
      volume_box=NULL;
      if (lendfrom_menuptr)
	{
	  tud_menuptr->killmenu(lendfrom_menuptr);
	  lendfrom_menuptr=NULL;
	  tud_menuptr->get_parentspriteptr()->map(lendfrom_rect);
	}
      if (lendto_menuptr)
	{
	  rechtecktype r(*lendto_menuptr);
	  tud_menuptr->killmenu(lendto_menuptr);
	  tud_menuptr->get_parentspriteptr()->map(r);
	  lendto_menuptr=NULL;
	}
      if (give_menuptr)
	{
	  rechtecktype r(*give_menuptr);
	  tud_menuptr->killmenu(give_menuptr);
	  tud_menuptr->get_parentspriteptr()->map(r);
	  give_menuptr=NULL;
	}
      tud_menuptr->calc(actplayer_rect);
      tud_menuptr->get_parentspriteptr()->map(actplayer_rect);
      active=false;
    }
}

void einheit_client_zeigerelemtype::paintto(sprite_lineartype *spr,const rechtecktype &rect)
{
  einheit_datenptr->paint_icon_to(spr,rect);
}

einheit_client_zeigerelemtype::einheit_client_zeigerelemtype() : lendfrom_rect(372,263,74,39)
{
  oldsprite=NULL;
  reloaded=1;
  status_menuptr=NULL;
  lendfrom_menuptr=NULL;
  lendto_menuptr=NULL;
  give_menuptr=NULL;
  box=NULL;
  active=false;
}

rechtecktype einheit_client_zeigerelemtype::actplayer_rect(373,100,74,49);

einheit_client_zeigerelemtype::~einheit_client_zeigerelemtype()
{
  //  cout << "~einheit_client_zeigerelemtype() aufgerufen\n";
  if (active)
    status_deactivate();
  delete oldsprite;
}













einheit_client_zeigerelemtype *einheit_client_kettetype::best_near
(einheit_client_zeigerelemtype *akt)
{
  if (!akt)
    return NULL;
  // todo soll die naeheste nicht die erste zurueckgeben !!
  einheit_client_zeigerelemtype *akt2=anfang->next;
  while (akt2!=ende)
    {
      if ((akt2!=akt)&&(akt->near(akt2)))
	  return akt2;
      akt2=akt2->next;
    }
  return NULL;
}







void einheit_client_kettetype::change(iotype *ioptr,int8 mode)
{
    if (ioptr->getmode()!=IOTYPE_READ_MODE)
      // SPEICHERN **************************************************************
      kette_changetype<einheit_client_zeigerelemtype>::change(ioptr,mode);
    else
      {
	//	cout << "einheit_client_kettetype::change\n";
	// LADEN ******************************************************************
	// kette initialisieren
	einheit_client_zeigerelemtype *akt=anfang->next;
	while (akt!=ende)
	  {
	    akt->reloaded=0;
	    akt=akt->next;
	  }

	// Elementanzahl changen !
	int32 toload;
	cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
	cfgptr->change_int32_check(&toload);
	delete cfgptr;
	while (toload)
	  {
	    // Erstmal neues erstellen, da ich bis jetzt nicht einfach einheitnummer laden kann
	    // todo muss natuerlich anders werden !
	    int32 oldseek=ioptr->getpos();
	    einheit_client_zeigerelemtype *neues=
	      einheit_client_zeigerelemtype::create(ioptr,mode);
	    if (kette_search(this,neues->einheitnummer,akt))
	      {
		// Reload, d.h. neu geladenes ueberfluessig => kick it
		delete neues;
		ioptr->seekset(oldseek);
		akt->change(ioptr,mode);
		akt->reloaded=1;
	      }
	    else
	      {
		// Noch nicht vorhanden
		//		cout << "Neues!\n";
		zeiger_insert_sorted(neues);
	      }
	    toload--;
	  }
	akt=anfang->next;
	while (akt!=ende)
	  {
	    if (!(akt->reloaded))
	      {
		// Element gibt es nichtmehr
		// todo evtl. besser 
		tudscreenptr->einheit_killed(akt->einheitnummer);
		del(akt);
	      }
	    akt=akt->next;
	  }
      }
}

void einheit_client_kettetype::zeiger_insert_sorted(einheit_client_zeigerelemtype *neue)
{
  if (!strcmp(firmatype::headerstring,neue->getheaderstring()))
    // Firmen zuletzt
    zeiger_push(neue);
  else
    zeiger_addafter(anfang,neue);
}



// Dynamische Firmendaten des Klienten ****************************************************
// Dynamische Firmendaten des Klienten ****************************************************
// Dynamische Firmendaten des Klienten ****************************************************

int firma_client_zeigerelemtype::einheit_in_firma()
{
  einheit_client_zeigerelemtype *laufzeiger
    = einheit_client_ketteptr->anfang->next;
  while(laufzeiger!=einheit_client_ketteptr->ende)
    {
      if (einheitnummer!=laufzeiger->einheitnummer)
	{
	  if (near(laufzeiger))
	    {
	      // Vektorcheck !! ??? soll ich richtig gucken ob in der firma ne einheit steht ?
	      return 1;
	    }	
	}
      laufzeiger=laufzeiger->next;
    }
  return 0;
}

int firma_client_zeigerelemtype::calc()
{
  int offen=einheit_in_firma();
  if ((einheitdir+scrollscreenptr->transform.winkel()!=oldwinkel)||(oldzoom!=scrollscreenptr->transform.zoom())||(!oldsprite)||(offen!=oldoffen))
    {
      delete oldsprite;
      if (offen)
	oldsprite=firma_datenptr->firma_offen_spriteptr->rotate(einheitdir+scrollscreenptr->transform.winkel(),scrollscreenptr->transform.zoom());
      else
	oldsprite=einheit_datenptr->spriteptr->rotate(einheitdir+scrollscreenptr->transform.winkel(),scrollscreenptr->transform.zoom());
      oldwinkel=einheitdir+scrollscreenptr->transform.winkel();
      oldoffen=offen;
    }
  scrollscreenptr->paintsprite(pos.x,pos.y,oldsprite);
  calcflag();
  return(0);
}


void firma_client_zeigerelemtype::update_displays()
{
  einheit_client_zeigerelemtype::update_displays();
  paint_build_icon();
  paint_buildbox();
}

void firma_client_zeigerelemtype::paint_buildbox()
{
  if (buildbox)
    if (building())
      {
	float t=time_tobuild();
	buildbox->setvalue((t-countdown)/t);
      }
    else
      buildbox->setvalue(0);
}

void firma_client_zeigerelemtype::paint_build_icon()
{
  if (tobuild!=oldtobuild)
    {
      if (typeof_tobuild=="object")
	status_product_datenptr=objekt_daten_ketteptr->make_elementadress(tobuild.c_str());
      else if (typeof_tobuild=="vehicle")
	status_product_datenptr=einheit_daten_ketteptr->make_elementadress(tobuild.c_str());
      else
	{
	  status_product_datenptr=NULL;
	  // todo 
	  return; 
	}
      tud_menuptr->calc(iconrect);
      status_product_datenptr->paint_icon_to(tudscreenptr,iconrect);
    }
}

void firma_client_zeigerelemtype::status_activate(menutype *_tud_menuptr)
{
  buildbox=new bardiag_type(298,-52,77,9,32,allsprites_ketteptr->paletteptr->black(),tudscreenptr);
  firma_menuptr=new menutype();
  firma_menuptr->mx=374;
  firma_menuptr->my=-95;
  firma_menuptr->sx=200;
  firma_menuptr->sy=110;
  _tud_menuptr->addmenu(firma_menuptr);
  einheit_client_zeigerelemtype::status_activate(_tud_menuptr);
}

void firma_client_zeigerelemtype::make_buildable_buttons()
{
  rechtecktype oldr=(*firma_menuptr);
  firma_menuptr->killmenus();
  // calculate new pushbuttons
  strstreambuf buffer;
  ostream o_order(&buffer);
  istream i_order(&buffer);
  o_order << "send vehicle "<<einheitnummer<<" build ";
  string first;
  getline(i_order,first);
  string second="object ";

  int32 akty=-firma_menuptr->my;
  int32 left=-firma_menuptr->mx;
  int32 aktx=left;
  rechtecktype rect(0,0,30,30);
  kettetype<string_zeigerelemtype> *buildable=akt_buildable_objekts();
  string_zeigerelemtype *akt=buildable->anfang->next;
  while (akt!=buildable->ende)
    {
      objekt_datentype *aktprdaten=objekt_daten_ketteptr->make_elementadress(akt->c_str());	  
      rect.mx=-aktx;
      rect.my=-akty;

      buttontype *newb=new buttontype(aktprdaten->spritename.c_str(),(first+second+akt->c_str()).c_str(),rect);
      firma_menuptr->addmenu(newb);
      objekt_daten_ketteptr->delete_elementadress(aktprdaten);
      aktx+=rect.sx;
      if (aktx+rect.sx>left+oldr.sx)
	{
	  akty+=rect.sy;
	  aktx=left;
	}
      akt=akt->next;
    }
  delete buildable;
  // todo the same with the vehicles
  second="vehicle ";
  buildable=akt_buildable_vehicles();
  aktx=left;
  akty+=50;
  akt=buildable->anfang->next;
  while (akt!=buildable->ende)
    {
      einheit_datentype *aktprdaten=einheit_daten_ketteptr->make_elementadress(akt->c_str());	  
      rect.mx=-aktx;
      rect.my=-akty;
      buttontype *newb=new buttontype(aktprdaten->spritename.c_str(),(first+second+akt->c_str()).c_str(),rect);
      firma_menuptr->addmenu(newb);
      einheit_daten_ketteptr->delete_elementadress(aktprdaten);
      aktx+=rect.sx;
      if (aktx+rect.sx>left+oldr.sx)
	{
	  akty+=rect.sy;
	  aktx=left;
	}
      akt=akt->next;
    }
  delete buildable;

  firma_menuptr->sx=oldr.sx;
  rechtecktype clip;
  if (oldr.sy<firma_menuptr->sy)
    // window enlarged
    clip=*firma_menuptr;
  else
    // window shrinked
    clip=oldr;
  firma_menuptr->paintparent(clip);
  //  firma_menuptr->parentspriteptr->malerechteck_clip(-mx,-my,sx,sy,32);
  firma_menuptr->get_parentspriteptr()->map(clip);
}

void firma_client_zeigerelemtype::status_deactivate()
{
  if (!active) return;
  einheit_client_zeigerelemtype::status_deactivate(); 
  //  cout <<"firma_client_zeigerelemtype::status_deactivate(): aufgerufen\n";

  rechtecktype olds=*((rechtecktype *)firma_menuptr);
  tud_menuptr->killmenu(firma_menuptr);
  firma_menuptr=NULL;
  tud_menuptr->get_parentspriteptr()->map(olds);

  
  tud_menuptr->calc(iconrect);
  ((sprite_lineartype *)tudscreenptr)->map(iconrect);

  tud_menuptr->calc(*buildbox);
  ((sprite_lineartype *)tudscreenptr)->map(*buildbox);
  delete buildbox;
  buildbox=NULL;
}
  

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

int canon_clienttype::calc()
{
  if ((einheitptr->einheitdir+relturmdir+scrollscreenptr->transform.winkel()!=roldwinkel)||(oldzoom!=scrollscreenptr->transform.zoom())||(!roldsprite))
    {
      delete roldsprite;
      roldsprite=canon_datenptr->turm_spriteptr->rotate(einheitptr->einheitdir+relturmdir+scrollscreenptr->transform.winkel(),scrollscreenptr->transform.zoom());
      roldwinkel=einheitptr->einheitdir+relturmdir+scrollscreenptr->transform.winkel();
      // Steht nicht ohne grund nur hier !!
      oldzoom=scrollscreenptr->transform.zoom();
    }
  // Ziemlich kacke spaeter besser machen ?
  vektor2_koordtype aktturmpos;
  calc_aktturmpos(aktturmpos);
  aktturmpos.add(&einheitptr->pos);
  scrollscreenptr->paintsprite(aktturmpos.x,aktturmpos.y,roldsprite);
  return 0;
}


// Dynamische Panzerdaten des Klienten  ****************************************************
// Dynamische Panzerdaten des Klienten  ****************************************************
// Dynamische Panzerdaten des Klienten  ****************************************************

panzer_client_zeigerelemtype::panzer_client_zeigerelemtype()
{
}

panzer_client_zeigerelemtype::~panzer_client_zeigerelemtype()
{
}

int panzer_client_zeigerelemtype::calc()
{
  einheit_client_zeigerelemtype::calcsprite();

  kette_calc(&canon_kette_client);
  oldzoom=scrollscreenptr->transform.zoom();

  einheit_client_zeigerelemtype::calcflag();

  return(0);
}

void panzer_client_zeigerelemtype::change(iotype *ioptr,int8 mode)
{
  panzertype::change(ioptr,mode);
  //  if (ioptr->getmode()==IOTYPE_READ_MODE)
    //    cout <<"panzer_clientzeigerelemtype::change: load called\n";
  //  cout <<"panzer_clientzeigerelemtype::change: panzer_datenptr->canon_daten_kette.anzzeigerelem="<<panzer_datenptr->canon_daten_kette.anzzeigerelem<<endl;
  canon_kette_client.change(ioptr,mode,&panzer_datenptr->canon_daten_kette,this);
}





// Schussobjekt (Client)   ****************************************************
// Schussobjekt (Client)   ****************************************************
// Schussobjekt (Client)   ****************************************************

int schuss_client_zeigerelemtype::calc()
{
  int32 scrx,scry;
  scrollscreenptr->transform.spr_to_scr(ftoi(pos.x),ftoi(pos.y),&scrx,&scry);
  // todo putpixel_clip_to needed and coords wrong
  tudscreenptr->putpixel_clip_to(scrx,scry,255,*scrollscreenptr);
  return(0);
}


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

explosions_client_zeigerelemtype::explosions_client_zeigerelemtype()
{
  sprite_movieptr=(sprite_movietype *)allsprites_ketteptr->make_elementadress("misc/expl.spr");
  if (strcmp(sprite_movieptr->getheaderstring(),sprite_movietype::headerstring))
    fatalfehler("explosions_client_zeigerelemtype:\n"
		"Das Sprite 'misc/expl.spr' muss ein sprite_movietype sein.");
  sprite_movieptr->repeat=0;
}

explosions_client_zeigerelemtype::~explosions_client_zeigerelemtype()
{
  allsprites_ketteptr->delete_elementadress(sprite_movieptr);
}

int explosions_client_zeigerelemtype::calc()
{
  int32 scrx,scry;
  scrollscreenptr->transform.spr_to_scr(ftoi(pos.x),ftoi(pos.y),&scrx,&scry);
  sprite_movieptr->copysprite_rotate_clip_to(scrx,scry,scrollscreenptr->transform.winkel(),scrollscreenptr->transform.zoom(),tudscreenptr,rechtecktype(*scrollscreenptr),ftoi(deltati*1000));
  return(sprite_movieptr->getloop());
}


void explosions_client_zeigerelemtype::change(iotype *ioptr,int8 mode)
{
  explosionstype::change(ioptr,mode);
  // Play sound
  if (soundptr) soundptr->play(sound.c_str());
}

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

void clientmsgtype::verarbeitemsg(char *msg,int32 laenge,int32 msgart)
{
  switch(msgart)
    {
    case DENY_SPIELERPLATZ_MSG:
      printf("Sorry diese Spielernummer ist schon vergeben !\n");
      break;
    case GIVE_SPIELERPLATZ_MSG:
      printf("O.K. Spielernummer bestaetigt !\n");
      break;
    case SEND_PANZER_KETTE_MSG:
      verarbeite_panzer_kette_msg(msg,laenge);
      break;
    case SEND_EXPLOSION_KETTE_MSG:
      verarbeite_explosion_kette_msg(msg,laenge);
      break;
    case SEND_SPIELER_KETTE_MSG:
      verarbeite_spieler_kette_msg(msg,laenge);
      break;
    case SEND_STREAM_MSG:
      verarbeite_stream_msg(msg,laenge);
      break;
    default:
      fatalfehler("clientmsgtype::verarbeitemsg:  Unbekannte MSG empfangen");
    }
}

inline void clientmsgtype::req_spieler_kette_msg()
{
  sendmsg(NULL,0,REQ_SPIELER_KETTE_MSG);
}

inline void clientmsgtype::req_panzer_kette_msg()
{
  sendmsg(NULL,0,REQ_PANZER_KETTE_MSG);
}

inline void clientmsgtype::req_panzer_kette_msg(int32 x1,int32 y1,int32 x2,int32 y2)
{
  iotype io;
  cfgtype *cfgptr=choose_cfgtype(&io,CFG_TEXT_MODE);
  cfgptr->write_int32(x1);
  cfgptr->write_int32(y1);
  cfgptr->write_int32(x2);
  cfgptr->write_int32(y2);
  delete cfgptr;
  sendmsg(io.get_buffer(),io.get_buffersize(),REQ_PANZER_KETTE_MSG);
}


void clientmsgtype::send_eventmask_msg(eventmasktype *eventmaskptr)
{
  iotype io;
  eventmaskptr->change(&io,CFG_BINAER_MODE);
  sendmsg(io.get_buffer(),io.get_buffersize(),SEND_EVENTMASK_MSG);
}

void clientmsgtype::send_eingabe_msg(int einheitnummer, eingabetype *eingabe)
{
  // Steuern der EInheit => sende eingabetype an server
  iotype *ioptr=new iotype;
  cfgtype *cfgptr=choose_cfgtype(ioptr,CFG_BINAER_MODE);
  cfgptr->change_int32_check(&einheitnummer);
  eingabe->change(ioptr,CFG_BINAER_MODE);
  sendmsg(ioptr->get_buffer(),ioptr->get_buffersize(),
		 SEND_EINGABE_MSG);
  delete ioptr;
}

void clientmsgtype::verarbeite_panzer_kette_msg(char *msg,int32 laenge)
{
    iotype io(msg,laenge);
    einheit_client_ketteptr->change(&io,CFG_BINAER_MODE);

    //    cout << "schuss_client_kette::change\n";
    schuss_client_ketteptr->change(&io,CFG_BINAER_MODE);
    reqcoords--;
}

void clientmsgtype::verarbeite_explosion_kette_msg(char *msg,int32 laenge)
{
    iotype io(msg,laenge);
    //    cout << "explosions_client_kette::change\n";
    explosions_client_ketteptr->merge(&io,CFG_BINAER_MODE);
}

void clientmsgtype::verarbeite_spieler_kette_msg(char *msg,int32 laenge)
{
  iotype io(msg,laenge);
  cout << "Received new playerlist ...\n";
  spieler_ketteptr->change(&io,CFG_TEXT_MODE);
  tudscreenptr->update_spielermenu();
}

void clientmsgtype::wait_ping_msg()
{
  char *buf;
  int32 len;
  int32 msgart;
  recvmsg(&buf,&len,&msgart,RECVMSG_UNENDLICH);
  if (msgart!=SEND_PING_MSG)
    fatalfehler("tudinc_client.C: clientmsgtype::wait_ping_msg(): Got wrong messagetype");
  sendmsg(NULL,0,SEND_PING_MSG);
  delete buf;
}

int32 clientmsgtype::wait_spieleranz_msg()
{
  char *buf;
  int32 len;
  int32 msgart;
  recvmsg(&buf,&len,&msgart,RECVMSG_UNENDLICH);
  if ((msgart!=SEND_SPIELERANZ_MSG)||(len!=sizeof(int32)))
    fatalfehler("tudinc_client.C: clientmsgtype::wait_spieleranz_msg(): Got wrong message");
  int32 spieleranz=*((int32 *)buf);
  delete buf;
  return spieleranz;
}

string clientmsgtype::wait_landsname_msg()
{
  int32 len;
  int32 msgart;
  char *msg;
  recvmsg(&msg,&len,&msgart,RECVMSG_UNENDLICH);
  if (msgart!=LANDSNAME_MSG)
    fatalfehler("tudinc_client.C: clientmsgtype::wait_landsname_msg():\n"
		"Got a wrong messagetype");
  iotype io(msg,len);
  cfgtype *cfgptr=choose_cfgtype(&io,CFG_BINAER_MODE);
  string landsname;
  cfgptr->read_string_check(&landsname);
  delete cfgptr;
  return landsname;
}

string clientmsgtype::wait_freespielerdatei_msg()
{
  int32 len;
  int32 msgart;
  char *username;
  recvmsg(&username,&len,&msgart,RECVMSG_UNENDLICH);
  if (msgart!=SEND_FREESPIELERDATEI_MSG)
    fatalfehler("tudinc_client.C: clientmsgtype::wait_freespielerdatei_msg():\n"
		"Got a wrong messagetype");
  string erg;
  if (len)
    {
      erg=username;
      delete username;
    }
  return erg;
}

int32 clientmsgtype::wait_freespielerplatz_msg()
{
  int32 len;
  int32 msgart;
  char *buf;
  recvmsg(&buf,&len,&msgart,RECVMSG_UNENDLICH);
  if (msgart!=SEND_FREESPIELERPLATZ_MSG)
    fatalfehler("tudinc_client.C: clientmsgtype::wait_freespielerplatz_msg():\n"
		"Got a wrong messagetype");

  if (!len)
    return 0;
  iotype io(buf,len);
  cfgtype *cfgptr=choose_cfgtype(&io,CFG_TEXT_MODE);
  int32 spno;
  cfgptr->read_int32_check(&spno);
  delete cfgptr;
  return spno;
}

/*
void clientmsgtype::wait_quit_msg()
{
  char *buf;
  int32 len;
  int32 msgart;
  do
    {
      recvmsg(&buf,&len,&msgart,RECVMSG_UNENDLICH);
      free(buf);
    }while(msgart!=);
}
*/

// The Game **********************************************************************
// The Game **********************************************************************
// The Game **********************************************************************
// The Game **********************************************************************
// The Game **********************************************************************
// The Game **********************************************************************
// The Game **********************************************************************

gametype::gametype(const string &server,string spielerfilename,const string &setupfilename)
{
  // Setup laden
  iotype *ioptr=make_file_to_io_check(setupfilename.c_str());
  cfgtype *cfgptr=choose_cfgtype(ioptr,CFG_TEXT_MODE);
  int32 scrollsx,scrollsy;
  cfgptr->change_int32_check(&scrollsx);
  cfgptr->change_int32_check(&scrollsy);
  cfgptr->change_int32_check(&maskmode);
  cfgptr->change_int32_check(&sound);
  cfgptr->change_marke_check("ende");
  delete cfgptr;
  delete ioptr;

  // Connect to soundserver if sound is on
  if (sound)
    {
      soundptr=new yyysound_client_noexception();
      if (soundptr->init("127.0.0.1"))
	soundptr->play("NSFREELA"); //.sample kann wegbleiben
      else
	{
	  cerr <<"Soundserver not found\n";
	  sound=0;
	  soundptr=NULL;
	}
    }
  else
    soundptr=NULL;

  // Verbindung erstellen
  verbindungstype verbindung;
  communication_client_connect(server.c_str(),4000,&verbindung);
  streamptr=new clientmsgtype(&verbindung);
  
  // Ping test !!!
  streamptr->wait_ping_msg();
  
  // Maximale Spieleranzahl anfordern 
  streamptr->req_spieleranz_msg();
  cout << "Maximum Players: "<<streamptr->wait_spieleranz_msg()<<endl;
  
  // Landschaftname anfordern !!
  streamptr->req_landsname_msg();
  string landsname=streamptr->wait_landsname_msg();
  cout << "Landscape is: "<<landsname<<endl;
  // Landschaft laden 
  // spaeter hier ueberpruefen ob richtige landschaft auf der Platte !
  landscapeptr=new landschafttype(landsname.c_str());
  
  if (!spielerfilename.empty())
    {
      streamptr->req_spielerdatei_msg(spielerfilename.c_str());
      string extended="users/";
      extended+=spielerfilename;
      extended+=".usr";
      spielerfilename=extended;
    }
  else
    {
      streamptr->req_freespielerdatei_msg();
      // sollte schauen ob die Dateien auf dem server und client gleich sind !!
      string name=streamptr->wait_freespielerdatei_msg();
      if (name!="")
	{
	  spielerfilename=name;
	  cout << "Server says: I should use: "<<spielerfilename<<endl;
	}
      else
	{
	  cout << "Server says: Sorry no free userfile\n";
	  prepare_exit();
	}
    }
  if (!spielerfilename.empty())
    ich.ladespieler(spielerfilename.c_str());
  
  // Spielernummer anfordern 
  streamptr->req_freespielerplatz_msg();
  int32 no=streamptr->wait_freespielerplatz_msg();
  if (no)
    {
      ich.spielernummer=no;
      cout <<"I am no. "<<no<<endl;
    }
  else
    {
      cout <<"Server says there is no free number left :-(\n";
      prepare_exit();
    }
  // screen init
  tudscreenptr=new tudscreentype(&ich,0,0,scrollsx,scrollsy,"palette.ppm","TUD");
  // paint everything
  tudscreenptr->paint_all();
  tudscreenptr->map();
  //  landscreenptr=new landscreentype(0,0,640,240,"palette.ppm","Landscape");
  //  landscreenptr->calc();
  // request playerlist 
  streamptr->req_spieler_kette_msg();
  
  // Coord requests sent - none  :-)
  reqcoords=0;

  
  // set Eventmask 
  eventmask.explosions=1;
  eventmask.playerlist=1;
  streamptr->send_eventmask_msg(&eventmask);
  
  minti=100;
  maxti=0;
  avgti=0;
  anztakte=0;
  wunschti=0.1;
  gettimeofday(&zeit,NULL);
  help();
  //statusscreenptr=new statusscreentype(ich.flaggenname.c_str(),0,0,"palette.ppm","Statusscreen");
  //spieler_kette_screenptr=new spieler_kette_screentype(ich.spielernummer,0,0,"palette.ppm","Spielerliste");
  //einheit_screenptr=new einheit_screentype(-1,0,0,"palette.ppm","Vehicle Status");
  //  show_my_player();
}

gametype::~gametype()
{
  cout <<"\nServer allowed me to go\n";
  // Disconnect soundserver
  delete soundptr;
  soundptr=NULL;
  delete streamptr;
  cout <<"Minimum  Deltati: "<<minti <<"       Maximum Deltati: "<<maxti<<"\n";
  cout <<"Average Deltati: "<<avgti  <<"       Number of Loops: "<<anztakte<<endl;
  delete tudscreenptr;
  //  delete landscreenptr;
  //delete statusscreenptr;
  //delete spieler_kette_screenptr;
  //delete einheit_screenptr;
  delete landscapeptr;
}


void gametype::help()
{
  cout << 
    "CLIENT COMMAND SET: WARNING THIS INFORMATION IS OUT OF DATE!\n"
    "Command      Arguments              Description\n"
    "====================================================================\n"
    "player       number(>0)             Choose Player Number\n"
    "tank         number(>=0)            Choose Tank Number\n"
    "send vehicle number(>=0) ..below..  Send orders to vehicle\n"
    "autoshot     0/1                    Toggle autoshot off/on\n"
    "autoshotat   number                 Shot at Tank Number\n"
    "shot         0/1                    Toggle Shot off/on\n"
    "autodrive    0/1/2/3                Set Autodrive mode\n"
    "autodriveto  x y                    Drive to X,Y\n"
    "autofollow   number                 Follow Tank Number\n"
    "autoaim      0/1                    Toggle autoaim off/on\n"
    "stop                                Stop vehicle.\n"
    //    "Keys are:                           q,a,w,s,o,p,9,0\n"
    "--------------------------------------------------------------------\n"
    "scroll       x y                    Scroll to X,Y\n"
    "zoom         x                      Zoom to scale x\n"
    "zoomin                              Zoom in (3/2)\n"
    "zoomout                             Zoom out (3/4)\n"
    "rotate       x                      Rotate to x (rad)\n"
    "turnleft                            Rotate left (45°)\n"
    "turnright                           Rotate right (45°)\n"
    "toggleflags  0/1                    Toggle flags off/on\n"
    "display      0/1                    Switch off/on painting\n"
    "sync         0/1                    Switch off/on XSync\n"
    "showti                              Show the Timeinterval\n"
    "showsleep                           Show the time available\n"
    "wantedti                            Set the wanted Timeinterval\n"
    "help                                This Message\n"
    "exit                                Exit  Game\n";
}


int gametype::verarbeite_befehl(istream &ist)
{
  string befehl;
  if (ist>>befehl)
    {
      if (befehl=="exit")
	prepare_exit();
      else if (befehl=="help")
	help();
      else if (befehl=="showti")
	cout <<"Deltati is: "<<deltati<<"\n";
      else if (befehl=="wantedti")
	ist >> wunschti;
      else if (befehl=="showsleep")
	cout <<"Available time: "<<timeavailable<<endl;
      else if (befehl=="player")
	{
	  /*		    cout << "Choose your Playernumber: "<<flush;
			    ist >> spielernummer;
			    streamptr->sendmsg((char *)(&spielernummer),
			    sizeof(spielernummer),
			    REQ_SPIELERPLATZ_MSG);*/
	  cout << "I am sorry but this doesn't work right now.\n";
	}
      else if (befehl=="toggleflags")
	ist >>showflags;
      else if (befehl=="display")
	ist >>scrollscreenptr->painting;
      else if (befehl=="sync")
	ist >>tudscreenptr->sync;
      else if (befehl=="zoom")
	{
	  float zoom_to;
	  ist >>zoom_to;
	  scrollscreenptr->transform.zoomto(zoom_to);
	}
      else if (befehl=="zoomin")
	scrollscreenptr->transform.zoomin();
      else if (befehl=="zoomout")
	scrollscreenptr->transform.zoomout();
      else if (befehl=="rotate")
	{
	  float winkel_to;
	  ist >> winkel_to;
	  scrollscreenptr->transform.rotate(winkel_to);
	}
      else if (befehl=="turnleft")
	scrollscreenptr->transform.turnleft();
      else if (befehl=="turnright")
	scrollscreenptr->transform.turnright();
      else if (befehl=="tank")
	{
	  int no;
	  ist >> no;
	  tudscreenptr->neweinheit(no);
	}
      else if (befehl=="scroll")
	{
	  int32 tx,ty;
	  ist >>tx>>ty;
	  scrollscreenptr->transform.scroll(tx,ty);
	  cout << "Scroll to: "<<tx<<"/"<<ty<<endl;
	}
      else if (befehl=="scrollup")
	{
	  scrollscreenptr->transform.scrollup();
	}
      else if (befehl=="scrolldown")
	{
	  scrollscreenptr->transform.scrolldown();
	}
      else if (befehl=="scrollleft")
	{
	  scrollscreenptr->transform.scrollleft();
	}
      else if (befehl=="scrollright")
	{
	  scrollscreenptr->transform.scrollright();
	}
      else if ((befehl=="scrolltoact")&&((tudscreenptr->geteinheitptr())||(tudscreenptr->special_selected())))
	{
	  einheit_client_zeigerelemtype *akt;
	  if (tudscreenptr->geteinheitptr())
	    akt=tudscreenptr->geteinheitptr();
	  else
	    akt=tudscreenptr->get_specialselect_einheitptr();
	  if (akt)
	    {
	      int x=ftoi(akt->pos.x);
	      int y=ftoi(akt->pos.y);
	      scrollscreenptr->transform.scroll(x,y);
	    }
	}
      else if ((befehl=="scrolltonearest")&&(tudscreenptr->getnearestptr()))
	{
	  einheit_client_zeigerelemtype *akt=tudscreenptr->getnearestptr();
	  int x=ftoi(akt->pos.x);
	  int y=ftoi(akt->pos.y);
	  scrollscreenptr->transform.scroll(x,y);
	}


      /*      else if (befehl=="q")
	eingabe.gas+=0.5;
      else if (befehl=="a")
	eingabe.gas-=0.5;
      else if (befehl=="w")
	eingabe.turmfahren+=0.5;
      else if (befehl=="s")
	eingabe.turmfahren-=0.5;
      else if (befehl=="o")
	eingabe.drehen--;
      else if (befehl=="p")
	eingabe.drehen++;
      else if (befehl=="9")
	eingabe.turmdrehen--;
      else if (befehl=="0")
	eingabe.turmdrehen++;
      else if (befehl=="8")
	eingabe.turmfahren++;
      else if (befehl=="i")
	eingabe.turmfahren--;*/
      else if (befehl=="send")
	{
	  string tosend;
	  if (getline(ist,tosend))
	    {
	      streamptr->send_stream_msg(tosend+"\n");
	      cout <<"Sent following command to server:\n\""<<tosend<<"\""<<endl;
	    }
	  else
	    cerr <<"gametype::verarbeite_befehl(): Uncomplete server command\n";
	}
      else if (befehl=="selectplayer")
	{
	  int32 pl;
	  if (ist>>pl)
	    tudscreenptr->set_activeplayer(pl);
	}
      else
	cout<<"Unknown Command :\""<<befehl<<"\" -> type 'help'\n";
      //      eingabe.checkbereich();
      //      streamptr->send_eingabe_msg(scrollscreenptr->einheitnummer,&eingabe);
      if (ist)
	return 1;
    }
  //  else
  ist.clear();
  //  cerr <<"gametype::verarbeite_befehl(): wrong input => clear ist\n";
  return 0;

}


int gametype::calc()
{
  oldzeit=zeit;
  gettimeofday(&zeit,NULL);
  deltati=getdeltatime(&oldzeit,&zeit);
  if (deltati<wunschti)
    {
      timeavailable=wunschti-deltati;
      usleep( (ulong)(timeavailable*1000000) );
      
      // ANDERE VARIANTE :
      // Warten abbrechen wenn vom server eine msg kommt !
      /*		    timeval timeout;
			    timeout.tv_sec=0;
			    timeout.tv_usec=(ulong)((wunschti-deltati)*1000000);
			    streamptr->msgavail(&timeout);*/
      gettimeofday(&zeit,NULL);
      deltati=getdeltatime(&oldzeit,&zeit);
    }
  else
    timeavailable=0;
  
  if (!deltati)
    {
      cout <<"Deltati is 0 !!!\n";
      deltati=0.000001;
    }
  if (deltati<minti)
    minti=deltati;
  if (deltati>maxti)
    maxti=deltati;
  // todo is bad ...
  avgti*=anztakte;
  anztakte+=1.0;
  avgti+=deltati;
  avgti/=anztakte;

  // Kommunikation
  ende=streamptr->calc();

  // Scrollscreen aufbauen 
  tudscreenptr->calc();
  //  landscreenptr->calc();
  //statusscreenptr->calc();
  //spieler_kette_screenptr->calc();
  //einheit_screenptr->calc();
  
  //  istrstream *ist=
  while (verarbeite_befehl(tudscreenptr->get_output()));
  //  delete ist;
 
  //  ist=
  //while (verarbeite_befehl(statusscreenptr->get_output()));
  //  delete ist;

  //while (verarbeite_befehl(spieler_kette_screenptr->get_output()));
  //while (verarbeite_befehl(einheit_screenptr->get_output()));


  while (kbhit())
    verarbeite_befehl(cin);
  
  // Neue Koordinaten nur anfordern wenn noch hoechstens x stueck kommt (<x+1)
  if (reqcoords<2)
    {
      // todo darf nicht jedesmal sein !!
      if (scrollscreenptr->transform.transforming())
	{
	  calc_new_rechteck();
	  streamptr->req_panzer_kette_msg(x1,y1,x2,y2);
	}
      else
	streamptr->req_panzer_kette_msg();
      reqcoords++;
    }
  return ende;
}


void gametype::prepare_exit()
{
  tudscreenptr->neweinheit(-1);
  streamptr->sendquitmsg();
  // spaeter net so !!
  cout <<"\nClosing Game. Ask Server to quit  ........ \n";
}

void gametype::calc_new_rechteck()
{
  // todo kann man auch besser machen evtl. auch im Zusammenhang mit sprites !!!
  int32 x,y;
  // OL
  scrollscreenptr->transform.scr_to_spr(-scrollscreenptr->mx,-scrollscreenptr->my,&x,&y);
  x1=x;
  x2=x;
  y1=y;
  y2=y;
  //UR
  scrollscreenptr->transform.scr_to_spr(-scrollscreenptr->mx+(scrollscreenptr->sx)-1,
		       -scrollscreenptr->my+(scrollscreenptr->sy)-1,&x,&y);
  if (x<x1) x1=x;
  if (x>x2) x2=x;
  if (y<y1) y1=y;
  if (y>y2) y2=y;
  // todo :-)
  if (scrollscreenptr->transform.winkel()==0.0)
    return;
  //OR
  scrollscreenptr->transform.scr_to_spr(-scrollscreenptr->mx+(scrollscreenptr->sx)-1,-scrollscreenptr->my,&x,&y);
  if (x<x1) x1=x;
  if (x>x2) x2=x;
  if (y<y1) y1=y;
  if (y>y2) y2=y;
  //UL
  scrollscreenptr->transform.scr_to_spr(-scrollscreenptr->mx,-scrollscreenptr->my+(scrollscreenptr->sy)-1,&x,&y);
  if (x<x1) x1=x;
  if (x>x2) x2=x;
  if (y<y1) y1=y;
  if (y>y2) y2=y;
}










