/* borg_spells.c  
   "Parsival" borg spellcasting routines and spell-gaining routines
   Copyright (c) Frits Daalmans, 1995
   Read the file README.parsival for more info
*/
#include "angband.h"
extern player_type *p_ptr; /* needed for VERY UGLY quitting hack */

#ifdef AUTO_PLAY

/* this is not the main routine */
#define EXTERN extern
#include "borg.h"
#undef EXTERN
#define EXTERN			/* normal */





#ifdef FRITS

/* extract the numeric value of a stat */
EXTERN int
stat2int (statstring)
     cptr statstring;
{
  int stat;
  cptr slash;

  if (!strcmp (statstring, "18/***")) return(18+220);
  if ((slash=strchr (statstring, '/'))!=NULL)
    {
      stat=18+atoi(slash+1);
    }
  else
    {
      stat=atoi(statstring);
    }
  return (stat);
}



/* this routine is re-entrant; comes back once, after the books have been checked. */
EXTERN bool
borg_can_gain_spell ()
{
  int spellstat = 0;
  int i,j;
  bool go_ahead;

  if (sclass == SCLASS_NONE)
    return (TRUE);		/* continue old goal */
  if (sclass == SCLASS_PRIEST)
    spellstat = 2;		/* wis */
  if (sclass == SCLASS_MAGE)
    spellstat = 1;		/* int */

  /* need the study capacity, the books and the levels */
  if (known_spells != 0)
    {
      borg_note ("borg survived known_spells test");
      borg_note (format ("known_spells = %d, INT/WIS= %d", known_spells, auto_stat[spellstat]));
      borg_note (format ("max. learnable spells = %d", maxknownspells (auto_stat[spellstat], auto_level)));

      if (maxknownspells (auto_stat[spellstat], auto_level) <= known_spells)
	{
          do_study=FALSE;
          borg_note("No spells to be gained right now");
	  return (TRUE);	/* continue old goal */
	}
      else
	{

          /* test for spell level */
          go_ahead=FALSE;
          for(i=0;i<9;i++)
          {
            if (books[i]== -1) continue;
            for (j=0;j<9;j++)
            {
               if ((splevel[pclass][i][j] <= auto_level) && (spells_known[i][j]==FALSE))
                  go_ahead=TRUE;
            }
          }
          if  (go_ahead==FALSE) {
             borg_note("Pity.. either gain some levels or get more books.");
             do_study=FALSE;
             return(TRUE);        /* new goal */
          }

            /* actual gaining */
	  if (sclass == SCLASS_MAGE)
	    {
	      borg_keypress ('G');
	      borg_keypress ('a');
	    }
	  else
	    {			/* priest */
	      borg_keypress ('G');
	    }
	  /* restart the process of gaining spells and fit in the new one */
	  do_study = FALSE;
	  known_spells = 0;
	  return (FALSE);	/* continue old goal */
	}
    }

  /* known_spells = 0; test further */

  /* still need the books and the levels */
  current_book = borg_check_spellbooks ('a');	/* just check 'em all */
  if (current_book == -1)
  {
    borg_oops ("OOPS! Borg can't find *any* spellbooks!");
    state = STATE_START;
    do_study=FALSE;
    known_spells=0;
    return(TRUE);
  }

  /* activate the routine for 1st spellbook */

  borg_note ("Activating borg_prepare_spells()");
  current_book = 0;
  do_study = TRUE;
  state = STATE_BOOKCHECK;
  return (FALSE);
}


/* fills known_spells; has to give keypresses, and read info. */
/* this routine parses the info from cmd5.c 's print_spells() */
EXTERN bool
borg_prepare_spells ()
{
  int spell;
  int book;
  int i, j;
  char buf[128];
  byte t_a;
  int priestmage;
  static int trouble = 0;
  int nrbooks;
  int letter;


#define COL_SPELLWIN	22
#define ROW_SPELLBOOK	1

  /* only stay in this loop when called by borg_can_gain_spell() */
  /* the loop starts after borg_prepare_store() */
  if (do_study == FALSE)
    {
      borg_note ("borg_prepare_spells() call unasked for");
      state = STATE_START;
      return (FALSE);
    }

  priestmage = ((sclass == SCLASS_PRIEST) ? 0 : 1);
  /* assumes borg_check_spellbooks() done */
  nrbooks = 0;
  for (j = 0; j < 9; j++)
    if (books[j] != -1)
      nrbooks++;

  borg_note (format ("Entering borg_prepare_spells, current book=%d,nrbooks=%d", current_book, nrbooks));

  if (0 == Term_what_text (COL_SPELLWIN + 35, ROW_SPELLBOOK, -12, &t_a, buf))
    {
/*      borg_note (format ("check_spells buf=[%s]", buf)); */
      if (!strcmp (buf, "Lv Mana Fail"))
	{
	  book = -1;
	  for (i = 0; i < 9; i++)
	    if (books[i] == current_book)
	      book = i;


	  borg_note (format ("Checking all known spells from book %d ('%c')...", book+1, current_book + 'a'));
	  /* do this only once; we need the books array info */
	  for (spell = 0; spell < 9; spell++)
	    {
              /* zero out buf */
              bzero(buf,127);
	      Term_what_text (COL_SPELLWIN, ROW_SPELLBOOK + spell + 1, 55, &t_a, buf);
	      borg_note (format ("line %02d=[%s]", spell, buf));
	      letter = buf[2];
	      /* ( keep vi happy */
	      if (buf[3] != ')')
		continue;
	      if (letter - 'a' != spell)
		borg_note (format ("Hm. spell # is %d but letter '%c'", spell+1, letter));
	      /* 36 ev = level */
	      if (strstr (buf, "unknown") == NULL)
		{
		  /* untried or known */
		  spells_known[book][letter - 'a'] = TRUE;
		  known_spells++;
		  if (strstr (buf, "untried") != NULL)
		    borg_note (format ("Untried: book %d ('%c') spell '%c'", book+1, current_book+'a', letter));
		  /* else
   borg_note(format("Known: book %c spell '%c'",current_book+'a',letter));
*/
		}

	    }
	  /* everything went OK */
	  trouble = 0;
	  current_book++;
          /* bail out here if next book unavailable */
          if (current_book >= nrbooks) {
	      borg_note ("*** all books checked, bail out next go ***");
              borg_keypress(ESCAPE);
          }
	}
      else
	{
	  if (current_book >= nrbooks)
	    {
	      borg_note ("*** all books checked ***");
              borg_keypress(ESCAPE);
              borg_keypress(' ');
              borg_keypress('\n');
	      state = STATE_START;
                   borg_note("book avail?   spells");
              for(i=0;i<9;i++) 
              {
                 sprintf(buf," %1d  %c         . . . . . . . . . .",i+1,((books[i]==-1)?'n':'y'));
                 for(j=0;j<9;j++)
                    buf[14+j*2]=(spells_known[i][j]?j+'a':' ');
                 borg_note(format("%s",buf));
              }
              /* goto kapermee; */
	      return (FALSE);
	    }
	  else
	    {
	      /* this must be an uninitialized call; build the spells_known */
	      borg_note ("error! couldn't read preamble");
	      borg_note (format ("curbook=%d, trouble-lev=%d", current_book, trouble));
	      trouble++;
	      if (trouble > 5)
		goto kapermee;
	    }
	}
      state = STATE_BOOKCHECK;

      /* check the next book */
      borg_note (format ("prepare_spells pressing ' P%c'", 'a' + current_book));
      borg_keypress (' ');
      borg_keypress ('P');
      borg_keypress ('a' + current_book);
      return (TRUE);

    }
  else
    {
      borg_note ("oops. empty buffer.");
      if (known_spells != 0)
	{
	  borg_note ("end of spellbooks. already :-()");
	  state = STATE_START;
	  return (FALSE);
	}
      borg_note ("FAILURE in borg_prepare_spells(), trying again");
      trouble++;
      state = STATE_BOOKCHECK;
      if (trouble > 5)
	goto kapermee;
      return (FALSE);
      trouble++;
      borg_keypress ('P');
      borg_keypress ('a' + current_book);
      state = STATE_BOOKCHECK;
      return (TRUE);

    kapermee:
      /* This is a VERY ugly hack to force the borg to quit */
      borg_oops ("QUITTING!");
      state = STATE_START;
      trouble = 0;
      p_ptr->chp = 5;
      borg_keypress (' ');
      borg_keypress ('^');
      borg_keypress ('w');
      return (FALSE);
    }
}


/* check which spellbooks are available */
/* can be used both for borg_can_gain_spell() and borg_can_cast() */
EXTERN int
borg_check_spellbooks (book)
     char book;
{
  int i, j;
  auto_item *item;
  static int priestbooks[9] =
  {OBJ_PBOOK_1, OBJ_PBOOK_2, OBJ_PBOOK_3,
   OBJ_PBOOK_4, OBJ_PBOOK_5, OBJ_PBOOK_6,
   OBJ_PBOOK_7, OBJ_PBOOK_8, OBJ_PBOOK_9};
  static int magebooks[9] =
  {OBJ_SBOOK_1, OBJ_SBOOK_2, OBJ_SBOOK_3,
   OBJ_SBOOK_4, OBJ_SBOOK_5, OBJ_SBOOK_6,
   OBJ_SBOOK_7, OBJ_SBOOK_8, OBJ_SBOOK_9};

  if (sclass == SCLASS_NONE)
    return (FALSE);
  for (i = 0; i < 9; i++)
    books[i] = -1;

  if (sclass == SCLASS_PRIEST)
    {
      for (i = 0; i < MIN (INVEN_PACK, 9); i++)
	{
	  item = &auto_items[i];
	  for (j = 0; j < 9; j++)
	    if (item->kind == priestbooks[j])
	      {
		books[j] = i;
		continue;
	      }
	}
    }
  else
    {				/* (sclass == SCLASS_MAGE) */
      for (i = 0; i < MIN (INVEN_PACK, 9); i++)
	{
	  item = &auto_items[i];
	  for (j = 0; j < 9; j++)
	    if (item->kind == magebooks[j])
	      {
		books[j] = i;
		continue;
	      }
	  for (j = 0; j < 9; j++)
	    if (item->kind == priestbooks[j])
	      {
		books[j] = i;
		continue;
	      }
	}
    }


  for (i = 0; i < 9; i++)
    if (books[i] == (book - 'a'))
      {
#ifdef FRITSDEBUG
	borg_note (format ("check spellbook: '%c' = item[%d]", book, i));
#endif /* FRITSDEBUG */
	return (i);
      }

  /* book not found */
  if (book != 'z')		/* don't warn if wants to gain a spell */
    borg_note (format ("attempt to use spellbook '%c': not available.", book));
  return (-1);
}



/* see cmd5.c for table in calc_spells() */
EXTERN int
maxknownspells (intwis, level)
     int intwis;
     int level;
{
  int spelllevs;
  /*  from tables.c, class_info[].
    mind that the ordering is a bit different here. */
  static int spellfirst[6] =
  {99, 1, 1, 5, 3, 1};

  spelllevs = level + 1 - spellfirst[pclass];

  /* from stat_adj() in misc.c */
  if (intwis <= 7)
    return (0);			/* stat_adj = 0 */
  if (intwis <= 67)
    return (spelllevs);		/* stat_adj = 1,2,3 */
  if (intwis <= 107)
    return (3 * spelllevs / 2);	/* stat_adj = 4,5 */
  if (intwis <= 117)
    return (2 * spelllevs);	/* stat_adj = 6 */
  return (5 * spelllevs / 2);	/* stat_adj > 6 */
}



EXTERN bool
borg_cast_spell (sclass, book, spell)
     int sclass;
     char book;
     char spell;
{

#ifdef FRITSDEBUG
  borg_note (format ("In routine borg_cast_spell(%d,%c,%c)", sclass, book, spell));
#endif /* FRITSDEBUG */

  /* check mana cost, prayer/spellbook available, etc.
	      return FALSE if not possible, TRUE if possible */
  /* no way to check if spell worked though */
  if (!borg_can_cast (sclass, book, spell))
    return (FALSE);

  /* not in town, in case of stores */
  if ((state==STATE_INVEN)||(state==STATE_STORE)||(state==STATE_BOOKCHECK)||(state==STATE_EQUIP))
  {
      borg_note ("borg spellcast in illegal state");
      return (FALSE);
  }
  if (auto_depth == 0)
    {
      borg_note ("borg doesn't cast spells in town!");
      return (FALSE);
    }

  if (sclass == SCLASS_PRIEST)
    {
      borg_note (format ("Borg casting prayer '%c' from book '%c'", spell, book));
      borg_keypress ('p');
      borg_keypress ('a' + current_book);
      borg_keypress (spell);
      return (TRUE);
    }
  else
    {
      if (sclass == SCLASS_MAGE)
	{
	  borg_note (format ("Borg casting spell '%c' from book '%c'", spell, book));
	  borg_keypress ('m');
	  borg_keypress ('a' + current_book);
	  borg_keypress (spell);
	  return (TRUE);
	}
    }

  return (FALSE);
}


/* This code is derived from Ben Harrison's borg_play_fire() routine */
EXTERN bool
borg_cast_spell_at (sclass, book, spell, x2, y2)
     int sclass;
     char book;
     char spell;
     int x2, y2;
{
  int x1 = c_x, y1 = c_y;

  auto_grid *ag;

  /* not in town, in case of stores */
  if (auto_depth == 0)
    {
      borg_note ("borg doesn't cast spells in town!");
      return (FALSE);
    }

  /* Only a two in five chance */
  if (rand_int (5) > 1)
    return (FALSE);

  /* Paranoia -- Must be "on screen" */
  if (!panel_contains (y2, x2))
    return (FALSE);

  /* Must not be adjacent */
  if (distance (y1, x1, y2, x2) <= 1)
    return (FALSE);

  /* Must not be too far away */
  if (distance (y1, x1, y2, x2) > 10)
    return (FALSE);

  /* Must have "missile line of sight" */
  if (!borg_projectable (y1, x1, y2, x2))
    return (FALSE);


  /* XXX Hack -- do not "fire" at mushrooms/skeletons */
  ag = grid (x2, y2);
  if (ag->o_c == ',')
    return (FALSE);
  if (ag->o_c == 's')
    return (FALSE);

  if (borg_can_cast (sclass, book, spell) == FALSE)
    return (FALSE);

  borg_note (format ("Casting spell from (%d,%d) at (%d,%d)", c_x, c_y, x2, y2));

  /* Use that spellbook/prayerbook! */
  if (sclass == SCLASS_PRIEST)
    borg_keypress ('p');
  else if (sclass == SCLASS_MAGE)
    borg_keypress ('m');
  borg_keypress ('a' + current_book);
  borg_keypress (spell);

  /* Target the location */
  borg_keypress ('*');
  borg_keypress ('p');

  /* Start at the player */
  x1 = c_x;
  y1 = c_y;

  /* Move to the location */
  for (; y1 < y2; y1++)
    borg_keypress ('2');
  for (; y1 > y2; y1--)
    borg_keypress ('8');
  for (; x1 < x2; x1++)
    borg_keypress ('6');
  for (; x1 > x2; x1--)
    borg_keypress ('4');

  /* Select the target */
  borg_keypress ('t');

  /* Success */
  return (TRUE);
}


EXTERN bool borg_cast_spell_oninv (sclass, book, spell, invitem)
     int sclass;
     char book;
     char spell;
     int invitem;
{

#ifdef FRITSDEBUG
  borg_note (format ("In routine borg_cast_spell(%d,%c,%c)", sclass, book, spell));
#endif /* FRITSDEBUG */

  /* check mana cost, prayer/spellbook available, etc.
	      return FALSE if not possible, TRUE if possible */
  /* no way to check if spell worked though */
  if (borg_can_cast (sclass, book, spell)==FALSE)
    return (FALSE);

  /* not in town, in case of stores */
  if (auto_depth == 0)
    {
      borg_note ("borg doesn't cast spells in town!");
      return (FALSE);
    }

  if (sclass == SCLASS_PRIEST)
    {
      borg_note (format ("Borg casting prayer '%c' from book '%c' on inv. item '%c'", spell, book,invitem));
      borg_keypress ('p');
      borg_keypress ('a' + current_book);
      borg_keypress (spell);
      borg_keypress (invitem);
      return (TRUE);
    }
  else
    {
      if (sclass == SCLASS_MAGE)
	{
	  borg_note (format ("Borg casting spell '%c' from book '%c' on inv. item '%c'", spell, book,invitem));
	  borg_keypress ('m');
	  borg_keypress ('a' + current_book);
	  borg_keypress (spell);
          borg_keypress (invitem);
	  return (TRUE);
	}
    }

  return (FALSE);
}


/* current_book is the inventory item; book is the spellbook type */
EXTERN bool
borg_can_cast (sclass, book, spell)
     int sclass;
     char book;
     char spell;
{
  int cost;

  /* check confused/blind */
  if (do_confused | do_blind)
    {
      borg_note (format ("borg can't cast book '%c' spell '%c': blind/confused",
			 book, spell));
      return (FALSE);
    }

  /* not in town, in case of stores; but this code moved to actual spell procs */

  /* check mana */
  cost = manacost[pclass][book - 'a'][spell - 'a'];
  if (auto_curmana < cost)
    {
/* generates LOADS of unnecessary messages */
/*
      borg_note (format ("borg can't cast book '%c' spell '%c': cost %d, mana %d",
			 book, spell, cost, auto_curmana));
*/
      return (FALSE);
    }

  /* check spellbook -- in actual routine, current_book is reused. */
  if ((current_book = borg_check_spellbooks (book)) == -1)
    return (FALSE);

  /* check spell known */
  return (spells_known[book - 'a'][spell - 'a']);

}

#endif /* FRITS */

#endif /* AUTO_PLAY */
