//////////////////////////////////////
// Metro sim beta 2 v0.1
// metro_beta.cpp
// (C) 2005 Vigovsky Mikhail
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <windows.h>
#include <commctrl.h>
#include <time.h>
#include "OpenGL.h"
#include "world.h"
#include "input.h"
#include "common.h"
#include "object.h"
#include "sound.h"
#include "path.h"
#define xc (ply->x)
#define yc (ply->y)
#define zc (ply->z)
#define xi (ply->vx)
#define yi (ply->vy)
#define zi (ply->vz)
#define xr (ply->rx)
#define yr (ply->ry)
#define MAXSPD 8
#define ACCEL 0.2
#define vlen 50
#define rs 4
dword path1,path2,ord,pss;
WORLD *wrld;
dword annsym,yansym,pragsym;
void CreateRailway(PATH *path)
{ PATH rail1,rail2;
  ZeroMemory(&rail1,sizeof(rail1));
  ZeroMemory(&rail2,sizeof(rail2));
  rail1.x=path->x+sin(path->delta)*rs;rail1.y=path->y+cos(path->delta)*rs;rail1.delta=path->delta;
  rail1.copypath(path,0,path->p.size(),1, rs);
  rail2.x=path->x-sin(path->delta)*rs;rail2.y=path->y-cos(path->delta)*rs;rail2.delta=path->delta;
  rail2.copypath(path,0,path->p.size(),1,-rs);
  wrld->CreateInstance(BuildPath(wrld,rail1,-0.25,1,20,0,0),0,0,0,0,0,0);
  wrld->CreateInstance(BuildPath(wrld,rail2,-0.25,1,20,0,0),0,0,0,0,0,0);
}
void CreatePaths()
{ dword sym;
  dword int1,int2;
  PATH *p=(PATH*)wrld->GetSymbol(path1=wrld->AddSymbol(PATH_ID));
  p->x=40;p->y=-1600;p->delta=-90*deg;  //starting point
  DPPOINT end; 
//path curves
  p->line(900,0);//0
  p->line(400,0);//1
  p->line(400,0);//2
  end=TrackP(p,p->length(),0);
  wrld->CreateInstance(annsym,end.x+(sin(end.delta)*40),end.y+(cos(end.delta)*40),0,0,0,-end.delta/deg+90);//Annino station
  p->line(400,0);//3
  p->line(2000,0);//4
  p->line(400,1.0/12800);//5
  p->line(500,-1.0/9600);//6
  p->line(800,0);//7
  p->line(400,0);//8
  end=TrackP(p,p->length(),0);
  wrld->CreateInstance(yansym,end.x+(sin(end.delta)*40),end.y+(cos(end.delta)*40),0,0,0,-end.delta/deg+90);//Yangel station
  p->line(400,0);//9
  p->line(800,0);//10
  p->line(800,-1.0/7200);//11
  p->line(1400,1.0/7200);//12
  p->line((PI/3)*160,-1.0/690.0/2/10);
  p->line((PI/3)*160, 1.0/690.0/2/10);
  p->line(1000,0);//15
  p->line(400,0);//16
  end=TrackP(p,p->length(),0);
  wrld->CreateInstance(pragsym,end.x+(sin(end.delta)*36),end.y+(cos(end.delta)*36),5,0,0,-end.delta/deg+90);//Prashskaya station
  p->line(400,0);//17
  p->line(400,0);//18
  p->line(900,0);//19
  CreateRailway(p);
  end=TrackP(p,90,0); 
  PATH *p2=(PATH*)wrld->GetSymbol(path2=wrld->AddSymbol(PATH_ID));
  p2->x=-40;p2->y=-1600;p2->delta=-90*deg;
  p2->copypath(p,0,13,1,40);
  p2->line((PI/3)*160, 1.0/690.0/2/10);
  p2->line((PI/3)*160,-1.0/690.0/2/10);
  p2->copypath(p,15,20,1,40);
  CreateRailway(p2);
  //Build interchanges
  PATH *n1=(PATH*)wrld->GetSymbol(int1=wrld->AddSymbol(PATH_ID));
  end=TrackP(p,p->length()-1200,0);n1->x=end.x;n1->y=end.y;n1->delta=end.delta;
  n1->line((PI/3)*160,-1.0/770.0);
  n1->line((PI/3)*160, 1.0/770.0);
  CreateRailway(n1);
  ///////
  PATH *n2=(PATH*)wrld->GetSymbol(int2=wrld->AddSymbol(PATH_ID));
  end=TrackP(p2,1200,0);n2->x=end.x;n2->y=end.y;n2->delta=end.delta+PI;
  n2->line((PI/3)*160,-1.0/690.0);
  n2->line((PI/3)*160, 1.0/690.0);
  CreateRailway(n2);

  pss = wrld->AddSymbol(PATHSYS_ID);
  p=(PATH*)wrld->GetSymbol(path1);
  PATHSYS_COMMON *pc = (PATHSYS_COMMON*)wrld->GetSymbol(pss);
  pc->pathc.resize(4);
  pc->pathc[0].pathid=path1;
  pc->pathc[1].pathid=path2;
  pc->pathc[2].pathid=int1;
  pc->pathc[3].pathid=int2;
// Create switches
  pc->CreateSwitch(0,p->length()-1200,2,0,0);//Prazhskaya switch1
  pc->CreateSwitch(1,1200,3,0,1);//Annino switch1
  DPPOINT end2=TrackP(p2,p2->length(),0);end=TrackP(n1,n1->length(),0);
  end2.x=(end2.x-end.x)*cos(end2.delta)-(end2.y-end.y)*sin(end2.delta);
  pc->CreateSwitch(2,n1->length(),1,p2->length()-end2.x,0);//Prazhskaya switch2
  end2=TrackP(p,0,0);end=TrackP(n2,n2->length(),0);
  end2.x=(end.x-end2.x)*cos(end2.delta)-(end.y-end2.y)*sin(end2.delta);
  pc->CreateSwitch(3,n2->length(),0,end2.x,1);//Annino switch2
  ORDERS_COMMON *or = (ORDERS_COMMON*)wrld->GetSymbol(ord=wrld->AddSymbol(VEHORDER_ID));
  // train orders
  or->orderstage(0.1,10,p->length(0,2)-50,0,0,p->length(0,2)+50+(vlen/2));//0,1,2 
  or->order(0,150,0);                                                 //3
  or->orderstage(0.1,10,p->length(2,8),0,0,p->length(0,8)+50+(vlen/2));   //4,5,6
  or->order(0,150,0);                                                 //7
  or->orderstage(0.1,10,p->length(8,16),0,0,p->length(0,16)+50+(vlen/2)); //8,9,10
  or->order(0,150,0);                                                   //11
  or->orderstage(0.15,10,800+170+(PI/3)*160*2,1,1,p2->length()-800+(vlen/2));//12,13,14
  or->order(0,10,0);                                                    //15
  or->orderstage(-0.1,10,p->length(0,2)-50,0,1,p2->length(0,16)+50-(vlen/2));//16,17,18
  or->order(0,150,0);                                                    //19
  or->orderstage(-0.1,10,p2->length(9,17),0,1,p2->length(0,8)+50-(vlen/2));  //20,21,22
  or->order(0,150,0);                                                    //23
  or->orderstage(-0.1,10,p2->length(3,9),0,1,p2->length(0,2)+50-(vlen/2));   //24,25,26
  or->order(0,150,0);                                                    //27
  or->orderstage(-0.15,10,800+170+(PI/3)*140*2,1,0,100-(vlen/2));             //28,29,30
  or->order(0,10,0);                                                     //10
}
dword vagsym;
void CreateTrain(dword path,double pos,dword ord2,word ordpos)
{ dword vagi[8];
  dword vagv[8];
  VEHICLE *veh;
  for(byte v=0;v<8;v++)
  { vagi[v]=wrld->CreateInstance(vagsym,0,0,0,0,0,0);
    veh = (VEHICLE*)wrld->GetObj(vagv[v]=wrld->AddObject(VEHICLE_ID));
    veh->len=vlen;
    veh->z=15;
    veh->Move(path,v*100+pos);
    veh->pathsys=pss;
    veh->obj=vagi[v];
    if (v)
    {    veh->vehlink=vagv[v-1];veh->linkpos=100;
    } else
    { PATH *p=(PATH*)wrld->GetSymbol(path1);
      veh->orders=ord;
      veh->ord=ord2;veh->ordp=ordpos;
    }
    veh->Control();
    wrld->ResetObj(vagi[v]);
  }
}
void ControlWinMsg()
{ PeekMessage(&msg, 0, 0, 0, PM_REMOVE);
  TranslateMessage(&msg);
  DispatchMessage(&msg);
}
double xri,yri,spd;
PLAYER *ply;
void ControlKeys()
{ GetKeyboardState();
  if (KeyPressed(DIK_LSHIFT)||KeyPressed(DIK_RSHIFT)){spd*=10;}
  if (KeyPressed(DIK_LCONTROL)||KeyPressed(DIK_RCONTROL)){spd/=10;}
  if (KeyPressed( DIK_LEFTARROW)||KeyPressed(DIK_A)){xi-=yri*spd;yi+=xri*spd;}
  if (KeyPressed(DIK_RIGHTARROW)||KeyPressed(DIK_D)){xi+=yri*spd;yi-=xri*spd;}
  if (KeyPressed(   DIK_UPARROW)||KeyPressed(DIK_W)){xi+=xri*spd;yi+=yri*spd;}
  if (KeyPressed( DIK_DOWNARROW)||KeyPressed(DIK_S)){xi-=xri*spd;yi-=yri*spd;}
  if (KeyPressed(DIK_Q)){zi=spd;}
  if (KeyPressed(DIK_Z)){zi-=spd;}
  if (KeyPressed(DIK_X)){xc=0;yc=0;zc=6;ply->xo=0;ply->yo=0;ply->zo=6;xi=0;yi=0;zi=0;}
  if (KeyPressed(DIK_ESCAPE)){DestroyWindow(Window);}
}
void ControlMouse()
{ GetMouseState();
  xr += x;yr = y;
  while (xr<-180) xr += 360;while (xr> 180) xr -= 360;
}
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{ Instance = hInstance;
  wrld =new WORLD;ZeroMemory(wrld,sizeof(wrld));
  InitGL(4.0/3.0,0.1,1000);
  ShowWindow(Window,SW_SHOW);
  UpdateWindow(Window);
  ShowCursor(0);//hide mouse cursor
  InitDInput(hInstance);
  vagsym = wrld->ImportObject("vag.vmd");// load models
  annsym = wrld->ImportObject("m.annino.vmd");
  yansym = wrld->ImportObject("m.yangel.vmd");
  pragsym = wrld->ImportObject("m.prag.vmd");
  CreatePaths();
  {PATH *p=(PATH*)wrld->GetSymbol(path1);PATH *p2=(PATH*)wrld->GetSymbol(path2);
  // we have 6 trains on map
   CreateTrain(0,p->length(0,2)+50,3,0);
   CreateTrain(0,p->length(0,8)+50,7,0);
   CreateTrain(0,p->length(0,16)+50,11,0);
   CreateTrain(1,p2->length(0,16)+50,19,0);
   CreateTrain(1,p2->length(0,8)+50,23,0);
   CreateTrain(1,p2->length(0,2)+50,27,0);
  }
  ply = (PLAYER*)wrld->Objects[wrld->AddObject(PLAYER_ID)].data;
  xc=0;ply->xo=0;xi=0;xr=0; // player's starting position
  yc=0;ply->yo=0;yi=0;
  zc=20;ply->zo=20;zi=0;
  dword t1,t2=GetTickCount(),ti=0,Interval=40;//Setup clock. Game tick interval - 40ms
  while (Window) // main loop
  { ControlWinMsg();
    t1 = t2;
    t2 = GetTickCount();
    ti += t2-t1;   
    if (ti<Interval){if(MsgWaitForMultipleObjects(0,0,0,Interval-ti,QS_ALLEVENTS)!=WAIT_TIMEOUT)continue;t1=t2;t2 = GetTickCount();ti += t2-t1;}
    for (;ti>=Interval;ti-=Interval) // game ticks loop
    { xri=sin(xr*deg);yri=cos(xr*deg);
      spd=0.4;
      ControlKeys();
      wrld->Control();//process world
      ControlMouse();
	  }
    ply->RenderViewport();
  }
  return 0;
}