/* * 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; }