/* vi: set ts=2:
 *
 * Eressea PB(E)M host Copyright (C) 1998-2003
 *      Christian Schlittchen (corwin@amber.kn-bremen.de)
 *      Katja Zedel (katze@felidae.kn-bremen.de)
 *      Henning Peters (faroul@beyond.kn-bremen.de)
 *      Enno Rehling (enno@eressea.de)
 *      Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
 *
 * This program may not be used, modified or distributed without
 * prior permission by the authors of Eressea.
 */

#include <platform.h>
#include <kernel/config.h>
#include "unitcurse.h"

/* kernel includes */
#include <kernel/curse.h>
#include <kernel/message.h>
#include <kernel/race.h>
#include <kernel/skill.h>
#include <kernel/unit.h>
#include <kernel/faction.h>
#include <kernel/objtypes.h>
#include <kernel/version.h>

/* util includes */
#include <util/language.h>
#include <util/nrmessage.h>
#include <util/message.h>
#include <util/base36.h>
#include <util/functions.h>
#include <util/storage.h>

/* libc includes */
#include <string.h>
#include <stdlib.h>
#include <assert.h>

/* ------------------------------------------------------------- */
/*
 * C_AURA
 */
/* erh�ht/senkt regeneration und maxaura um effect% */
static message *cinfo_auraboost(const void *obj, typ_t typ, const curse * c,
  int self)
{
  struct unit *u = (struct unit *)obj;
  unused(typ);
  assert(typ == TYP_UNIT);

  if (self != 0) {
    if (curse_geteffect(c) > 100) {
      return msg_message("curseinfo::auraboost_0", "unit id", u, c->no);
    } else {
      return msg_message("curseinfo::auraboost_1", "unit id", u, c->no);
    }
  }
  return NULL;
}

static struct curse_type ct_auraboost = {
  "auraboost",
  CURSETYP_NORM, CURSE_SPREADMODULO, (NO_MERGE),
  cinfo_auraboost
};

/* Magic Boost - Gabe des Chaos */
static struct curse_type ct_magicboost = {
  "magicboost",
  CURSETYP_UNIT, CURSE_SPREADMODULO | CURSE_IMMUNE, M_MEN, cinfo_simple
};

/* ------------------------------------------------------------- */
/*
 * C_SLAVE
 */
static message *cinfo_slave(const void *obj, typ_t typ, const curse * c,
  int self)
{
  unit *u;
  unused(typ);

  assert(typ == TYP_UNIT);
  u = (unit *) obj;

  if (self != 0) {
    return msg_message("curseinfo::slave_1", "unit duration id", u, c->duration,
      c->no);
  }
  return NULL;
}

static struct curse_type ct_slavery = { "slavery",
  CURSETYP_NORM, 0, NO_MERGE,
  cinfo_slave
};

/* ------------------------------------------------------------- */
/*
 * C_CALM
 */
static message *cinfo_calm(const void *obj, typ_t typ, const curse * c,
  int self)
{
  unused(typ);
  assert(typ == TYP_UNIT);

  if (c->magician && c->magician->faction) {
    faction *f = c->magician->faction;
    unit *u = (unit *) obj;

    if (f == NULL || self == 0) {
      const struct race *rc = u_irace(c->magician);
      return msg_message("curseinfo::calm_0", "unit race id", u, rc, c->no);
    }
    return msg_message("curseinfo::calm_1", "unit faction id", u, f, c->no);
  }
  return NULL;
}

static struct curse_type ct_calmmonster = {
  "calmmonster",
  CURSETYP_NORM, CURSE_SPREADNEVER | CURSE_ONLYONE, NO_MERGE,
  cinfo_calm
};

/* ------------------------------------------------------------- */
/*
 * C_SPEED
 */
static message *cinfo_speed(const void *obj, typ_t typ, const curse * c,
  int self)
{
  unused(typ);
  assert(typ == TYP_UNIT);

  if (self != 0) {
    unit *u = (unit *) obj;
    return msg_message("curseinfo::speed_1", "unit number duration id", u,
      c->data.i, c->duration, c->no);
  }
  return NULL;
}

static struct curse_type ct_speed = {
  "speed",
  CURSETYP_UNIT, CURSE_SPREADNEVER, M_MEN,
  cinfo_speed
};

/* ------------------------------------------------------------- */
/*
 * C_ORC
 */
message *cinfo_unit(const void *obj, typ_t typ, const curse * c, int self)
{
  unused(typ);
  assert(typ == TYP_UNIT);

  if (self != 0) {
    unit *u = (unit *) obj;
    return msg_message(mkname("curseinfo", c->type->cname), "unit id", u,
      c->no);
  }
  return NULL;
}

static struct curse_type ct_orcish = {
  "orcish",
  CURSETYP_UNIT, CURSE_SPREADMODULO | CURSE_ISNEW, M_MEN,
  cinfo_unit
};

/* ------------------------------------------------------------- */
/*
 * C_KAELTESCHUTZ
 */
static message *cinfo_kaelteschutz(const void *obj, typ_t typ, const curse * c,
  int self)
{
  unused(typ);
  assert(typ == TYP_UNIT);

  if (self != 0) {
    unit *u = (unit *) obj;
    return msg_message("curseinfo::warmth_1", "unit number id", u,
      get_cursedmen(u, c), c->no);
  }
  return NULL;
}

static struct curse_type ct_insectfur = {
  "insectfur",
  CURSETYP_UNIT, CURSE_SPREADMODULO, (M_MEN | M_DURATION),
  cinfo_kaelteschutz
};

/* ------------------------------------------------------------- */
/*
 * C_SPARKLE
 */
static message *cinfo_sparkle(const void *obj, typ_t typ, const curse * c,
  int self)
{
  const char *effects[] = {
    NULL,                       /* end grau */
    "sparkle_1",
    "sparkle_2",
    NULL,                       /* end traum */
    "sparkle_3",
    "sparkle_4",
    NULL,                       /* end tybied */
    "sparkle_5",
    "sparkle_6",
    "sparkle_7",
    "sparkle_8",
    NULL,                       /* end cerrdor */
    "sparkle_9",
    "sparkle_10",
    "sparkle_11",
    "sparkle_12",
    NULL,                       /* end gwyrrd */
    "sparkle_13",
    "sparkle_14",
    "sparkle_15",
    "sparkle_16",
    "sparkle_17",
    "sparkle_18",
    NULL,                       /* end draig */
  };
  int m, begin = 0, end = 0;
  unit *u;
  unused(typ);

  assert(typ == TYP_UNIT);
  u = (unit *) obj;

  if (!c->magician || !c->magician->faction)
    return NULL;

  for (m = 0; m != c->magician->faction->magiegebiet; ++m) {
    while (effects[end] != NULL)
      ++end;
    begin = end + 1;
    end = begin;
  }

  while (effects[end] != NULL)
    ++end;
  if (end == begin)
    return NULL;
  else {
    int index = begin + curse_geteffect_int(c) % (end - begin);
    return msg_message(mkname("curseinfo", effects[index]), "unit id", u,
      c->no);
  }
}

static struct curse_type ct_sparkle = { "sparkle",
  CURSETYP_UNIT, CURSE_SPREADMODULO, (M_MEN | M_DURATION), cinfo_sparkle
};

/* ------------------------------------------------------------- */
/*
 * C_STRENGTH
 */
static struct curse_type ct_strength = { "strength",
  CURSETYP_UNIT, CURSE_SPREADMODULO, M_MEN, cinfo_simple
};

/* ------------------------------------------------------------- */
/*
 * C_ALLSKILLS (Alp)
 */
static struct curse_type ct_worse = {
  "worse", CURSETYP_UNIT, CURSE_SPREADMODULO | CURSE_NOAGE, M_MEN, cinfo_unit
};

/* ------------------------------------------------------------- */

/*
 * C_ITEMCLOAK
 */
static struct curse_type ct_itemcloak = {
  "itemcloak", CURSETYP_UNIT, CURSE_SPREADNEVER, M_DURATION, cinfo_unit
};

/* ------------------------------------------------------------- */

static struct curse_type ct_fumble = {
  "fumble", CURSETYP_NORM, CURSE_SPREADNEVER | CURSE_ONLYONE, NO_MERGE,
    cinfo_unit
};

/* ------------------------------------------------------------- */

static struct curse_type ct_oldrace = {
  "oldrace", CURSETYP_NORM, CURSE_SPREADALWAYS, NO_MERGE, NULL
};

static struct curse_type ct_magicresistance = {
  "magicresistance", CURSETYP_UNIT, CURSE_SPREADMODULO, M_MEN, cinfo_simple
};

/* ------------------------------------------------------------- */
/*
 * C_SKILL
 */

static int read_skill(struct storage *store, curse * c, void *target)
{
  int skill;
  if (store->version < CURSETYPE_VERSION) {
    int men;
    skill = store->r_int(store);
    men = store->r_int(store);
  } else {
    skill = store->r_int(store);
  }
  c->data.i = skill;
  return 0;
}

static int
write_skill(struct storage *store, const curse * c, const void *target)
{
  store->w_int(store, c->data.i);
  return 0;
}

static message *cinfo_skillmod(const void *obj, typ_t typ, const curse * c,
  int self)
{
  unused(typ);

  if (self != 0) {
    unit *u = (unit *) obj;
    int sk = c->data.i;
    if (c->effect > 0) {
      return msg_message("curseinfo::skill_1", "unit skill id", u, sk, c->no);
    } else if (c->effect < 0) {
      return msg_message("curseinfo::skill_2", "unit skill id", u, sk, c->no);
    }
  }
  return NULL;
}

static struct curse_type ct_skillmod = {
  "skillmod", CURSETYP_NORM, CURSE_SPREADMODULO, M_MEN, cinfo_skillmod,
  NULL, read_skill, write_skill
};

/* ------------------------------------------------------------- */
void register_unitcurse(void)
{
  ct_register(&ct_auraboost);
  ct_register(&ct_magicboost);
  ct_register(&ct_slavery);
  ct_register(&ct_calmmonster);
  ct_register(&ct_speed);
  ct_register(&ct_orcish);
  ct_register(&ct_insectfur);
  ct_register(&ct_sparkle);
  ct_register(&ct_strength);
  ct_register(&ct_worse);
  ct_register(&ct_skillmod);
  ct_register(&ct_itemcloak);
  ct_register(&ct_fumble);
  ct_register(&ct_oldrace);
  ct_register(&ct_magicresistance);
}