/* object OBJID_HUNTER */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include "obj-hunter.h"

unsigned int objnew_HUNTER(void *);

static void f_free(void *, void *);
static VG_BOOL f_run(void *, struct VG_Object *);
static void f_draw(void *, struct VG_Object *);


/* export-function to create a new object-instance of OBJID_HUNTER
 * @param vgame  private structure of the game
 * @return  instance-ID or 0 = error
 */
unsigned int
objnew_HUNTER(void *vgame)
{
  const int coll_percent = 80;
  struct s_game *sgame = (struct s_game *)vgame;
  struct VG_Object *objp;
  struct sobj_hunter *objvars;
  char pfad[512];

  if (sgame == NULL) { return 0; }

  /* create private struct */

  objvars = calloc(1, sizeof(*objvars));
  if (objvars == NULL) { return 0; }

  { int ht = ZUFALL(OBJID_HUNTER, 1, 12);
    if (ht <= 6) {
      objvars->htype = 1;
    } else if (ht <= 10) {
      objvars->htype = 2;
    } else {
      objvars->htype = 3;
    }
  }

  /* load images and sprites */
  snprintf(pfad, sizeof(pfad), "files/images/hunter/%d/hunter%d-appear.sprite", sgame->svdt.dnew.gamelevel + 1, objvars->htype);
  if (access(pfad, R_OK) == 0) { objvars->images.appear = vg4->sprite->load(pfad); }
  snprintf(pfad, sizeof(pfad), "files/images/hunter/%d/hunter%d-stand.bmp", sgame->svdt.dnew.gamelevel + 1, objvars->htype);
  if (access(pfad, R_OK) == 0) { objvars->images.stand = vg4->image->load(pfad); }
  snprintf(pfad, sizeof(pfad), "files/images/hunter/%d/hunter%d-go.sprite", sgame->svdt.dnew.gamelevel + 1, objvars->htype);
  objvars->images.go = vg4->sprite->load(pfad);
  if (objvars->images.go == NULL) { f_free(vgame, objvars); return 0; }
  snprintf(pfad, sizeof(pfad), "files/images/hunter/%d/hunter%d-attack.bmp", sgame->svdt.dnew.gamelevel + 1, objvars->htype);
  if (access(pfad, R_OK) == 0) { objvars->images.attack = vg4->image->load(pfad); }
  snprintf(pfad, sizeof(pfad), "files/images/hunter/%d/hunter%d-die.sprite", sgame->svdt.dnew.gamelevel + 1, objvars->htype);
  objvars->images.die = vg4->sprite->load(pfad);
  if (objvars->images.die == NULL) { f_free(vgame, objvars); return 0; }

  vg4->sprite->imagesize(objvars->images.go, "avg", &objvars->rectc.rect.w, &objvars->rectc.rect.h);

  { struct VG_Point *pntp;
    int ix, iy;
    ix = ZUFALL(OBJID_HUNTER, 2, sgame->nodes.max_x);
    iy = ZUFALL(OBJID_HUNTER, 2, sgame->nodes.max_y);
    snprintf(objvars->nodes.n, sizeof(objvars->nodes.n), "%d/%d", ix, iy);
    pntp = (struct VG_Point *)vg4->hash->get(sgame->nodes.hnode, objvars->nodes.n, NULL);
    my_assert(pntp != NULL);
    objvars->rectc.rect.x = pntp->x - objvars->rectc.rect.w / 2;
    objvars->rectc.rect.y = pntp->y - objvars->rectc.rect.h / 2;
  }

  objvars->status = SOBJ_HUNTER_APPEAR;
  objvars->moving = SOBJ_HUNTER_MOV_LEFT;

  /* create object-instance */
  objp = vg4->object->create(OBJID_HUNTER, 0, 0, 4, objvars);
  objp->f_free = f_free;
  objp->f_run = f_run;
  objp->f_draw = f_draw;

  /* insert object-instance into collision-tag */
  vg4->collision->insert(sgame->coll_tag, objp->instanceid, &objvars->rectc.rect, coll_percent);

  return objp->instanceid;
}


/* free private struct of object-instance, called from vg4->object->destroy() */
static void
f_free(void *vgame, void *opriv)
{
  struct sobj_hunter *objvars = (struct sobj_hunter *)opriv;
  struct s_game *sgame = (struct s_game *)vgame;

  /* if destroyed inform object-management */
  if (sgame != NULL) {
    vg4->object->call_mgmt_data(sgame, OBJID_HUNTER, NULL);
  }

  /* free private struct */
  if (objvars->images.appear != NULL) { vg4->sprite->destroy(objvars->images.appear); }
  if (objvars->images.stand != NULL) { vg4->image->destroy(objvars->images.stand); }
  if (objvars->images.go != NULL) { vg4->sprite->destroy(objvars->images.go); }
  if (objvars->images.attack != NULL) { vg4->image->destroy(objvars->images.attack); }
  if (objvars->images.die != NULL) { vg4->sprite->destroy(objvars->images.die); }
  if (objvars->nodes.nmove != NULL) { free(objvars->nodes.nmove); }
  free(objvars);
}


/* move object-instance, called from vg4->object->call_run() */
static VG_BOOL
f_run(void *vgame, struct VG_Object *objp)
{
  int moving_factor, follow_percent;
  struct s_game *sgame = (struct s_game *)vgame;
  struct sobj_hunter *objvars = (struct sobj_hunter *)objp->opriv;
  struct VG_Rect plrect;

  if (sgame == NULL) { return VG_TRUE; }

  switch (sgame->svdt.dnew.gamelevel + 1) {
    case 1: moving_factor = 8; follow_percent = 10; break;
    case 2: moving_factor = 10; follow_percent = 15; break;
    case 3: moving_factor = 12; follow_percent = 20; break;
    case 4: moving_factor = 14; follow_percent = 25; break;
    case 5: moving_factor = 16; follow_percent = 30; break;
    default: moving_factor = 5; follow_percent = 0;
  }
  moving_factor += objvars->htype * 3;

  if (objvars->status == SOBJ_HUNTER_DIE) {
    if (!vg4->sprite->next(objvars->images.die, NULL, NULL)) { vg4->object->destroy(vgame, objp->instanceid); return VG_TRUE; }
    return VG_TRUE;
  }

  if (objvars->status == SOBJ_HUNTER_APPEAR) {
    if (!vg4->sprite->next(objvars->images.appear, NULL, NULL)) { objvars->status = SOBJ_HUNTER_STAND; objvars->st_number = 10; }
    return VG_TRUE;
  }

  vg4->object->call_data(sgame, sgame->instanceid.player, &plrect);

  /* attacking? */
  objvars->show_attack = VG_FALSE;
  if (objvars->rectc.rect.x + objvars->rectc.rect.w * 3 / 2 >= plrect.x
      && objvars->rectc.rect.x <= plrect.x + plrect.w + objvars->rectc.rect.w / 2) {
    if (objvars->rectc.rect.y + objvars->rectc.rect.h * 3 / 2 >= plrect.y
        && objvars->rectc.rect.y <= plrect.y + plrect.h + objvars->rectc.rect.h / 2) {
      objvars->show_attack = VG_TRUE;
    }
  }

  if (objvars->status == SOBJ_HUNTER_STAND) {
    if (--objvars->st_number == 0) {
      int ix, iy;
      char n[32];

      /* get destination node */
      if (ZUFALL(OBJID_HUNTER, 1, 100) <= (unsigned int)follow_percent) {
        get_node_near_position(sgame, plrect.x + plrect.w / 2, plrect.y + plrect.h / 2, n, sizeof(n));
      } else {
        ix = ZUFALL(OBJID_HUNTER, 1, sgame->nodes.max_x);
        iy = ZUFALL(OBJID_HUNTER, 1, sgame->nodes.max_y);
        snprintf(n, sizeof(n), "%d/%d", ix, iy);
      }
      objvars->status = SOBJ_HUNTER_GO;

      /* get way to destination node */
      objvars->nodes.maxmove = vg4->nodelink->moveto(sgame->nodes.ndlnk, objvars->nodes.n, n, &objvars->nodes.nmove, VG_FALSE);
      if (objvars->nodes.maxmove == 0) { objvars->status = SOBJ_HUNTER_STAND; objvars->st_number = 5; return VG_TRUE; }
      objvars->nodes.imove = 0;
    }
    return VG_TRUE;
  }

  /* move and check for collisions */
  { struct VG_RectCent *rectcp;
    struct VG_Point *pntp;
    int rectc_nr;

    if (objvars->nodes.maxmove > 0) {
      pntp = (struct VG_Point *)vg4->hash->get(sgame->nodes.hnode, objvars->nodes.nmove[objvars->nodes.imove], NULL);
    } else {  /* just moving to next node */
      pntp = (struct VG_Point *)vg4->hash->get(sgame->nodes.hnode, objvars->nodes.n, NULL);
    }
    my_assert(pntp != NULL);

    rectc_nr = vg4->misc->moving_one_step_to_dst(&objvars->rectc, pntp, moving_factor, &rectcp);
    if (rectc_nr > 0) {
      if (rectcp[0].rect.x > objvars->rectc.rect.x) {
        objvars->moving = SOBJ_HUNTER_MOV_RIGHT;
      } else if (rectcp[0].rect.x < objvars->rectc.rect.x) {
        objvars->moving = SOBJ_HUNTER_MOV_LEFT;
      }
      if (!vg4->misc->move_and_check_collisions(vgame, objp->instanceid, &objvars->rectc, sgame->coll_tag, rectcp, rectc_nr)) {
        ; /* object-instance is dead: ignore it here */
      }
      free(rectcp);

    } else {
      if (objvars->nodes.maxmove > 0) {
        vg4->misc->strcpy(objvars->nodes.n, sizeof(objvars->nodes.n), objvars->nodes.nmove[objvars->nodes.imove]);
        if (++objvars->nodes.imove == objvars->nodes.maxmove) {
          free(objvars->nodes.nmove);
          objvars->nodes.nmove = NULL;
          objvars->status = SOBJ_HUNTER_STAND;
          objvars->st_number = 50;
        }
      } else {  /* was just moving to next node */
        objvars->status = SOBJ_HUNTER_STAND;
        objvars->st_number = 50;
      }
    }
  }

  return VG_TRUE;
}


/* draw object-instance, called from vg4->object->call_draw() */
static void
f_draw(void *vgame, struct VG_Object *objp)
{
  struct s_game *sgame = (struct s_game *)vgame;
  struct sobj_hunter *objvars = (struct sobj_hunter *)objp->opriv;
  struct VG_Image *imgp;
  struct VG_ImagecopyAttr iattr;
  struct VG_Position posi;

  if (sgame == NULL) { return; }

  imgp = NULL;
  VG_IMAGECOPY_ATTR_DEFAULT(&iattr);

  if (objvars->status == SOBJ_HUNTER_DIE) {  /* hunter dying */
    if (!vg4->sprite->current(objvars->images.die, &imgp, &iattr)) {
      /* hunter dead */
      return;
    }

  } else {
    if (objvars->status == SOBJ_HUNTER_APPEAR) {
      vg4->sprite->current(objvars->images.appear, &imgp, &iattr);
    } else if (objvars->status == SOBJ_HUNTER_STAND) {
      imgp = objvars->images.stand;
    }
    if (objvars->show_attack && objvars->images.attack != NULL) {
      imgp = objvars->images.attack;
    } else if (imgp == NULL || objvars->status == SOBJ_HUNTER_GO) {
      vg4->sprite->next(objvars->images.go, &imgp, &iattr);
    }
  }

  if (imgp != NULL) {
    if (objvars->moving == SOBJ_HUNTER_MOV_LEFT) {
      iattr.image.flip = VG_AXE_VERTICAL;
    }
    vg4->misc->rect2position(&posi, &objvars->rectc.rect);
    posi = vg4->misc->bgposition_getobj(posi);
    vg4->window->copy(imgp, &posi, &iattr);
  }
}
