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 Daemon, version 1.0
 * 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>

#include "musicmud.h"
#include "util.h"
#include "pflags.h"
#include "death.h"
#include "hooks.h"
#include "misc.h"
#include "events.h"
#include "trap.h"
#include "move.h"

static bool has_rad_suit(MudObject *ob) {
    MudObject *o;
    int i;
    if (ob->get_flag(FL_RADIATIONSUIT))
      return 1;
    foreach(ob->children, o, i) 
	if (o->get_flag(FL_RADIATIONSUIT))
	    return true;
    return false;
}

static int loctemp(MudObject *where) 
{
  int when = mudtime(where).hour;

  /* Returns rough temperature in degrees C */
  if (where->get_flag(FL_COLD))
    return -5;

  if (where->get_flag(FL_HOT))
    return 40;

  if (where->get_flag(FL_TEMPEXTREME)) {
    if (when <= 4)
      return -5;

    if (when >= 21)
      return -5;

    if (when >= 10 && when <= 15)
      return 40;

    return 10;

    /*  
      0 C Midnight        chilly
      1 C night           chilly
      2 C night           chilly
      3 C night           chilly
      4   night
      5   early morning    sun peeks over the horizon
      6   early morning
      7   early morning    a new day begins
      8   morning
      9   morning                                        
     10 H morning                                        
     11 H morning         warm
     12 H Midday          warm
     13 H afternoon       warm
     14 H afternoon       warm
     15 H afternoon
     16   afternoon
     17   evening
     18   evening          sun begins to set
     19   late evening
     20   night            sun sets
     21 C night           chilly
     22 C night           chilly
     23 C night           chilly
    */

    return 40;
  }

  if (when <= 4 || when >= 21)
    return 0;
  
  if (when >= 11 && when <= 14)
    return 15;

  return 10;
}

static bool mobile_ok(MudObject *who, MudObject *dest) {
    if (dest->get_flag(FL_DEATH) ||
	dest->get_flag(FL_NOMOBILES) ||
        (dest->get_flag(FL_AIRLESS) && !wf_wears_with_flag(who, FL_SPACESUIT))) 
	return false;
     
    if (who->get_flag(FL_PITIT)
	&& dest->get_flag(FL_QUARTERS) || dest->get_flag(FL_SHIP)) {
      return false;
    }

    if (who->get_flag(FL_WANDERZONE) && !streq(dest->get("zone"), who->get("zone")))
      return false;

    if (dotrap(E_BEFOREWANDER, who, who, dest))
      /* ::: before_wander o1==wandered, o2==dest; return 1 if we won't wander there */
      return false;

    return !who->get("wander.zone") ||
           streq(who->get("wander.zone"), dest->get("zone"));
}

static void mobile_wander(MudObject *who) {
  if (who->get("_fighting"))
    return;
    
  if (!who->owner)
    return;

  if (streq(who->owner->id, "empty"))
    return;

    MudObject *o;
    int i, count=0;
    foreach(who->owner->children, o, i) {
      MudObject *dest = o->get_object("link");
      if (MudObject*dor=o->get_object("door")) {
	if (dor->get_int(KEY_STATE)!=0) {
	  continue;
	}
      }
      
      if (dest && mobile_ok(who, dest))
	count++;
    }
    
    if (count==0) 
	return;

    int which = random_number(count);
    
    count=0;
    foreach(who->owner->children, o, i) {
	MudObject *dest = o->get_object("link");

	if (MudObject*dor=o->get_object("door")) {
	  if (dor->get_int(KEY_STATE)!=0) {
	    continue;
	  }
	}

	if (dest && mobile_ok(who, dest)) {
	    if (count==which) {
		traverse(who, o);
		break;
	    }
	    count++;
	}
    }
}

static void mobile_aggr(MudObject *who, int aggr)
{
  if (who->get("_fighting"))
    return;

  if (aggr > 0 && randperc() <= aggr) {
    if (!((who->owner->get_flag(FL_PEACEFUL) || (who->owner->owner && who->owner->owner->get_flag(FL_PEACEFUL))))) {
      MudObject *o;
      int i;
      foreach(who->owner->children, o, i) {
	if (is_player(o) && !o->get_priv(PFL_NOHASSLE)) {
	  who->interpretf("attack %s", o->id);
	  break;
	}
      }
    }
  }
}

void mob_rant(MudObject *who) {
  if (who->get("_fighting"))
    return;
  if (who->rant_time > now)
    return;

  int rantcount = who->array_size("rant");
  if (rantcount>=1) {
    int whichrant = (random_number(rantcount));
    
    const char *rant = who->array_get("rant", whichrant);
    
    if (rant) {
      who->ilc++;
      who->interpret(rant);
      who->ilc--;
    } else
      who->interpretf("say Error : can't find rant %i", whichrant);
  }
  
  who->rant_time = now + who->get_int("rantspeed", 65);
}


static bool afflicted(MudObject *who)
{
  if (is_player(who))
    return 1;
  if (strength_of(who)!=who->get_int("maxstrength"))
    return 1;
  if (who->owner) {
    if (who->owner->get_flag(FL_AIRLESS))
      return 1;
    if (who->owner->get_flag(FL_UNDERWATER))
      return 1;
    if (who->owner->get_flag(FL_ONFIRE))
      return 1;
    if (who->owner->get_flag(FL_HOT))
      return 1;
    if (who->owner->get_flag(FL_COLD))
      return 1;
    if (who->owner->get_flag(FL_TEMPEXTREME))
      return 1;
    if (who->owner->get_flag(FL_RADIATION))
      return 1;
  }
  return 0;
}

bool fade(MudObject *who, const char *p2, const char *propname, const char *msg, PRINT_ARGS)
{
  time_t b = who->get_int(propname);
  if (b > 0 && b <= now) {
    who->real_printf(msg, GET_PARMS());
    who->unset(propname);
    if (p2)
      who->unset(p2);
    return 1;
  }
  return 0;
}

void regen(MudObject *who) {
  if (!is_player(who) && !is_mobile(who))
    return;

    int healing = 1;

    if (!who->owner && who != mud)
      set_owner(who, mud);

    int bot = 0;

    if (streq(body(who), "droid")) 
      bot = 1;

    if (who->get_flag(FL_SITTING))
      healing = random_number(4)?1:2;
    if (who->get_flag(FL_SLEEPING))
      healing = 2;

    fade(who, 0,        KEY_BUNNIED,"The ^PBunnies^n vanish!\n");
    fade(who, 0,        "$blissed", "You feel mortal once more.\n");
    fade(who, 0,        "$trip",    "Things fade.\n");
    fade(who, 0,        KEY_PISSED, "You suddenly feel clear-headed.\n");

    if (fade(who, "$piggy", "$pigged",  "You are less %s.\n", who->get("$piggy")?:"porcine")) {
      if (species(who))
	who->oprintf("%#M %[turns/turn] into a %s.\n", who, species(who));
    }

    if (int booze = who->get_int(KEY_PISSED, now)>0) {
      if (booze - now > 210*12 && randperc() < 1 && randperc () < 5) {
	who->printf ("You ^Gpuke^n on your shoes.\n");
	who->oprintf(cansee, "%#M ^Gpukes^n on %s shoes.\n", who, his_or_her(who));
      } else if (booze - now > 173*12 && randperc() < 1 && randperc () < 5) {
	who->printf ("You ^csway^n around like some sort of drunkard.\n");
	who->oprintf(cansee, "%#M ^csways^n around like %s has drunk too much ^Ybooze^n.\n", who, he_or_she(who));
      } else if (booze - now > 135*12 && randperc() < 1 && randperc () < 5) {
	who->printf ("You let everyone know what you had for ^Rlunch^n.\n");
	who->oprintf(canhear, "%#M ^RB U R P S^n loudly^n.\n", who);
      }
    }

    const char *cause = "died of exhaustion";
    const char *others = "%#M %[dies/die] from exhaustion.\n";

    if (!who->get_priv(PFL_IMMORTAL) && !bot) {
       if (who->owner && who->owner->get_flag(FL_ONFIRE) && !wf_wears_with_flag(who, FL_SPACESUIT)) {
	 who->printf("The intense ^Rfire^n burns you.\n");
	 cause = "died from severe burns";
	 others = "%#M %[burns/burn] to death.\n";
	 healing = -10;
       }


       if (who->owner && who->owner->get_flag(FL_AIRLESS)  
	   && !wf_wears_with_flag(who, FL_SPACESUIT)) {
	    if ((now & 31) == 0) {
		who->printf("The lack of an atmosphere harms you.\n");
		cause = "asphyxiated to death";
		others = "%#M %[asphyxiates/asphyxiate] to death.\n";
		healing = -40;
	    }
	    else healing = 0;
	}
    }

    if (who->owner && who->owner->get_flag(FL_UNDERWATER) 
	   && !wf_wears_with_flag(who, FL_SPACESUIT) && 
              !wf_wears_with_flag(who, FL_GILLS) && !bot) {
	    if ((now & 7) == 0) {
		who->printf("You can't breathe underwater.\n");
		cause = "drowned";
		others = "%#M %[drowns/drown].\n";
		healing = -20;
	    }
	    else healing = 0;
    }

    if ((is_mobile(who) || is_player(who)) && !who->get_priv(PFL_IMMORTAL) && !bot) {
	int temp = loctemp(who->owner);

	if (!wf_wears_with_flag(who, FL_SPACESUIT)) {

        if ((temp < 0) && !wf_wears_with_flag(who, FL_COLDPROTECT))
	  if (now&3) {
	      who->printf("The extreme ^Ccold^n bites into your skin.\n");
	      cause = "died from frostbite";
	      others = "%#M %[freezes/freeze] to death.\n";
	      healing = -1;
	  } else {
  	    healing = 0;
	  }

        if (temp >= 40 && !wf_wears_with_flag(who, FL_HEATPROTECT))
	  if (now&3) {
	    who->printf("The intense ^Rheat^n burns you.\n");
	    cause = "died from overheating";
	    others = "%#M %[dies/die] from overheating.\n";
	    healing = -1;
	  } else {
	    healing = 0;
	  }
	}

	if (who->owner->get_flag(FL_RADIATION)  && !has_rad_suit(who)) {
	    if ((now & 31) == 0) {
		who->printf("The deadly ^Gradiation^n harms you.\n");
		cause = "died from radiation poisoning";
		others = "%#M %[dies/die] from radiation.\n";
		healing = -10;
	    }
	    else healing = 0;
	}
    }

    if (who->get("_fighting") && healing > 0) healing = 0;

    if (healing > 0 && who->get_flag(FL_NOHEAL) || who->owner->get_flag(FL_NOHEAL))
      healing = 0;

    int strength = strength_of(who);
    int max = who->get_int("maxstrength", 200);

    if (strength==-1 && max==-1) {
      return;
    }
    
    if ((strength+healing) > max)
	healing -= (max - strength);

    if (healing == 0)
      return;
    
    strength += healing;

    if (strength > max) {
	strength = max;
	healing = 0;
    }

    set_strength(who, strength);
    if (strength==max && (healing>0)) {
	who->printf("You feel fully healed.\n");
    }
    
    if (strength < 0 && !who->get_priv(PFL_IMMORTAL)) {
	dumpstuff(who, who->owner);
	who->printf("Oh dear... you seem to be slightly dead.\n");
	who->oprintf(others, who);
	MudObject *corpse = do_die(who, privs_of(who)*20, cause);
	if (corpse) {
	  corpse->setf("desc", "%#M seems to have %s.", who, cause);
	}
    }

}

void MudObject::execute() {
  if (!this) {
    return;
  }

  extern MudObject *qui;
    if (quit) {
	nuke_me = 1;
	return;
    }

    if (nuke_me)
      return;

    MudObject *oq = qui;
    qui = this;

    if (get_flag(FL_WILDERNESS) && ((now - reftime) > 60)) {
      interpret("timeout");
    }

    if (get_flag(FL_ONFIRE)) {
      if (get_int("!burnout", 0)>1 && get_int("!burnout")<=now) {
	oprintf(cansee, "%#P burns out.\n", this);
	/* replace it with ashes */
	replace_with_empty(this);
      }
    }

    bool is_mob = is_mobile(this);
    bool is_ply = is_player(this);

    if (is_ply) {
      if (owner && owner->get_flag(FL_OUTDOORS) && !owner->get_flag(FL_NOGRAVITY)) {
	if (mudtime(owner).hour != get_int("!timeofday")) {
	  if (get_int("!timeofday")!=-1) {
	    int tday = mudtime(owner).hour;
	    if (tday==5) {
	      printf("The ^ysun^n begins to peek over the horizon.\n");
	    }
	    if (tday==7) {
	      printf("With the ^Ysun^n fully above the horizon, a new day begins.\n");
	    }
	    if (tday==18) {
	      printf("The ^ysun^n begins to set behind the horizon.\n");
	    }
	    if (tday==20) {
	      printf("The ^rsun^n sets over the horizon.\n");
	    }

	    set("!timeofday", tday);
	  }
	}
      }
    }

    if (get_flag(FL_MISSION) && MISSION_ROUTINE)
      MISSION_ROUTINE(this);
    
    if (get_flag(FL_TIMER)) {
      int c = 0;
      int qhen = get_int("!when");
      if (qhen == -1)
	set_flag(FL_TIMER, 0);
      while (qhen > 0 && qhen <= now && c < 5) {
	c++;
	unset("!reschedule");
	ilc++;
	interpret(get("!what"));
	ilc--; 
	
        int resched = get_int("!reschedule");
	if (resched != -1) {
	  qhen = resched + now;
	  set("!when", qhen);
	  break;
	}
	
	if (!get("!plan")) {
	  unset("!when");
	  unset("!what");
	  unset("!plan");
          break;
	}

	char *plan = strdup(get("!plan")); /* FIXME : uniq */
	char *qhat= plan ? strchr(plan, ' ') : NULL;

	if (!qhat) {
	  unset("!when");
	  unset("!what");
	  free(plan);
	  break;
	}
	*qhat = 0;
	qhat ++;
	char *newplan = strchr(qhat, ';');
	char *newln = strchr(qhat, '\n');
	if (!newplan && newln) newplan = newln;
	else if (newln && newln < newplan) newplan = newln;

	if (!newplan) 
	  newplan = "";
	else {
	  *newplan = 0;
	  newplan++;
	}
	qhen = atoi(plan) + now;
	set("!when", qhen);
	set("!what", qhat);
	set("!plan", newplan);
	free(plan);
      }
    }

    if (game_mobiles) {
      if ((now & 7) && is_mob || is_ply) {
	int aggr = get_int("aggr");
	if (aggr > 0 && owner->players_here)
	  mobile_aggr(this, aggr);
      }

      if (get_flag(FL_WANDER) && wander_time <= now) {
	mobile_wander(this);
	wander_time = now+get_int("wander.time", 8+random_number(4));
      }

      if (get_flag(FL_RANTER) && rant_time <= now) {
	mob_rant(this);
      }
    }

    if ((now & 1) && get("_fighting") && COMBAT_ROUTINE) {
      COMBAT_ROUTINE(this);
    }

    if (!(now & 1))
      if (afflicted(this))	    
	regen(this);

    qui = oq;

    return;
}