#include "Graphics.h"
#include "swis.h"
#include <kernel.h>
#include "Sound.h"

extern int tick;
extern int lasttick;
extern int screen;

extern _kernel_swi_regs inreg;
extern _kernel_swi_regs outreg;

#define TILESX 10
#define TILESY 10
#define SMARTTILES 200
#define AREAS 20

#define MAXEVENTS 200
#define MAXEVENTACTIONS 1000

// map[0] is the 'master', [1] and [2] represents what is currently
// believed to be displayed in the corresponding (+1) screen buffer
// and we run a compare to see if re-drawing is needed. 0xFF is used
// for a re-draw being required (so it's set on the tile under the player)
// _overlay is used for the second layer on of tiles (optional)
unsigned char map[3][TILESX][TILESY];
unsigned char map_overlay[3][TILESX][TILESY];

unsigned char fullmap[10000*2];

unsigned char areaname[13];

char textbuffer[63];

struct EntityLocation_s {
  short signed int X,Y;
};

struct Area_s {
  unsigned char name[16];
};

struct Area_s Areas[AREAS];

#define DIRECTION_NONE 0
#define DIRECTION_N 0
#define DIRECTION_E 1
#define DIRECTION_S 2
#define DIRECTION_W 3

struct TilePlayer_s {
  struct EntityLocation_s location;
  struct EntityLocation_s lastlocation;
  struct EntityLocation_s hitbox_bl;
  struct EntityLocation_s hitbox_tr;
  struct EntityLocation_s drawbox_bl;
  struct EntityLocation_s drawbox_tr;
  struct EntityLocation_s mapoffset;
  struct EntityLocation_s lastmapoffset;
  struct EntityLocation_s localtile;
  int rawtile;
  int lastrawtile;

  unsigned char direction;
  unsigned char facedirection;
  unsigned char sprite[13];
  unsigned char basesprite[13];
  unsigned char animframe;
  int nextanimframe;
  int nextanimidle;
};

struct TilePlayer_s TilePlayer;

/* VVV deprecated VVV */
struct SmartTile_s {
  int Tile;
  int ActionTarget;
  unsigned char Action;
  unsigned char ActionValue;
};
struct SmartTile_s SmartTiles[SMARTTILES];
/* ^^^ deprecated ^^^ */


struct EventAction_s {
  int Event;
  unsigned char Action;         //0=change tile     / 1=change area    / 2=sound     / 3=rearm    / 4=schedule
  unsigned char ActionValue;    //tile sprite no.   / area ID          / sound ID    / na         / eventid
  int ActionTarget;             //tile ID           / n/a              / channel ID  / eventid    / ticks
};
struct EventAction_s EventActions[MAXEVENTACTIONS];

struct Event_s {
  unsigned char Name[16];
  unsigned char Triggered;
  int RearmDelay;
  int NextRearm;
};
struct Event_s Events[MAXEVENTS];

struct ScheduledEvent_s {
  int Event;
  int Ticks;
};
struct ScheduledEvent_s ScheduledEvents[MAXEVENTS];


void game2_saveevents(char* filename)
{
  // Attempt to get file info
  inreg.r[0] = 10;
  inreg.r[1] = (int) filename;
  inreg.r[2] = 0xffd;
  inreg.r[4] = (int) Events;
  inreg.r[5] = (int) Events + (sizeof(Events));

  _kernel_swi(OS_File,&inreg,&outreg);
}
void game2_saveeventactions(char* filename)
{
  // Attempt to get file info
  inreg.r[0] = 10;
  inreg.r[1] = (int) filename;
  inreg.r[2] = 0xffd;
  inreg.r[4] = (int) EventActions;
  inreg.r[5] = (int) EventActions + (sizeof(EventActions));

  _kernel_swi(OS_File,&inreg,&outreg);
}

void game2_loadevents(char* filename)
{
  int length;
  int i;
  
  // Populate with inactive entries
  for(i = 0; i<MAXEVENTS; i++)
  {
    // Default to Triggered with no re-arm so event never fires
    sprintf(Events[i].Name,"INVALID");
    Events[i].Triggered = 1;
    Events[i].RearmDelay = -1;
    Events[i].NextRearm = -1;

    // We can populate these here as we use MAXEVENTS for both
    ScheduledEvents[i].Event = -1;
    ScheduledEvents[i].Ticks = -1;
  }

  // Attempt to get file info
  inreg.r[0] = 5;
  inreg.r[1] = (int) filename;
  _kernel_swi(OS_File,&inreg,&outreg);

  // Length will be in R4 if it exists
  length = outreg.r[4];

  if(length > sizeof(Events))
  {
    screen_nobuffer();
    while (1)
      printf("Events exceeds %d bytes (%d bytes) object type is %d\n",sizeof(Events),length,outreg.r[0]);
  }

  // Attempt to get file info
  inreg.r[0] = 16;
  inreg.r[1] = (int) filename;
  inreg.r[2] = (int) Events;
  inreg.r[3] = 0;

  _kernel_swi(OS_File,&inreg,&outreg);
}

void game2_loadeventactionss(char* filename)
{
  int length;
  int i;

  // Populate with inactive entries
  for(i = 0; i<MAXEVENTACTIONS; i++)
  {
    EventActions[i].Event = -1;
    EventActions[i].Action = -1;
    EventActions[i].ActionValue = -1;
    EventActions[i].ActionTarget = -1;
  }

  // Attempt to get file info
  inreg.r[0] = 5;
  inreg.r[1] = (int) filename;
  _kernel_swi(OS_File,&inreg,&outreg);

  // Length will be in R4 if it exists
  length = outreg.r[4];

  if(length > sizeof(EventActions))
  {
    screen_nobuffer();
    while (1)
      printf("EventActions exceeds %d bytes (%d bytes) object type is %d\n",sizeof(EventActions),length,outreg.r[0]);
  }

  // Attempt to get file info
  inreg.r[0] = 16;
  inreg.r[1] = (int) filename;
  inreg.r[2] = (int) EventActions;
  inreg.r[3] = 0;

  _kernel_swi(OS_File,&inreg,&outreg);
}

void game2_loadsmarttiles(char* filename)
{
  int length;

  // Attempt to get file info
  inreg.r[0] = 5;
  inreg.r[1] = (int) filename;
  _kernel_swi(OS_File,&inreg,&outreg);

  // Length will be in R4 if it exists
  length = outreg.r[4];

  if(length > sizeof(SmartTiles))
  {
    screen_nobuffer();
    while (1)
      printf("Smarttiles exceeds %d bytes (%d bytes) object type is %d\n",sizeof(SmartTiles),length,outreg.r[0]);
  }

  // Attempt to get file info
  inreg.r[0] = 16;
  inreg.r[1] = (int) filename;
  inreg.r[2] = (int) SmartTiles;
  inreg.r[3] = 0;

  _kernel_swi(OS_File,&inreg,&outreg);
}

void game2_loadareanames(char* filename)
{
  int length;

  // Attempt to get file info
  inreg.r[0] = 5;
  inreg.r[1] = (int) filename;
  _kernel_swi(OS_File,&inreg,&outreg);

  // Length will be in R4 if it exists
  length = outreg.r[4];

  if(length > sizeof(Areas))
  {
    screen_nobuffer();
    while (1)
      printf("Areas exceeds %d bytes (%d bytes) object type is %d\n",sizeof(Areas),length,outreg.r[0]);
  }

  // Attempt to get file info
  inreg.r[0] = 16;
  inreg.r[1] = (int) filename;
  inreg.r[2] = (int) Areas;
  inreg.r[3] = 0;

  _kernel_swi(OS_File,&inreg,&outreg);
}

void game2_loadmap(char* filename)
{
  int length,i;

  // Attempt to get file info
  inreg.r[0] = 5;
  inreg.r[1] = (int) filename;
  _kernel_swi(OS_File,&inreg,&outreg);

  // Length will be in R4 if it exists
  length = outreg.r[4];

  if(length > sizeof(fullmap))
  {
    screen_nobuffer();
    while(1)
      printf("Map exceeds %d bytes (%d bytes) object type is %d\n",sizeof(fullmap),length,outreg.r[0]);
  }

  // Attempt to get file info
  inreg.r[0] = 16;
  inreg.r[1] = (int) filename;
  inreg.r[2] = (int) fullmap;
  inreg.r[3] = 0;

  _kernel_swi(OS_File,&inreg,&outreg);

  for(i = 0; i < SMARTTILES; i++)
    SmartTiles[i].Tile = -1;
}

void game2_death()
{
  int currentstart = 0;
  int introframe = 0;

  sound_set_voice(1,"WaveSynth-Beep");
  sound_set_voice(2,"WaveSynth-Beep");
  sound_set_voice(3,"WaveSynth-Beep");
  sound_set_voice(4,"WaveSynth-Beep");
  sound_composition_init();

  sound_composition_load("music.cmpagrac");

  tick = clock();

  sound_composition_start(clock());

  draw_sprite("spacebar",(DISPLAY_X/2)-106,50);
  draw_sprite("kia",(DISPLAY_X/2)-300,500);

  screen_flipbuffer();

  while(sound_composition_incomplete())
  {
    sound_composition_tick(clock());

    if(clock() > (tick + 100))
    {
      if(input_readkey(98))
        sound_composition_stop();
    }
  }
}

void game2_briefing()
{
  screen_clear();

  draw_spritetext(
"~~~~~~~~{ chief engineers log - uss archimedes - stardate 1234567890 ==}\n\n\ndo stuff on the ship. not sure what yet. go for a wander. \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n~~~~~~~~{======================~~~~~~~~===========================}"
, 50, 950);

  draw_sprite("spacebar",(DISPLAY_X/2)-106,50);

  screen_flipbuffer();

  tick = clock();
  while(1)
  {
    if(clock() > (tick + 100))
    {
      if(input_readkey(98))
        return;
    }
  }
}

void game2_fillmap(int xoffset, int yoffset)
{
  memcpy(map[0][0],fullmap+yoffset+(xoffset*100),10);
  memcpy(map[0][1],fullmap+yoffset+(xoffset*100)+100,10);
  memcpy(map[0][2],fullmap+yoffset+(xoffset*100)+200,10);
  memcpy(map[0][3],fullmap+yoffset+(xoffset*100)+300,10);
  memcpy(map[0][4],fullmap+yoffset+(xoffset*100)+400,10);
  memcpy(map[0][5],fullmap+yoffset+(xoffset*100)+500,10);
  memcpy(map[0][6],fullmap+yoffset+(xoffset*100)+600,10);
  memcpy(map[0][7],fullmap+yoffset+(xoffset*100)+700,10);
  memcpy(map[0][8],fullmap+yoffset+(xoffset*100)+800,10);
  memcpy(map[0][9],fullmap+yoffset+(xoffset*100)+900,10);

  memcpy(map_overlay[0][0],fullmap+yoffset+(xoffset*100)+10000,10);
  memcpy(map_overlay[0][1],fullmap+yoffset+(xoffset*100)+100+10000,10);
  memcpy(map_overlay[0][2],fullmap+yoffset+(xoffset*100)+200+10000,10);
  memcpy(map_overlay[0][3],fullmap+yoffset+(xoffset*100)+300+10000,10);
  memcpy(map_overlay[0][4],fullmap+yoffset+(xoffset*100)+400+10000,10);
  memcpy(map_overlay[0][5],fullmap+yoffset+(xoffset*100)+500+10000,10);
  memcpy(map_overlay[0][6],fullmap+yoffset+(xoffset*100)+600+10000,10);
  memcpy(map_overlay[0][7],fullmap+yoffset+(xoffset*100)+700+10000,10);
  memcpy(map_overlay[0][8],fullmap+yoffset+(xoffset*100)+800+10000,10);
  memcpy(map_overlay[0][9],fullmap+yoffset+(xoffset*100)+900+10000,10);
}

void game2_setup_audio()
{
  sound_pcm_loadsample(PCMSAMPLE_HAIL,"sounds.commbdg");
  sound_pcm_loadsample(PCMSAMPLE_DOOR,"sounds.door");
  sound_pcm_loadsample(PCMSAMPLE_ALERT,"sounds.alert");
  sound_pcm_loadsample(PCMSAMPLE_TRACTOREND,"sounds.tracend");
}

void game2_setup()
{
  screen_flipbuffer();
  screen_clear();
  screen_flipbuffer();
  screen_clear();

  TilePlayer.location.X = 102;
  TilePlayer.location.Y = 102;
  
  TilePlayer.hitbox_bl.X = 10;
  TilePlayer.hitbox_bl.Y = 10;
  TilePlayer.hitbox_tr.X = 70;
  TilePlayer.hitbox_tr.Y = 70;

  TilePlayer.drawbox_bl.X = 0;
  TilePlayer.drawbox_bl.Y = 0;
  TilePlayer.drawbox_tr.X = 80;
  TilePlayer.drawbox_tr.Y = 80;

  TilePlayer.direction = DIRECTION_NONE;
  TilePlayer.facedirection = 1;
  TilePlayer.animframe = 0;
  TilePlayer.nextanimframe = 0;
  TilePlayer.nextanimidle = 0;
  TilePlayer.lastrawtile = -1;
  memset(map[0],0xFF,100);
  memset(map[1],0xFF,100);
  memset(map[2],0xFF,100);

  game2_loadmap("m2_map");
  game2_loadsmarttiles("m2_smart");
  game2_loadareanames("m2_areas");
  game2_setup_audio();
  game2_loadevents("m2_evt");
  game2_loadeventactionss("m2_evact");
  game2_fillmap(TilePlayer.mapoffset.X,TilePlayer.mapoffset.Y);
}

int game2_check_collide()
{
  int x,y,hit;

  hit = 0;

  for(x = 0; x < TILESX; x++)
  {
    for(y = 0; y < TILESY; y++)
    {
      // Finds any tile we collide with
      if(game_hitbox_collide(
      (TilePlayer.location.X + TilePlayer.hitbox_bl.X),(TilePlayer.location.Y + TilePlayer.hitbox_bl.Y),
      (TilePlayer.hitbox_tr.X - TilePlayer.hitbox_bl.X),(TilePlayer.hitbox_tr.Y - TilePlayer.hitbox_bl.Y),
      x*100,y*100,
      100,100
      ))
      {
        if(((map[0][x][y] >> 7)  & 0x01))
        {
          hit = 1;
        }
      }
    }
  }

  return hit;
}

void game2_tick_input()
{
  int movex = 0;
  int movey = 0;

  TilePlayer.direction = 0;

  if(input_readkey(57)) // UP
    TilePlayer.direction |= 1 << DIRECTION_N;
  if(input_readkey(41)) // DOWN
    TilePlayer.direction |= 1 << DIRECTION_S;
  if(input_readkey(121)) // RIGHT
    TilePlayer.direction |= 1 << DIRECTION_E;
  if(input_readkey(25))   // LEFT
    TilePlayer.direction |= 1 << DIRECTION_W;

  // If Up & Down then cancel both
  if((TilePlayer.direction & (1 << DIRECTION_N)) && (TilePlayer.direction & (1 << DIRECTION_S)))
    TilePlayer.direction -= 5;
  // If Left & Right then cancel both
  if((TilePlayer.direction & (1 << DIRECTION_E)) && (TilePlayer.direction & (1 << DIRECTION_W)))
    TilePlayer.direction -= 10;

  // If N
  if(TilePlayer.direction & (1 << DIRECTION_N))
    movey += 3;
  // If S
  if(TilePlayer.direction & (1 << DIRECTION_S))
    movey -= 3;
  // If W
  if(TilePlayer.direction & (1 << DIRECTION_W))
    movex -= 3;
  // If E
  if(TilePlayer.direction & (1 << DIRECTION_E))
    movex += 3;

  // Handle diagonals by reducing to sin(45) * 3 (conveniently about 2)
  if((movex == 3) && (movey == 3)) // NE
  {
    movex = 2;
    movey = 2;
  }else if((movex == 3) && (movey == -3)) // SW
  {
    movex = 2;
    movey = -2;
  }else if((movex == -3) && (movey == 3)) // NW
  {
    movex = -2;
    movey = 3;
  }else if((movex == -3) && (movey == -3)) // SE
  {
    movex = -2;
    movey = -2;
  }

  // Store the last movement so we know where to face an idle player
  if(TilePlayer.direction > 0)
  {
    TilePlayer.facedirection = TilePlayer.direction;
    if(tick > TilePlayer.nextanimframe)
    {
      TilePlayer.animframe++;
      TilePlayer.nextanimframe = tick + 10;
      TilePlayer.nextanimidle = tick + 20;
    }
    if(TilePlayer.animframe > 3)
      TilePlayer.animframe = 0;
  }else{
    if(tick > TilePlayer.nextanimidle)
      TilePlayer.animframe = 0;
  }

  // Store in case we have a vertical collide
  TilePlayer.lastlocation.X = TilePlayer.location.X;
  TilePlayer.lastlocation.Y = TilePlayer.location.Y;
  TilePlayer.lastmapoffset.X = TilePlayer.mapoffset.X;
  TilePlayer.lastmapoffset.Y = TilePlayer.mapoffset.Y;

  if(movey > 0)
  {
    TilePlayer.location.Y += movey * (tick - lasttick);
    if(TilePlayer.location.Y > (910))
    {
      TilePlayer.location.Y = 100;
      TilePlayer.mapoffset.Y += 10;
      game2_fillmap(TilePlayer.mapoffset.X,TilePlayer.mapoffset.Y);
    }
  }
  else if(movey < 0)
  {
    TilePlayer.location.Y += movey * (tick - lasttick);
   if(TilePlayer.location.Y < (10))
    {
      if(TilePlayer.mapoffset.Y > 0)
      {
        TilePlayer.location.Y = 900;
        TilePlayer.mapoffset.Y -= 10;
        game2_fillmap(TilePlayer.mapoffset.X,TilePlayer.mapoffset.Y);
      }else{
        TilePlayer.location.Y = TilePlayer.lastlocation.Y;
      }
    }
  }

  if(game2_check_collide())
  {
    TilePlayer.location.X = TilePlayer.lastlocation.X;
    TilePlayer.location.Y = TilePlayer.lastlocation.Y;
    TilePlayer.mapoffset.X = TilePlayer.lastmapoffset.X;
    TilePlayer.mapoffset.Y = TilePlayer.lastmapoffset.Y;
  }

  // Store in case we have a horizontal collide
  TilePlayer.lastlocation.X = TilePlayer.location.X;
  TilePlayer.lastlocation.Y = TilePlayer.location.Y;

  if(movex > 0)
  {
    TilePlayer.location.X += movex * (tick - lasttick);
    if(TilePlayer.location.X > (910))
    {
      TilePlayer.location.X = 100;
      TilePlayer.mapoffset.X += 10;
      game2_fillmap(TilePlayer.mapoffset.X,TilePlayer.mapoffset.Y);
    }
  }
  else if(movex < 0)
  {
    TilePlayer.location.X += movex * (tick - lasttick);
    if(TilePlayer.location.X < (10))
    {
      if(TilePlayer.mapoffset.X > 0)
      {
        TilePlayer.location.X = 900;
        TilePlayer.mapoffset.X -= 10;
        game2_fillmap(TilePlayer.mapoffset.X,TilePlayer.mapoffset.Y);
      }else{
        TilePlayer.location.X = TilePlayer.lastlocation.X;
      }
    }
  }

  if(game2_check_collide())
  {
    TilePlayer.location.X = TilePlayer.lastlocation.X;
    TilePlayer.location.Y = TilePlayer.lastlocation.Y;
  }
}

int game2_newevent()
{
  int i;
  int freeid = -1;
  
  for(i = 0; i<MAXEVENTS; i++)
  {
    if(ScheduledEvents[i].Event < 0)
    {
      freeid = i;
      i = MAXEVENTS;
    }
  }

  if(freeid < 0)
  {
    while(1)
    printf("No free slots in event scheduler!\n");
  }

  return freeid;
}

void game2_triggerevent(int id)
{
  int i;

  // Re-arm if appropriate
  if(Events[id].NextRearm > 0)
  {
    if(tick > Events[id].NextRearm)
    {
      Events[id].Triggered = 0;
      Events[id].NextRearm = -1;
    }
  }

  // Don't trigger if we've been fired and not reset
  if(Events[id].Triggered == 1)
    return;

  // Record firing
  Events[id].Triggered = 1;

  // Schedule re-arm if required
  if(Events[id].RearmDelay >= 0)
    Events[id].NextRearm = tick + Events[id].RearmDelay;

  // Go through our actions
  for(i = 0; i<MAXEVENTACTIONS; i++)
  {
    if(EventActions[i].Event == id)
    {
      if(EventActions[i].Action == 0)         // Change tile sprite
        fullmap[EventActions[i].ActionTarget] = EventActions[i].ActionValue;
      else if(EventActions[i].Action == 1)    // Change area name
        sprintf(areaname,"%s",Areas[EventActions[i].ActionValue].name);
      else if(EventActions[i].Action == 2)    // Play sound
        sound_pcm_playsample_ifidle(EventActions[i].ActionTarget,EventActions[i].ActionValue);
      else if(EventActions[i].Action == 3)    // Re-arm
        Events[EventActions[i].ActionTarget].Triggered = 0;
      else if(EventActions[i].Action == 4)    // Schedule Event
      {
        int scheduleid = game2_newevent();
        ScheduledEvents[scheduleid].Event = EventActions[i].ActionValue;
        ScheduledEvents[scheduleid].Ticks = tick + EventActions[i].ActionTarget;
      }
      else if(EventActions[i].Action == 5)         // Change overlay tile sprite
        fullmap[EventActions[i].ActionTarget + 10000] = EventActions[i].ActionValue;
    }
  }
}

void game2_triggerscheduledevents()
{
  int i;
  for(i = 0; i<MAXEVENTS; i++)
  {
    if(ScheduledEvents[i].Event > 0)
    {
      if(tick > ScheduledEvents[i].Ticks)
      {
        // Trigger the event
        game2_triggerevent(ScheduledEvents[i].Event);

        // Clear it
        ScheduledEvents[i].Event = -1;
        ScheduledEvents[i].Ticks = -1;
      }
    }
  }
}

int game2_tick()
{
  int x;
  int y;
  int i;
  char flipv = 0;
  char fliph = 0;

  lasttick = tick;
  tick = clock();

  screen_flipbuffer();

  if(1)
  {
    // Fill the map0 with our chunk of the full map
    game2_fillmap(TilePlayer.mapoffset.X,TilePlayer.mapoffset.Y);
    
    draw_spritetext("#############", 1020, 950);
    draw_spritetext(areaname, 1020, 950);
 
    for(x = 0; x < TILESX; x++)
    {
      for(y = 0; y < TILESY; y++)
      {
        // Finds any tile we collide with
        if(game_hitbox_collide(
        (TilePlayer.location.X + TilePlayer.drawbox_bl.X),(TilePlayer.location.Y + TilePlayer.drawbox_bl.Y),
        (TilePlayer.hitbox_tr.X - TilePlayer.drawbox_bl.X),(TilePlayer.drawbox_tr.Y - TilePlayer.drawbox_bl.Y),
        x*100,y*100,
        100,100
        ))
        {
          map[1][x][y] = 255;
          map[2][x][y] = 255;
        }

        // Find the tile under our centre of mass
        if(game_hitbox_collide(
        (TilePlayer.location.X +  TilePlayer.hitbox_bl.X + (TilePlayer.hitbox_tr.X/2)),(TilePlayer.location.Y + TilePlayer.hitbox_bl.Y + (TilePlayer.hitbox_tr.Y/2)),
        (1),(1),
        x*100,y*100,
        100,100
        ))
        {
          TilePlayer.localtile.X = x;
          TilePlayer.localtile.Y = y;
        }

        // Redraw any tiles we're overlapping
        if((map[0][x][y] ^ map[screen+1][x][y]) || (map_overlay[0][x][y] ^ map_overlay[screen+1][x][y]))
        {
          map[screen+1][x][y] = map[0][x][y];
          if(map[screen+1][x][y] < 128)
            draw_tile(map[screen+1][x][y],x*100,y*100);
          else
            draw_tile((map[screen+1][x][y]-128),x*100,y*100);

          map_overlay[screen+1][x][y] = map_overlay[0][x][y];
          if(map_overlay[screen+1][x][y] > 0)
          {
            draw_tile_trans(map_overlay[screen+1][x][y],x*100,y*100);
          }
        }
      }
    }

    TilePlayer.lastrawtile = TilePlayer.rawtile;
    TilePlayer.rawtile = (TilePlayer.mapoffset.Y) + TilePlayer.localtile.Y + (TilePlayer.mapoffset.X * 100) + (TilePlayer.localtile.X * 100);

    if(TilePlayer.rawtile != TilePlayer.lastrawtile)
    {
      // Trigger any smart tiles for our centre of mass
      for(i = 0; i < SMARTTILES; i++)
      {
        if(SmartTiles[i].Tile == TilePlayer.rawtile)
        {
          if(SmartTiles[i].Action == 2)    // Trigger event
            game2_triggerevent(SmartTiles[i].ActionValue);
        }
      }
    }

  game2_triggerscheduledevents();

  game2_tick_input();

  if((TilePlayer.facedirection & (1 << DIRECTION_N)) && (TilePlayer.facedirection & (1 << DIRECTION_E)))        //NE
  {
    fliph = 1;
    sprintf(TilePlayer.basesprite, "man_se");
  }else if((TilePlayer.facedirection & (1 << DIRECTION_S)) && (TilePlayer.facedirection & (1 << DIRECTION_E)))   // SE
  {
    sprintf(TilePlayer.basesprite, "man_se");
  }else if((TilePlayer.facedirection & (1 << DIRECTION_S)) && (TilePlayer.facedirection & (1 << DIRECTION_W)))   // SW
  {
    flipv = 1;
    sprintf(TilePlayer.basesprite, "man_se");
  }else if((TilePlayer.facedirection & (1 << DIRECTION_N)) && (TilePlayer.facedirection & (1 << DIRECTION_W)))   // NW
  {
    flipv = 1;
    fliph = 1;
    sprintf(TilePlayer.basesprite, "man_se");
  }else if(TilePlayer.facedirection & (1 << DIRECTION_N))                                                    // N
  {
    fliph = 1;
    sprintf(TilePlayer.basesprite, "man_s");
  }else if(TilePlayer.facedirection & (1 << DIRECTION_S))                                                    // S
  {
    sprintf(TilePlayer.basesprite, "man_s");
  }else if(TilePlayer.facedirection & (1 << DIRECTION_E))                                                    // E
  {
    sprintf(TilePlayer.basesprite, "man_e");
  }else if(TilePlayer.facedirection & (1 << DIRECTION_W))                                                    // W
  {
    flipv = 1;
    sprintf(TilePlayer.basesprite, "man_e");
  }

  if(TilePlayer.animframe == 0)
    sprintf(TilePlayer.sprite, "%s",TilePlayer.basesprite);
  if(TilePlayer.animframe == 1)
    sprintf(TilePlayer.sprite, "%s_l",TilePlayer.basesprite);
  if(TilePlayer.animframe == 2)
    sprintf(TilePlayer.sprite, "%s",TilePlayer.basesprite);
  if(TilePlayer.animframe == 3)
  {
    // Use 'right' for diagonals, otherwise we flip
    if(strlen(TilePlayer.basesprite) > 5)
    {
      sprintf(TilePlayer.sprite, "%s_r",TilePlayer.basesprite);
    }
    else
    {
      if((TilePlayer.facedirection & (1 << DIRECTION_N)) || (TilePlayer.facedirection & (1 << DIRECTION_S)))
        flipv = 1;
      if((TilePlayer.facedirection & (1 << DIRECTION_E)) || (TilePlayer.facedirection & (1 << DIRECTION_W)))
        fliph = 1;
      sprintf(TilePlayer.sprite, "%s_l",TilePlayer.basesprite);
    }
  }

  if(fliph && flipv)
    draw_sprite_flippedhv(TilePlayer.sprite,TilePlayer.location.X,TilePlayer.location.Y);
  else if(fliph)
    draw_sprite_flippedh(TilePlayer.sprite,TilePlayer.location.X,TilePlayer.location.Y);
  else if(flipv)
    draw_sprite_flippedv(TilePlayer.sprite,TilePlayer.location.X,TilePlayer.location.Y);
  else
    draw_sprite(TilePlayer.sprite,TilePlayer.location.X,TilePlayer.location.Y);

#ifdef M2_DEBUG_HITBOXES
    draw_rectangle(
    (TilePlayer.location.X + TilePlayer.hitbox_bl.X),
    (TilePlayer.location.Y + TilePlayer.hitbox_bl.Y),
    (TilePlayer.location.X + TilePlayer.hitbox_tr.X),
    (TilePlayer.location.Y + TilePlayer.hitbox_tr.Y)
    );
    draw_rectangle(
    (TilePlayer.location.X + TilePlayer.drawbox_bl.X),
    (TilePlayer.location.Y + TilePlayer.drawbox_bl.Y),
    (TilePlayer.location.X + TilePlayer.drawbox_tr.X),
    (TilePlayer.location.Y + TilePlayer.drawbox_tr.Y)
    );
#endif
    return 0;
  }else{
/*    screen_flipbuffer();
    screen_clear();
    game2_death();
    return 1;*/
  }
}
