musicmud-2.1.6/data/
musicmud-2.1.6/data/help/
musicmud-2.1.6/data/policy/
musicmud-2.1.6/data/wild/
musicmud-2.1.6/data/world/
musicmud-2.1.6/doc/
musicmud-2.1.6/src/ident/
musicmud-2.1.6/src/lua/
musicmud-2.1.6/src/lua/include/
musicmud-2.1.6/src/lua/src/lib/
musicmud-2.1.6/src/lua/src/lua/
musicmud-2.1.6/src/lua/src/luac/
/* 
 * MusicMUD - Rooms module
 * Copyright (C) 1998-2003 Abigail Brady
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 * 
 */


#include <ctype.h>

#include "events.h"
#include "musicmud.h"
#include "misc.h"
#include "util.h"
#include "verbs.h"
#include "trap.h"
#include "rooms.h"
#include "pflags.h"
#include "paths.h"
#include "shared.h"
#include "zoneload.h"
#include "move.h"
#include "pos.h"

#define WIERD get_wierd()

#define MODULE "rooms"

static bool numeric(const char *what) {
    while (*what) {
	if (!isdigit(*what)) return false;
	what++;
    }
    return true;
}

static bool verb_gotoin(MudObject *player, int argc, const char*argv[]) {
    if (player->get_flag(FL_SLEEPING)) {
        player->printf("You toss and turn in your sleep.\n");
        player->oprintf(cansee, "%#M tosses and turns in %s sleep.\n", player, his_or_her(player));
        return true;
    }
    MudObject *dest = 0;
    MudObject *old = player->owner;

    if (argc >= 2) {
      string a1 = argv[1];
      dest = find_object(player, a1.c_str());
      string name;

      if (player->owner && (!dest || numeric(a1.c_str()))) {
	const char *z3 = player->owner->id;
	if (z3 && strchr(z3, '_')) {
	  z3 = strdup(z3);
	  *strchr(z3, '_')=0;
	} else {
          const char *z4 = player->owner->get("zone");
          if (!z4) {
	    goto argh;
          }
          z3 = strdup(z4);
        }
	name = z3;
	name += "_";
	name += a1;
        dest = planet->get(name.c_str());
	strfree(z3);
      }
    } else {
      dest = player->get_object("start");
      if (!dest) {
	MudObject *df = MUD_DEFHOME;
	if (!df)
	  return true;

	player->printf ("You appear to have no start property. Setting to %s.\n", df->id);
	player->set("start", df->id);
	dest = df;
       }
    }
 argh:
    MudObject *where = NULL;
    
    if (argv[0][2]=='b' && argc >= 2) 
	where = dest ? dest->owner : NULL;
    else if (argv[0][2]=='t' && argc >= 2) {
      if (dest) {
	if (!dest->get_flag(FL_ROOM)) {
	  where = dest->owner;
	} else
	  where = dest;
      }
    }
    else {
      where = dest;
    }

    if (streq(argv[1],"here") && player->owner && player->owner->owner) {
      where = player->owner->owner;
    }

    if (!where) {
	player->printf("Can't find '%s'.\n", argv[1]);
	return true;
    }
    if (is_player(player) && dest && !can_affect(player, where->get("zone")) && !player->ilc) {
      if (where->get("zone")) {
	player->printf("You can't go to that zone (%s) without remorting.\n", where->get("zone"));
      }  else {
	player->printf("You can't go to unzoned objects without remorting.\n");
      }
      return true;
    }
    if (is_in(where, player)) {
	player->printf(WIERD);
	return true;
    }
    if (where == player->owner) {
	player->printf("You are there already!\n");
	return true;
    }
    
    if (!spare_people_capacity(where)) {
	player->printf("That location is full.\n");
	return true;
    }

    player->oprintf(secret(player) && cansee, "%s\n", build_setin(player, setmout).c_str());
    player->lprintf(secret(player) && cansee, "%s\n", build_setin(player, setmout).c_str());

    set_owner(player, where);
    player->printf("You displace yourself %s.\n",  format_roomname(where, player, "^{D", "^}", "to", IS_COMMANDER(player)).c_str(), where);

    player->oprintf(secret(player) && cansee, "%s\n",build_setin(player, setmin).c_str());
    player->lprintf(secret(player) && cansee, "%s\n",build_setin(player, setmin).c_str());

    rectify_state(player);

    player->interpret("look -");
    newplace(player, old);
    return true;
}


static MudObject* random_exit_from(MudObject *where, MudObject *player)
{
  MudObject *o;
  int i;
  NewWorld exits;
  foreach(where->children, o, i) {
    if (MudObject *l=o->get_object("link")) {
      if (is_mobile(player) && l->get_flag(FL_NOMOBILES))
	continue;
      exits.add(*o);
    }
  }
  if (exits.getsize()) {
    return exits.get_nth(random_number(exits.getsize()));
  }
  return 0;
}


static bool verb_go(MudObject *player, int argc, const char*argv[]) {
    if (player->get_flag(FL_SLEEPING)) {
        player->printf("You can't sleepwalk.\n");
        player->oprintf(cansee, "%#M tosses and turns in %s sleep.\n",player, his_or_her(player));
        return true;
    }
    if (!player->get_flag(FL_MOBILE) && argc < 2) {
        player->printf("Go where?\n");
        return true;
    }
    if (MudObject *vic=player->get_object("_fighting")) {
      if (vic->owner != player->owner) {
	player->unset("_fighting");
      } else {
	player->printf("Not whilst fighting.\n");
	return true;
      }
    }

    MudObject *what = 0;
    int pissed = 0;

    const char *wanted = argv[1];

 hmm:
    if (argc >= 2) {
      what = find_exit(player->owner, argv[1]);
    } else {
      what = random_exit_from(player->owner, player);
    }

    if (player->get_flag(FL_SLEEPING)) {
	player->printf("You can't sleepwalk.\n");
	return true;
    }

    if (!what || (!what->get_flag(FL_EXIT) && !what->get_flag(FL_PARTEXIT))) {    

      if (player->get_flag(FL_NSEW)) {
       	if (streq(argv[1], "north")||
	    streq(argv[1], "south")||
	    streq(argv[1], "east")||
	    streq(argv[1], "west")) {
	  if (argv[1][0]=='n')
	    argv[1] = "rimwards";
	  if (argv[1][0]=='s')
	    argv[1] = "hubwards";
	  if (argv[1][0]=='e')
	    argv[1] = "clockwise";
	  if (argv[1][0]=='w')
	    argv[1] = "anticlockwise";
	  
	  goto hmm;
	}
      }

      if (argc>=2) {
	player->printf("You can't go ^d%s^n.\n", wanted);;
      } else {
	player->printf("There is nowhere to go.\n");
      }
      return true;
    }

    if ((player->get_int(KEY_PISSED)) && !mount(player)) {
      pissed = (int)((player->get_int(KEY_PISSED) - now)*(100.0/1200.0));
      int r = random_number(100);
      if (r<pissed) {
	if (player->get_flag(FL_FLYING)) {
	  player->printf("You flutter around aimlessly.\n");
	  player->oprintf(secret(player) && cansee, "%#M %[flutters/flutter] around aimlessly.\n", player);
	} else if (player->get_flag(FL_SWIMMING)) {
	  player->printf("You swim around aimlessly.\n");
	  player->oprintf(secret(player) && cansee, "%#M %[swims/swim] around aimlessly.\n", player);
	} else {
	  player->printf("You stagger around aimlessly.\n");
	  player->oprintf(secret(player) && cansee, "%#M %[staggers/stagger] around aimlessly.\n", player);
	}
	what = random_exit_from(player->owner, player);
	if (!what)
	  return true;
      }
    }  

    traverse(player, what);
    return true;
}

static const char *expand_dir(const char *arg, MudObject *where)
{
	switch (arg[0]) {
	 case 'n' : case 'N': return "north"; break;
	 case 's' : case 'S':
	   if (where->get_flag(FL_SHIP) || tolower(arg[1])=='t')
  	     return "starboard";
	   else
	     return "south";
	 break;
	 case 'e' : case 'E': return "east";break;
	 case 'f' : case 'F': return "fore";break;
	 case 'w' : case 'W': return "west";break;
	 case 'u' : case 'U': return "up";break;
	 case 'd' : case 'D': return "down";break;
	 case 'r' : case 'R': return "rimwards"; break;
	 case 'p' : case 'P': return "port"; break;
	 case 'h' : case 'H': return "hubwards";break;
	 case 'a' : case 'A': 
	   if (where->get_flag(FL_SHIP) || tolower(arg[1])=='f')
  	     return "aft";
	   else
	     return "anticlockwise";
	   break;
	 case 'c' : case 'C': return "clockwise";break;
	 case 'o' : case 'O': return "out";break;
	 case 'i' : case 'I': return "in";break;
	}
	return "?";
}

static bool go_implicit(MudObject *player, int, const char*argv[]) {
	const char *argv2[] = {
	  "go", NULL, NULL,
	};
	argv2[1] = expand_dir(argv[0], player->owner);
	return verb_go(player, 2, argv2);
}

enum qstat_t {
  Q_UNOWNED,
  Q_YOURS,
  Q_OTHERS,
};

static qstat_t quarstat(MudObject *where, MudObject *who)
{
  if (where->get("$player")) {    
    const char *own = where->get("$player");
    MudObject *hvem = planet->get(own);
    if (hvem == who)
      return Q_YOURS;
    else
      return Q_OTHERS;
  } else {
    return Q_UNOWNED;
  }
}

static bool player_exists(const char *name) {
  if (planet->get(name)) return 1;
  FILE *f = xopen(DATA_USERS, name, "r");
  if (!f)
    return 0;
  fclose(f);
  return 1;
}

static bool verb_invite(MudObject *who, int argc, const char **argv)
{
  if (!who->owner)
    return true;
  
  if (argc < 2) {
    who->printf("syntax: invite <who>\n");
    return true;
  }

  if (!who->owner->get_flag(FL_QUARTERS)) {
    who->printf("This is not quarters.\n");
    return true;
  }

  MudObject *q = who->owner;

  switch (quarstat(who->owner, who)) {
  case Q_UNOWNED:
    who->printf("You can't invite someone to unowned quarters.\n");
    return true;
  case Q_OTHERS:
    who->printf("You can't invite someone to someone else's quarters.\n");
    return true;
  default:

    if (!player_exists(argv[1])) {
      who->printf("No such player as ^p%#s^n.\n", argv[1]);
      return true;
    }

    MudObject *hvem = planet->get(argv[1]);
    if (hvem == who) {
      who->printf("You can't invite yourself.\n");
      return true;
    }
    
    if (q->get("$guestlist")) {
      if (permitted_access(argv[1], q->get("$guestlist"))) {
	who->printf("Already invited.\n");
	return true;
      }
    }

    if (q->get("$guestlist")) {
      q->setf("$guestlist", "%s,%s", q->get("$guestlist"), 
	     argv[1]);
    } else {
      q->set("$guestlist", argv[1]);
    }
    who->printf("Guestlist updated.\n");

    if (hvem) {
      hvem->printf("%M %[has/have] added you to %s guest list.\n", who, 
		  his_or_her(who));
    }

    //    who->printf("Ok. You now own these.\n");
    //    who->owner->set("$player", who->id);
    //    who->set("quarters", who->owner->id);
    ;
  }

  return true;
}

static bool verb_uninvite(MudObject *who, int argc, const char **argv)
{
  if (!who->owner)
    return true;
  
  if (argc < 2) {
    who->printf("syntax: uninvite <who>\n");
    return true;
  }

  if (!who->owner->get_flag(FL_QUARTERS)) {
    who->printf("This is not quarters.\n");
    return true;
  }

  MudObject *q = who->owner;

  switch (quarstat(who->owner, who)) {
  case Q_UNOWNED:
    who->printf("You can't uninvite someone from unowned quarters.\n");
    return true;
  case Q_OTHERS:
    who->printf("You can't uninvite someone from someone else's quarters.\n");
    return true;
  default:

    if (!player_exists(argv[1])) {
      who->printf("No such player as ^p%#s^n.\n", argv[1]);
      return true;
    }

    MudObject *hvem = planet->get(argv[1]);
    if (hvem == who) {
      who->printf("You can't uninvite yourself.\n");
      return true;
    }
    
    if (q->get("$guestlist")) {
      if (!permitted_access(argv[1], q->get("$guestlist"))) {
	who->printf("Not on the guestlist.\n");
	return true;
      }
    } else 
      who->printf("Not on the guestlist.\n");

    q->set("$guestlist", uninvite(argv[1], q->get("$guestlist"))); 
    who->printf("Guestlist updated.\n");

    if (hvem) {
      hvem->printf("%M %[has/have] removed you from %s guest list.\n", who, his_or_her(who));
    }
    //    who->printf("Ok. You now own these.\n");
    //    who->owner->set("$player", who->id);
    //    who->set("quarters", who->owner->id);
    ;
  }

  return true;
}

static MudObject *load_player(const char *id) {
    MudObject *p = new MudObject("^thingy");
    FILE *f = xopen(DATA_USERS, id, "r");
    if (!f) {
      return 0;
    }
    
    string buf = getline(f);
    while (buf != "}" && !feof(f)) {
      buf = getproperty(f);
      p->load(buf.c_str());
    }
    xclose(f);    
    return p;
}

static int dispose_contents(MudObject *o2) {
    if (is_player(o2))
      return 0;
    if (o2->mission)
      return 0;

  if (!o2->get_flag(FL_ROOM)) {
    if (o2->get_object("start")!=o2->owner)
      vanish(o2);
  }
  int cost = o2->get_int("cost", 0);
  MudObject *o;
  int i;
  NewWorld d;
  foreach(o2->children, o, i) {
    d.add(*o);
  }
  foreach((&d), o, i) {
    cost += dispose_contents(o);
  }
  return cost;
}

static bool dontbother(MudObject *o2) {
  if (is_player(o2)) 
    return 1;
  if (o2->mission) 
    return 1;
  MudObject *o;
  int i;
  foreach(o2->children, o, i) {
    if (dontbother(o))
      return 1;
  }
  return 0;
}

static bool verb_evict(MudObject *who, int argc, const char **argv) 
{
  if (!who->owner)
    return true;

  
  MudObject *q = who->owner;

  if (q->array_size("room")>0 && q->get("qoffice")) {
    
    int l = q->array_size("room");
    int i=0;
    
    for (i=0;i<l;i++) {
      MudObject *q2 = q->array_get_object("room", i);
      if (!q2)
	continue;
      if (dontbother(q2))
	continue;
      const char *o = q2->get("$player");
      if (o) {
	MudObject *m = planet->get(o);
	if (!m) {
	  MudObject *p = load_player(o);
	  if (p) {
	    time_t n = p->get_int("lastlogin");
	    if ((now-n)/(24*60*60)>7) {
	      q2->unset("$player");
	      int compensate = dispose_contents(q2);
	      char bar[100];
	      sprintf(bar, "$owe.%s", o);
	      q->set(bar, q->get_int(bar)+(compensate*9)/10);
	      who->printf("%M - %s - %i days, now evicted, %K compensation.\n", 
			  q2, p->get("_name")?:p->get("name"), (now-n)/(24*60*60), compensate);
	      log(PFL_SEEINFO, 0, "wiz", "autoevicting %s from %s", p->get("_name"), q2->id);
	    }
	    delete p;
	  } else {
	    log(PFL_SEEINFO, 0, "wiz", "autoevicting %s from %s", q2->get("$player"), q2->id);
	    q2->unset("$player");
	    q2->unset("$guestlist");
	    dispose_contents(q2);
	  }
	}
      }
      if (q2->get("$desc") && !q2->get("$player")) {
	q2->unset("$desc");
      }
    }
    return true;
  }
  return true;
}

static const char *find_route(MudObject *who, MudObject *src, MudObject *dst)
{
  if (src == dst)
    return 0;
  if (dst->l.exit) {
    find_route(who, src, dst->l.exit->owner);
    if (dst->l.exit->owner == src) {
      who->interpretf("go %s", dst->l.exit->get("short"));
    }
  }
  return 0;
}

static bool verb_route(MudObject *who, int argc, const char **argv)
{
  if (is_player(who) && !who->get_priv(PFL_CODER)) {
    who->printf("You can't do that.\n");
    return true;
  }

  if (argc < 2) {
    who->printf("syntax: route <whereto>\n");
    return true;
  }

  MudObject *src = who->owner;
  MudObject *dest = planet->get(argv[1]);
  if (!dest) {
    who->printf("Can't find dest.\n");
    return true;
  }

  MudObject *o;
  int i;

  if (who->get_flag(FL_LANDVEHICLE) &&
      who->get_object("$headingfor")==dest) {
    NewWorld exits;
    MudObject *cf = who->get_object("$camefromloc");
    int cfv = 0;
    foreach(who->owner->children, o, i) {
      if (o==who)
	continue;
      MudObject *l = o->get_object("link");
      if (l==cf)
	cfv = 1;
      else if (l)
	exits.add(o);
    }
    if (exits.getsize()==1 && cfv) {
      who->interpretf("go %s", exits.get(0)->get("short"));
      if (who->owner != dest) {
	who->set("!reschedule", 1);
      }
      return true;
    }
  }

  foreach(planet, o, i) {
    o->l.s = 0;
    o->l.exit = 0;
  }
  
  src->l.s = 1;
  while (1) {
    int change = 0;
    foreach(planet, o, i)
      if (o->l.s==1)
	o->l.s = 2;

    foreach(planet, o, i)  {
      if (o->get_flag(FL_WILDERNESS)) {
	int ok = 0;
	
	if (o->get_int("wild.z", 0)==-2)
	  ok = 1;

	if (!ok)
	  continue;
      }
      
      if (o->l.s==2) {
	o->l.s = 3;
	if (o->get_flag(FL_DEATH)) continue;
	change = 1;
	MudObject *p;
	int j;
	foreach(o->children, p, j) {
	  MudObject *to = p->get_object("link");
	  if (to) {
	    if (to->l.s==0)
	      {
		to->l.s=1;
		to->l.exit = p;
	      }
	  }
	}
      }
    }
    
    if (!change)
      break;

    if (dest->l.s)
      break;
  }

  if (dest->l.s) {
    find_route(who, src, dest);
  } else {
    who->printf("Route to %s not found.\n", dest->id);
  }

  who->set("$headingfor", dest->id);
  
  if (who->owner != dest) {
    who->set("!reschedule", 1);
  }

  return true;
}

static bool verb_track(MudObject *who, int, const char **)
{
  MudObject *where = who->owner;
  if (!where)
    return true;
  MudObject *last = where->get_object("$lastperson");
  MudObject *lastdir = where->get_object("$lastdir");
  
  int when = where->get_int("$lasttime");
  const char *whenstr = " very recently";
  if (when<(now-60))
    whenstr = " recently";
  if (when<(now-120))
    whenstr = " not long ago";
  if (when<(now-300))
    whenstr = " at some point";
  if (when<(now-600))
    whenstr = " a while ago";
  if (when<(now-900))
    last = NULL;

  MudObject *fl = floor(where);

  if (where->get_flag(FL_NOGRAVITY) || !fl) {
    who->printf("No tracks can be left here.\n");
    return true;
  }
  
  if (!last || !lastdir) {
    who->printf("%#P is undisturbed.\n", fl);
    return true;
  }
  const char *body = last->get("body");
  if (!body)
    body = "human";
  who->printf("A %s seems to have gone %s from here%s.\n", body, lastdir->get("short"), whenstr);
  return true;
}

static bool verb_links(MudObject *who, int argc, const char **argv)
{
  const char *zone = who->owner?who->owner->get("zone"):0;
  if (argc > 1) {
    zone = argv[1];
  }
  if (!zone || !zones->get(zone)) {
    if (!zone)
      who->printf("This object has no zone.\n");
    else
      who->printf("No such zone as '%s'.\n", zone);
    return true;
  }
  MudObject *o;
  int i;
  who->spec_printf("^W%15s %-15s %s^n\n", "From", "Direction", "To");
  bool yes = 0;
  foreach(planet, o, i) {
    if (const char *l=o->get("link")) {
      if (o->owner && o->owner->get_flag(FL_WILDERNESS) && l[0]=='@')
	continue;
      
      MudObject *lo = planet->get(l);
      if ((l[0]==':'&&streq(o->get("zone"), zone))
	  || (lo && !streq(lo->get("zone"), o->get("zone")) && (streq(lo->get("zone"), zone) ||
								streq(o->get("zone"), zone)))) {
	who->printf("%15s %-15s %s\n", o->owner?o->owner->id:"nowhere", o->get("short"), l);
	yes = 1;
      }

      if (streq(o->get("zone"), zone) && !lo) {
	who->printf("%15s %-15s %s\n", o->owner?o->owner->id:"nowhere", o->get("short"), "-");
	yes = 1;
      }
    }
  }
  if (!yes) {
    who->cancel_printf();
    who->printf("No interzone links involving %s.\n", zone);
  }
  return true;
}

#include "verbmodule.h"

void startup() {

  //AUTO_VERB(quarters, 3, 0, PFL_NONE );
AUTO_VERB(invite, 4, 0, PFL_NONE );
AUTO_VERB(uninvite, 4, 0, PFL_NONE );

AUTO_VERB(evict, 3, 0, PFL_EDITALL, VFL_DENYEXISTS );

AUTO_VERB(route, 3, 0, PFL_NONE );

AUTO_VERB(go, 2, 0, PFL_AWAKE );

ADD_VERB("down", 1, go_implicit, 0, PFL_NONE);
ADD_VERB("east", 1, go_implicit, 0, PFL_NONE);

ADD_VERB("north", 3, go_implicit, 0, PFL_NONE);
 ADD_ALIAS(n, 1, north);

ADD_VERB("south", 1, go_implicit, 0, PFL_NONE);
ADD_VERB("out", 1, go_implicit, 0, PFL_NONE);
ADD_VERB("in", 2, go_implicit, 0, PFL_NONE);
ADD_VERB("up", 1, go_implicit, 0, PFL_NONE);
ADD_VERB("west", 1, go_implicit, 0, PFL_NONE);

ADD_VERB("fore", 1, go_implicit, 0, PFL_NONE);
ADD_VERB("aft", 2, go_implicit, 0, PFL_NONE);

ADD_VERB("port", 1, go_implicit, 0, PFL_NONE);
ADD_VERB("starboard", 5, go_implicit, 0, PFL_NONE);

ADD_VERB("rimwards", 1, go_implicit, 0, PFL_NONE);
ADD_VERB("hubwards", 1, go_implicit, 0, PFL_NONE);
ADD_VERB("clockwise", 1, go_implicit, 0, PFL_NONE);
ADD_VERB("anticlockwise", 1, go_implicit, 0, PFL_NONE);

ADD_VERB("goby", 3, verb_gotoin, 0, PFL_GOTO);
ADD_VERB("goto", 3, verb_gotoin, 0, PFL_GOTO);
ADD_VERB("goin", 3, verb_gotoin, 0, PFL_GOTO);

AUTO_VERB(track, 2, 0, PFL_AWAKE);

AUTO_VERB(links, 5, 0, PFL_CODER);

}