inherit "std/object";
#define HOME "/obj/handlers/weather_room"
/*
 * ok format...
 * name ({ your st, everyone st })
 * or (one arg version ie sigh)
 * name ({ your st, their st, everyone st })
 * or (two only arg version.)
 * name ({ your st, everyone st, arg st, their arg, everyone arg })
 * or (one or two arg version)
 * name ({ ({ as above }), ({ as above }) })
 * for cases where the male and female versions are different.
 * works on targets gender. should really be the two arg only version.
 * hmmm going to need some actual processing.
 *
 * 0 == search for living name
 * 1 == search for living name and change thingy
 * 2 == search for change thingy and living name
 * 3 == search for change thingy
 */
mapping soul_data;
string  lastarg, calc_long, global_adj;
mapping query_soul_data() { return soul_data + ([ ]); }
void create() 
{
    ::create();
    set_name("soul");
    set_short(0);
    calc_long = 0;
    lastarg = "";
    // Taniwha 1995, move it here, players can't pick it up
    catch(load_object(HOME));
    call_out("move",2,HOME);
#include "/obj/handlers/soul_data.c"
}
string query_long() 
{
    int i;
    string s, s1, s2, bit;
    string *cmds;
    mixed  *values;
    s = "Here are the current soul commands in this hoopy soul.\n"
    "The # before a soul command means it has strange arguments.\n"
    "The * after a soul command means you can only use it at someone.\n"
    "Total number of soul data is "+m_sizeof(soul_data)+"\n"
    "The + after a soul command means you can use it both at someone and "
    "not.\n";
    if (stringp(calc_long)) 
    {
        s += sprintf("%#-*s\n", this_player()->query_cols(), calc_long);
        s += "\nShare and enjoy.\nPlease use the \"soul\" command "
        "to report errors and additions.\n";
        return s; 
    }
    cmds   = m_indices(soul_data);
    values = m_values(soul_data);
    calc_long = "";
    cmds = sort_array(cmds, 1);
    for (i = 0; i < sizeof(cmds);i ++) 
    {
        bit = cmds[i];
        values = soul_data[bit];
        if (sizeof(values[1]) == 3) 
            bit += "*";
        else if (sizeof(values[1]) == 5) 
            bit += "+";
        if (sscanf(values[1][0],"%s$arg:%s",s1,s2) == 2)
            bit = "#"+bit;
        calc_long += bit+"\n";
    }
    s += sprintf("%#-*s\n", this_player()->query_cols(), calc_long);
    s += "\nShare and enjoy.\nPlease use the \"soul\" command "
    "to report errors and additions.\n";
    return s;
}
int soul_sort(string s1, string s2) 
{
    return s1 > s2;
}
string long(string str, int dark) 
{
    return query_long();
}
//string parse_string(string s, object me, object ob, string arg, int uhn)
string parse_string(string s, object me, mixed ob, string arg, int uhn)
{
    string s1, s2, s3, s4, str, s5;
    int i;
    str=s;
    s4 = "";
    while (sscanf(str,"%s$%s$%s",s1,s2,s3) == 3)
        switch (s2) 
    {
    case "mcname" :
        str = s1+me->query_cap_name()+s3;
        break;
    case "mname" :
        str = s1+me->query_name()+s3;
        break;
    case "mpronoun" :
        str = s1+me->query_pronoun()+s3;
        break;
    case "hpronoun" :
        str = s1+ob->query_pronoun()+s3;
        break;
    case "mobj" :
        str = s1+me->query_objective()+s3;
        break;
    case "hobj" :
        str = s1+ob->query_objective()+s3;
        break;
    case "mposs" :
        str = s1+me->query_possessive()+s3;
        break;
    case "hposs" :
        str = s1+ob->query_possessive()+s3;
        break;
    case "lastarg" :
        str = s1+lastarg+s3;
        break;
    case "mhcname" :
        if (uhn) 
        {
            str = s1+ob->query_cap_name()+"'s"+s3;
            break;
        }
    case "hcname" :
        if (uhn) 
        {
            str = s1+ob->query_cap_name()+s3;
            break;
        }
    case "hname" :
        if (uhn) 
        {
            str = s1+ob->query_name()+s3;
            break;
        }
    default :
        s4 += s1+"$"+s2;
        if (!s3)
            str = "$";
        else
            str = "$"+s3;
        break;
    }
    str = s4+str;
    while (sscanf(str,"%s$force#%s#%d$%s",s1,s2,i,s3)==4) 
    {
        call_out("do_force", i, ({s2, ob}));
        str = s1+s3;
    }
    while (sscanf(str,"%s$arg:%s$%s",s1,s2,s3)==3) 
        if (arg == "?") 
        {
            string *yellow;
            yellow = explode(s2, ",");
            lastarg = yellow[random(sizeof(yellow))];
            str = s1+lastarg+s3;
            lastarg = replace(lastarg, "your", me->query_possessive());
        } 
        else if (s2 == "#") 
        {
            lastarg = replace(arg, "your", me->query_possessive());
            str = s1+arg+s3;
        } 
        else if (sscanf(","+s2+global_adj+",", "%s,"+arg+"%s,%s", s2, s4, s5) == 3) 
        {
            str = s1+arg+s4+s3;
            lastarg = replace(arg+s4, "your", me->query_possessive());
        } 
        else if (sscanf(","+s2+",", "%s,#,%s", s2, s4) == 2) 
        {
            str = s1+arg+s3;
            lastarg = replace(arg, "your", me->query_possessive());
        } 
        else 
        {
            // Cadogan by hand of Radix...
            write("You cannot do that.  Type \"help <soul>\" for "
              "available options.\n");
            //    write("You cannot do that. Available options are "+
            //      replace(s2, ",", ", ")+"\n");
            return 0;
        }
    while (sscanf(str,"%s$ifarg:%s~$%s",s1,s2,s3)==3) 
    {
        string estr;
        sscanf(s2,"%s$else$%s",s2,estr);
        if (arg && arg != "")
            str = s1+parse_string(s2,me,ob,arg, 1)+s3;
        else if (estr)
            str = s1+parse_string(estr,me,ob,arg, 1)+s3;
        else
            str = s1+s3;
    }
    return str;
}
object* find_all_liv(string str, object me) 
{
    mixed ob; 
    object *ret;
    int i;
    ret = ({ });
    str = lower_case(str);
    /* Wonder how the players will like this one, the thieves surely will..
     * removing the pssibility to soul all in a room
     * Baldrick, jan '95 (Hmm.. this years first change..:=)
     */
    if (str == "all" || str[0..0] == "0")
    {
        notify_fail("Sorry, you don't know all.\n");
        return 0;
    } 
    if (str == "someone") 
    {
        // Radix was, was a random() return of users() array
        // Wonderflug, it is again.  But we filter invisibles
        ret = users();
        for (i=0;i<sizeof(ret);i++)
            if ( ret[i]->query_invis() )
                ret = delete(ret, i--, 1);
        return ({ ret[random(sizeof(ret))] });
    }
    ob = find_match(str, environment(me), 1);
    for (i=0;i<sizeof(ob);i++)
        if ( living(ob[i]) && ob[i] != me
          && member_array(ob[i], ret) == -1)
            ret += ({ ob[i] });
    if (sizeof(ret)) 
        return ret;
    /* Will add an attemt to hide invis people in the room 
     * Baldrick, dec '94
     * Fixed above attempt, Wonderflug oct '95
     */
    if ( (ob = find_living(str)) && ob != me
      && ( !ob->query_invis() || me->query_creator() )
    )
        ret = ({ ob });
    return ret;
} /* find_all_liv() */
string get_name(object ob) 
{
    return (string)ob->query_cap_name();
}
int soul_command(string verb, string str, object m)
{
    int i, j, lvl;
    //object *ob, *tmp_ob;
    mixed ob, tmp_ob;
    object me;
    string tmp, last, liv, other, s1, s2, livfail;
    mixed  *data;
    /* set up whoever is doing this soul */
    if ( m )
        me = m;
    else if ( previous_object() )
        me = previous_object();
    else 
        me = this_player();
    lastarg = "";
    ob = ({ });
    if ( !verb )
        return 0;
    data = soul_data[verb];
    if (!data) 
        return 0;
    if (str && sizeof(data[1]) == 2 && data[1][0] != '#') 
        notify_fail("No matter how hard you try, you fail to manage this.\n");
    /* this if/else/for/switch parses the string passed by the player into 
     * object bits and string bits, according to how the specific soul
     * expects the string.  each pair of elements in data[0] represents
     * a different way of parsing things
     */
    if (!data[0] || !str) 
    {
        liv = 0;
        other = "";
    } 
    else 
        for (j = 0; j < sizeof(data[0]); j += 2)
            switch (data[0][j]) 
        {
        case 0 :
            if (lvl > 1)
                break;
            if (sscanf(str, data[0][j+1], s1)==1
              && (sizeof((tmp_ob=find_all_liv(s1, me))))) 
            {
                lvl = 1;
                other = "";
                liv = s1;
                ob = tmp_ob;
            } 
            else
                livfail = s1;
            break;
        case 1 :
            if (lvl > 2)
                break;
            if (sscanf(str, data[0][j+1], s1, s2)==2
              && (sizeof((tmp_ob=find_all_liv(s2, me))))) 
            {
                lvl = 2;
                liv = s2;
                other = s1;
                if (data[0][j+1] != "%s %s")
                    lvl++;
                ob = tmp_ob;
            } 
            else
                livfail = s2;
            break;
        case 2 :
            if (lvl > 2)
                break;
            if (sscanf(str, data[0][j+1], s1, s2) ==2
              && (sizeof((tmp_ob=find_all_liv(s1, me))))) 
            {
                lvl = 2;
                liv = s1;
                other = s2;
                if (data[0][j+1] != "%s %s")
                    lvl++;
                ob = tmp_ob;
            } 
            else
                livfail = s2;
            break;
        case 3 :
            if (lvl > 0)
                break;
            if (sscanf(str, data[0][j+1], s1) == 1) 
            {
                other = s1;
                liv = 0;
                ob = ({ });
            }
            break;
        }
    if (liv) 
    {
        /* The soul has been directed at someone.  The string of someone's
         * is now in liv; ob may be an array of objects corresponding to them.
         * Extra stuff they typed is in other.
         */
        string mine, his, every;
        str = other;
        if (!sizeof(ob)) 
        {
            notify_fail("Sorry, but '"+liv+"' is not logged in.\n");
            return 0;
        }
        /* Get the strings that will be parsed. */
        if (sizeof(data[1])==3) 
        {
            mine = data[1][0];
            his = data[1][1];
            every = data[1][2];
        } 
        else if (sizeof(data[1])==5) 
        {
            mine = data[1][2];
            his = data[1][3];
            every = data[1][4];
        } 
        else 
        {
            notify_fail("You cannot use that soul command in two thingy mode.\n");
            return 0;
        }
        if (sizeof(ob) == 1) 
        {
            tmp = parse_string(mine, me, ob[0], str, 1);
            if (!tmp)
                return 1;
            s2 = parse_string(every, me, ob[0], str, 1);
            /* Now do various events. */
            /* To me */
            me->event_soul(me, tmp+".\n");
            /* To him */
            ob[0]->event_soul(me, 
              parse_string(his, me, ob[0], str, 1)+".\n");
            if(ob[0]->query_npc())
                ob[0]->soul_act(me, query_verb());
            /* This is undefined by almost everything.  I fail to see any use. 
             * So it goes.  Wonderflug
             * ob[0]->event_soul_command(this_object(), verb, me, liv, other);
             */
            /* To everyone in the room. */
            event(environment(me), "soul", s2+".\n",
              ({ ob[0], me }), verb, last, ob[0]);
            /* To everyone if its a far-soul AND target is not hidden */
            if (environment(ob[0]) && environment(ob[0]) != environment(me)
              && !ob[0]->query_invis() && !ob[0]->query_hide_shadow() )
                event(environment(ob[0]), "soul", s2+".\n",
                  ({ ob[0], me }), verb, last, ob[0]);
        } 
        else 
        {
            tmp = parse_string(mine, me, ob, str, 0);
            if (!tmp)
                return 1;
            parse_string(his, me, ob, str, 0); /* To get the forces */
            s2 = parse_string(every, me, ob, str, 0);
            tmp_ob = map_array(ob, "get_name", this_object());
            s1 = implode(tmp_ob[1..1000], ", ")+" and "+tmp_ob[0];
            s1 = replace(s2, ({ "$hcname$", s1, "$mhcname$", s1+"'s" }));
            me->event_soul(me, s1+".\n");
            /* This goes away, Wonderflug
             *if ((int)this_player()->query_social_points() < sizeof(ob)*3) 
             *{
             *  notify_fail("Not enough social points.\n");
             *  return 0;
             *}
             *this_player()->adjust_social_points(-sizeof(ob)*3);
             */
            event(environment(ob[0]), "soul", s1+".\n", 
              ({ me })+ob, verb, last, ob);
            for (i=0;i<sizeof(ob);i++)
                ob[i]->event_soul(me, 
                  replace(s2, 
                    ({ "$hcname$", 
                      implode(tmp_ob - ({ get_name(ob[i])}),", ")+" and you",
                      "$mhcname$", 
                      implode(tmp_ob - ({ get_name(ob[i])}),", ")+" and your",
                    }))+ ".\n" );
        } /* else .. sizeof(ob) != 1 */
        return 1;
    } /* if (liv) */
    else if (sizeof(data[1])==3) 
    {
        if (!livfail)
            notify_fail("You don't have the courage to do that.\n");
        else
            notify_fail("Cannot find '"+livfail+"'.\n");
        return 0;
    }
    if (!other)
        other = "";
    tmp = parse_string(data[1][0], me, ob, other, 0);
    if (!tmp)
        return 1;
    me->event_soul(me, tmp+".\n");
    event(environment(me), "soul",
      parse_string(data[1][1], me, me, other, 0)+".\n",
      ({ me }), verb, last, 0);
    return 1;
}
void do_force(mixed* str)
{
    int i;
    if (pointerp(str[1]))
        for (i=0;i<sizeof(str[1]);i++)
            str[1][i]->soul_com_force(str[0]);
    else
        str[1]->soul_com_force(str[0]);
}
void add_soul_command(string name, mixed format, mixed thingo) 
{
    if (soul_data[name]) 
        return;
    if (format && !pointerp(format))
        return ;
    if (!stringp(name) || !pointerp(thingo)
      || member_array( sizeof(thingo), ({ 2, 3, 5 }) ) == -1 )
        return ;
    soul_data[name] = ({ format, thingo });
}
string query_soul_command(string name)
  {
  return (soul_data[name]);
}
int query_soul_command_exist(string name)
  {
  if (soul_data[name])
    return 1;
   else
    return 0;
}
void delete_soul_command(string name) 
{
    soul_data = m_delete(soul_data, name);
}
string help_soul(string str) 
{
    int j, off;
    string s1, s2, s3, ret, *bit;
    mixed *data;
    data = soul_data[str];
    if (!data) 
        return 0;
    ret = "";
    if (!pointerp(data[0])) 
        return "The soul command "+str+" has no optional parameters at all.\n";
    for (j = 0; j < sizeof(data[0]);j += 2) 
    {
        bit = explode(" " + data[0][j+1]+" ","%s");
        switch (data[0][j]) 
        {
        case 0: 
            ret += str+bit[0]+"<person>"+bit[1];
            break;
        case 2:
            ret += str+bit[0]+"<person>"+bit[1]+"<argument>"+bit[2];
            break;
        case 1:
            ret += str+bit[0]+"<argument>"+bit[1]+"<person>"+bit[2];
            break;
        case 3:
            ret += str+bit[0]+"<argument>"+bit[1];
            break;
        }
        ret += "\n";
    }
    ret += "Usage of the soul command "+str+"\n"+
    sprintf("%-#*s\n\n\n", this_player()->query_cols(), ret);
    if (sizeof(data[1]) == 2 || sizeof(data[1]) == 5) 
    {
        ret += "In no living object mode.\n";
        bit = ({ });
        if (sscanf(data[1][0], "%s$arg:%s$%s", s1,s2,s3) == 3)
            bit = explode(s2,",");
        if (sscanf(data[1][0], "%s$ifarg:%s~$%s", s1, s2, s3) == 3) 
            ret += "Has a different no arguments command.\n"
            "The arguments are selected from "+implode(bit,", ")+"\n";
        else if (!sizeof(bit))
            ret += "Has no cute arguments\n";
        else
            ret += "Has cute arguments of "+implode(bit,", ")+"\n";
        ret += "\n\n";
        off = 2;
    }
    if (sizeof(data[1]) == 3 || sizeof(data[1]) == 5) 
    {
        ret += "In living object mode\n";
        bit = ({ });
        if (sscanf(data[1][off+0], "%s$arg:%s$%s", s1,s2,s3) == 3)
            bit = explode(s2,",");
        if (sscanf(data[1][off+0], "%s$ifarg:%s~$%s", s1, s2, s3) == 3) 
            ret += "Has a different no arguments command.\n"
            "The arguments are selected from "+implode(bit,", ")+"\n";
        else if (!sizeof(bit))
            ret += "Has no cute arguments\n";
        else
            ret += "Has cute arguments of "+implode(bit,", ")+"\n";
        off = 2;
    }
    return ret;
}