
#include "eruta.h"
#include "sprite.h"
#include "spritelayout.h"

/* Custom and built-in sprite layouts and loading them. */


/* Layout info of the ULPCSS sprites. */
static int ulpcss_sprites_per_row[] = {
  7, 7, 7, 7,  
  8, 8, 8, 8,  
  9, 9, 9, 9,  
  6, 6, 6, 6,  
  13, 13, 13, 13,  
  6
};

/* Type info of the ULPCSS sprites. */
static int ulpcss_row_type[] = {
  SPRITE_CAST , SPRITE_CAST , SPRITE_CAST , SPRITE_CAST ,
  SPRITE_STAB , SPRITE_STAB , SPRITE_STAB , SPRITE_STAB ,
  SPRITE_WALK , SPRITE_WALK , SPRITE_WALK , SPRITE_WALK ,
  SPRITE_SLASH, SPRITE_SLASH, SPRITE_SLASH, SPRITE_SLASH,
  SPRITE_SHOOT, SPRITE_SHOOT, SPRITE_SHOOT, SPRITE_SHOOT,
  SPRITE_DOWN
};

/* Direction info of the ULPCSS sprites. */
static int ulpcss_row_direction[] = {
  SPRITE_NORTH , SPRITE_WEST , SPRITE_SOUTH, SPRITE_EAST,
  SPRITE_NORTH , SPRITE_WEST , SPRITE_SOUTH, SPRITE_EAST,
  SPRITE_NORTH , SPRITE_WEST , SPRITE_SOUTH, SPRITE_EAST,
  SPRITE_NORTH , SPRITE_WEST , SPRITE_SOUTH, SPRITE_EAST,
  SPRITE_NORTH , SPRITE_WEST , SPRITE_SOUTH, SPRITE_EAST,
  SPRITE_ALL
};

/* Frame duration info of ULPCSS sprites. */
static double ulpcss_row_duration[] = {
  0.1 , 0.1 , 0.1 , 0.1 ,
  0.07, 0.07, 0.07, 0.07,
  0.2 , 0.2 , 0.2 , 0.2 ,
  0.07, 0.07, 0.07, 0.07,  
  0.1 , 0.1 , 0.1 , 0.1 ,
  0.07,
};

/* Layout info of the ULPCSS sprites. Has 21 rows of cells.*/
static SpriteLayout ulpcss_layout = {
  21,
  ulpcss_sprites_per_row, ulpcss_row_type, 
  ulpcss_row_direction  , ulpcss_row_duration,
  64, 64, 0, -16, -32
}; 


/* Layout info of the oversized ULPCSS sprites, for weapons only. */
static int ulpcss_oversized_sprites_per_row[] = {
  6, 6, 6, 6
};

/* Type info of the oversized ULPCSS sprites, for slashinhg weapons. */
static int ulpcss_oversized_slash_row_type[] = {
  SPRITE_SLASH, SPRITE_SLASH, SPRITE_SLASH, SPRITE_SLASH
};

/* Type info of the ULPCSS sprites, for stabbing weapons. */
static int ulpcss_oversized_stab_row_type[] = {
  SPRITE_STAB, SPRITE_STAB, SPRITE_STAB, SPRITE_STAB
};

/* Duration info of the ULPCSS sprites, for oversized weapons. */
static double ulpcss_oversized_duration[] = {
  0.07, 0.07, 0.07, 0.07
};

/* Direction info of the oversized ULPCSS sprites. */
static int ulpcss_oversized_row_direction[] = {
  SPRITE_NORTH , SPRITE_WEST , SPRITE_SOUTH, SPRITE_EAST
};

/* Layout of an oversized slashing weapon ULPCSS sprite. */
static SpriteLayout ulpcss_oversized_slash_layout = {
  4,
  ulpcss_oversized_sprites_per_row, ulpcss_oversized_slash_row_type,
  ulpcss_oversized_row_direction, ulpcss_oversized_duration,
  64 * 3, 64 * 3, 0, -80, -96 
}; 

/* Layout of an oversized stabbing weapon ULPCSS sprite. */
static SpriteLayout ulpcss_oversized_stab_layout = {
  4,
  ulpcss_oversized_sprites_per_row, ulpcss_oversized_stab_row_type,
  ulpcss_row_direction, ulpcss_oversized_duration,
  64 * 3, 64 * 3, 0, -80, -96
}; 



/* Amount of rows in a layout. */
int spritelayout_rows(SpriteLayout * layout) {
  int index;
  if(!layout) return 0;
  if(!layout->per_row) return 0;
  return layout->rows;
}


/** Loads the stand-in-walk layers for sprites with layouts that have them. 
* It's ugly but it's needed because of how the ULPCSS sprite sheets are 
* organized...
Sprite * sprite_loadlayerlayout_standinwalk(Sprite * self, 
                                            int layerindex, 
                                            Image * source, 
                                            int oversized, 
                                            SpriteLayout * layout) {
  return NULL;
}
*/


/* Loads a single row and column of a sprite layout from the given image
 * into the given layer for a normal cell. */
int spritelayout_load_rc_normal(
  SpriteLayout * layout, Sprite * sprite, Image * source, 
  int layeri, int rowi, int coli, int pose, int direction) {
  
  Point where           = bevec(layout->size_x * coli, layout->size_y * rowi);
  Point size            = bevec(layout->size_x, layout->size_y);
  Point offset          = bevec(layout->offset_x, layout->offset_y);

  double duration       = layout->row_duration[rowi];
  SpriteCell * cell     = sprite_load_cell_from(
    sprite, pose, direction, layeri, source, size, where, offset, duration);
  if (!cell) return -1;
  return 1;
}


/* Loads a single row and column of a sprite layout from the given image
 * into the given layer for a stand in walk cell. */
int spritelayout_load_rc_standinwalk(
  SpriteLayout * layout, Sprite * sprite, Image * source, 
  int layeri, int rowi, int coli, int pose, int direction) {
  
  Point where           = bevec(layout->size_x * coli, layout->size_y * rowi);
  Point size            = bevec(layout->size_x  , layout->size_y);
  Point offset          = bevec(layout->offset_x, layout->offset_y);
  
  double duration       = layout->row_duration[rowi];
  SpriteCell * cell     =  sprite_load_cell_from(
    sprite, SPRITE_STAND, direction, layeri, source, size, where, offset, duration);
  (void) pose;
  if (!cell) return -1;
  return 1;
}



/* Loads a single row and column of a sprite layout from the given image
 * into the given layer. */
int spritelayout_load_rc(
  SpriteLayout * layout, Sprite * sprite, Image * source, 
  int layeri, int rowi, int coli) {
  int pose              = layout->row_type[rowi];
  int direction         = layout->row_dir[rowi];
  
  /* special case for stand-in-walk cells. */
  if (   (layout->standinwalk >= 0) 
      && (coli == layout->standinwalk)
      && (pose == SPRITE_WALK)
     ) {
      return spritelayout_load_rc_standinwalk(
        layout, sprite, source, layeri, rowi, coli, pose, direction);       
  }
  /* Normal case */
  return spritelayout_load_rc_normal(
        layout, sprite, source, layeri, rowi, coli, pose, direction);
}



/* Loads a row of sprite cells into an action for the sprite, 
 * according to the layout. */
int spritelayout_load_row(
  SpriteLayout * layout, Sprite * sprite, Image * source, int layeri, int rowi){
  
  int col_max; 
  int coli;
  
  if (rowi > spritelayout_rows(layout)) return -1;
  
  col_max = layout->per_row[rowi];
  
  for (coli = 0 ; coli < col_max; coli++) {
    spritelayout_load_rc(layout, sprite, source, layeri, rowi, coli);
  }
  return col_max;
}

/* Loads sprite cells for a whole layer in the sprite. The layout info in the 
 * struct is used to correctly set up the sprite parts. 
 */ 
Sprite * spritelayout_load_layer
(SpriteLayout * layout, Sprite * sprite, Image * source, int layeri) {
  int stop;
  int rowi;

  stop        = spritelayout_rows(layout);
  for (rowi = 0 ; rowi < stop ; rowi++) {
    spritelayout_load_row(layout, sprite, source, layeri, rowi);
  }
  return sprite;
}

/** Returns a layout for a load type. Returns NULL on error or unknown type. */
SpriteLayout * spritelayout_for(int load_type) {
  switch (load_type) {
    case SPRITE_LOAD_ULPCSS_NORMAL:
      return &ulpcss_layout;
    case SPRITE_LOAD_ULPCSS_OVERSIZED_SLASH:
      return &ulpcss_oversized_slash_layout;
    case SPRITE_LOAD_ULPCSS_OVERSIZED_STAB:
      return &ulpcss_oversized_stab_layout;
    default:
      return NULL;
  }
}





