/*
    Nonroom.m  Class definition.
    Copyright (C) 1995  David Flater.

    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 "cheezmud.h"

@implementation Nonroom

+ new
{
  self = [super new];
  location = NULL;
  return self;
}

- free
{
  [location remove: self];
  return [super free];
}

- logout
{
  if (!loggedout) {
    if (!dead)
      [location emote: self: "disappear": "disappears":
        " from the face of the Earth"];
    [self setlocation: NULL];
    [super logout];
  }
  return self;
}

- (int) level
{
  return 0;
}

- getlocation
{
  return location;
}

- setlocation: whereto
{
  [location remove: self];
  location = whereto;
  [location add: self];
  return self;
}

- teleport: whereto
{
  [location emote: self: "vanish": "vanishes":
      " into a cloud of magic smoke"];
  [self setlocation: whereto];
  [location emote: self: "appear": "appears":
      " out of a cloud of magic smoke"];
  return self;
}

- (float) priority: (char *) action: (int) numargs
{
  /* Not supported */
  return -1.0;
}

- resolve_action: (char *) action: (int) numargs
{
  id actor = NULL;
  float prio = -1.0, t_prio;

  if ((t_prio = [self priority: action: numargs]) > prio) {
    if (t_prio >= 0.0) {
      prio = t_prio;
      actor = self;
    }
  }

  if (location && ((t_prio = [location priority: action: numargs]) > prio)) {
    if (t_prio >= 0.0) {
      prio = t_prio;
      actor = location;
    }
  }

  if ([self isKindOf: [Container class]]) {
    int i,m;
    id c = [self contents];
    for(i=0,m=[c size];i<m;i++) {
      id whatever = [c at:i];
      if ((t_prio = [whatever priority: action: numargs]) > prio) {
        if (t_prio >= 0.0) {
          prio = t_prio;
          actor = whatever;
        }
      }
    }
  }
  return actor;
}

/*  Do an action.  This method is complicated, but it has a big job to do. */
- (int) act: (char *) someaction
{
  SEL a;
  int i,m;
  id c,t, dobj = NULL;
  char verb[80], directobject[80];
  int numargs, number;
  numargs = sscanf (someaction, "%s %s %d", verb, directobject, &number);

  /*  This is a crummy cheat to make take an alias for get. */
  if (!strcmp (verb, "take"))
    strcpy (verb, "get");
  /*  Ditto for l, look. */
  if (!strcmp (verb, "look"))
    strcpy (verb, "l");

  switch (numargs) {
  case 1:
    number = 1;
    break;
  case 2:
    number = 1;
    /*  Fall through */
  case 3:
    /*  3 args is just 2 args with a qualifier that goes away.  The other */
    /*  functions will get confused if we leave numargs = 3. */
    numargs = 2;

    /*  Get, drop, bag, and unbag are exceptions to the inventory + room */
    /*  contents resolution.  Get only applies to room contents.  Drop and */
    /*  bag only apply to inventory.  Unbag only applies to bag contents. */

    if ((!strcmp (verb, "drop")) || (!strcmp (verb, "bag"))) {
      if (![self isKindOf: [Container class]])
        return 0;
      dobj = [self find: directobject: number];
    } else if (!strcmp (verb, "get")) {
      dobj = [location find: directobject: number];
    } else if (!strcmp (verb, "unbag")) {
      BOOL flag = YES;
      if (![self isKindOf: [Container class]])
        return 0;
      c = [self contents];
      for(i=0,m=[c size];(i<m) && flag;i++) {
	id whatever = [c at:i];
        if ([whatever isKindOf: [Sack class]]) {
          dobj = generic_find_creturn ([whatever contents],
            directobject, &number);
          if (dobj)
            flag = NO;
        }
      }
    } else {
      if ([self isKindOf: [Container class]])
        dobj = generic_find_cascade ([self contents], [location contents],
          directobject, number);
      else
        dobj = [location find: directobject: number];
    }
    if (!dobj) {
      [self echo: "Not found."];
      return 1;
    }
    break;
  default:
    return 0;
  }
  if ((t = [self resolve_action: verb: numargs])) {
    char temp[80];
    sprintf (temp, "%s:", verb);
    if (numargs > 1)
      strcat (temp, ":");
    a = [Object findSel:temp];
    if (numargs == 1)
      [t perform: a with: self];
    else
      [t perform: a with: self with: dobj];
    return 1;
  }

  /*  Try to print a helpful message for missing args. */
  if (numargs == 1) {
    if ((t = [self resolve_action: verb: 2])) {
      char temp[80];
      sprintf (temp, "%s what?", capitalize (verb));
      [self echo: temp];
      return 1;
    }
  }
  if (numargs == 2) {
    if ((t = [self resolve_action: verb: 1])) {
      [self echo: "That action does not get a direct object."];
      return 1;
    }
  }

  return 0;
}

- getread: who
{
  char temp[80];
  sprintf (temp, "%s is not legible.", capitalize (def));
  [who echo: temp];
  return self;
}

/*  Clone this object. */
/* - clone */
/* { */
/*   return [[[self class] new] describe: [self mudname]: */
/*     [self indef]: [self def]: [self longdesc]]; */
/* } */

- hit: fromwho: (float) damage
{
  [location emote: self: "suffer": "suffers": " no damage"];
  [[fromwho getlocation] emote: fromwho: "": "":
    "may need psychological help"];
  [fromwho clue: self];
  return self;
}

- (int) isdead
{
  return dead;
}

- theres_a_fight_going_on
{
  /* So what? */
  return self;
}

/*  These have to be here to get rid of stupid compiler warnings. */

- contents
{
  assert (0);
  return NULL;
}

- find: (char *) what: (int) number
{
  assert (0);
  return NULL;
}

@end