/* * MusicMUD - Object handling 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. * */ #define BOOZE_FACTOR 12 #define BOOZE_MAX 6000 #include "musicmud.h" #include "verbs.h" #include "misc.h" #include "util.h" #include "events.h" #include "trap.h" #include "pflags.h" #include "musictok.h" #include "units.h" #include "shared.h" #include "match.h" #include "death.h" #include "hooks.h" #include "emsg.h" #include "nations.h" #include <vector> #include <algorithm> static inline bool is_fillable(const TeleObject &o) { return o->get_flag(FL_WATERTIGHT); } static inline bool is_person(const TeleObject &o) { return is_person(o.what); } static void consolidate(MudObject *what, bool anyway) { if (used_volume(what)==0 || anyway) { what->unset("$fill.0"); what->unset("$fillamt.0"); what->set("$fill.count", 0); what->set("$fillamt.count", 0); } } static void collapse_cash(MudObject *what) { MudObject *player = what->owner; if (!is_person(player)) return; if (what->get_flag(FL_CASH)) { moveallcash(what, player); vanish(what); } } #define MODULE "objects" static string fshort(MudObject *what) { return subshort(what); } static void consume_obs(MudObject *who, NewWorld what, int drink) { MudObject *o; int i; int strength = strength_of(who), oldstrength = strength; int maxstrength = who->get_int("maxstrength"); NewWorld empties; foreach((&what), o, i) { if (dotrap(E_ONCONSUME, who, o, 0, 0)) { /* ::: consume o1==what eaten; before everything, return 1 to abort */ what.remove(*o); i--; continue; } } NewWorld inedible; NewWorld recs; foreach((&what), o, i) { if (o->get_flag(FL_WATERTIGHT)) { recs.add(*o); what.remove(*o); i--; continue; } if (o->get_object("fount")) { recs.add(*o); what.remove(*o); i--; continue; } if (o->get_flag(FL_DRINK)!=drink) { inedible.add(*o); what.remove(*o); i--; continue; } if (!real_is_edible(o)) { inedible.add(*o); what.remove(*o); i--; continue; } } set<string> ins; foreach((&inedible), o, i) { if (o==who) ins.insert("yourself"); else if (is_person(o)) ins.insert("others"); else ins.insert(plural_name(o)); } set<string>::iterator init = ins.begin(); string cant; while (init != ins.end()) { string s = *init; init++; if (init==ins.end() && cant.length()) cant += " or "; else cant += ", "; cant += s; } if (cant.length()) { who->printf("You can't %s %s.\n", drink?"drink":"eat", cant.c_str()+2); } NewWorld drinks, eats; foreach((&what), o, i) { if (o->get_flag(FL_DRINK)) drinks.add(*o); else eats.add(*o); } if (drinks.getsize()) { who->printf("You drink %s.\n", magiclist(drinks).c_str()); who->oprintf(cansee, "%#M %[drinks/drink] %s.\n", who, magiclist(drinks).c_str()); } if (eats.getsize()) { who->printf("You eat %s.\n", magiclist(eats).c_str()); who->oprintf(cansee, "%#M %[eats/eat] %s.\n", who, magiclist(eats).c_str()); } foreach((&what), o, i) { strength += o->get_int("food", 0); if (strength > maxstrength) { strength = maxstrength; if (oldstrength < maxstrength) { who->printf("You feel fully healed.\n"); } } int booze = (abv(o)*serving(o)*BOOZE_FACTOR)/10000; if (booze>0) { who->set(KEY_PISSED, who->get_int(KEY_PISSED, now)+booze); } if (MudObject *em=o->get_object("empty")) { MudObject *e=0; if (o->get_object("cloneof")) e = clone_object(em, o->owner, NULL); else { set_owner(em, o->owner); e = em; } empties.add(e); } vanish(o); } NewWorld empty, sub, sdrink; foreach((&recs), o, i) { if (dotrap(E_BEFOREFOUNTAIN, who, o, 0, 0)) { /* ::: before_fountain o1==fountain, o2==container (if any); before someone uses a fountain. if on container, being drunken from. return 1 to abort. */ recs.remove(*o); i--; continue; } MudObject *substance = o->get_object("fount"); int amount = 100; if (!substance) { substance = o->array_get_object("$fill", 0); amount = used_volume(o); } if (!substance || !amount) { empty.add(*o); continue; } if (!real_is_edible(substance)) { who->printf("You can't drink %s.\n", subshort(substance)); continue; } if (!sub.get(substance->id)) { sub.add(*substance); } sdrink.add(*o); strength += substance->get_int("food", 0); if (strength > maxstrength) { strength = maxstrength; if (oldstrength < maxstrength) { who->printf("You feel fully healed.\n"); } } int booze = abv(substance) * amount /10000; if (booze > 0) { who->set(KEY_PISSED, who->get_int(KEY_PISSED, now)+(booze*BOOZE_FACTOR)); } consolidate(o, true); } if (sdrink.getsize()) { who->printf("You drink %s from %s.\n", magiclist(sub, fshort).c_str(), magiclist(sdrink).c_str()); who->oprintf(cansee, "%#M %[drinks/drink] from %s.\n", who, magiclist(sdrink).c_str()); } empties += sdrink; set_prons(who, empties); if (what.getsize()==1 ^ sdrink.getsize()==1) { MudObject *ob = (what.getsize()?what:sub).get_nth(0); MudObject *subs = sub.getsize()?sub.get_nth(0):0; if (ob->get("taste")) { who->printf("%s\n", ob->get("taste")); } else { if (!subs) subs = ob->get_object("substance"); if (!subs) subs = ob; int alc = abv(subs); if (alc>4000) who->printf("%|%[It tastes/They taste] very strongly of alcohol.\n", subs); else if (alc>2000) who->printf("%|%[It tastes/They taste] strongly of alcohol.\n", subs); else if (alc>200) who->printf("%|%[It tastes/They taste] of alcohol.\n", subs); else if (is_person(subs)) who->printf("%|%[It tastes/They taste] of meat.\n", subs); else who->printf("%|%[It tastes/They taste] like %s.\n", subs, subs->get("short")); } } if (is_player(who)) { int booze = who->get_int(KEY_PISSED, now); if (booze - now > 300*12) { do_die(who, privs_of(who)*20, "alcohol poisoning"); return; } } foreach((&recs), o, i) { if (dotrap(E_AFTERCONSUME, who, o, 0, 0)) { /* ::: after_consume o1==thing consumed; after taste, alcohol death, return 1 to abort. */ recs.remove(*o); i--; continue; } } foreach((&what), o, i) { if (dotrap(E_AFTERCONSUME, who, o, 0, 0)) { what.remove(*o); i--; continue; } } if (empty.getsize()) { who->printf("%#s %s empty.\n", magiclist(empty).c_str(), plural(empty)?"are":"is"); } set_strength(who, strength); if (strength < 0) { MudObject *cor = do_die(who, privs_of(who)*20, "food poisoning"); if (cor) { cor->setf("desc" ,"%#M seems to have died from food poisoning.", who); } } } static bool can_seeinto(MudObject *player, MudObject *what) { if (what->get_flag(FL_TRANSPARENT)) return true; if (!what->get_flag(FL_CONTAINER)) return false; if (what->get_flag(FL_STATED)) return true; return state(what)==0; } static bool is_corpse(const TeleObject &what) { if (what->get_object("treatas") == MUD_CORPSE) { return 1; } return 0; } static void rmcard(MudObject *deck, int which) { int s = deck->array_size("$card"); for (int i=which;i<(s-1);i++) { deck->array_set("$card", i, deck->array_get_int("$card", i+1)); } deck->array_unset("$card", s); deck->set("$card.count", s-1); } static void addcard(MudObject *from, int card, int hidden) { int cc = from->array_size("$card"); from->array_set("$card", cc, card+(hidden?256:0)); from->set("$card.count", cc+1); } #define DEAL_ALLSEE 0 #define DEAL_TARSEE 1 #define DEAL_NONSEE 2 static void do_deal(MudObject *who, MudObject *deck, MudObject *target, int mode, int howmany) { string cards; int dealt=0; for (int h=0;h<howmany;h++) { int s = deck->array_size("$card"); if (s==0) { continue; } int card = deck->array_get_int("$card", 0); string cardst = describe_card(card, 1); const char *cardstr = cardst.c_str(); const char *repstr = cardstr; if (cards.length()) { cards += " and "; } cards += cardstr; if (mode==DEAL_NONSEE) cardstr = repstr = "a card"; if (mode==DEAL_TARSEE) cardstr = "a card"; #if 0 if (who==target) { who->printf("You deal %s to yourself.\n", repstr); who->oprintf(cansee, "%#M %[deal/deals] %s to %sself.\n", who, cardstr, his_or_her(who)); } else { who->printf("You deal %s to %M.\n", cardstr, target); who->oprintf(cansee, target, "%#M %[deals/deal] %s to %M.\n", who, cardstr, target); target->printf("%#M %[deals/deal] %s to you.\n", who, repstr); } #endif rmcard(deck, 0); addcard(target, card, mode==DEAL_NONSEE); dealt++; } string reps = cards; if (mode==DEAL_NONSEE) { if (dealt==1) cards = reps = "a card"; else cards = reps = ssprintf("%s cards", numbertostring(dealt)); } if (mode==DEAL_TARSEE) { if (dealt==1) cards = "a card"; else cards = ssprintf("%s cards", numbertostring(dealt)); } if (dealt) { if (target==who) { who->printf("You deal %s to yourself.\n", reps.c_str()); who->oprintf(cansee, "%#M %[deals/deal] %s to %sself.\n", who, cards.c_str(), him_or_her(who)); } else { who->printf("You deal %s to %M.\n", cards.c_str(), target); who->oprintf(cansee && avoid(target), "%#M %[deals/deal] %s to %M.\n", who, cards.c_str(), target); target->printf("%#M %[deals/deal] %s to you.\n", who, reps.c_str()); } } } //! A playing card struct card { int suit; int val; }; static struct card parsecard(const char *a) { struct card cd = {-1, -1}; int &val = cd.val; int &suit = cd.suit; if (strchr(a, '*')) { val = -2; suit = -2; } if (streq(a, "all")) { val = -2; suit = -2; return cd; } if (strchr(a, 'A')||strchr(a,'a')) val= 0; if (strchr(a, '2')) val= 1; if (strchr(a, '3')) val= 2; if (strchr(a, '4')) val= 3; if (strchr(a, '5')) val= 4; if (strchr(a, '6')) val= 5; if (strchr(a, '7')) val= 6; if (strchr(a, '8')) val= 7; if (strchr(a, '9')) val= 8; if (strchr(a, 'T')||strchr(a,'t')) val= 9; if (strchr(a, 'J')||strchr(a,'j')) val= 10; if (strchr(a, 'Q')||strchr(a,'q')) val= 11; if (strchr(a, 'K')||strchr(a,'k')) val= 12; if (strchr(a, 'S')||strchr(a,'s')) suit = 0; if (strchr(a, 'H')||strchr(a,'h')) suit = 1; if (strchr(a, 'C')||strchr(a,'c')) suit = 2; if (strchr(a, 'D')||strchr(a,'d')) suit = 3; if (strchr(a, '?')) { suit = -3; val = -3; } if (val == -1 || suit == -1) { suit = -1; val = -1; return cd; } return cd; } static int matches(int a, struct card cd) { int va = (a&0xff)%13, sa=(a&0xff)/13; int vb = cd.val, sb=cd.suit; if (va == vb && sa == sb) return 1; if (va == vb && sb == -2) return 1; if (sa == sb && vb == -2) return 1; if (sb == -2 && vb == -2) return 1; if (a & 256 && vb==-3) return 1; return 0; } static bool verb_discard(MudObject *who, int argc, const char **argv) { if (argc < 2) { who->printf("Discard what?\n"); return true; } struct card c = parsecard(argv[1]); if (c.val==-1) { who->printf("Can't decode that.\n"); return true; } int count = 0; for (int i=0;i<who->array_size("$card");i++) { if (matches(who->array_get_int("$card", i), c)) { rmcard(who, i); i--; count++; } } if (count) { who->printf("You discard %i card%s.\n", count, count==1?"":"s"); who->oprintf("%#M %[discards/discard] %i card%s.\n", who, count, count==1?"":"s"); dotrap(E_AFTERDISCARDINROOM, who, who->owner); } else { who->printf("You have no matching cards.\n"); } return true; } static bool verb_deal(MudObject *who, int argc, const char **argv) { MudObject *deck=0; MudObject *o; int i; foreach(who->children, o, i) { if (streq(o->get("short"), "deck")) deck = o; } if (!deck) { who->printf("No deck.\n"); return true; } int mode = DEAL_TARSEE; int d = 1; int n = 1; if (streq(argv[1], "two")) { n = 2; d++; } if (streq(argv[d], "openly")) { mode = DEAL_ALLSEE; d++; } if (streq(argv[d], "privately")) { mode = DEAL_TARSEE; d++; } if (streq(argv[d], "secretly")) { mode = DEAL_NONSEE; d++; } NewWorld w = match(who, argc-d, argv+d, is_person, LOOK_BOTH|IGNORE_EXITS); if (w.getsize()==0) { who->printf("Deal to who?\n"); return true; } foreach((&w), o, i) { do_deal(who, deck, o, mode, n); if (deck->array_size("$card")==0) { who->printf("Deck exhausted.\n"); vanish(deck); return true; } } return true; } static bool verb_shuffle(MudObject *who, int argc, const char **argv) { NewWorld w = match(who, argc-1, argv+1, 0, LOOK_BOTH|IGNORE_EXITS); MudObject *what = 0; if (w.getsize()>1) { who->printf("You can only shuffle one thing at a time.\n"); return true; } else if (w.getsize()) { what = w.get_nth(0); } if (!what) { who->printf("Shuffle what?\n"); return true; } int siz = what->array_size("$card"); if (!siz) { return true; } int cards[siz]; for (int i=0;i<siz;i++) cards[i] = what->array_get_int("$card", i); for (int n=0;n<5;n++) { for (int i=0;i<siz;i++) { int r = random_number(siz); int tmp = cards[i]; cards[i] = cards[r]; cards[r] = tmp; } } for (int i=0;i<siz;i++) what->array_set("$card", i, cards[i]); who->printf("You give %Y a good shuffle.\n", what); who->oprintf(cansee, "%#M shuffles %P.\n", who, what); return true; } static bool verb_examine(MudObject *player, int argc, const char*argv[]) { if (argc < 2) { player->printf("Examine what?\n"); return true; } fixup_lapels(player, NULL); TeleWorld w = multi_match(player, argc-1, argv+1, 0, LOOK_BOTH|LOOK_MWIELD|ALLOW_ME); MudObject *what = 0; TeleObject rreal; const TeleObject *real=0; if (w.getsize()>1) { player->printf("You can only examine one thing at a time.\n"); return true; } else if (w.getsize()) { what = w.get_nth(0); real = &w.get(0); } const char *tlink = 0; if (!what) { if (player->owner->get_flag(FL_LINKED)) { int i; MudObject *obj; foreach(player->owner->children, obj, i) { MudObject *o = linkedlink(obj); if (o && o->get_flag(FL_LINKED)) { w = multi_match(player, argc-1, argv+1, NULL, LOOK_SPECIAL|IGNORE_EXITS, NULL, o->children); if (w.getsize()>1) { player->printf("You can only examine one thing at a time.\n"); return true; } if (w.getsize()==1) { MudObject *wh = w.get_nth(0); if (!is_mobile(wh) && !is_player(wh)) continue; what = w.get_nth(0); rreal = w.get(0); real = &rreal; tlink = obj->get("short"); } } } } } if (what && what->get_flag(FL_EXIT)) { MudObject *o = what->get_object("link"); if (o) { string tostr = format_roomname(o, player, "", "", "to"); // XXX : fix this for buildings player->printf("It leads %s.\n", tostr.c_str()); return true; } } if (!what || what->get_flag(FL_EXIT)) { player->printf("You cannot locate '^o%s^n'.\n", w.txt.c_str()); return true; } int oldstate = state(what); set_prons(player, *real); if (what->get_flag(FL_EXAMFLIPS)) what->set(KEY_STATE, 0); /* ::: examine o1==thing examined; before "You examine..." messages, return 1 to abort */ if (dotrap(E_ONEXAMINE, player, what, 0, 0)) return true; if (what->get("newsgroup")) { player->interpret("scan"); return true; } if (player==what) { player->printf("You examine yourself.\n"); player->oprintf(cansee, "%#M %[examines/examine] %s.\n", player, himself_or_herself(player)); } else { if (tlink) { if (!is_person(what)) { player->printf("You look %s and examine %Y.\n", tlink, real); player->oprintf(cansee && avoid(what), "%#M %[looks/look] %s and %[examines/examine] %P.\n", player, tlink, what); } else { player->printf("You look %s at %Y.\n", tlink, real); player->oprintf(cansee && avoid(what), "%#M %[looks/look] %s at %P.\n", player, tlink, what); } } else { if (!what->get_flag(FL_NOEXAMTEXT)) { if (is_person(what)) player->printf("You look at %Y.\n", real); else player->printf("You examine %Y.\n", real); } if (is_person(what)) player->oprintf(cansee && avoid(what), "%#M %[looks at/look at] %P.\n", player, real); else player->oprintf(cansee && avoid(what), "%#M %[examines/examine] %P.\n", player, real); } if (is_person(what)) what->printf("%#M %[looks/look] at you.\n", player); else what->printf("%#M %[examines/examine] you.\n", player); if (player->get_object(KEY_WIELD)==what) player->printf("You are wielding %s.\n", it_them(what)); if (what->get_object(KEY_WORNBY)==player) { const char *w = what->get("$wornon"); if (!w) w = what->get("wornon"); player->printf("You are wearing %s %s your %s.\n", it_them(what), streq(w, "allover")?"over":"on", looknice(w)); } if (player->get_object(KEY_SITON)== what && player->get_int(KEY_SITONN, 0)==rreal.nth) { if (player->get_flag(FL_SITTING)) player->printf("You are sitting on %s.\n", it_them(what)); else player->printf("You are standing on %s.\n", it_them(what)); } if (!player->get_object(KEY_SITON) && what->get_flag(FL_FLOOR)) { if (player->get_flag(FL_SITTING)) player->printf("You are sitting on %s.\n", it_them(what)); else if (player->get_flag(FL_FLYING)); else if (player->get_flag(FL_SLEEPING)); else if (player->get_flag(FL_SWIMMING)); else player->printf("You are standing on %s.\n", it_them(what)); } if (what->get("on_examine")) { player->ilc++; player->interpret(what->get("on_examine")); player->ilc--; return true; } } /* ::: before_examine o1==thing examined; after "You examine...", you are wearing messages, but before main desc ; return 1 to abort */ if (dotrap(E_BEFOREEXAMINE, player, what, 0, 0)) return true; if (what->array_size("$fill") == 1) { describe_liquid_to(player, what); } /* ::: before_show_desc o1==thing examined; instead of printing the 'desc' when examined. returning 1 averts that, but will still print clothes etc. */ if (!dotrap(E_BEFORESHOWDESC, player, what, 0, 0)) { const char *d = what->array_get("desc", oldstate); if (!d) d = what->get("object_desc"); if (!d) d = what->get("desc"); if (!d) { MudObject *t = what->get_object("treatas"); if (t) { d = t->get("desc"); } } if (streq(d, "This player has no description.") || streq(d, "A typical mobile...")) d = 0; if (d && !strchr(d, '\n')) player->printf(" %s\n", d?d:"You notice nothing unusual."); else player->printf("%s\n", d?d:"You notice nothing unusual."); } if (shelf_low_enough(player, what)) { MudObject *o; int i; NewWorld stuff; foreach(what->owner->children, o, i) { if (o->get_object(KEY_SITON)==what && o->get_int(KEY_SITONN, 0)==real->nth) { if (!is_person(o)) { stuff.add(o); } } } if (stuff) player->printf("Upon %s %s %W.\n", it_them(what), plural(stuff)?"are":"is", &stuff); } else { player->printf("It's too high to see on top of %s.\n", it_them(what)); } if (is_player(what) || is_mobile(what) || can_seeinto(player, what) || is_corpse(what)) { TeleWorld cloth = clothes(what); MudObject *wornfrom = ::wornfrom(what); if (wornfrom == what) wornfrom = 0; MudObject *wp = what->get_object(KEY_WIELD); if (!wp && wornfrom) wp = wornfrom->get_object(KEY_WIELD); if (wp) { player->printf("%#H %[is/are] wielding %M.^n\n", what, wp); } MudObject *rid = mount(what); if (rid) { const char *rv = rid->get("riding_verb"); if (!rv) rv = "riding"; player->printf("%#H %[is/are] %s %M.^n\n", what, rv, rid); } NewWorld seencloth; MudObject *o; int i; foreach((&cloth), o, i) { if (o->get("name")) { int wl = o->get_int("wornlevel", 0); const char *wn = wornon(o); if (is_player(what) || is_mobile(what)) { StrTok t(wn); int yes = 0; while (const char *won=t.next(",")) { if (worn_on(what, won, wl+1)) { continue; } if (wornfrom && worn_on(wornfrom, won, wl+1)) continue; yes = 1; } if (!yes) continue; } seencloth.add(o); } } if (seencloth) player->printf("%#H %[is/are] wearing %w.\n", what, seencloth); NewWorld unworn; foreach(what->children, o, i) { if (!iswornby(o, what) && o != wp && o != rid) unworn.add(*o); } NewWorld carrying; foreach((&unworn), o, i) { if (o->get_flag(FL_EXIT)) continue; if (!o->get("name")) continue; if (o->get_flag(FL_EXIT)) continue; if (o == wp || o == rid) continue; carrying.add(o); } if (carrying) if (is_person(what)) player->printf("%#H %[is/are] carrying %w.\n", what, carrying); else player->printf("%#H %[contains/contain] %w.\n", what, carrying); } if (what->get_flag(FL_CANOPEN)) { int stat = state(what); if (stat==1) { player->printf("%#s %s closed.\n", it_they(what), is_are(what)); } else if (stat==2) { player->printf("%#s %s locked.\n", it_they(what), is_are(what)); } } NewWorld find; if (!what->get_flag(FL_DISCOVERED)) { if (what->get("discover")) { MudObject *d = what->get_object("discover"); if (d) { find.add(d); set_owner(d, player->owner); what->set_flag(FL_DISCOVERED, 1); /*return true;*/ } else player->printf("bug : invalid discover property on %s (%s).\n", what->id, what->get("discover")); } if (int s = what->array_size("discover")) { for (int i=0;i<s;i++) { MudObject *d = what->array_get_object("discover", i); if (d) { find.add(d); set_owner(d, player->owner); what->set_flag(FL_DISCOVERED, 1); /*return true;*/ } } } if (int z = what->array_size("disc")) { for (int j=0;j<z;j++) { MudObject *t = what->array_get_object("disc", j); int c = what->array_get_int("disc", j, "count", 1); if (c > 10) c = 10; if (t) { while (c) { MudObject *o2=clone_object(t, player->owner, 0); o2->set_bflag(FL_DESTROYONRESET, 1); o2->set_bflag(FL_NOSAVE, 1); o2->set("zone", what->get("zone")); o2->set("start", player->owner->id); find.add(o2); c--; } } } what->set_flag(FL_DISCOVERED, 1); } } if (find) { player->printf("Examining %P, you discover %W.\n", what, &find ); player->oprintf(cansee && avoid(what), "%#M %[discovers/discover] %W.\n", player, &find); set_prons(player, find); } /* ::: after_examine o1==thing examined; after everything */ if (dotrap(E_AFTEREXAMINE, player, what, 0, 0)) return true; return true; } static MudObject *find_pot(MudObject *where) { MudObject *o; int i; foreach(where->children, o, i) { if (o->get_flag(FL_CASH)) return o; } return 0; } bool is_droppable(const TeleObject &t) { return is_droppable(t.what); } static bool verb_drop(MudObject *who, int argc, const char **argv) { if (argc == 1) { who->printf("Drop what?\n"); return true; } NewWorld what = match(who, argc-1, argv+1, is_droppable, LOOK_INV|IGNORE_EXITS|IGNORE_MISSION); if (!who->owner) { set_owner(who, "@musicmud"); } if (argc == 3) { { cashinfo c = curmatch(argc-1, argv+1); if (c.cur && (c.amt || c.all)) { int have = cash(who, c.cur); if (c.all) c.amt = have; if (c.amt > have) { who->printf("You have only got %s.\n", formatcash(have, c.cur, 0)); return true; } if (c.amt <= 0) { who->printf("Very funny.\n"); return true; } MudObject *where = who->owner; MudObject *pot = find_pot(where); if (!pot) pot = clone_object(MUD_CASH, who->owner, NULL); if (!pot) throw emsg("Can't drop the cash."); set_cash(pot, c.cur, cash(pot, c.cur)+c.amt); set_cash(who, c.cur, cash(who, c.cur)-c.amt); who->printf("You drop %s.\n", formatcash(c.amt, c.cur, 1)); who->oprintf("%M %[drops/drop] %s.\n", who, formatcash(c.amt, c.cur, 1)); describe_pot(pot); return true; } } } if (what.getsize()) { drop_obs(who, what, 0, streq(argv[0], "put")); fixup_lapels(who, NULL); set_prons(who, what); } else { if (who->get_flag(FL_LOGGEDIN)) { if (what.all_nothing==1) who->printf("You aren't carrying anything.\n"); else if (what.all_nothing==0) who->printf("You aren't carrying anything like that.\n"); else if (what.all_nothing==103) who->printf("Drop any what?\n"); else who->printf("You aren't carrying anything you can drop.\n"); } } return true; } static bool verb_throw(MudObject *who, int argc, const char **argv) { if (argc == 1) { who->printf("Throw what?\n"); return true; } NewWorld what = match(who, argc-1, argv+1, is_droppable, LOOK_INV|IGNORE_EXITS|IGNORE_MISSION); TeleWorld what2 = multi_match(who, argc-1, argv+1, 0, LOOK_BOTH|IGNORE_EXITS|LOOK_LINKED, 0, 0, "at"); if (what2.getsize()>1) { who->printf("You can only throw at one (or zero) things.\n"); return true; } TeleObject tat = what2.getsize()?what2.get(0):0; if (!tat && streq(what2.prep, "at")) { who->printf("Throw at what?\n"); return true; } if (!who->owner) { set_owner(who, "@musicmud"); } if (what.getsize()) { drop_obs(who, what, true, 0, tat); set_prons(who, what); } else { if (what.all_nothing==1) who->printf("You aren't carrying anything.\n"); else if (what.all_nothing==103) who->printf("Throw any what?\n"); else who->printf("You aren't carrying anything like that.\n"); } return true; } static bool is_food(const TeleObject &o) { return is_edible(o.what) && !(o->get_flag(FL_DRINK) || o->get_flag(FL_WATERTIGHT)); } static bool is_drink(const TeleObject &o) { return is_edible(o.what) && (o->get_flag(FL_DRINK) || o->get_flag(FL_WATERTIGHT)); } static bool verb_eat(MudObject *who, int argc, const char **argv) { if (argc == 1) { who->printf("Eat what?\n"); return true; } NewWorld what = match(who, argc-1, argv+1, is_food, LOOK_INV|LOOK_ROOM|IGNORE_EXITS|ALLOW_ME); if (!who->owner) { set_owner(who, "@musicmud"); } if (what.getsize()) { consume_obs(who, what, 0); fixup_lapels(who, NULL); } else { if (what.all_nothing==2) who->printf("You aren't carrying anything edible.\n"); else if (what.all_nothing==1) who->printf("You aren't carrying anything.\n"); else who->printf("You aren't carrying anything like that.\n"); } return true; } static bool verb_drink(MudObject *who, int argc, const char **argv) { if (argc == 1) { who->printf("Drink what?\n"); return true; } NewWorld what = match(who, argc-1, argv+1, is_drink, LOOK_INV|LOOK_ROOM|IGNORE_EXITS|ALLOW_ME); if (!who->owner) { set_owner(who, "@musicmud"); } if (what.getsize()) { consume_obs(who, what, 1); fixup_lapels(who, NULL); } else { if (what.all_nothing==2) who->printf("You aren't carrying anything you can drink.\n"); else if (what.all_nothing==1) who->printf("You aren't carrying anything.\n"); else who->printf("You aren't carrying anything like that.\n"); } return true; } static bool is_takeable(const TeleObject &o) { if (o->get_flag(FL_FIXED)) return 0; if (o->get_flag(FL_EXIT)) return 0; if (is_player(o.what)) return 0; if (is_big_mobile(o.what)) return 0; return 1; } TeleObject upon(MudObject *o) { return TeleObject(o->owner, o->get_object(KEY_SITON), o->get_int(KEY_SITONN)); } static void take_obs(MudObject *player, NewWorld what, MudObject *fromwhat=0, int carehands=1) { NewWorld too_heavy, cantget; MudObject *o; int i; int hands = freehands(player); int wanthands = 0; int spare = mass_capacity_left_in_grams(player); NewWorld extra; map<MudObject*, MudObject*> trayed; set<MudObject*> tabled; map<MudObject*, MudObject*> tableof; foreach(&what, o, i) { MudObject *p; int j; foreach(o->owner->children, p, j) { if (p->get_object(KEY_SITON)==o) { extra.add(p); trayed[p] = o; } } } what += extra; foreach(&what, o, i) { if (o->get_object(KEY_SITON)) { tabled.insert(o); tableof[o] = o->get_object(KEY_SITON); } /* ::: get o1==object getting; before any checking, messaging. return 1 to abort. */ if (dotrap(E_ONGET, player, o, 0, 0)) { what.remove(*o); i--; continue; } /* ::: before_getfrom o1==table o2==object being taken; return 1 to abort */ if (tabled.find(o)!=tabled.end() && dotrap(E_BEFOREGETFROM, player, tableof[o], o)) { what.remove(*o); i--; continue; } } foreach(&what, o, i) { if (o==player || o == fromwhat) { player->printf("You cannot get yourself.\n"); what.remove(*o); i--; continue; } if (!is_takeable(o)) { cantget.add(o); what.remove(o); i--; continue; } if (spare != SIZE_INFINITE) { int newspare = spare - mass_in_grams(o); if (newspare < 0) { what.remove(*o); i--; too_heavy.add(*o); continue; } spare = newspare; } if (carehands) { if (!hands) { wanthands = 1; what.remove(*o); i--; continue; } hands--; } } if (what.getsize()) { if (!fromwhat) { player->printf("You get ^Z%s.\n", magiclist(what).c_str()); player->oprintf(cansee, "%#M %[gets/get] ^Z%s.\n", player, magiclist(what).c_str()); } else { player->printf("You get ^Z%s from %Y.\n", magiclist(what).c_str(), fromwhat); player->oprintf(cansee, "%#M %[gets/get] ^Z%s from %P.\n", player, magiclist(what).c_str(), fromwhat); } } foreach(&what, o, i) { o->printf("%#M gets you.\n", player); set_owner(o, player); } if (too_heavy.getsize()) { player->printf("%#s %s too heavy to carry.\n", magiclist(too_heavy).c_str(), plural(too_heavy)?"are":"is"); } if (cantget) { player->printf("You cannot get %W.\n", cantget); } if (wanthands) { player->printf("You haven't enough hands/pockets to carry any more.\n"); } foreach(&what, o, i) { collapse_cash(o); if (dotrap(E_ONHANDLE, player, o, 0, 0)) { /* ::: handle o1==object gotten; after an object has been picked up in any way. */ what.remove(*o); i--; continue; } if (dotrap(E_AFTERGET, player, o, 0, 0)) { /* ::: after_get o1==object gotten; after everything */ what.remove(*o); i--; continue; } /* ::: after_getfrom o1==table o2==object that was taken */ if (tabled.find(o)!=tabled.end() && dotrap(E_AFTERGETFROM, player, tableof[o], o, 0)) { what.remove(*o); i--; continue; } if (o->get_flag(FL_GETFLIPS)) o->set(KEY_STATE, 0); if (o->get_flag(FL_INVISIBLE)) o->set_flag(FL_INVISIBLE, 0); } iforeach(i, trayed) { i->first->set(KEY_SITON, i->second); i->first->set(KEY_SITONN, 0); } } void do_steal(MudObject *who, TeleObject item, MudObject *victim) { if (victim == who) { who->printf("Very funny.\n"); return; } if (weapon(victim)==item) { who->printf("You can't steal a wielded weapon.\n"); return; } if (item->get_object(KEY_WORNBY)==victim) { who->printf("You can't steal worn clothes.\n"); return; } if (mount(victim)==item) { who->printf("You can't steal mounts.\n"); return; } if (item->get_flag(FL_MISSION) || item->get_flag(FL_QUEST)) { who->printf("You can't steal missions.\n"); return; } if (item.where != victim) { who->printf("You can't steal %Y.\n", &item); return; } if (dotrap(E_BEFORESTEAL, who, item, victim)) /* ::: before_steal o1==object to steal, o2==victim; return 1 to abort */ return; if (!is_person(victim)) { who->printf("You can't steal from %Y.\n", victim); return; } if (!is_player(victim)) { who->printf("%#Y is too alert.\n", victim); return; } if (mass_capacity_left_in_grams(who) < mass_in_grams(item) || !freehands(who)) { who->printf("You try to steal %M from %Y.\n", &item, victim); victim->printf("%#M %[tries/try] to steal %Y from you.\n", who, &item); who->oprintf(cansee && avoid(victim), "%#M %[tries/try] to steal %M from %M.\n", who, &item, victim); } else { who->printf("You steal %M from %Y.\n", &item, victim); victim->printf("%#M %[steals/steal] %Y from you.\n", who, &item); who->oprintf(cansee && avoid(victim), "%#M %[steals/steal] %M from %M.\n", who, &item, victim); set_owner(item, who); set_prons(who, item); dotrap(E_AFTERSTEAL, who, item, victim); /* ::: after_steal o1==object stolen, o2==from who? */ } } static bool verb_steal(MudObject *who, int argc, const char **argv) { NewWorld what2 = match(who, argc-1, argv+1, NULL, LOOK_BOTH|IGNORE_EXITS, "from"); TeleWorld what; if (what2.getsize()==0) { if (!what2.prep) { what = multi_match(who, argc-1, argv+1, NULL, LOOK_BOTH|LOOK_MWIELD|IGNORE_EXITS); if (what.getsize()>1) { who->printf("You can only steal one thing at a time.\n"); return true; } if (what.getsize()==0) { who->printf("Steal what?\n"); return true; } TeleObject o = what.get(0); if (!is_person(o.where)) { who->printf("Er, you can only steal from people.\n"); return true; } do_steal(who, o.what, o.where); return true; } who->printf("Steal from who?\n"); return true; } else if (what2.getsize()>1) { who->printf("You can only steal from one person at a time.\n"); return true; } MudObject *victim = what2.get(0); what = multi_match(who, argc-1, argv+1, is_droppable, LOOK_SPECIAL, NULL, victim->children); if (what.getsize()==0) { who->printf("Steal what?\n"); return true; } if (what.getsize()>1) { who->printf("You can only steal one thing at a time.\n"); return true; } MudObject *item = what.get_nth(0); do_steal(who, item, victim); return true; } static bool verb_loot(MudObject *who, int argc, const char *argv[]) { NewWorld what = match(who, argc-1, argv+1, is_corpse, LOOK_BOTH|IGNORE_EXITS); if (what.getsize()==0) { who->printf("Loot what?\n"); return true; } if (what.getsize()>1) { who->printf("You can only loot one thing at a time.\n"); return true; } MudObject *corpse = what.get_nth(0); if (!is_corpse(corpse)) { if (is_person(corpse)) { who->printf("%#Y %[isn't/aren't] dead.\n", corpse); } else { who->printf("%#Y %[isn't/aren't] a corpse.\n", corpse); } return true; } NewWorld what2; int i; MudObject *o; foreach(corpse->children, o, i) { what2.add(*o); } take_obs(who, what2, corpse); set_prons(who, what2); return true; } static bool verb_get(MudObject *who, int argc, const char *argv[]) { if (streq(argv[1], "off")) { Verb *v = verbs->get("remove"); if (v) v->invoke(who, argc-1, argv+1); else who->printf("Remove not loaded.\n"); return true; } if (argc < 2) { who->printf("Get what?\n"); return true; } if (argc == 3) { { cashinfo c = curmatch(argc-1, argv+1); if (c.cur) { MudObject *pot = find_pot(who->owner); if (!pot) throw emsg("There is no cash here."); int avail = cash(pot, c.cur); if (c.all) c.amt = avail; if (c.amt<0) throw emsg("You can't take negative money."); if (avail<c.amt) throw emsg("There isn't that much there."); set_cash(pot, c.cur, cash(pot, c.cur)-c.amt); set_cash(who, c.cur, cash(who, c.cur)+c.amt); if (totalcash(pot)==0) vanish(pot); who->printf("You take %s.\n", formatcash(c.amt, c.cur, 1)); who->oprintf("%M %[takes/take] %s.\n", who, formatcash(c.amt, c.cur, 1)); describe_pot(pot); return true; } } } TeleObject container = NULL; if (strhas(argc, argv, "from")) { TeleWorld what2 = multi_match(who, argc-1, argv+1, NULL, LOOK_BOTH|IGNORE_EXITS, 0, 0, "from"); if (what2.getsize()==0) { who->printf("Take from what?\n"); return true; } else if (what2.getsize()>1) { who->printf("You can only take from one thing at a time.\n"); return true; } container = what2.get(0); if (container->get_flag(FL_FLOOR)) container = 0; else { if (!container->get_flag(FL_TABLE)) { if (!is_container(container) && !is_corpse(container)) { who->printf("%#Y %[isn't/aren't] a container.\n", &container); return true; } if (is_closed(container) && !is_corpse(container)) { who->printf("%#Y %[isn't/aren't] open.\n", &container); return true; } } } } MudObjectWorld stuff; if (container) { stuff = *container->children; MudObject *o; int i; foreach(container.where->children, o, i) { if (low_enough(who, o) && (upon(o)==container)) { stuff.add(*o); } } } NewWorld what = match(who, argc-1, argv+1, is_takeable, container?(LOOK_SPECIAL|IGNORE_EXITS): (LOOK_ROOM|IGNORE_EXITS), NULL, &stuff); if (what.prep) { if (container) who->printf("Take what from %Y?\n", &container); else who->printf("Take what?\n"); return true; } if (what.getsize()) { take_obs(who, what, container); set_prons(who, what); return true; } if ((who->owner->get_flag(FL_ONFIRE)||!has_light(who->owner))&&!wf_wears_with_flag(who, FL_NIGHTVISION)) { if (who->owner->get_flag(FL_ONFIRE)) who->printf("You can't see anything through the smoke and flames.\n"); else who->printf("You can't see anything in the dark.\n"); return true; } if (what.all_nothing==0) { who->printf("There is nothing like that %s.\n", container?"in there":"here"); return true; } else if (what.all_nothing!=103) { who->printf("There is nothing to take %s.\n", container?"from there":"here"); return true; } else { who->printf("Take any what?\n"); return true; } return true; } static int strfind(int argc, const char **argv, const char *what) { for (int i = 0 ; i < argc ; i++) { if (streq(argv[i], what)) return i; } return 0; } static void do_pay(MudObject *who, MudObject *vic, cashinfo c) { int have = cash(who, c.cur); if (c.all) c.amt = have; if (c.amt > have) { who->printf("You don't have that much.\n"); return; } if (c.amt <= 0) { who->printf("Very funny.\n"); return; } if (!is_person(vic)) { who->printf("You can't pay %M.\n", vic); return; } if (vic == who) { who->printf("Very funny.\n"); return; } if (dotrap(E_BEFOREPAID, who, vic, c.cur, ssprintf("%i", c.amt).c_str())) return; /* ::: before_paid o1==mobile paid, o2==the currency, txt==amount to be paid; before messaging/cash transfer, return 1 to abort */ string sum = formatcash(c.amt, c.cur, 1); who->printf("You give %M %s.\n", vic, sum); who->oprintf(cansee && avoid(vic), "%#M %[gives/give] %M %s.\n", who, vic, sum); vic->printf("%#M %[gives/give] you %s.\n", who, sum); set_cash(who, c.cur, cash(who, c.cur)-c.amt); set_cash(vic, c.cur, cash(vic, c.cur)+c.amt); if (dotrap(E_AFTERPAID, who, vic, c.cur, ssprintf("%i", c.amt).c_str())) return; } static bool verb_pay(MudObject *who, int argc, const char **argv) { int i = strfind(argc, argv, "to"); if (i<2) { who->printf("Pay what to who?\n"); return true; } NewWorld what = match(who, argc-i, argv+i, is_person, LOOK_ROOM|IGNORE_EXITS|ALLOW_ME); if (what.getsize()==0) { who->printf("Pay to who?\n"); return true; } if (what.getsize()>1) { who->printf("You can only pay to one person at a time.\n"); return true; } cashinfo c = curmatch(i-1, argv+1, currency(who)); if (!c.cur) { who->printf("Pay what?\n"); return true; } MudObject *vic = what.get(0); do_pay(who, vic, c); return 1; } class can_affect : public showto { const char *z; public: can_affect(const char *z) : z(z) { } bool operator()(const MudObject *o) const { return ::can_affect(o, z); } }; static void give_obs(MudObject *from, MudObject *to, NewWorld what) { MudObject *o; int i; if (from==to) { from->printf("You already have %s.\n", plural(what)?"them":"it"); return; } NewWorld cantcarry; int spare = mass_capacity_left_in_grams(to); what = try_remove_obs(from, what); foreach((&what), o, i) { if (to==o) { what.remove(*o); i--; if (!what.getsize()) { from->printf("You can't give %Y to %sself!\n", o, his_or_her(o)); return; } continue; } if (is_in(to, o)) { from->printf("Giving %Y to %Y would cause a paradox.\n", o, to); what.remove(*o); i--; continue; } from->spec_printf("You show %Y to %M.\n", o, to); if (dotrap(E_AFTERSHOWNTO, from, o, to)) { /* ::: after_shown_to o1==object, o2==mobile; return 1 if we saw it. */ what.remove(*o); i--; continue; } from->cancel_printf(); MudObject *ta = to->get_object("treatas")?:to; if (o->get(KEY_ACCEPTER) && (to->get("lua.shown_mission")|| ta->get("lua.shown_mission"))) { from->spec_printf("You show %Y to %M.\n", o, to); /* ::: shown_mission o1==mobile, o2==mission; return 1 to not want to see the mission. */ if (!dotrap(E_ONSHOWNMISSION, from, to, o)) { from->cancel_printf(); from->printf("%#M doesn't want to see %Y.\n", to, o); } what.remove(*o); i--; continue; } from->spec_printf("You show %Y to %M.\n", o, to); int abort = !dotrap(E_AFTERSHOWN, from, to, o); /* ::: after_shown o1==mobile, o2==object; return 1 to not want to see. */ MudObject *obj = o; if (MudObject *b=obj->get_object("cloneof")) obj = b; if (MudObject *b=obj->get_object("treatas")) obj = b; const char *i=0; if (!i) i = to->get(ssprintf("shown_%s.%i", obj->id, obj->get_int(KEY_STATE, 0)).c_str()); if (!i) i = to->get(ssprintf("shown_%s", obj->id).c_str()); if (i) { from->oprintf(cansee, "%#M %[shows/show] %P to %M.\n", from, o, to); to->interpret(i); abort = 0; } if (abort) { from->cancel_printf(); } else { what.remove(*o); i--; continue; } if (o->get_flag(FL_NOGIVE)) { from->printf("%#M would self-destruct.\n", o); what.remove(*o); i--; continue; } if ((o->get_flag(FL_MISSION) || o->get_flag(FL_QUEST)) && is_player(to) && is_player(from)) { from->printf("You can't give missions to players.\n"); what.remove(*o); i--; continue; } if (is_player(o) || (is_mobile(o) && o->get_flag(FL_FIXED))) { from->printf("You can't get rid of %Y so easily.\n", o); what.remove(*o); i--; continue; } if (o->owner != from) { from->printf("You aren't carrying %Y.\n", o); what.remove(*o); i--; continue; } if (spare != SIZE_INFINITE) { int newspare = spare - mass_in_grams(o); if (newspare < 0) { what.remove(*o); i--; cantcarry.add(*o); continue; } spare = newspare; } if (dotrap(E_ONGIVEN, from, o, to)) { /* ::: given o1==gift, o2==mobile; after basic validity checking. return 1 to abort */ what.remove(*o); i--; continue; } /* ::: give o1==mobile, o2==gift; after basic validity checking. return 1 to abort */ if (dotrap(E_ONGIVE, from, to, o)) { what.remove(*o); i--; continue; } } string ml = magiclist(what); if (what.getsize()) { from->printf("You give ^Z%s to %Y.\n", ml.c_str(), to); from->oprintf(cansee && avoid(to), "%#M %[gives/give] ^Z%s to %Y.\n", from, ml.c_str(), to); to->printf("%#M %[gives/give] ^Z%s to you.\n", from, ml.c_str()); } if (cantcarry.getsize()) { from->printf("%#Y can't carry ^Z%s.\n", to, magiclist(cantcarry).c_str()); } foreach((&what), o, i) { o->printf("%#M gives you to %Y.\n", from, to); set_owner(o, to); if (dotrap(E_AFTERGIVEN, from, o, to)) { /* ::: after_given o1==gift, o2==mobile; after object given; return 1 to suppress an auto-give-back */ what.remove(*o); i--; continue; } if (dotrap(E_AFTERGIVE, from, to, o)) { /* ::: after_give o1==mobile, o2==gift; after object given; return 1 to suppress an auto-give-back */ what.remove(*o); i--; continue; } } if (is_mobile(to) && is_player(from) && to->get_int("aggr",0)==0 && !to->get_flag(FL_CANTTALK)) { MudObject *only = 0; if (what.getsize()==1) { only = what.get(0); } if (what.getsize()) { const char *response="shake"; if ((!only || (!only->get_flag(FL_QUEST) && !only->get_flag(FL_MISSION))) && to->owner && to->owner->get_flag(FL_STORE) && to->owner->get_object("shopmob")==to) { response = lang("say If you want to sell it, use the '^WSELL^n' command.", to); } foreach((&what), o, i) if (o->get_flag(FL_CONTRABAND)) { response = lang("say No way...", to); } if (what.getsize()==1) { log(class can_affect(to->get("zone")), FL_NOTELLSPAM, PFL_SEEINFO, 0, "give", "%s didn't want %s", drillid(to), drillid(what.get_nth(0))); } to->interpret(response); to->oprintf(cansee && avoid(from), "%#Y %[gives/give] ^Z%s back to %Y.\n", to, magiclist(what).c_str(), from); from->printf("%#Y %[gives/give] ^Z%s back to you.\n", to, magiclist(what).c_str()); } foreach((&what), o, i) { set_owner(o, from); } } } static bool verb_give(MudObject *who, int argc, const char **argv) { TeleWorld what2 = multi_match(who, argc-1, argv+1, is_person, LOOK_ROOM|IGNORE_EXITS|ALLOW_ME|LOOK_LINKED, NULL, NULL, "to"); MudObject *to; int i; int y = 0; foreach((&what2), to, i) { if (!is_person(to)) { continue; } y = 1; if (what2.get(i).where != who->owner) { who->printf("%#M %[is/are] too far away.\n", to); continue; } if (to->get_flag(FL_SLEEPING)) { who->printf("%#Y is asleep.\n", to); continue; } NewWorld what = match(who, argc-1, argv+1, is_droppable, LOOK_INV|IGNORE_EXITS); if (what.getsize()) { give_obs(who, to, what); fixup_lapels(who, NULL); } else { if (what.all_nothing==2) { who->printf("You aren't carrying anything you can give.\n"); break; } else if (what.all_nothing==1) { who->printf("You aren't carrying anything.\n"); break; } else if (what.all_nothing==0) { int i = strfind(argc, argv, "to"); if (i>=2) { cashinfo c = curmatch(i-1, argv+1, currency(who)); if (c.cur) { do_pay(who, to, c); continue; } } who->printf("You aren't carrying anything like that.\n"); break; } else if (what.all_nothing==-1) { who->printf("Give what?\n"); break; } } y = 1; } if (!y) { who->printf("Give to who?\n"); } return true; } static bool verb_drinkfind(MudObject *who, int argc, const char **argv) { MudObject *o; int i; foreach_alpha(planet, o, i) if (o->get_flag(FL_DRINK)) { MudObject *em = o->get_object("empty"); if (em) { who->printf("%20s %-35M - %20M - %4i - %2i.%02i%%.\n", o->id, o, em, serving(em), abv(o)/100, abv(o)%100); } else { who->printf("%20s %-35M.\n", o->id, o); } } return true; } static bool verb_fill(MudObject *who, int argc, const char **argv) { if (argc < 2) { who->printf("%#s what?\n", argv[0]); return true; } if (streq(argv[0], "fill")) { if (!strhas(argc, argv, "from") && !strhas(argc, argv, "with")) { who->printf("Fill with what?\n"); return true; } } if (streq(argv[0], "pour")) { if (!strhas(argc, argv, "into")) { who->printf("Pour into what?\n"); return true; } } NewWorld first; NewWorld second; if (streq(argv[0], "fill")) { first = match(who, argc-1, argv+1, is_fillable, LOOK_BOTH|IGNORE_EXITS); second = match(who, argc-1, argv+1, is_fillable, LOOK_BOTH|IGNORE_EXITS, "from"); if (second.getsize()==0) second = match(who, argc-1, argv+1, is_fillable, LOOK_BOTH|IGNORE_EXITS, "with"); } else { second = match(who, argc-1, argv+1, is_fillable, LOOK_BOTH|IGNORE_EXITS); first = match(who, argc-1, argv+1, is_fillable, LOOK_BOTH|IGNORE_EXITS, "into"); } if (first.getsize()==0) { if (first.all_nothing == 2) { who->printf("You aren't carrying anything you can %s.\n", argv[0]); } else { who->printf("%#s what?\n", argv[0]); } return true; } if (first.getsize()>1) { who->printf("You can only fill one thing at a time.\n"); return true; } if (second.getsize()==0) { who->printf("%#s %Y from what?\n", argv[0], first.get(0)); return true; } if (second.getsize()>1) { who->printf("You can only pour from one thing.\n"); return true; } MudObject *what = first.get(0); MudObject *from = second.get(0); if (from == what) { who->printf("You can't fill %Y from itself.\n", what); return true; } if (!is_fillable(what) || (what->get_int("volume")<1)) { if (what->get_object("empty")) { who->printf("It is already full of %s.\n", subshort(what)); } else { who->printf("You can't fill %Y from %Y.\n", what, from); } return true; } MudObject *sub = from->get_object("fount"); int fromamt = -1; int replace = 0; if (streq(argv[0], "pour") && sub) { who->printf("You can't pour from %Y.\n", sub); return true; } if (!sub && from->array_size("$fill")) { sub = from->array_get_object("$fill", 0); fromamt = from->array_get_int("$fillamt", 0); } if (!sub && from->get_object("empty") && from->get_flag(FL_DRINK)) { sub = from->get_object("substance"); if (!sub) { sub = from; if (sub->get_object("cloneof")) sub = sub->get_object("cloneof"); } fromamt = serving(from); replace = 1; } if (!sub) { who->printf("You can't fill %Y from %Y.\n", what, from); return true; } MudObject *already = 0; int alvol = 0; if (what->array_size("$fill")!=0) { already = what->array_get_object("$fill", 0); alvol = what->array_get_int("$fillamt", 0, 0); if (already != sub) { if (!streq(subshort(already), subshort(sub))) { who->printf("%#Y already %[contains/contain] %s.\n", what, subshort(already)); } else { who->printf("%#Y already %[contains/contain] a different type of %s.\n", what, subshort(already)); } return true; } } if (already == sub) { if (used_volume(what) >= what->get_int("volume")) { who->printf("%#Y %[is/are] already full.\n", what); return true; } } if (dotrap(E_BEFOREFOUNTAIN, who, from, what, 0)) { return true; } const char *adjective = ""; int wanted = what->get_int("volume") - used_volume(what); int amount = wanted; if (fromamt != -1 && wanted > fromamt) { adjective = "partially "; amount = fromamt; } what->array_set("$fill", 0, sub); what->array_set("$fillamt", 0, amount + alvol); who->printf("You %sfill %Y with %s from %Y.\n", adjective, what, subshort(sub), from); who->oprintf(cansee, "%#M %s%[fills/fill] %P with %s from %P.\n", who, adjective, what, subshort(sub), from); if (fromamt != -1) { if (replace) { MudObject *rw = replace_with_empty(from); if ((fromamt - amount)>0) { rw->array_set("$fill", 0, sub); rw->array_set("$fillamt", 0, fromamt - amount); } } else { from->array_set("$fillamt", 0, fromamt - amount); consolidate(from, false); } } /* ::: after_fill o1==object, o2==substance; after the object has been perhaps (partially) filled with substance */ if (dotrap(E_AFTERFILL, who, what, sub, 0)) { return true; } return true; } static bool verb_pour(MudObject *who, int argc, const char **argv) { return verb_fill(who, argc, argv); } static bool verb_taste(MudObject *who, int argc, const char **argv) { NewWorld w = match(who, argc-1, argv+1, 0, LOOK_INV|IGNORE_EXITS|ALLOW_ME); if (w.getsize()==0) { who->printf("Taste what?\n"); return true; } else if (w.getsize()>1) { who->printf("You can only taste one thing at a time.\n"); return true; } MudObject *what = w.get_nth(0); if (!what) { who->printf("Taste what?\n"); return true; } set_prons(who, what); if (!is_edible(what) && !what->get("taste")) { if (who==what) who->printf("Tastes like meat.\n"); else who->printf("You can't taste %Y.\n", what); return true; } if (what->get("taste")) { who->oprintf(cansee, "%#Y %[tastes/taste] %P.\n", who, what); who->printf("%s\n", what->get("taste")); return true; } MudObject *sub = what->array_get_object("$fill", 0); if (!sub) sub = what->get_object("substance"); if (!sub) sub = what; int alc = abv(sub); if (sub==what) who->oprintf(cansee, "%#M %[tastes/taste] %P.\n", who, what); else who->oprintf(cansee, "%#M %[tastes/taste] the contents of %P.\n", who, what); if (alc>4000) who->printf("%|%[It tastes/They taste] very strongly of alcohol.\n", what); else if (alc>2000) who->printf("%|%[It tastes/They taste] strongly of alcohol.\n", what); else if (alc>200) who->printf("%|%[It tastes/They taste] of alcohol.\n", what); else who->printf("%|%[It tastes/They taste] like %s.\n", what, sub->get("short")); return true; } bool prep(const char *o); static bool verb_empty(MudObject *player, int argc, const char*argv[]) { if (argc < 2) { player->printf("Empty what?\n"); return true; } NewWorld w = match(player, argc-1, argv+1, 0, LOOK_BOTH|IGNORE_EXITS|ALLOW_ME); if (w.getsize()==0) { player->printf("Empty what?\n"); return true; } else if (w.getsize()>1) { player->printf("You can only empty one thing at once.\n"); return true; } for (int i=1;i<argc;i++) { if (prep(argv[i])) { player->printf("You can't empty %s things.\n", argv[i]); return true; } } MudObject *fl = floor(player->owner); MudObject *what = w.get_nth(0); if (!what) { player->printf("It's not here.\n"); return true; } set_prons(player, what); /* ::: empty o1==object; before openness checking; return 1 to abort */ if (dotrap(E_ONEMPTY, player, what, 0, 0)) return true; if (!is_container(what) && !is_fillable(what) && !(what->get_object("empty") && what->get_object("empty")-> get_flag(FL_WATERTIGHT))) { player->printf("%#Y %[is/are] not a container.\n", what); return true; } if (is_closed(what)) { player->printf("%#Y %[is/are] closed.\n", what); return true; } if (is_fillable(what)) { if (!used_volume(what)) { player->printf("%#Y %[is/are] already empty.\n", what); return true; } MudObject *stuff = what->array_get_object("$fill", 0); if (stuff) { if (fl) { player->printf("You pour the %s from %Y onto %Y.\n", subshort(stuff), what, fl); player->oprintf(cansee, "%#M %[pours/pour] the %s from %P onto %Y.\n", player, subshort(stuff), what, fl); } else { player->printf("You pour the %s from %Y.\n", subshort(stuff), what); player->oprintf(cansee, "%#M %[pours/pour] the %s from %P.\n", player, subshort(stuff), what); } } consolidate(what, true); return true; } if (what->get_object("empty")) { if (fl) { player->printf("You empty %Y onto %Y.\n", what, fl); player->oprintf(cansee, "%#M %[empties/empty] %P onto %Y.\n", player, what, fl); } else { player->printf("You empty %Y.\n", what); player->oprintf(cansee, "%#M %[empties/empty] %P.\n", player, what); } replace_with_empty(what); return true; } bool done = false; int i; MudObject *which; NewWorld emptied; foreach(what->children, which, i) { if (!which->get_flag(FL_FIXED)) { emptied.add(*which); set_owner(which, player->owner); dotrap(E_ONHANDLE, player, which, 0, 0); i--; } done = true; } if (emptied.getsize()) { player->printf("You empty ^Z%s from %Y.\n", magiclist(emptied).c_str(), what); player->oprintf(cansee, "%#M %[empties/empty] ^Z%s from %Y.\n", player, magiclist(emptied).c_str(), what); set_prons(player, emptied); } if (!done) { player->printf("%#Y %[is/are] empty already.\n", what); return true; } return true; } static MudObject *has_onfire(MudObject *who) { int i; MudObject *o; foreach(who->children, o, i) { if (o->get_flag(FL_ONFIRE)) { return o; } } return 0; } static bool verb_light(MudObject *who, int argc, const char **argv) { if (argc < 2) { who->printf("Light what?\n"); return true; } NewWorld w = match(who, argc-1, argv+1, 0, LOOK_BOTH|IGNORE_EXITS|ALLOW_ME); if (w.getsize()==0) { who->printf("Light what?\n"); return true; } else if (w.getsize()>1) { who->printf("You can only light one thing at once.\n"); return true; } MudObject *what = w.get_nth(0); set_prons(who, what); /* ::: light o1==object; before anything; return 1 to abort */ if (dotrap(E_ONLIGHT, who, what)) return true; set_prons(who, what); if (is_player(what) || is_mobile(what)) { who->printf("You can't light %s.\n", him_or_her(what)); return true; } MudObject *source = has_onfire(who); if (!source) source = has_onfire(who->owner); if (!source) { who->printf("You don't have anything to light %s from.\n", it_them(what)); return true; } if (!what->get_flag(FL_CANLIGHT)) { who->printf("You can't light that.\n"); // XXXX that/those? return true; } if (is_lit(what)) { who->printf("%#Y %[is/are] already alight.\n", what); return true; } who->printf("You light %Y from %Y.\n", what, source); who->oprintf(cansee, "%#M %[lights/light] %P from %P.\n", who, what, source); what->set_flag(FL_ONFIRE, 1); if (what->get_int("burnsfor", 0)) { what->set("!burnout", now+what->get_int("burnsfor", 0)); } return true; } static bool verb_extinguish(MudObject *who, int argc, const char **argv) { if (argc < 2) { who->printf("Extinguish what?\n"); return true; } NewWorld w = match(who, argc-1, argv+1, 0, LOOK_BOTH|IGNORE_EXITS|ALLOW_ME); if (w.getsize()==0) { who->printf("Extinguish what?\n"); return true; } else if (w.getsize()>1) { who->printf("You can only extinguish one thing at once.\n"); return true; } MudObject *what = w.get_nth(0); /* ::: extinguish o1==object; before anything; return 1 to abort */ if (dotrap(E_ONEXTINGUISH, who, what)) return true; if (is_player(what) || is_mobile(what)) { who->printf("You can't extinguish %s.\n", him_or_her(what)); return true; } if (!is_lit(what)) { who->printf("%#Y %[is/are] not alight.\n", what); return true; } if (!what->get_flag(FL_ONFIRE)) { who->printf("%#Y %[isn't/aren't] on fire.\n", what); return true; } if (!what->get_flag(FL_CANLIGHT)) { who->printf("You can't extinguish that.\n"); return true; } who->printf("You extinguish %Y.\n", what); who->oprintf(cansee, "%#M %[extinguishes/extinguish] %P.\n", who, what); what->set_flag(FL_ONFIRE, 0); return true; } static void puton_obs(MudObject *who, NewWorld &what, TeleObject on) { if (!shelf_low_enough(who, on)) { who->printf("%#P %[is/are] too high for you.\n", &on); return; } MudObject *o; int i; foreach((&what), o, i) { /* ::: before_puton o1==table, o2==object you are putting on it; return 1 to abort */ if (dotrap(E_BEFOREPUTON, who, on, o)) { what.remove(o); i--; continue; } /* ::: before_putupon o1==object, o2==table; return 1 to abort */ if (dotrap(E_BEFOREPUTUPON, who, o, on)) { what.remove(o); i--; continue; } } foreach((&what), o, i) { set_owner(o, on.where); o->set(KEY_SITON, on.what->id); o->set(KEY_SITONN, on.nth); } if (what) { who->printf("You put ^Z%s onto %Y.\n", magiclist(what).c_str(), &on); who->oprintf(cansee && avoid(on), "%#M %[puts/put] ^Z%s onto %P.\n", who, magiclist(what).c_str(), &on); on->printf("%#M %[puts/put] ^Z%s onto you.\n", who, magiclist(what).c_str()); } foreach((&what), o, i) { /* ::: after_puton o1==table, o2==object you have put on it */ if (dotrap(E_AFTERPUTON, who, on, o)) { what.remove(o); i--; continue; } /* ::: after_putupon o1==object you have put on it, o2==table */ if (dotrap(E_AFTERPUTUPON, who, o, on)) { what.remove(o); i--; continue; } } } static void put_obs(MudObject *who, NewWorld &what, MudObject *in) { what = try_remove_obs(who, what); if (!is_container(in)) { MudObject *o; int i; foreach((&what), o, i) { /* ::: put o1==object, o2==container; called whether or not o2 is a container, return 1 to abort */ if (dotrap(E_ONPUT, who, o, in, 0)) { what.remove(*o); i--; continue; } /* ::: contain o1==container, o2==object; called whether or not o1 is a container, return 1 to abort */ if (dotrap(E_ONCONTAIN, who, in, o, 0)) { what.remove(*o); i--; continue; } } if (what.getsize()) { if (in->get_flag(FL_MOBILE)) { who->printf("%#M wouldn't appreciate it.\n", in); return; } who->printf("%#Y %[is/are] not a container.\n", in); } return; } if (is_closed(in)) { MudObject *o; int i; foreach((&what), o, i) { if (dotrap(E_ONPUT, who, o, in, 0)) { what.remove(*o); i--; continue; } if (dotrap(E_ONCONTAIN, who, in, o, 0)) { what.remove(*o); i--; continue; } } if (what.getsize()) who->printf("%#Y %[is/are] closed.\n", in); return; } NewWorld justcant, selfdestruct, fixed, wontfit; MudObject *o; int i; int spare = mass_capacity_left_in_grams(in); int sparevol = in->get_int("volume", SIZE_INFINITE) - used_volume(in); foreach((&what), o, i) { if (is_in(in, o)) { justcant.add(*o); what.remove(*o); i--; continue; } if (o->get_flag(FL_NOGIVE)) { selfdestruct.add(*o); what.remove(*o); i--; continue; } if (o->get_flag(FL_FIXED) || is_player(o) || is_big_mobile(o)) { fixed.add(*o); what.remove(*o); i--; continue; } if (MudObject *cs=in->get_object("contains")) { MudObject *ta = o->get_object("treatas"); if (!ta) { ta = o; } if (cs != ta) { what.remove(*o); i--; wontfit.add(*o); continue; } } if (spare != SIZE_INFINITE) { int newspare = spare - mass_in_grams(o); if (newspare < 0) { what.remove(*o); i--; wontfit.add(*o); continue; } spare = newspare; } if (sparevol != SIZE_INFINITE) { int newspare = sparevol - (o)->get_int("ovolume", 0); if (newspare < 0) { what.remove(*o); i--; wontfit.add(*o); continue; } sparevol = newspare; } if (dotrap(E_ONHANDLE, who, o, 0, 0)) { what.remove(*o); i--; continue; } if (dotrap(E_ONPUT, who, o, in, 0)) { what.remove(*o); i--; continue; } if (dotrap(E_ONCONTAIN, who, in, o, 0)) { what.remove(*o); i--; continue; } } foreach((&what), o, i) { set_owner(o, in); } if (what.getsize()) { who->printf("You put ^Z%s in %Y.\n", magiclist(what).c_str(), in); who->oprintf(cansee && avoid(in), "%#M %[puts/put] ^Z%s in %P.\n", who, magiclist(what).c_str(), in); in->printf("%#M %[puts/put] ^Z%s in you.\n", who, magiclist(what).c_str()); } if (selfdestruct.getsize()) { who->printf("%#s would self-destruct.\n", magiclist(selfdestruct).c_str(), in); } if (justcant.getsize()) { who->printf("You can't put %s in %P.\n", magiclist(justcant).c_str(), in); } if (fixed.getsize()) { who->printf("You can't remove %s to put it in %P.\n", magiclist(fixed).c_str(), in); } if (wontfit.getsize()) { who->printf("You can't fit %s in %P.\n", magiclist(wontfit).c_str(), in); } foreach((&what), o, i) { dotrap(E_AFTERPUT, who, o, in, 0); /* ::: after_put o1==object, o2==container; called after everything */ dotrap(E_AFTERCONTAIN, who, in, o, 0); /* ::: after_contain o1==container, o2==object; called after everything */ } /* AFTERPUT trigger on everything */ } static bool is_puttable(const TeleObject &what) { MudObject *w = what.what; if (w->get_flag(FL_FIXED)) return 0; if (is_big_mobile(w)) return 0; if (is_player(w)) return 0; if (!is_person(what.where)) return 0; return 1; } static bool verb_put(MudObject *who, int argc, const char *argv[]) { if (streq(argv[1], "on")) { Verb *v = verbs->get("wear"); if (v) v->invoke(who, argc-1, argv+1); else who->printf("Wear not loaded.\n"); return true; } if (argc < 4) { who->printf("Put what in what?\n"); return true; } NewWorld from = match(who, argc-1, argv+1, NULL, LOOK_BOTH|IGNORE_EXITS|ALLOW_ME, "from"); if (from.prep) { NewWorld what2 = match(who, argc-1, argv+1, NULL, LOOK_BOTH|IGNORE_EXITS|ALLOW_ME, "in"); if (from.getsize()==0) { who->printf("Put from what?\n"); return true; } if (from.getsize()!=1) { who->printf("You can only put stuff from one thing at a time.\n"); return true; } if (what2.getsize()==0) { who->printf("Put in what?\n"); return true; } if (what2.getsize()!=1) { who->printf("You can only put stuff into one thing at a time.\n"); return true; } MudObject *cont = from.get_nth(0); NewWorld what = match(who, argc-1, argv+1, 0, LOOK_SPECIAL|IGNORE_EXITS, 0, cont->children); if (what.getsize()==0) { who->printf("Put what?\n"); return true; } if (cont == what2.get_nth(0)) { who->printf("%#s already there.\n", plural(what)?"they're":"it's"); return true; } take_obs(who, what, cont, 0); NewWorld w2; MudObject *o; int i; foreach((&what), o, i) { w2.add(o); } put_obs(who, w2, what2.get_nth(0)); set_prons(who, w2); return true; } int next = 1; NewWorld what = match(who, argc-1, argv+1, is_puttable, LOOK_INV|IGNORE_EXITS|IGNORE_MISSION, &next); int on = streq(argv[next], "on"); TeleWorld what2 = multi_match(who, argc-1, argv+1, NULL, LOOK_BOTH|IGNORE_EXITS|ALLOW_ME, 0, 0, on?"on":"in"); if (!on && what2.getsize()==0) { what2 = multi_match(who, argc-1, argv+1, NULL, LOOK_BOTH|IGNORE_EXITS|ALLOW_ME, 0, 0, "into"); } if (what.getsize()==0) { if (what.all_nothing==1) who->printf("You aren't carrying anything.\n"); else if (what.all_nothing==0) who->printf("You aren't carrying anything like that.\n"); else if (what.all_nothing==103) who->printf("Put any what?\n"); else who->printf("Put what?\n"); return true; } if (what2.getsize()==0) { who->printf("Put in what?\n"); return true; } if (what2.getsize()!=1) { who->printf("You can only put stuff %sto one thing at a time.\n", what.prep); return true; } TeleObject container = what2.get(0); if (container->get_flag(FL_FLOOR)) { verb_drop(who, argc, argv); return true; } if (what.getsize()==1 && what.get(0)==container) { who->printf("You can't put %M in %sself.\n", what.get(0), him_or_her(container)); return true; } if (what.get(container->id)) { what.remove(*container); } if (container->get_flag(FL_PIT)) { drop_obs(who, what, 0, 0); return true; } // on = 0; /* DISABLE TABLES for the moment */ if (on && (container->get_flag(FL_CANSITON) || container->get_flag(FL_CANSLEEPON) || container->get_flag(FL_TABLE))) { puton_obs(who, what, container); set_prons(who, what); } else { put_obs(who, what, container); set_prons(who, what); } fixup_lapels(who, NULL); return true; } #include "verbmodule.h" void startup() { //AUTO_VERB(image, 3, 0, PFL_AWAKE); AUTO_VERB(eat, 3, 0, PFL_AWAKE); AUTO_VERB(drink, 3, 0, PFL_AWAKE); AUTO_VERB(taste, 2, 0, PFL_AWAKE); AUTO_VERB(examine, 2, 0, PFL_AWAKE); ADD_ALIAS(x, 1, examine); ADD_ALIAS(read, 3, examine); AUTO_VERB(drop, 2, 0, PFL_AWAKE); AUTO_VERB(throw, 2, 0, PFL_AWAKE); AUTO_VERB(empty, 3, 0, PFL_AWAKE); AUTO_VERB(fill, 3, 0, PFL_AWAKE); AUTO_VERB(pour, 3, 0, PFL_AWAKE); AUTO_VERB(put, 3, 0, PFL_AWAKE); ADD_ALIAS(insert, 3, put); AUTO_VERB(get, 1, 0, PFL_AWAKE); ADD_ALIAS(take, 1, get); AUTO_VERB(steal, 5, 0, PFL_AWAKE); AUTO_VERB(give, 2, 0, PFL_AWAKE); AUTO_VERB(loot, 4, 0, PFL_AWAKE); AUTO_VERB(pay, 2, 0, PFL_AWAKE); AUTO_VERB(shuffle, 2, 0, PFL_AWAKE); AUTO_VERB(deal, 2, 0, PFL_AWAKE); AUTO_VERB(discard, 5, 0, PFL_AWAKE); AUTO_VERB(light, 2, 0, PFL_AWAKE); AUTO_VERB(extinguish, 3, 0, PFL_AWAKE); ADD_ALIAS(quench, 4, extinguish); ADD_ALIAS(unlight, 4, extinguish); AUTO_VERB(drinkfind, 6, 0, PFL_AWAKE); }