/*
 * Drop-in code that can replace any use of send_to_char
 * for dynamic room descriptions, character and object
 * descs, extra descs and anything else. Idea from a post
 * on kyndig.com: thought about, discarded, thought about
 * again, nagged by, forgotten, remembered and finally
 * coded in self defense to shut the little voice in my
 * head up.
 *
 * Requirements: OLC -or- the format_string function from
 * Ivan Toledo's OLC. Not really required, but won't look
 * nicely formatted without it.
 *
 * No credit required. Contact me if you have interesting
 * projects: imapopsyckle@hotmail.com. New coders welcome.
 * Queries of a below average IQ level amusingly mocked.
 *
 * Written for Rot 1.4, compatible with ROM with minor
 * changes to allow for small differences.
 */

/*
 * Notes:
 *
 * This supports room "taglines" much like HTML tags if
 * you've ever played with making webpages. They look like
 * this:
 * [#weather sunny: The sun shines on a field of flowers.]
 * [#sex male: A pretty barmaid winks at you as she goes about.]
 * [#wis > 16: You notice a sale on dresses in your size.]
 * [#name: The mirror shows your reflection $.]
 *
 * It is important to note that the operators can't really be
 * combined: I was just too lazy to go through the process of
 * determining how they combine and affect the outcome. If you
 * want something like 'wis >= 15', feel free to write it in.
 *
 * To Install:
 * Add this line to merc.h under the "/* act_info.c */" header:
 * void	tagline_to_char		args( ( const char *text, CHAR_DATA *ch ) );
 *
 * Drop the following function into act_info.c anywhere you
 * like. If you want to make your own taglines, there's a
 * section below marked for it, the format should be simple if
 * you have code experience. Now anywhere that send_to_char
 * is used to send players a description, such as do_look in the
 * act_info.c file, just replace send_to_char with this function.
 * This:    "send_to_char(ch->in_room->description, ch);"
 * To this: "tagline_to_char(ch->in_room->description, ch);"
 *
 * Other things might be sending extra descs to players, or
 * showing players' descriptions to each other. Your choice.
 * Examples and arguments are listed below the code.
 */

void tagline_to_char(const char *text, CHAR_DATA *ch)
{
    /* If it's an empty string, save some time. */
    if (strlen(text) <= 0)   { return; }

    char output[MAX_STRING_LENGTH];
    char tagline[MAX_STRING_LENGTH];
    char buf[MAX_STRING_LENGTH];
    char arg[256];
    char arg2[256];
    int value;

    bool bGo = FALSE;

    const char *desc;
    char *p_output = output;
    char *common;

    for (desc = text; *desc; desc++)
      {
       /* Reset. */
       bGo      = FALSE;
       value    = 0;

       if (*desc != '[')
         {  *p_output = *desc;
            *++p_output = '\0';
            continue;  }

       if (*++desc != '#')
         {  *p_output = *--desc;
            *++p_output = '\0';
            continue;  }

       /* Skip beginning '[#'. */
       ++desc;

       /* Read in the tag. */
       common = buf;
       while(*desc != ':')
         {
          if (*desc == '\0')
            { logf("Error: tag has no parser ':'. Room: %d.", ch->in_room->vnum);
              *common = *desc; break; }
          *common = *desc;
          *++common = '\0';
          ++desc;
         }

       /* Skip the colon and space ': '. */
       desc += 2;

       /* Read in the description. */
       common = tagline;
       while (*desc != ']')
         {
          if (*desc == '\0')
            { logf("Error: tag has no ending ']'. Room: %d.", ch->in_room->vnum);
              *common = *desc; break; }
          *common = *desc;
          *++common = '\0';
          ++desc;
         }

       /* Separate the arguments. */
       common = buf;
       common = one_argument(common, arg);
       common = one_argument(common, arg2);
       if (is_number(common)) { value = atoi(common); }
       else if (strlen(common) > 0)
         { logf("Tag in room %d is odd: %s %s %s.", ch->in_room->vnum, arg, arg2, common); }

       /*======[  Cases  ]======*/
       switch (UPPER(arg[0]))
         {
          case 'A':
            if (!str_cmp(arg, "age"))
              {
               if (value < 0) { bGo = FALSE; }
               else
                 { switch (arg2[0])
                     { case '>': if (get_age(ch) > value)    { bGo = TRUE; }; break;
                       case '<': if (get_age(ch) < value)    { bGo = TRUE; }; break;
                       case '=': if (get_age(ch) == value)   { bGo = TRUE; }; break;
                       default: bGo = FALSE; break; }
                 }
              }
            else if (!str_cmp(arg, "align") || !str_cmp(arg, "alignment"))
              {
               if (!str_cmp(arg2, "good") && (ch->alignment > 250))
                 { bGo = TRUE; }
               else if (!str_cmp(arg2, "evil") && (ch->alignment < -250))
                 { bGo = TRUE; }
               else if (!str_cmp(arg2, "nuetral") &&
                    ((ch->alignment < 250) && (ch->alignment > -250)) )
                 { bGo = TRUE; }
              }
            break;

          case 'C':
            if (!str_cmp(arg, "con"))
              { switch (arg2[0])
                  { case '>': if (get_curr_stat(ch, STAT_CON) > value)  { bGo = TRUE; }; break;
                    case '<': if (get_curr_stat(ch, STAT_CON) < value)  { bGo = TRUE; }; break;
                    case '=': if (get_curr_stat(ch, STAT_CON) == value) { bGo = TRUE; }; break;
                    default: bGo = FALSE; break; }  }
            else if (!str_cmp(arg, "class"))
              {  if (class_lookup(arg2) == ch->class)               { bGo = TRUE; }  }
            break;

          case 'D':
            if (!str_cmp(arg, "dex"))
              { switch (arg2[0])
                  { case '>': if (get_curr_stat(ch, STAT_DEX) > value)  { bGo = TRUE; }; break;
                    case '<': if (get_curr_stat(ch, STAT_DEX) < value)  { bGo = TRUE; }; break;
                    case '=': if (get_curr_stat(ch, STAT_DEX) == value) { bGo = TRUE; }; break;
                    default: bGo = FALSE; break; }  }
            else if (!str_cmp(arg, "day"))
              { switch (arg2[0])
                  { case '>': if (time_info.day > value)  { bGo = TRUE; }; break;
                    case '<': if (time_info.day < value)  { bGo = TRUE; }; break;
                    case '=': if (time_info.day == value) { bGo = TRUE; }; break;
                    default: bGo = FALSE; break; }  }
            break;

          case 'G':
            if (!str_cmp(arg, "gold"))
              {
               if (value < 0) { bGo = FALSE; }
               else
                 { switch (arg2[0])
                     { case '>': if (ch->gold > value)    { bGo = TRUE; }; break;
                       case '<': if (ch->gold < value)    { bGo = TRUE; }; break;
                       case '=': if (ch->gold == value)   { bGo = TRUE; }; break;
                       default: bGo = FALSE; break; }
                 }
              }
            break;

          case 'I':
            if (!str_cmp(arg, "int"))
              { switch (arg2[0])
                  { case '>': if (get_curr_stat(ch, STAT_INT) > value)  { bGo = TRUE; }; break;
                    case '<': if (get_curr_stat(ch, STAT_INT) < value)  { bGo = TRUE; }; break;
                    case '=': if (get_curr_stat(ch, STAT_INT) == value) { bGo = TRUE; }; break;
                    default: bGo = FALSE; break; }  }
            break;

          case 'L':
            if (!str_cmp(arg, "level"))
              {
               if (value < 1) { bGo = FALSE; }
               else
                 { switch (arg2[0])
                     { case '>': if (ch->level > value)    { bGo = TRUE; }; break;
                       case '<': if (ch->level < value)    { bGo = TRUE; }; break;
                       case '=': if (ch->level == value)   { bGo = TRUE; }; break;
                       default: bGo = FALSE; break; }
                 }
              }
            break;

          case 'M':
            if (!str_cmp(arg, "month"))
              {
               if (value < 1) { bGo = FALSE; }
               else
                 { switch (arg2[0])
                     { case '>': if (time_info.month > value)    { bGo = TRUE; }; break;
                       case '<': if (time_info.month < value)    { bGo = TRUE; }; break;
                       case '=': if (time_info.month == value)   { bGo = TRUE; }; break;
                       default: bGo = FALSE; break; }
                 }
              }
            break;

          case 'N':
            if (!str_cmp(arg, "name"))
              {
               bGo = TRUE;
               char p_name[128];
               common = buf;
               char *t = tagline;
               char *n;

               while (*t != '\0')
                 {
                  if (*t != '$')
                    {
                     *common = *t;
                     *++common = '\0';
                     ++t;
                     continue;
                    }

                  sprintf(p_name, "%s", ch->name);
                  n = p_name;

                  while (*n != '\0')
                    {
                     *common = *n;
                     *++common = '\0';
                     ++n;
                    }

                  ++t;
                 }

               sprintf(tagline, "%s", buf);
              }
            break;

          case 'P':
            if (!str_cmp(arg, "plat") || !str_cmp(arg, "platinum"))
              {
               if (value < 0) { bGo = FALSE; }
               else
                 { switch (arg2[0])
                     { case '>': if (ch->platinum > value)    { bGo = TRUE; }; break;
                       case '<': if (ch->platinum < value)    { bGo = TRUE; }; break;
                       case '=': if (ch->platinum == value)   { bGo = TRUE; }; break;
                       default: bGo = FALSE; break; }
                 }
              }
            break;

          case 'R':
            if (!str_cmp(arg, "race"))
              {  if (race_lookup(arg2) == ch->race)           { bGo = TRUE; }  }
            break;

          case 'S':
            if (!str_cmp(arg, "sex"))
              {  if (sex_lookup(arg2) == ch->sex)           { bGo = TRUE; } }
            else if (!str_cmp(arg, "silver"))
              {
               if (value < 0) { bGo = FALSE; }
               else
                 { switch (arg2[0])
                     { case '>': if (ch->silver > value)    { bGo = TRUE; }; break;
                       case '<': if (ch->silver < value)    { bGo = TRUE; }; break;
                       case '=': if (ch->silver == value)   { bGo = TRUE; }; break;
                       default: bGo = FALSE; break; }
                 }
              }
            else if (!str_cmp(arg, "str"))
              { switch (arg2[0])
                  { case '>': if (get_curr_stat(ch, STAT_STR) > value)  { bGo = TRUE; }; break;
                    case '<': if (get_curr_stat(ch, STAT_STR) < value)  { bGo = TRUE; }; break;
                    case '=': if (get_curr_stat(ch, STAT_STR) == value) { bGo = TRUE; }; break;
                    default: bGo = FALSE; break; }  }
            else if (!str_cmp(arg, "sun"))
              {
               if (!str_cmp(arg2, "sunrise") && (weather_info.sunlight == SUN_RISE))
                 { bGo = TRUE; }
               else if (!str_cmp(arg2, "sunset") && (weather_info.sunlight == SUN_SET))
                 { bGo = TRUE; }
               else if (!str_cmp(arg2, "day") && (weather_info.sunlight == SUN_LIGHT))
                 { bGo = TRUE; }
               else if (!str_cmp(arg2, "night") && (weather_info.sunlight == SUN_DARK))
                 { bGo = TRUE; }
              }
            break;

          case 'T':
            if (!str_cmp(arg, "time"))
              {
               if (value < 0 || value > 24)
                 { bGo = FALSE; }
               else
                 { switch (arg2[0])
                     { case '>': if (time_info.hour > value)    { bGo = TRUE; }; break;
                       case '<': if (time_info.hour < value)    { bGo = TRUE; }; break;
                       case '=': if (time_info.hour == value)   { bGo = TRUE; }; break;
                       default: bGo = FALSE; break; }
                 }
              }
            break;

          case 'W':
            if (!str_cmp(arg, "wis"))
              { switch (arg2[0])
                  { case '>': if (get_curr_stat(ch, STAT_WIS) > value)  { bGo = TRUE; }; break;
                    case '<': if (get_curr_stat(ch, STAT_WIS) < value)  { bGo = TRUE; }; break;
                    case '=': if (get_curr_stat(ch, STAT_WIS) == value) { bGo = TRUE; }; break;
                    default: bGo = FALSE; break; }  }
            else if (!str_cmp(arg, "weather"))
              {
               if (!str_cmp(arg2, "sunny") && (weather_info.sky == SKY_CLOUDLESS))
                 { bGo = TRUE; }
               else if (!str_cmp(arg2, "cloudy") && (weather_info.sky == SKY_CLOUDY))
                 { bGo = TRUE; }
               else if (!str_cmp(arg2, "rainy") && (weather_info.sky == SKY_RAINING))
                 { bGo = TRUE; }
               else if (!str_cmp(arg2, "lightning") && (weather_info.sky == SKY_LIGHTNING))
                 { bGo = TRUE; }
              }
            break;

          default:
            bGo = FALSE;
            break;
         }
       /*======[End Cases]======*/


       /* Copy in the tagline. */
       if (bGo == TRUE)
         {
          common = tagline;
          while (*common != '\0')
            {
             if (strlen(output) >= (MAX_STRING_LENGTH - 1)) {  break;  }

             *p_output = *common;
             ++common;
             *++p_output = '\0';
            }
         }
      }
   /* ^=--> End of for. */

    /* Send the whole thing to the player. */
       common = str_dup(strdup(output));
       common = format_string(common);
       send_to_char(common, ch);
       free_string(common);

 return;
}






/**********[ Examples ]**************

Rooms:
[#weather rainy: Rain drips from overhangings and clotheslines.]
[#weather lightning: Bolts of lightning periodically strike treetops.]
[#weather sunny: A mysterious figure shades their face from the sun beneath a cowl.]
[#wis > 14: You sense something unusual about the oakwood ahead.]
[#sex female: You catch several men staring at you with interest.]
[#name: Your guild is to the north $.]
[#time = 19: The sun is setting above the rooftops.]
[#class thief: Wealthy shoppers are practically begging to be robbed.]
[#class cleric: A crowd of cripples stare at you with desperate hope.]

Mobs:
[#int > 14: You notice rune tattoos on their skin.]
[#class warrior: It looks like a rough match-up with this creature.]
[#sex male: She doesn't look like the sweep-me-off-my-feet type.]
[#weather rainy: Rain cleans the filth from this troll's hide.]
[#align evil: This looks like your kind of rotten guy!]

Objects:
[#name: This degree is for $ as a Graduate of Mud School.]
[#str < 10: This sword appears too heavy for you to use effectively.]
[#weather sunny: Sunlight gleams off of the well polished mace head.]
[#name: A small tag on the side says 'Made for $'.]


Tag Name                        Usage
-----------                     ---------------
str                             [#str < 9: You're a weakling!]
int                             [#int > 15: You're a smart cookie.]
wis                             [#wis = 10: You're no wiser than normal.]
dex                             [#dex < 9: You stumble over your own feet.]
con                             [#con > 17: You've never been sick once.]
age                             [#age < 21: This bar is not open to minors.]
sun                             [#sun sunset: The sunset through the leaves is nice.]
time                            [#time > 19: Thieves come out with the night.]
day                             [#day = 20: Today is Ribbon Day!]
month                           [#month = 12: It is the depths of winter.]
weather                         [#weather rainy: Rain drips from the rooflines.]
plat                            [#plat < 2: Merchants sneer at your poor appearance.]
gold                            [#gold > 40: You draw the eye of every thief here.]
silver                          [#silver > 90: Beggars look at you hopefully.]
level                           [#level < 50: These creatures look too hard for you.]
sex                             [#sex female: The bartender hurries to fill your order.]
race                            [#race human: Humans are not welcome in the village.]
class                           [#class thief: The bodies of failed thieves rot here.]
align                           [#align evil: This place stinks of holiness.]
name                            [#name: Your guild is to the north $.]


Tag Name                        Arguments
------------                    --------------
All Stats                       >  <  =
Age                             >  <  =
Sun                             sunrise, sunset, day, night
Time                            >  <  =  (Time is in hours, from 1 - 24)
Day                             >  <  =  (There are 35 days to a month)
Month                           >  <  =  (There are 17 months in a year)
Weather                         sunny, cloudy, rainy, lightning
Platinum                        >  <  =
Gold                            >  <  =
Silver                          >  <  =
Level                           >  <  =
Alignment                       good, evil, nuetral
Sex                             male, female, none, either
Race                            (any race name you have)
Class                           (any class name you have)
Name                            (no arguments)


 ***********************************/