dotd-2.3.7/area/
dotd-2.3.7/clans/
dotd-2.3.7/classes/
dotd-2.3.7/councils/
dotd-2.3.7/deity/
dotd-2.3.7/dict/
dotd-2.3.7/doc/mudprogs/
dotd-2.3.7/player/a/
dotd-2.3.7/player/g/
/******************************************************
            Desolation of the Dragon MUD II
      (C) 1997-2002  Jesse DeFer
          http://www.dotd.com  dotd@dotd.com
 ******************************************************/

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

#include "mud.h"

static void free_variable(VARC_DATA *varc, VAR_DATA *var)
{
    if (var->name)
        DISPOSE(var->name);
    if (var->val)
        DISPOSE(var->val);
    UNLINK(var, varc->first_var, varc->last_var, next, prev);
    DISPOSE(var);
}

void free_variables(VARC_DATA *varc)
{
    VAR_DATA *var;

    if (!varc)
        return;

    while ((var = varc->first_var))
        free_variable(varc, var);

    DISPOSE(varc);
}

VAR_DATA *get_var(VARC_DATA *varc, char *name)
{
    VAR_DATA *var;

    if (!varc || !name || !*name)
        return NULL;

    for (var = varc->first_var; var; var = var->next)
        if (!str_cmp(var->name, name))
            return var;

    return NULL;
}

char *get_var_val(VARC_DATA *varc, char *name)
{
    VAR_DATA *var;

    if (!varc || !name || !*name)
        return NULL;

    for (var = varc->first_var; var; var = var->next)
        if (!str_cmp(var->name, name))
            return var->val;

    return NULL;
}

char *get_var_val_ch(CHAR_DATA *ch, char *name)
{
    static char sbuf[MAX_INPUT_LENGTH];

    if (!ch || !name || !*name)
        return NULL;

    if ( *name == '_' )
    {
        switch (LOWER(*name+1))
        {
        case 'e':
            if (!str_cmp(name, "_exp")) sprintf(sbuf, "%d", GET_EXP(ch));
            break;
        case 'i':
            if (!str_cmp(name, "_idle"))
            {
                if (IS_NPC(ch) || !ch->desc)
                    sprintf(sbuf, "%d", 0);
                else
                    sprintf(sbuf, "%d", ch->desc->idle);
            }
            break;
        case 'g':
            if (!str_cmp(name, "_gold")) sprintf(sbuf, "%d", GET_MONEY(ch, CURR_GOLD));
            break;
        case 'm':
            if (!str_cmp(name, "_master"))
            {
                if (ch->master)
                    sprintf(sbuf, "%s", GET_NAME(ch->master));
                else
                    strcpy(sbuf, "");
            }
            break;
        default:
            return NULL;
            break;
        }
    }

    return get_var_val(ch->vars, name);
}

char *get_var_val_obj(OBJ_DATA *obj, char *name)
{
//    static char sbuf[MAX_INPUT_LENGTH];

    if (!obj || !name || !*name)
        return NULL;

    if ( *name == '_' )
    {
        switch (LOWER(*name+1))
        {
        default:
            return NULL;
            break;
        }
    }

    return get_var_val(obj->vars, name);
}

int get_var_val_int(VARC_DATA *varc, char *name)
{
    char *val = get_var_val(varc, name);

    if (val)
        return atoi(val);

    return 0;
}

int get_var_val_int_ch(CHAR_DATA *ch, char *name)
{
    char *val = get_var_val_ch(ch, name);

    if (val)
        return atoi(val);

    return 0;
}

int get_var_val_int_obj(OBJ_DATA *obj, char *name)
{
    char *val = get_var_val_obj(obj, name);

    if (val)
        return atoi(val);

    return 0;
}

static VAR_DATA *new_var(VARC_DATA **varc, char *name, char *val)
{
    VAR_DATA *var;
    char vname[MAX_VAR_NAME_LEN];
    unsigned int x;
    int y = 0;

    if (!name || !*name)
        return NULL;

    if (!*varc)
    {
        CREATE((*varc), VARC_DATA, 1);
        (*varc)->first_var = NULL;
        (*varc)->last_var = NULL;
    }

    CREATE(var, VAR_DATA, 1);
    LINK(var, (*varc)->first_var, (*varc)->last_var, next, prev);

    for (x = 0; x < strlen(name) && x < MAX_VAR_NAME_LEN-1; x++)
        if (isalnum(name[x]) || name[x] == '_')
            vname[y++] = name[x];
    vname[y] = '\0';

    if (vname[0] == '\0')
    {
        free_variable((*varc), var);
        return NULL;
    }

    var->name = str_dup(vname);
    if (val)
        var->val = str_dup(val);

    return var;
}

void set_var(VARC_DATA **varc, char *name, char *val)
{
    VAR_DATA *var, *var2 = NULL;
    char *nval;

    if (!*varc)
        CREATE(*varc, VARC_DATA, 1);

    if (val[0] == '%' && (var2 = get_var((*varc), val+1)))
        nval = var2->val;
    else
        nval = val;

    if (!(var = get_var((*varc), name)))
    {
        if (!(var = new_var(varc, name, nval)))
            return;
        if (str_cmp(var->name, name))
            bug("set_var: NOTE: var '%s' renamed to '%s'", name, var->name);
        return;
    }

    if (var->val)
        DISPOSE(var->val);

    if (nval)
        var->val = str_dup(nval);
}

void set_var_int(VARC_DATA **varc, char *name, int val)
{
    char buf[16];
    sprintf(buf, "%d", val);
    set_var(varc, name, buf);
}

void modify_var(VARC_DATA **varc, char *name, char *modstr)
{
    VAR_DATA *var;
    int value;

    if (!modstr || !*modstr)
        return;

    if (!(var = get_var((*varc), name)))
        return;

    value = atoi(var->val);
    value += dice_parse(NULL, value, modstr);

    set_var_int(varc, name, value);
}

void del_var(VARC_DATA *varc, char *name)
{
    VAR_DATA *var;

    if ((var = get_var(varc, name)))
        free_variable(varc, var);
}

int check_var_equals(VARC_DATA *varc, char *name, char *compareval)
{
    VAR_DATA *var;

    if (!(var = get_var(varc, name)))
        return 0;

    if (!str_cmp(var->val, compareval))
        return 1;

    return 0;
}

char *expand_variables(char *str, CHAR_DATA *ch)
{
    static char outbuf[MAX_STRING_LENGTH];
    char word[MAX_INPUT_LENGTH], varname[MAX_INPUT_LENGTH];
    char *point = outbuf, *origstr = str, *t;
    CHAR_DATA *vch = ch;

    if (!ch)
        return origstr;

    while (*str != '\0')
    {
        if ( *str != '%' && *str != '#' )
        {
            *point++ = *str++;
            continue;
        }

        str = one_argument(str, word);

        t = one_argumentx(word, varname, '(');

        if (varname[0] == '\0' || varname[1] == '\0')
        {
            bug("expand_variables: zero length variable name");
            return origstr;
        }

        if (*t != '\0')
        {
            if (t[strlen(t)-1] == ')')
                t[strlen(t)-1] = '\0';
            else
            {
                bug("expand_variables: missing )");
                return origstr;
            }

            if (!(vch = get_char_world(ch, t)))
            {
                bug("expand_variables: %s not found", t);
                return origstr;
            }
        }
        else
        {
            bug("expand_variables: extra (");
            return origstr;
        }

        if (!(t = get_var_val(vch->vars, &varname[1])))
        {
            bug("expand_variables: variable %s not found on %s", varname, GET_NAME(vch));
            return origstr;
        }

        while (*t != '\0')
            *point++ = *t++;
        *point++ = ' ';
    }
    *point = '\0';

    return outbuf;
}

void fwrite_variables(VARC_DATA *varc, FILE *fp)
{
    VAR_DATA *var;

    if (!varc || !varc->first_var)
        return;

    for (var = varc->first_var; var; var = var->next)
        fprintf(fp,
                "#VARIABLE\n"
                "Name         %s~\n"
                "Value        %s~\n"
                "End\n\n",
                var->name, var->val?var->val:"");
}

void fread_variable(VARC_DATA **varc, FILE *fp)
{
    VAR_DATA *var = NULL;
    const char *word;
    char *str;
    bool fMatch;

    for ( ; ; )
    {
        word   = feof( fp ) ? "End" : fread_word( fp );
        fMatch = FALSE;

        switch ( UPPER(word[0]) )
        {
        case '*':
            fMatch = TRUE;
            fread_to_eol( fp );
            break;
        case 'E':
            if ( !str_cmp( word, "End" ) )
                return;
            break;
        case 'N':
            if ( !str_cmp( word, "Name" ) )
            {
                str = fread_string_nohash(fp);
                var = new_var(varc, str, NULL);
                DISPOSE(str);
                fMatch = TRUE;
                break;
            }
            break;
        case 'V':
            if ( !str_cmp( word, "Value" ) )
            {
                str = fread_string_nohash(fp);
                if (var)
                    set_var(varc, var->name, str);
                else
                    bug("Fread_variable: value without name");
                DISPOSE(str);
                fMatch = TRUE;
                break;
            }
            break;
        }

        if ( !fMatch )
        {
            bug( "Fread_variable: no match: %s", word );
            fread_to_eol(fp);
        }
    }
}

void print_variables(CHAR_DATA *ch, VARC_DATA *varc)
{
    VAR_DATA *var;
    int icnt=0;

    if (!varc || !varc->first_var)
    {
        send_to_char("No variables.\n\r", ch);
        return;
    }

    pager_printf(ch, "%-20s %s\n\r", "[Name]", "[Value]");
    for (var = varc->first_var; var; var = var->next)
    {
        pager_printf(ch, "%-20s %s\n\r",
                     var->name, var->val);
        icnt++;
    }
    pager_printf(ch, "%d variables.\n\r", icnt);
}

void do_variables(CHAR_DATA *ch, char *argument)
{
    char arg[MAX_INPUT_LENGTH];
    CHAR_DATA *vch = NULL;
    OBJ_DATA *obj = NULL;
    VARC_DATA *varc;
    VAR_DATA *var;

    if (!argument || !*argument)
    {
        send_to_char("Usage:\n\r"
                     "  variables <char|obj>\n\r"
                     "  variables <char|obj> del <name>\n\r"
                     "  variables <char|obj> set <name> [value]\n\r"
                     "  variables <char|obj> mod <name> [modstr]\n\r",
                     ch);
        return;
    }

    argument = one_argument(argument, arg);

    if (!(vch = get_char_world(ch, arg)))
    {
        if (!(obj = get_obj_world(ch, arg)))
        {
            send_to_char("Can't find that.\n\r", ch);
            return;
        }
        varc = obj->vars;
    }
    else
        varc = vch->vars;

    if (!*argument)
    {
        print_variables(ch, varc);
        return;
    }

    argument = one_argument(argument, arg);

    if (!str_cmp(arg, "del"))
    {
        if (!varc || !varc->first_var)
        {
            send_to_char("No variables to delete.\n\r", ch);
            return;
        }

        if (!(var = get_var(varc, argument)))
        {
            send_to_char("Can't find that variable.\n\r", ch);
            return;
        }

        del_var(varc, argument);

        send_to_char("Ok.\n\r", ch);
        return;
    }

    if (!str_cmp(arg, "set"))
    {
        argument = one_argument(argument, arg);

        if (arg[0] == '\0')
        {
            send_to_char("Variables must have a name.\n\r", ch);
            return;
        }

        if (!varc)
        {
            if (vch)
            {
                CREATE(vch->vars, VARC_DATA, 1);
                varc = vch->vars;
            }
            else if (obj)
            {
                CREATE(obj->vars, VARC_DATA, 1);
                varc = obj->vars;
            }
        }

        set_var(&varc, arg, argument);

        send_to_char("Ok.\n\r", ch);
        return;
    }

    if (!str_cmp(arg, "mod"))
    {
        if (!varc || !varc->first_var)
        {
            send_to_char("No variables to modify.\n\r", ch);
            return;
        }

        argument = one_argument(argument, arg);

        if (!argument || !*argument)
        {
            send_to_char("Modify it how?\n\r", ch);
            return;
        }

        if (!(var = get_var(varc, arg)))
        {
            send_to_char("Can't find that variable.\n\r", ch);
            return;
        }

        modify_var(&varc, arg, argument);

        send_to_char("Ok.\n\r", ch);
        return;
    }

    do_variables(ch, NULL);

}