#include <kernel/kernel.h> #include <kernel/access.h> #include <kernel/rsrc.h> #include <kernel/user.h> #include <phantasmal/log.h> #include <phantasmal/grammar.h> #include <phantasmal/search_locations.h> #include <phantasmal/lpc_names.h> #include <type.h> #include <status.h> #include <limits.h> inherit access API_ACCESS; /* * NAME: create() * DESCRIPTION: initialize variables */ static void create(varargs int clone) { if(clone) { } else { if(!find_object(LWO_PHRASE)) compile_object(LWO_PHRASE); } } static void upgraded(varargs int clone) { } static void destructed(varargs int clone) { } /********** Object Functions ***************************************/ static object resolve_object_name(object user, string name) { object obj; int obnum; if(sscanf(name, "#%d", obnum)) { obj = MAPD->get_room_by_num(obnum); if(obj) return obj; obj = EXITD->get_exit_by_num(obnum); if(obj) return obj; } return nil; } /* Set object description. This command is @set_brief, @set_look and @set_examine. */ static void cmd_set_obj_desc(object user, string cmd, string str) { object obj; string desc, objname; string look_type; int must_set; if(!sscanf(cmd, "@set_%s", look_type)) error("Unrecognized command to set desc: " + cmd); desc = nil; if(!str || str == "") { obj = user->get_location(); user->message("(This location)\n"); } else if(sscanf(str, "%s %s", objname, desc) == 2 || sscanf(str, "%s", objname)) { obj = resolve_object_name(user, objname); } if(!obj) { user->message("Not a valid object to be set!\n"); return; } user->message("Locale is "); user->message(PHRASED->name_for_language(user->get_locale()) + "\n"); if(!desc) { user->push_new_state(US_OBJ_DESC, obj, look_type, user->get_locale()); user->push_new_state(US_ENTER_DATA); return; } if(desc) { object phr; user->message("Setting " + look_type + " desc on object #" + obj->get_number() + "\n"); if(!function_object("get_" + look_type, obj)) error("Can't find getter function for " + look_type + " in " + object_name(obj)); must_set = 0; phr = call_other(obj, "get_" + look_type); if(!phr || (look_type == "examine" && phr == obj->get_look())) { phr = PHRASED->new_simple_english_phrase("CHANGE ME!"); must_set = 1; } phr->set_content_by_lang(user->get_locale(), desc); if(must_set) { call_other(obj, "set_" + look_type, phr); } } } private void priv_mob_stat(object user, object mob) { object mobbody, mobuser; mixed* tags; int ctr; string tmp; mobbody = mob->get_body(); mobuser = mob->get_user(); tmp = ""; tmp = "Body: "; if(mobbody) { tmp += "#" + mobbody->get_number() + " ("; tmp += mobbody->get_brief()->to_string(user); tmp += ")\n"; } else { tmp += "(none)\n"; } tmp += "User: "; if(mobuser) { tmp += mobuser->get_name() + "\n"; } else { tmp += "(NPC, not player)\n"; } tags = TAGD->mobile_all_tags(mob); if(!sizeof(tags)) { tmp += "\nNo tags set.\n"; } else { for(ctr = 0; ctr < sizeof(tags); ctr+=2) { tmp += " " + tags[ctr] + ": " + STRINGD->mixed_sprint(tags[ctr + 1]) + "\n"; } } user->message_scroll(tmp); } static void cmd_stat(object user, string cmd, string str) { int objnum, ctr; object obj, room, exit, location; string* words; string tmp; mixed* objs, *tags; object *details, *archetypes; if(!str || STRINGD->is_whitespace(str)) { user->message("Usage: " + cmd + " #<obj num>\n"); user->message(" " + cmd + " <object description>\n"); return; } if(sscanf(str, "#%d", objnum) != 1) { str = STRINGD->trim_whitespace(str); if(!STRINGD->stricmp(str, "here")) { if(!user->get_location()) { user->message("You aren't anywhere!\n"); return; } objnum = user->get_location()->get_number(); } else { objs = user->find_first_objects(str, LOC_INVENTORY, LOC_CURRENT_ROOM, LOC_BODY, LOC_CURRENT_EXITS); if(!objs) { user->message("You don't find any object matching '" + str + "' here.\n"); return; } if(sizeof(objs) > 1) { user->message("More than one object matches. You choose one.\n"); } objnum = objs[0]->get_number(); } } room = MAPD->get_room_by_num(objnum); exit = EXITD->get_exit_by_num(objnum); obj = room ? room : exit; if(!obj) { object mob; mob = MOBILED->get_mobile_by_num(objnum); if(!mob) { user->message("No object #" + objnum + " found registered with MAPD, EXITD or MOBILED.\n"); return; } priv_mob_stat(user, mob); return; } tmp = "Number: " + obj->get_number() + "\n"; if(obj->get_detail_of()) { tmp += "Detail of: "; } else { tmp += "Location: "; } location = obj->get_location(); if(location) { if(typeof(location->get_number()) == T_INT && location->get_number() != -1) { tmp += "#" + location->get_number(); if(location->get_brief()) { tmp += " ("; tmp += location->get_brief()->to_string(user); tmp += ")\n"; } else { tmp += "\n"; } } else { tmp += " (unregistered)\n"; } } else { tmp += " (none)\n"; } tmp += "Descriptions (" + PHRASED->locale_name_for_language(user->get_locale()) + ")\n"; tmp += "Brief: "; if(obj->get_brief()) { tmp += "'" + obj->get_brief()->to_string(user) + "'\n"; } else { tmp += "(none)\n"; } tmp += "Look:\n "; if(obj->get_look()) { tmp += "'" + obj->get_look()->to_string(user) + "'\n"; } else { tmp += "(none)\n"; } tmp += "Examine:\n "; if(obj->get_examine()) { if(obj->get_examine() == obj->get_look()) { tmp += "(defaults to Look desc)\n"; } else { tmp += "'" + obj->get_examine()->to_string(user) + "'\n"; } } else { tmp += "(none)\n"; } /* Show user the nouns and adjectives */ tmp += "Nouns (" + PHRASED->locale_name_for_language(user->get_locale()) + "): "; words = obj->get_nouns(user->get_locale()); tmp += implode(words, ", "); tmp += "\n"; tmp += "Adjectives (" + PHRASED->locale_name_for_language(user->get_locale()) + "): "; words = obj->get_adjectives(user->get_locale()); tmp += implode(words, ", "); tmp += "\n\n"; if(function_object("get_weight", obj)) { tmp += "Its weight is " + obj->get_weight() + " kilograms.\n"; tmp += "Its volume is " + obj->get_volume() + " liters.\n"; tmp += "Its length is " + obj->get_length() + " centimeters.\n"; } if(function_object("is_container", obj)) { if(obj->is_container()) { if(obj->is_open()) { tmp += "The object is an open container.\n"; } else { tmp += "The object is a closed container.\n"; } if(obj->is_openable()) { tmp += "The object may be freely opened and closed.\n"; } else { tmp += "The object may not be freely opened and closed.\n"; } if(function_object("get_weight_capacity", obj)) { tmp += "It contains " + obj->get_current_weight() + " of a max of " + obj->get_weight_capacity() + " kilograms.\n"; tmp += "It contains " + obj->get_current_volume() + " of a max of " + obj->get_volume_capacity() + " liters.\n"; tmp += "Its maximum height/length is " + obj->get_length_capacity() + " centimeters.\n"; } } else { tmp += "The object is not a container.\n"; } } tmp += "\n"; if(function_object("num_objects_in_container", obj)) { tmp += "Contains objects [" + obj->num_objects_in_container() + "]: "; objs = obj->objects_in_container(); for(ctr = 0; ctr < sizeof(objs); ctr++) { if(typeof(objs[ctr]->get_number()) == T_INT && objs[ctr]->get_number() != -1) { tmp += "#" + objs[ctr]->get_number() + " "; } else { tmp += "<unreg> "; } } tmp += "\nContains " + sizeof(obj->mobiles_in_container()) + " mobiles.\n\n"; } details = obj->get_immediate_details(); if(details && sizeof(details)) { object detail; tmp += "Has immediate details [" + sizeof(details) + "]: "; for(ctr = 0; ctr < sizeof(details); ctr++) { detail = details[ctr]; if(detail) { tmp += "#" + detail->get_number() + " "; } else { tmp += "<unreg> "; } } tmp += "\n"; } details = obj->get_details(); archetypes = obj->get_archetypes(); if(sizeof(archetypes) && sizeof(details)) { object detail; tmp += "Has complete details [" + sizeof(details) + "]: "; for(ctr = 0; ctr < sizeof(details); ctr++) { detail = details[ctr]; if(detail) { tmp += "#" + detail->get_number() + " "; } else { tmp += "<unreg> "; } } tmp += "\n"; } tags = TAGD->object_all_tags(obj); if(!sizeof(tags)) { tmp += "\nNo tags set.\n"; } else { tmp += "\nTag Name: Value\n"; for(ctr = 0; ctr < sizeof(tags); ctr+=2) { tmp += " " + tags[ctr] + ": " + STRINGD->mixed_sprint(tags[ctr + 1]) + "\n"; } } tmp += "\n"; if(obj->get_mobile()) { tmp += "Object is sentient.\n"; if(obj->get_mobile()->get_user()) { tmp += "Object is " + obj->get_mobile()->get_user()->query_name() + "'s body.\n"; } } if(sizeof(archetypes)) { tmp += "Instance of archetype(s): "; for(ctr = 0; ctr < sizeof(archetypes); ctr++) { tmp += "#" + archetypes[ctr]->get_number() + " (" + archetypes[ctr]->get_brief()->to_string(user) + ")"; } tmp += ".\n"; } if(room) { tmp += "Registered with MAPD as a room or portable.\n"; } if(exit) { tmp += "Registered with EXITD as an exit.\n"; } user->message_scroll(tmp); } static void cmd_add_nouns(object user, string cmd, string str) { int ctr; object obj, phr; string* words; if(str) str = STRINGD->trim_whitespace(str); if(!str || str == "" || !sscanf(str, "%*s %*s")) { user->message("Usage: " + cmd + " #<objnum> [<noun> <noun>...]\n"); return; } words = explode(str, " "); obj = resolve_object_name(user, words[0]); if(!obj) { user->message("Can't find object '" + words[0] + "'.\n"); return; } for(ctr = 1; ctr < sizeof(words); ctr++) { words[ctr] = STRINGD->to_lower(words[ctr]); } user->message("Adding nouns (" + PHRASED->locale_name_for_language(user->get_locale()) + ").\n"); phr = new_object(LWO_PHRASE); phr->set_content_by_lang(user->get_locale(), implode(words[1..],",")); obj->add_noun(phr); user->message("Done.\n"); } static void cmd_clear_nouns(object user, string cmd, string str) { object obj; if(str) str = STRINGD->trim_whitespace(str); if(!str || str == "" || sscanf(str, "%*s %*s")) { user->message("Usage: " + cmd + "\n"); return; } obj = resolve_object_name(user, str); if(obj) { obj->clear_nouns(); user->message("Cleared.\n"); } else { user->message("Couldn't find object '" + str + "'.\n"); } } static void cmd_add_adjectives(object user, string cmd, string str) { int ctr; object obj, phr; string* words; if(str) str = STRINGD->trim_whitespace(str); if(!str || str == "" || !sscanf(str, "%*s %*s")) { user->message("Usage: " + cmd + " #<objnum> [<adj> <adj>...]\n"); return; } words = explode(str, " "); obj = resolve_object_name(user, words[0]); if(!obj) { user->message("Can't find object '" + words[0] + "'.\n"); return; } for(ctr = 1; ctr < sizeof(words); ctr++) { words[ctr] = STRINGD->to_lower(words[ctr]); } user->message("Adding adjectives (" + PHRASED->locale_name_for_language(user->get_locale()) + ").\n"); phr = new_object(LWO_PHRASE); phr->set_content_by_lang(user->get_locale(), implode(words[1..],",")); obj->add_adjective(phr); user->message("Done.\n"); } static void cmd_clear_adjectives(object user, string cmd, string str) { object obj; if(str) str = STRINGD->trim_whitespace(str); if(!str || str == "" || sscanf(str, "%*s %*s")) { user->message("Usage: " + cmd + "\n"); return; } obj = resolve_object_name(user, str); if(obj) { obj->clear_adjectives(); user->message("Cleared.\n"); } else { user->message("Couldn't find object '" + str + "'.\n"); } } static void cmd_move_obj(object user, string cmd, string str) { object obj1, obj2; int objnum1, objnum2; string second; if(!str || sscanf(str, "%*s %*s %*s") == 3 || ((sscanf(str, "#%d #%d", objnum1, objnum2) != 2) && (sscanf(str, "#%d %s", objnum1, second) != 2))) { user->message("Usage: " + cmd + " #<obj> #<location>\n"); user->message(" or " + cmd + " #<obj> here\n"); return; } if(second && STRINGD->stricmp(second, "here")) { user->message("Usage: " + cmd + " #<obj> #<location>\n"); user->message(" or " + cmd + " #<obj> here\n"); } if(second) { if(user->get_location()) { objnum2 = user->get_location()->get_number(); } else { user->message("You can't move an object to your current location " + "unless you have one!\n"); return; } } obj2 = MAPD->get_room_by_num(objnum2); if(!obj2) { user->message("The second argument must be a room. Obj #" + objnum2 + " is not.\n"); return; } obj1 = MAPD->get_room_by_num(objnum1); if(!obj1) { obj1 = EXITD->get_exit_by_num(objnum1); } if(!obj1) { user->message("Obj #" + objnum1 + " doesn't appear to be a registered " + "room or exit.\n"); return; } if(obj1->get_location()) { obj1->get_location()->remove_from_container(obj1); } obj2->add_to_container(obj1); user->message("You teleport "); user->send_phrase(obj1->get_brief()); user->message(" (#" + obj1->get_number() + ") into "); user->send_phrase(obj2->get_brief()); user->message(" (#" + obj2->get_number() + ").\n"); } static void cmd_set_obj_parent(object user, string cmd, string str) { object obj, parent; string parentstr, *par_entries; object *parents; int objnum; mapping par_kw; if(!str || (sscanf(str, "#%d %s", objnum, parentstr) != 2)) { user->message("Usage: " + cmd + " #<obj> #<parent> [#<parent2>...]\n"); user->message(" " + cmd + " #<obj> none\n"); return; } parentstr = STRINGD->trim_whitespace(parentstr); obj = MAPD->get_room_by_num(objnum); if(!obj) { user->message("The object must be a room or portable. Obj #" + objnum + " is not.\n"); return; } parentstr = STRINGD->trim_whitespace(STRINGD->to_lower(parentstr)); if(!STRINGD->stricmp(parentstr, "none")) { obj->set_archetypes( ({ }) ); user->message("Object is now unparented.\n"); return; } par_entries = explode(parentstr, " "); parents = ({ }); par_kw = ([ "none" : 1, "add" : 1, "remove" : 1 ]); if(!par_kw[par_entries[0]]) { user->message("The operation keyword must be one of 'none', 'add' or " + "remove.\n Your keyword, '" + par_entries[0] + "', was not.\n See help entry.\n"); return; } for(objnum = 1; objnum < sizeof(par_entries); objnum++) { int parentnum; par_entries[objnum] = STRINGD->trim_whitespace(par_entries[objnum]); if(!par_entries[objnum] || par_entries[objnum] == "") continue; if(!sscanf(par_entries[objnum], "#%d", parentnum)) { user->message("Post-keyword arguments must be parent object numbers (" + "#<num>).\n" + " Your argument, '" + par_entries[objnum] + "', was not.\n"); return; } parent = MAPD->get_room_by_num(parentnum); if(!parent) { user->message("The parent must be a room or portable. Obj #" + parentnum + " is not.\n"); return; } parents += ({ parent }); } switch(par_entries[0]) { case "none": /* Should never get this far */ user->message("Don't include any object numbers with the keyword 'none'." + "\n"); return; case "add": parents = obj->get_archetypes() + parents; /* Fall through to next case */ case "set": obj->set_archetypes(parents); break; default: user->message("Internal error based on keyword name. " + "Throwing an exception.\n"); error("Internal error! Should never get here!"); } user->message("Done setting parents.\n"); } /* This function is called for set_obj_weight, set_obj_volume, and set_obj_height and their synonyms, as well as set_obj_weight_capacity, set_obj_height_capacity, set_obj_volume_capacity and so on. */ static void cmd_set_obj_value(object user, string cmd, string str) { object obj; int objnum, is_cap; float newvalue; mapping val_names; string cmd_value_name, cmd_norm_name; if(!str || sscanf(str, "%*s %*s %*s") == 3 || sscanf(str, "#%d %f", objnum, newvalue) != 2) { user->message("Usage: " + cmd + " #<obj> <value>\n"); return; } val_names = ([ "weight" : "weight", "volume" : "volume", "vol" : "volume", "length" : "length", "len" : "length", "height" : "length", ]); /* For set_obj_weight_capacity and company */ if(sscanf(cmd, "%*s_%*s_%s_%*s", cmd_value_name) == 4) { /* Normalize the name. */ cmd_norm_name = val_names[cmd_value_name]; is_cap = 1; } else if (sscanf(cmd, "%*s_%*s_%s", cmd_value_name) == 3) { /* Not a set_blah_capacity function */ cmd_norm_name = val_names[cmd_value_name]; is_cap = 0; } else { user->message("Internal parsing error on command name '" + cmd + "'. Sorry!\n"); return; } obj = MAPD->get_room_by_num(objnum); if(!obj) { user->message("The object must be a room or portable. Obj #" + objnum + " is not.\n"); return; } if(newvalue < 0.0) { user->message("Length, weight and height values must be positive or zero." + "\n. " + newvalue + " is not.\n"); return; } call_other(obj, "set_" + cmd_norm_name + (is_cap ? "_capacity" : ""), newvalue); user->message("Done.\n"); } static void cmd_set_obj_flag(object user, string cmd, string str) { object obj, link_exit; int objnum, flagval; string flagname, flagstring; mapping valmap; if(str) str = STRINGD->trim_whitespace(str); if(str && !STRINGD->stricmp(str, "flagnames")) { user->message("Flag names: cont container open openable locked lockable\n"); return; } if(!str || sscanf(str, "%*s %*s %*s %*s") == 4 || (sscanf(str, "#%d %s %s", objnum, flagname, flagstring) != 3 && sscanf(str, "#%d %s", objnum, flagname) != 2)) { user->message("Usage: " + cmd + " #<obj> flagname [flagvalue]\n"); user->message(" " + cmd + " flagnames\n"); return; } obj = MAPD->get_room_by_num(objnum); if(!obj) { obj = EXITD->get_exit_by_num(objnum); if (!obj) { user->message("Can't find object #" + objnum + "!\n"); return; } } valmap = ([ "true": 1, "false": 0, "1": 1, "0": 0, "yes": 1, "no": 0 ]); if(flagstring) { if( ({ flagstring }) & map_indices(valmap) ) { flagval = valmap[flagstring]; } else { user->message("I can't tell if value '" + flagstring + "' is true or false!\n"); return; } } else { flagval = 1; } if(!STRINGD->stricmp(flagname, "cont") || !STRINGD->stricmp(flagname, "container")) { obj->set_container(flagval); } else if(!STRINGD->stricmp(flagname, "open")) { obj->set_open(flagval); } else if(!STRINGD->stricmp(flagname, "openable")) { obj->set_openable(flagval); } else if(!STRINGD->stricmp(flagname, "locked")) { obj->set_locked(flagval); } else if(!STRINGD->stricmp(flagname, "lockable")) { obj->set_lockable(flagval); } user->message("Done.\n"); } static void cmd_make_obj(object user, string cmd, string str) { object state; string typename; if(str && !STRINGD->is_whitespace(str)) { user->message("Usage: " + cmd + "\n"); return; } if(cmd == "@make_room") { typename = "room"; } else if (cmd == "@make_port" || cmd == "@make_portable") { typename = "portable"; } else if (cmd == "@make_det" || cmd == "@make_detail") { typename = "detail"; } else { user->message("I don't recognize the kind of object " + "you're trying to make.\n"); return; } state = clone_object(US_MAKE_ROOM); user->push_new_state(US_MAKE_ROOM, typename); } static void cmd_set_obj_detail(object user, string cmd, string str) { int objnum, detailnum; object obj, detail; if(!str || sscanf(str, "%*s %*s %*s") == 3 || sscanf(str, "#%d #%d", objnum, detailnum) != 2) { user->message("Usage: " + cmd + " #<base_obj> #<detail_obj>\n"); return; } obj = MAPD->get_room_by_num(objnum); detail = MAPD->get_room_by_num(detailnum); if(objnum != -1 && !obj) { user->message("Base object (#" + objnum + ") doesn't appear to be a room or portable.\n"); } if(!detail) { user->message("Detail object (#" + detailnum + ") doesn't appear to be a room or portable.\n"); } if(!obj || !detail) return; if(obj && detail->get_detail_of()) { user->message("Object #" + detailnum + " is already a detail of object #" + detail->get_detail_of()->get_number() + "!\n"); return; } else if(!obj && !detail->get_detail_of()) { user->message("Object #" + detailnum + " isn't a detail of anything!\n"); return; } if(obj) { user->message("Setting object #" + detailnum + " to be a detail of obj #" + objnum + ".\n"); if(detail->get_location()) detail->get_location()->remove_from_container(detail); obj->add_detail(detail); } else { obj = detail->get_detail_of(); user->message("Removing detail #" + detailnum + " from object #" + obj->get_number() + ".\n"); obj->remove_detail(detail); } user->message("Done.\n"); }