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 - Actions 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 <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>

#include "musicmud.h"
#include "verbs.h"
#include "util.h"
#include "misc.h"
#include "Player.h"
#include "pflags.h"
#include "trap.h"
#include "events.h"
#include "paths.h"
#include "hooks.h"
#include "musictok.h"
#include "emsg.h"
#include "actions.h"

namespace {

//! A verb which is soft-coded, either coming from the files in the action or data/verbs dirs.
class ActionVerb : public Verb {
 private :
  string filename;
 public:
	virtual bool invoke(MudObject *invoker, int argc, const char*argv[]);
	ActionVerb(const char *id, int minlen, const char *filename);
	virtual ~ActionVerb();
};


ActionVerb::ActionVerb(const char *id, int minlen, const char *filename) :
Verb(id, minlen, 0, PFL_NONE, VFL_MAGICSPACE) {
  this->filename = filename;
  set("module", "action");
}

ActionVerb::~ActionVerb() {
}

}

#define GIVE_UP do { player->printf("giving up line %i \n", __LINE__ ); return true; } while(0)

static int viewers_at(MudObject *where) {
  if (!where)
    return 0;
  int i;
  MudObject *o;
  int c = 0;
  foreach(where->children, o, i) {
    if (is_player(o))
      c++;
  }
  return c;
}

static int viewers(MudObject *where) {
  if (!where) return 0;
  int c = viewers_at(where);
  if (where->get_flag(FL_LINKED)) {
    MudObject *obj;
    int i;
    foreach(where->children, obj, i) {
      c += viewers_at(linkedlink(obj));
    }
  }
  return c;
}


static void actresponse(MudObject *obj, MudObject *player, const char *id, 
			int needp=1) {
  char foo[1024];
  char bar[1024];
  sprintf(foo, "on_%s", id);
  sprintf(bar, "lua.act.%s", id);

  if (obj) {
    if (obj->get(foo)) {
      obj->set("!$1", player->id);
      itell(obj, obj->get(foo));
      return;
    }
    
    if (dotrap(bar+4, player, obj))
      /* ::: act.* o1==object or mobile an action has been done on */
      return;
    
    if ((is_mobile(obj) && is_player(player))==needp) {
      MudObject *at = archetype(obj);
      if (at && at->get(foo)) {
	obj->set("!$1", player->id);
	itell(obj, at->get(foo));
      }
    }
  }

  if (!obj || obj->owner == player->owner)
    dotrap(ssprintf("lua.act_in.%s", id).c_str(), player, player->owner, obj);
}

const char *nilifempty(const string &s)
{
  if (s.length()==0)
    return 0;
  return s.c_str();
}

void appendnewline(string &s)
{
  if (s.length())
    s += '\n';
}

bool ActionVerb::invoke(MudObject *player, int argc, const char*argv[]) {
  if (streq(get("module"), "luaverb")) {
    if (LUA_VERB)
      LUA_VERB(player, argc, argv);
    else
      player->printf("Real lua verb - but lua not loaded.\n");
    return true;
  }

  if (!viewers(player->owner)) {
    return true;
  }

  if (player->get_flag(FL_SLEEPING)) {
    player->printf("You toss and turn in your sleep.\n");
    player->oprintf("%#M %[tosses/toss] and %[turns/turn] in %s sleep.\n", player, his_or_her(player));
    return true;
  }

  try {
    parsedact resp = parse_action(player, argc, argv, 1);
    
    resp.who->action_to(resp.targ, resp.a_me.c_str(),   nilifempty(resp.txt), resp.prop);
    resp.who->action   (resp.targ, resp.a_rest.c_str(), nilifempty(resp.txt), resp.prop);
    
    if (resp.targ) {
      resp.targ->action_from(resp.who,resp.a_you.c_str(), nilifempty(resp.txt), NULL, resp.prop);
    }
    
    if (resp.targ && resp.r_me.length()) {
      resp.targ->action_to  (resp.who, resp.r_me.c_str(),   nilifempty(resp.txt), resp.rprop);
      resp.targ->action     (resp.who, resp.r_rest.c_str(), nilifempty(resp.txt), resp.rprop);
      resp.who ->action_from(resp.targ,resp.r_you.c_str(),  nilifempty(resp.txt), NULL, resp.prop);
    }
    
    actresponse(resp.targ, resp.who, argv[0]);
    
    /// XXX E_ONTHINK
    /// XXX Away messages

    /// done - sleeping
  } catch (emsg &e) {
    if (e.msg.length())
      player->printf("%s\n", e.msg);
  }
  return true;
}

#define MODULE "action"

static void do_dir(const char *name, const char *pr, const char *module) {
    char path[1024];
    DIR *dir=opendir(name);
    if (!dir) return;
    struct dirent *de;
    while ((de=readdir(dir))!=NULL) {
	if (verbs->get(de->d_name))
	    continue;
	char name[256];
	strcpy(name, de->d_name);
	name[strlen(de->d_name)] = 0;
		
	if (get_verb(name)) 
	  continue;
	
	if (de->d_name[0]=='.') continue;
	if (strchr(de->d_name, '~')) continue;
	if (de->d_name[0]=='#') continue;
	if (streq(de->d_name, "CVS")) continue;

	sprintf(path, pr, de->d_name);
	strcpy(name, de->d_name);
	
	ActionVerb *av=new ActionVerb(name, strlen(name),  path);
	if (module) {
	  av->set("module", module);
	  FILE *f = xopen(".", path, "r");
	  if (f) {
  	    char buf[1000];
	    fgets(buf, 1000, f);
	    av->pflag = PFL_NONE;
	    if (char *s=strchr(buf, '\n')) *s = 0;
	    StrTok st(buf);
	    int i = 0;
	    while (const char *a = st.next(" ")) {
	      if (i==1 && strncmp(a, "PFL_", 4)==0) {
		av->pflag = find_priv(a);
	      }
	      if (i==2) {
		av->privneeded = atoi(a);
	      }
	      if (i==3) {
		av->minlen = atoi(a);
	      }
	      i++;
	    }
	    av->vflags |= VFL_OKNOOWNER;
	    xclose(f);
	  }
	}
	verbs->add(*av);
    }
    closedir(dir);
}

static bool verb_reloadactions(MudObject*who, int, const char **) {
  Verb *o;
  int i;
  set<string> had;
  foreach(verbs, o, i) {
    if (IS_OF(o, ActionVerb)) {
      had.insert(o->id);
      verbs->remove(*o);
      delete o;
      i--;
    }
  }
  do_dir(DATA_ACTIONS, DATA_ACTIONS "/%s", NULL);
  do_dir(DATA_VERBS, DATA_VERBS "/%s", "luaverb");

  foreach(verbs, o, i) {
    if (IS_OF(o, ActionVerb))
      if (had.find(o->id)==had.end()) {
	who->printf("%s: added\n", o->id);
      }
  }
  set<string>::iterator it = had.begin();

  while (it != had.end()) {
    if (!verbs->get(it->c_str())) {
      who->printf("%s: removed\n", it->c_str());
    }
    it++;
  }

  //  who->interpret("actlist");
  return true;
}

NativeVerb *reloadactions;

extern "C" void register_verbs() {
  reloadactions = new NativeVerb("rescan", 4, 0, verb_reloadactions, PFL_ACTIONS);
  reloadactions->set("module","ActionVerb");
  verbs->add(*reloadactions);

  do_dir(DATA_ACTIONS, DATA_ACTIONS "/%s", NULL);
  do_dir(DATA_VERBS, DATA_VERBS "/%s", "luaverb");
  
}


extern "C" void remove_verbs() {
   verbs->remove(*reloadactions);
   delete reloadactions;

    Verb *o;
    int i;
    foreach(verbs, o, i) {
	Verb * v = (Verb *)o;
	if (IS_OF(v, ActionVerb)) {
	    verbs->remove(*o);
	    delete o;
	    i--;
	}
    }
}