/
roa/
roa/lib/boards/
roa/lib/config/
roa/lib/edits/
roa/lib/help/
roa/lib/misc/
roa/lib/plrobjs/
roa/lib/quests/
roa/lib/socials/
roa/lib/www/
roa/lib/www/LEDSign/
roa/lib/www/LEDSign/fonts/
roa/lib/www/LEDSign/scripts/
roa/src/s_inc/
roa/src/sclient/
roa/src/sclient/binary/
roa/src/sclient/text/
roa/src/util/
/************************************************************************
	Realms of Aurealis 		James Rhone aka Vall of RoA

screen.c 				VT100 emulation code, color code,
					vtmap code, vtsize code... all
					sorts of stuff dealing with a
					players screen...

		******** 100% Completely Original Code ********
		*** BE AWARE OF ALL RIGHTS AND RESERVATIONS ***
		******** 100% Completely Original Code ********
		        All rights reserved henceforth. 

    Please note that no guarantees are associated with any code from
Realms of Aurealis.  All code which has been released to the general
public has been done so with an 'as is' pretense.  RoA is based on both
Diku and CircleMUD and ALL licenses from both *MUST* be adhered to as well
as the RoA license.   *** Read, Learn, Understand, Improve ***
*************************************************************************/
#include "conf.h"
#include "sysdep.h"

#include "structures.h"
#include "utils.h"
#include "comm.h"
#include "interpreter.h"
#include "acmd.h"
#include "handler.h"
#include "db.h"
#include "screen.h"
#include "mudlimits.h"
#include "lists.h"
#include "global.h"

// internals
void update_vtmap(chdata *ch);

/**********************************/
/**********************************/
/**********************************/
/* RoA color and VT100 term stuff */
/**********************************/
/**********************************/
/**********************************/

/* clears screen and homes to 0 0 */
void clrscr(chdata *ch)
{
   send_to_char(CLRSCR, ch);
   if (VT100(ch))
     init_vtbar(ch);
}

void clrline(chdata *ch)
{
 if (ch->desc)
   send_to_q(CLRLINE, ch->desc);  /* erase */
}

/* sets scroll to 0 21 and inits the menu bar at bottom of screen */
void init_vtbar(chdata *ch)
{
   if (IS_NPC(ch) || !ch->desc)
     return; 

   // default vtsplit is 21
   sprintf(buf, SCROLLAREA, 0, VTSPLIT(ch), VTSPLIT(ch), 0);  S2C();

   sprintf(buf, CURSPOS, VTSPLIT(ch) + 1, 0); S2C();
   send_to_char(BARLINE, ch);

   sprintf(buf, CURSPOS, VTSPLIT(ch) + 2, 0); S2C();
   sprintf(buf, "  %%6%s%%0                               ", longmudname);
   S2C();

   sprintf(buf, CURSPOS, VTSPLIT(ch) + 2 + PSIZE(ch), 0); S2C();
   send_to_char(BARLINE, ch);

   // now go back up top
   sprintf(buf, CURSPOS, VTSPLIT(ch), 0); S2C(); 
   return;
}

// takes row and column, moves cursor there
void cursor_goto(chdata *ch, int row, int col)
{
  if (ch->desc)
  {
   CURSOR_ROW(ch) = row;
   CURSOR_COL(ch) = col;
   sprintf(buf, CURSPOS, CURSOR_ROW(ch), CURSOR_COL(ch));
   send_to_q(buf, ch->desc);  // send actual string
  }
}

void send_to_vtbar(char *messg, chdata *ch)
{
  if (ch->desc && messg)
  {
   cursor_goto(ch, VTSPLIT(ch) + 2, 0);
   clrline(ch);
   send_to_q(messg, ch->desc);   /* send message */
   cursor_goto(ch, VTSPLIT(ch), 0);

   if (PLR_FLAGGED(ch, PLR_VTMAP))
     update_vtmap(ch);  // look in misc.c for now
  }
  return;
}

void updatescr(chdata *ch)
{
   static char pstr[MAX_INPUT_LENGTH];

   if (IS_NPC(ch) || IN_NOWHERE(ch)) return;
   *pstr = '\0';
   display_prompt(ch, pstr);
   send_to_vtbar(pstr, ch);
   ch->pc_specials->needs_update = FALSE;
}

/* this clears the screen and sets scroll back to norm */
void resetscr(chdata *ch)
{
   clrscr(ch);
   sprintf(buf, CLRSCROLLAREA, 0, VTSPLIT(ch) + 2 + PSIZE(ch));  S2C();
   return;
}

// Mapping code, jtrhone aka vall RoA
#define NOT_MAPPED	0
#define NOTHING_HERE	1
#define CHAR_HERE	2

/* following is for ascii mapping on RoA
   once again, innovations... James Rhone */
void map_room(int room, int ar[22][22], int xpos, int ypos, int depth,
	      chdata *ch, BOOL zone_only)
{
  int dir;

  /* are we at an edge ? */
  if (!room || xpos > (11+depth) || xpos < (11-depth) ||
      ypos > (11+depth) || ypos < (11-depth))
    return;

  if (room == ch->in_room)
    ar[xpos][ypos] = CHAR_HERE;
  else 
    ar[xpos][ypos] = NOTHING_HERE;

  /* now map all exits if not mapped already */
  /* primary 4 dirs */
  for (dir = 0; dir < 4; dir++)
  {
    if (DIR(room, dir) && !INVALID_ROOM(DIR(room, dir)->to_room))
    {
      if (zone_only && world[DIR(room, dir)->to_room].zone != world[room].zone)
	continue;

      switch (dir)
      {
	case 0: /* north */
	  if (!ar[xpos][ypos-1])
	    map_room(world[room].dir_option[dir]->to_room, 
	             ar, xpos, (ypos-1), depth, ch, zone_only);
	  break;
	case 1: /* east */
	  if (!ar[xpos+1][ypos])
	    map_room(world[room].dir_option[dir]->to_room, 
	             ar, (xpos+1), ypos, depth, ch, zone_only);
	  break;
	case 2: /* south */
	  if (!ar[xpos][ypos+1])
	    map_room(world[room].dir_option[dir]->to_room, 
	             ar, xpos, (ypos+1), depth, ch, zone_only);
	  break;
	case 3: /* west */
	  if (!ar[xpos-1][ypos])
	    map_room(world[room].dir_option[dir]->to_room, 
	             ar, (xpos-1), ypos, depth, ch, zone_only);
	  break;
      }
    }
  }  

  /* secondary 4 dirs */
  for (dir = 6; dir < 10; dir++)
  {
    if (DIR(room, dir) && !INVALID_ROOM(DIR(room, dir)->to_room))
    {
      if (zone_only && world[DIR(room, dir)->to_room].zone != world[room].zone)
	continue;

      switch (dir)
      {
	case 6: /* northeast */
	  if (!ar[xpos+1][ypos-1])
	    map_room(world[room].dir_option[dir]->to_room, 
	             ar, (xpos+1), (ypos-1), depth, ch, zone_only);
	  break;
	case 7: /* southeast */
	  if (!ar[xpos+1][ypos+1])
	    map_room(world[room].dir_option[dir]->to_room, 
	             ar, (xpos+1), (ypos+1), depth, ch, zone_only);
	  break;
	case 8: /* southwest */
	  if (!ar[xpos-1][ypos+1])
	    map_room(world[room].dir_option[dir]->to_room, 
	             ar, (xpos-1), (ypos+1), depth, ch, zone_only);
	  break;
	case 9: /* northwest */
	  if (!ar[xpos-1][ypos-1])
	    map_room(world[room].dir_option[dir]->to_room, 
	             ar, (xpos-1), (ypos-1), depth, ch, zone_only);
	  break;
      }
    }
  }  

  return;
}

/* 
  beta mapping stuff  RoA  James Rhone
*/
ACMD(do_map)
{  
  int depth, x, y;
  int ar[22][22];
  byte xleft, xright, ytop, ybottom;
  char arg2[MAX_INPUT_LENGTH];
  BOOL mark, zone_only;

  if (IS_NPC(ch)) return;

  half_chop(argument, arg, arg2);
  if (!*arg || !is_number(arg) || ((depth = atoi(arg)) < 2) || depth > 10)
  {
    send_to_char("Usage: map <depth between 2 and 10>.\n\r",ch);
    return;
  }

  if (*arg2 && is_abbrev(arg2, "zone"))
    zone_only = TRUE;
  else
    zone_only = FALSE;

  /* init array to 0 */
  for(y = 0; y < 22; y++)
    for(x = 0; x < 22; x++)
      ar[x][y] = 0;  

  map_room(ch->in_room, ar, 11, 11, depth, ch, zone_only);

  /* throw top line on map */
  strcpy(buf, "\n\n\r%B");
  for (x = 0; x < 2*depth+1; x++)
    strcat(buf, "-");
  strcat(buf, "%0\n\r");

   /* 
      ok, now for map, if we in the depth ranges of x and y
      go ahead and throw a char into the buf, else
      ignore and move on... James Rhone 
   */

   xright = 11+depth;
    xleft = 11-depth;
     ytop = 11-depth;
   ybottom= 11+depth;

  for(y = 0; y < 22; y++)
   if ((y <= ybottom) && (y >= ytop))  
   {
    for(x = 0, mark = FALSE; x < 22; x++)
     if ((x <= xright) && (x >= xleft))  
     {
      if (ar[x][y]) mark = TRUE;
      switch (ar[x][y])
      {
	case 0 : /* nothing here */
	  strcpy(buf2, " ");
	  break;
	case 1 : /* hey, its a normal room here */
	  strcpy(buf2, "=");
	  break;
	case 2 : /* ok, we got the mapper here.. */
	  strcpy(buf2, "%B*%0"); 
	  break;
      }
      strcat(buf, buf2);
     }
     if (mark)
      strcat(buf, "\n\r");
     else
      strcat(buf, "\r");
   }

  /* now for bottom line on it */
  strcat(buf, "%B");
  for (x = 0; x < 2*depth+1; x++)
     strcat(buf, "-");
  strcat(buf, "%0\n\r");
  S2C();
}


/* 
  KEWL STUFF, little vtmap up in the right corner for now :) -jtrhone roa
*/
void update_vtmap(chdata *ch)
{  
  int depth, x, y;
  int ar[22][22];
  byte xleft, xright, ytop, ybottom;
  BOOL mark;
  int row, col;

  if (IS_NPC(ch)) return;

  depth = 3;  // could be preference sometime

  /* init array to 0 */
  for(y = 0; y < 22; y++)
    for(x = 0; x < 22; x++)
      ar[x][y] = 0;  

  // send TRUE for zone_only by default until i make a FLAG for that
  // on characters
  map_room(ch->in_room, ar, 11, 11, depth, ch, TRUE);

  // init first row
  row = 2;
  col = 70;

   xright = 11+depth;
    xleft = 11-depth;
     ytop = 11-depth;
   ybottom= 11+depth;

  sprintf(buf, CURSPOS, row, col);
  strcat(buf, "%6---------%0");
  sprintf(buf2, CURSPOS, ++row, col);
  strcat(buf, buf2);

  for(y = 0; y < 22; y++)
   if ((y <= ybottom) && (y >= ytop))  
   {
    strcat(buf, "%6|%0");
    for(x = 0, mark = FALSE; x < 22; x++)
     if ((x <= xright) && (x >= xleft))  
     {
      if (ar[x][y]) mark = TRUE;
      switch (ar[x][y])
      {
	case 0 : /* nothing here */
	  strcpy(buf2, " ");
	  break;
	case 1 : /* hey, its a normal room here */
	  strcpy(buf2, "=");
	  break;
	case 2 : /* ok, we got the mapper here.. */
	  strcpy(buf2, "%B*%0"); 
	  break;
      }
      strcat(buf, buf2);
     }
     if (mark)
     {
      strcat(buf, "%6|%0");
      sprintf(buf2, CURSPOS, ++row, col);
      strcat(buf, buf2);
     }
     else
     {
      strcat(buf, "%6|%0");

      sprintf(buf2, CURSPOS, row, col);
      strcat(buf, buf2);

      strcat(buf, "        ");

      sprintf(buf2, CURSPOS, row, col);
      strcat(buf, buf2);
     }
   }

  strcat(buf, "%6---------%0");

  sprintf(buf2, CURSPOS, VTSPLIT(ch), 0);
  strcat(buf, buf2);

  S2C();
}

// toggle the vtmap on and off
ACMD(do_vtmap)
{
  if(IS_NPC(ch)) return;

  TOGGLE_BIT(PLR_FLAGS(ch), PLR_VTMAP);

  if (PLR_FLAGGED(ch, PLR_VTMAP))
    send_to_char("%5VTmap activated%0.\r\n", ch);
  else 
    send_to_char("%5VTmap deactivated%0.\r\n", ch);
}

ACMD(do_vt100)
{
   int size;

   if (IS_NPC(ch))
      return;

   one_argument(argument, arg);

   if (!*arg) {
      sprintf(buf, "VT100 emulation %s.\n\r",(VT100(ch)? "on":"off"));
      S2C();
      if (VT100(ch))
        sprintf(buf, "Current top screen size: %%5%d%%0 rows.\n\r", VTSPLIT(ch));
      return;
   }

   if (!is_number(arg) && str_cmp(arg, "+") && str_cmp(arg, "-"))
   {
      send_to_char ("Usage: vt100 {<number> | %B+%0 | %B-%0}\n\r", ch);
      return;
   }

   if (is_number(arg))
   {
     size = atoi(arg);
     if (size < 10 || size > 100)
     {
	send_to_char("Value must be range between 10 and 100.\n\r",ch);
	return;
     }
     VTSPLIT(ch) = size;
     clrscr(ch);
     sprintf(buf, "Top screen size changed to %%5%d%%0 rows.\n\r",size);
     S2C();
     return;
   }

   ch->pc_specials->saved.vt100 = FALSE;
   if (!str_cmp(arg, "+"))
   {
     SET_BIT(PRF_FLAGS(ch), PRF_COLOR);
     ch->pc_specials->saved.vt100 = TRUE;
     init_vtbar(ch);
   }

   if (!VT100(ch))
     resetscr(ch);
   
   sprintf (buf, "VT100 emulation is now %s.\n\r",(VT100(ch)? "on":"off"));
   S2C();
   if (VT100(ch))
   {
     sprintf(buf, "Current top screen size: %%5%d%%0 rows.\n\r", VTSPLIT(ch));
     S2C();
   }
}

ACMD(do_page_length)
{
  int len;
  char *argu = argument;

  skip_spaces(&argu);
  if (!*argu)
  {
    sprintf(buf, "Current page length: %%6%d%%0 lines.\n\r",PAGE_LENGTH(ch));
    S2C();
    return;
  }

  if (!is_number(argu))
  {
    send_to_char("Usage: pagelength < # of lines >.\n\r",ch);
    return;
  }

  len = atoi(argu);
  if (len < 15 || len > 40)
  {
    send_to_char("Page length must be between 15 and 40 lines.\n\r",ch);
    return;
  }

  PAGE_LENGTH(ch) = len;
  sprintf(buf, "Page length changed to %%6%d%%0 lines.\n\r",len);
  S2C();
}

// adjust both vt100 screen top size and lower menu size
ACMD(do_vtsize)
{
   int size;

   if (IS_NPC(ch))
      return;

   half_chop(argument, arg, buf2);

   if (!*arg) {
      send_to_char("Usage: vtsize <top # rows> <bottom # rows>\n\r",ch);
      sprintf(buf, "VT100 emulation currently %%5%s%%0.\n\r",
		(VT100(ch)?"on":"off"));
      S2C();

      if (VT100(ch))
      {
        sprintf(buf, "Current # of top rows: %%5%d%%0 rows.\n\r",
		VTSPLIT(ch));
	S2C();
        sprintf(buf, "Current # of bot rows: %%5%d%%0 lines.\n\r",
		PSIZE(ch));
	S2C();
      }
      return;
   }

   if (!is_number(arg))
   {
      send_to_char("Usage: vtsize <top # rows> <bottom # rows>\n\r",ch);
      return;
   }

   size = atoi(arg);
   if (size < 10 || size > 100)
   {
     send_to_char("Top must be between 10 - 100 lines.\n\r",ch);
     return;
   }
   VTSPLIT(ch) = size;

   if (*buf2)
   {
     if(!is_number(buf2))
     {
      send_to_char("Usage: vtsize <top # rows> <bottom # rows>\n\r",ch);
      return;
     }

     size = atoi(buf2);
     if (size < 1 || size > 10)
     {
       send_to_char("Bottom must be between 1 - 10 lines.\n\r",ch);
       return;
     }
     PSIZE(ch) = size;
   }

   clrscr(ch);

   if (VT100(ch))
   {
     sprintf(buf, "%%6%%BVT100%%0 resize: Top %d, Bottom %d.\n\r", VTSPLIT(ch),PSIZE(ch));
     S2C();
   }
}

/********************************************************/
/* The following is for interpreting COLOR strings      */
/* encoded %1 - %7 based on colors... uses basic prompt */
/* decoding... JTRHONE   ROA                            */
/********************************************************/

/* killp removes the % symbols from a string unless there is two consecutive
   symbols of such, such as %% in which ONE will remain in the string at that
   point.  This is used for people with color OFF so they can ignore the
   color code sequences that we (RoA) use. JTRHONE 

   NOTE: It also removes the character after the %   so for example %1 it would
   remove both the % and the 1 */
void killp(char *str)
{
  char *tmp1, *tmp2;

   for (tmp1 = str; *tmp1; tmp1++)
   {
    /* if double percentage, keep one of them */
    if (*tmp1 == '%' && (*(tmp1+1) && *(tmp1+1) == '%'))
    {
	for (tmp2 = tmp1 + 1; *tmp2; tmp2++)
	  *(tmp2 - 1) = *tmp2;
	*(tmp2 - 1) = '\0';      
      continue;
    }
    else
    while (*tmp1 == '%' && (*(tmp1+1) && *(tmp1+1) != '%'))
    {
	/* kill the percent */
	for (tmp2 = tmp1 + 1; *tmp2; tmp2++)
	  *(tmp2 - 1) = *tmp2;
	*(tmp2 - 1) = '\0';

	/* now kill what was after it */
	for (tmp2 = tmp1 + 1; *tmp2; tmp2++)
	  *(tmp2 - 1) = *tmp2;
	*(tmp2 - 1) = '\0';
    }
   }
}

// updated to return delta chars from newstr to oldstr
int color_decode(chdata *orig, char *pstr, char *newstr)
{
   char *pstring = pstr;
   chdata *ch;
   int cnt = 0;

   if(!*pstring) return 0;

   if (strlen(pstring) > MAX_STRING_LENGTH)
   {
      strcpy(newstr, "MaxLength EXCEEDED.  Notify VALL immediately.");
      return 0;
   }

   ch = (orig->desc && orig->desc->original) ? orig->desc->original : orig;

   if (IS_NPC(ch))
   {
     strcpy(newstr,pstr);
     return 0;
   } 
   
   if (!ANSI(ch))
   {
     strcpy(newstr, pstr);
     killp(newstr);
     return 0;
   }

   *newstr = '\0';
   while(*pstring) 
   {
      if(*pstring != '%') 
      {
         sprintf(newstr, "%s%c", newstr, *pstring);
         pstring++;
         continue;
      }
      pstring++;
      switch(*pstring) {
         case '%':
            strcat(newstr, "%");
            pstring++;
            cnt++;
            break;
/*
         case ']':
            strcat(newstr, KBLK);
            pstring++;
            break;
	 case 'r':
         case '}':
            strcat(newstr, KREV);
            pstring++;
            break;
         case '{':
            strcat(newstr, KCON);
            pstring++;
            break;
*/
	 case 'F':  /* faint? */
            strcat(newstr, KFAI);
            pstring++;
            break;
	 case 'I':  /* italics never happenin */
            strcat(newstr, KITA);
            pstring++;
            break;
         case 'B':
	 case 'b':  /* bold */
            strcat(newstr, KBLD);
            pstring++;
            cnt += strlen(KBLD);
            break;
         case '0':
            strcat(newstr, KNRM);
            pstring++;
            cnt += strlen(KNRM);
            break;
         case '1':
            strcat(newstr, KRED);
            pstring++;
            cnt += strlen(KRED);
            break;
         case '2':
            strcat(newstr, KGRN);
            pstring++;
            cnt += strlen(KGRN);
            break;
         case '3':
            strcat(newstr, KYEL);
	    pstring++;
            cnt += strlen(KYEL);
            break;
         case '4':
            strcat(newstr, KBLU);
            pstring++;
            cnt += strlen(KBLU);
            break;
         case '5':
            strcat(newstr, KMAG);
            pstring++;
            cnt += strlen(KMAG);
 	    break;
         case '6':
            strcat(newstr, KCYN);
            pstring++;
            cnt += strlen(KCYN);
            break;
         case '7':
            strcat(newstr, KWHT);
            pstring++;
            cnt += strlen(KWHT);
            break;
         case '8':  /* dark grey */
            strcat(newstr, KBLA);
            pstring++;
            cnt += strlen(KBLA);
            break;
         default:
            break;
      }
   }
   strcat(newstr, KNRM);
   return cnt;
}

ACMD(do_color)
{
   if (IS_NPC(ch))
      return;

   one_argument(argument, arg);

   if (!*arg) 
   {
      sprintf(buf, "Your color is %s.\n\r",(ANSI(ch)? "ON":"OFF"));
      send_to_char(buf, ch);
      return;
   }

   if (*arg != '+' && *arg != '-')
   {
      send_to_char ("Usage: color {+|-}\n\r", ch);
      return;
   }

   REMOVE_BIT(PRF_FLAGS(ch), PRF_COLOR);

   if (*arg == '+')
     SET_BIT(PRF_FLAGS(ch), PRF_COLOR);

   sprintf (buf, "Your %%6color%%0 is now %s.\n\r",(ANSI(ch)? "ON":"OFF"));
   S2C();
}