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 - Dynamic Reset System
 * 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 "musicmud.h"
#include "verbs.h"
#include "misc.h"
#include "util.h"
#include "events.h"
#include "trap.h"
#include "pflags.h"
#include "startup.h"
#include "flagnames.h"

#define MODULE "dynreset"

static MudObject *link(MudObject *ext) {
  MudObject *dest = ext->get_object("link");
  if (!dest) {
    return 0;
  }
  if (ext->get_flag(FL_NEVEROBSERVED))
    return 0;
  return dest;
}

static void mark_observed(MudObject *o, MudObject *tainter, int linksaway=2) {
    if (o->get_flag(FL_OBSERVED)) return;
    if (o->get_flag(FL_NEVEROBSERVED)) return;
    o->set_flag(FL_OBSERVED, 1);
    o->set("!tainter", tainter->id);
    MudObject *m;
    int i;
    foreach(o->children, m, i) {
	mark_observed(m, tainter);
    }
    if (linksaway) {
      foreach(o->children, m, i) {
	if (MudObject *d=link(m)) {
	  mark_observed(d, tainter, linksaway-1);
	}
      }
    }
}

static bool object_touched(MudObject *o) {
  if (o->get_flag(FL_SHIP))
    return false;

    if (o->get_flag(FL_DONE) || o->get_flag(FL_TAMPERED)) { 
#ifdef DEBUG_DYNRESET
     log(PFL_SEEINFO, 0, "debug", "%s done/tampered", o->id);
 
#endif
	return true; 
    }
    for (Flag i=FL_FIRST;i<FL_MAX;i++)
	if (i != FL_OBSERVED && i != FL_TIMER)
	if (o->get_flag(i) != o->get_rflag(i)) {
#ifdef DEBUG_DYNRESET
     log(PFL_SEEINFO, 0, "debug", "%s flag on %s has changed", flag_names[i], o->id);
#endif
	    return true;
	}
    int is = o->get_int("initstate");
    int st = state(o);
    if (is != -1 && st != -1 && st != is) {
#ifdef DEBUG_DYNRESET
     log(PFL_SEEINFO, 0, "debug", "initstate(%i) of %s differs from current state(%i)", is, o->id, st);
#endif
	return true;
    }
    if (!o->get_flag(FL_WANDER))
	{
        if (o->owner && o->get("start") && 
	    (planet->get(o->get("start")) != o->owner)) {
#ifdef DEBUG_DYNRESET
	  log(PFL_SEEINFO, 0, "debug", "non-wandering %s has moved from start location",  o->id);
#endif
	  return true;
	}
    }
    
    if (o->owner == MUD_MOBILEHEAVEN)
      return true;

    int max = o->get_int("initstrength", o->get_int("maxstrength"));
    int s = o->get_int("!strength");
    if (max != -1 && s != -1 && max != s) {
#ifdef DEBUG_DYNRESET
log(PFL_SEEINFO, 0, "debug", "strength of %s has changed", o->id);
#endif
	return true;
    }
    return false;
}

static const char *relationship(MudObject *what, MudObject *who) {
    if (!what || !who) return "is observed by";
    if (who->owner == what) return "contains";
    MudObject *k = what;
    while (k) {
	if (k==who) return "is carried by";
	k = k->owner;
    }
    return "is observed by";
}

static MudObject *get_mudzone(const char *txt) {
    char name[256];
    sprintf(name, "%s_zone", txt);
    return planet->get(name);
}

static string ingreen(MudObject *o) {
  string s = "^G";
  if (o->id)
    s += o->id;
  s += "^g";
  return s;
}

static string mname(MudObject *o) {
  string s = "^M";
  if (o->get("mname"))
    s += o->get("mname");
  s += "^i";
  return s;
}

static bool verb_dynreset(MudObject *a, int argc, const char **) {
    int zones_reset = 0, unsafe=0;

    if ((!a->get_priv(PFL_RESET) && a->get_int("$blissed")<=now) && !a->ilc) {
      a->printf("You can't do that.\n");
      return true;
    }
    
    FILE *f = 0;
    
    if (is_mobile(a)) {
      f = xopen(DATA_INFO, "dynreset2.i", "w+");

      a->file_divert(f);
    }

	{
	    MudObject *o;
	    int i;
	    foreach(planet, o, i) 
		o->set_flag(FL_OBSERVED, 0);
	}

	{
	    Player *p;
	    int i;
	    foreach(players, p, i)
		if (p->owner && p->get_flag(FL_LOGGEDIN)) {
		    mark_observed(p->owner, p);
		}
	}

	NewWorld resetted;
	NewWorld quests;
    
    MudObject *zone;       
    int i;
    foreach(zones, zone, i) if (!zone->get_flag(FL_NORESET)) {
	
      if (!streq(zone->id, "@auto") && !streq(zone->id, "@ship")) {

	bool do_it = true;
	bool touched = false;
	MudObject *o, *failer = 0, *touchee = 0;
	int i2;
	foreach(zone->children, o, i2) {
	        if (o->get_flag(FL_NORESET))
		  continue;

		if (!o->get_flag(FL_NOSAVE)) {
		  bool this_touched = object_touched(o);
		  
		  if (this_touched) {
		    touched = true;
		    if (!touchee) 
		      touchee = o;
		  }
		  
		  if (touched) {
		    MudObject *mz = get_mudzone(zone->id);
		    if (mz)
		      {
			MudObject * q = mz->get_object("quest");
			if (q) {
			  q->set_flag(FL_TAMPERED, 1);
			}
		      }
		  }
		}

		if (o->get_flag(FL_OBSERVED)) {
		    failer = o;
		    do_it = false;
		}
		
		if (o->get_flag(FL_ALWAYSOBSERVED)) {
		    failer = o;
		    do_it = false;
		}
		
		if (!do_it && touched)
		  break;

	}


	if (!touched) { //a->printf("untouched\n");
	} else 
	  {
	    a->printf("%-20s : ", zone->id);
	    if (do_it) {
	      if (argc>1) {
		doreset(zone->id, true);
		zones_reset++;
		a->printf("^Greset because of %s (%s %i)^n\n", touchee->id, touchee->owner->id,
			  state(touchee));
		resetted.add(*zone);
		
		
		MudObject *mz = get_mudzone(zone->id);
		if (mz)
		  {
		    MudObject * q = mz->get_object("quest");
		    if (q && !q->get_flag(FL_PRIVATE) && !quests.contains(q))
		      quests.add(*q);
		  }
	      } else {
		a->printf("^Gsafe^n\n");
	      }
	    } else {
	      if (failer) {
		const char *tstr = failer->get("!tainter");
		MudObject *someone = 0;
		if (tstr) {
		  someone = planet->get(tstr);
		}
		a->printf("^Runsafe^n    (%s %s %s)\n", failer->id,
			  relationship(failer, someone),
			  someone ? someone->get("name") : "Someone");
	      } else
		a->printf("^Runsafe^n\n");
	      unsafe++;
	    }
	    	
	}
	a->send_data();
      }
    }

    if (resetted.getsize())
      broadcast(!getflag(FL_NORESET) && minlev(LEV_COMMANDER),
        "^Y[^GDYNRESET^g: %s by %s^Y]\n", magiclist(resetted, ingreen).c_str(), a->get("name"));
		
    MudObject *smith = MUD_ANNOUNCER;
    if (smith && quests.getsize()) {
      smith->interpretf("%s The %s mission%s now available.", 
			MUD_ANNCHMIS,
			magiclist(quests, mname).c_str(),
		        quests.getsize()==1?" is":"s are");
    }

    a->printf("%i out of %i zones reset. (%i unsafe to reset.)\n",
	      zones_reset, zones->getsize(), unsafe);

    MudObject *o;
    foreach(planet, o, i) 
      o->set_bflag(FL_OBSERVED, 0);
    
    if (f) {
      if (zones_reset)
        rename(DATA_INFO"/dynreset2.i", DATA_INFO"/dynreset.i");
      a->file_undivert();
      xclose(f);
    }
    
    return true;
}


#include "verbmodule.h"

void startup() {
  AUTO_VERB(dynreset, 4, 0, PFL_NONE); 
}