/*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.diku' as well the Merc * * license in 'license.merc'. In particular, you may not remove either * * of these copyright notices. * * * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * ***************************************************************************/ /* MurkMUD++ - A Windows compatible, C++ compatible Merc 2.2 Mud. \author Jon A. Lambert \date 08/30/2006 \version 1.4 \remarks This source code copyright (C) 2005, 2006 by Jon A. Lambert All rights reserved. Use governed by the MurkMUD++ public license found in license.murk++ */ #include "os.hpp" #include "config.hpp" #include "globals.hpp" #include "object.hpp" #include "room.hpp" #include "affect.hpp" #include "extra.hpp" #include "objproto.hpp" #include "io.hpp" #include "utils.hpp" Object::Object() : in_obj(NULL), carried_by(NULL), pIndexData(NULL), in_room(NULL), item_type(0), extra_flags(0), wear_flags(0), wear_loc(0), weight(0), cost(0), level(0), timer(0) { memset(value, 0, sizeof value); } /* * Return ascii name of an item type. */ std::string Object::item_type_name () { switch (item_type) { case ITEM_LIGHT: return "light"; case ITEM_SCROLL: return "scroll"; case ITEM_WAND: return "wand"; case ITEM_STAFF: return "staff"; case ITEM_WEAPON: return "weapon"; case ITEM_TREASURE: return "treasure"; case ITEM_ARMOR: return "armor"; case ITEM_POTION: return "potion"; case ITEM_FURNITURE: return "furniture"; case ITEM_TRASH: return "trash"; case ITEM_CONTAINER: return "container"; case ITEM_DRINK_CON: return "drink container"; case ITEM_KEY: return "key"; case ITEM_FOOD: return "food"; case ITEM_MONEY: return "money"; case ITEM_BOAT: return "boat"; case ITEM_CORPSE_NPC: return "npc corpse"; case ITEM_CORPSE_PC: return "pc corpse"; case ITEM_FOUNTAIN: return "fountain"; case ITEM_PILL: return "pill"; case ITEM_DARKNESS: return "darkness exuding"; } bug_printf ("Item_type_name: unknown type %d.", item_type); return "(unknown)"; } bool Object::can_wear (sh_int part) { return wear_flags & part; } bool Object::is_obj_stat(sh_int stat) { return extra_flags & stat; } /* * Return # of objects which an object counts as. * Thanks to Tony Chamberlain for the correct recursive code here. */ int Object::get_obj_number () { int number = 0; if (item_type == ITEM_CONTAINER) { for (ObjIter o = contains.begin(); o != contains.end(); o++) number += (*o)->get_obj_number(); } else number = 1; return number; } /* * Return weight of an object, including weight of contents. */ int Object::get_obj_weight () { int wt = weight; for (ObjIter o = contains.begin(); o != contains.end(); o++) wt += (*o)->get_obj_weight (); return wt; } /* * Move an obj out of a room. */ void Object::obj_from_room () { Room *in_rm = in_room; if (in_rm == NULL) { bug_printf ("obj_from_room: NULL."); return; } in_rm->contents.erase(find(in_rm->contents.begin(),in_rm->contents.end(),this)); in_room = NULL; return; } /* * Move an obj into a room. */ void Object::obj_to_room (Room * pRoomIndex) { pRoomIndex->contents.push_back(this); in_room = pRoomIndex; carried_by = NULL; in_obj = NULL; return; } /* * Move an object into an object. */ void Object::obj_to_obj (Object * obj_to) { obj_to->contains.push_back(this); in_obj = obj_to; in_room = NULL; carried_by = NULL; for (; obj_to != NULL; obj_to = obj_to->in_obj) { if (obj_to->carried_by != NULL) { obj_to->carried_by->carry_number += get_obj_number(); obj_to->carried_by->carry_weight += get_obj_weight(); } } return; } /* * Move an object out of an object. */ void Object::obj_from_obj () { Object *obj_from = in_obj; if (obj_from == NULL) { bug_printf ("Obj_from_obj: null obj_from."); return; } obj_from->contains.erase(find(obj_from->contains.begin(), obj_from->contains.end(), this)); in_obj = NULL; for (; obj_from != NULL; obj_from = obj_from->in_obj) { if (obj_from->carried_by != NULL) { obj_from->carried_by->carry_number -= get_obj_number(); obj_from->carried_by->carry_weight -= get_obj_weight(); } } return; } /* * Give an obj to a char. */ void Object::obj_to_char (Character * ch) { ch->carrying.push_back(this); carried_by = ch; in_room = NULL; in_obj = NULL; ch->carry_number += get_obj_number(); ch->carry_weight += get_obj_weight(); } /* * Find the ac value of an obj, including position effect. */ int Object::apply_ac (int iWear) { if (item_type != ITEM_ARMOR) return 0; switch (iWear) { case WEAR_BODY: return 3 * value[0]; case WEAR_HEAD: return 2 * value[0]; case WEAR_LEGS: return 2 * value[0]; case WEAR_FEET: return value[0]; case WEAR_HANDS: return value[0]; case WEAR_ARMS: return value[0]; case WEAR_SHIELD: return value[0]; case WEAR_FINGER_L: return value[0]; case WEAR_FINGER_R: return value[0]; case WEAR_NECK_1: return value[0]; case WEAR_NECK_2: return value[0]; case WEAR_ABOUT: return 2 * value[0]; case WEAR_WAIST: return value[0]; case WEAR_WRIST_L: return value[0]; case WEAR_WRIST_R: return value[0]; case WEAR_HOLD: return value[0]; } return 0; } /* * Take an obj from its character. */ void Object::obj_from_char () { Character *ch = carried_by; if (ch == NULL) { bug_printf ("Obj_from_char: null ch."); return; } if (wear_loc != WEAR_NONE) ch->unequip_char(this); ch->carrying.erase(find(ch->carrying.begin(),ch->carrying.end(), this)); carried_by = NULL; ch->carry_number -= get_obj_number(); ch->carry_weight -= get_obj_weight(); return; } /* * Extract an obj from the world. */ void Object::extract_obj () { Object *obj_content; if (in_room != NULL) obj_from_room (); else if (carried_by != NULL) obj_from_char (); else if (in_obj != NULL) obj_from_obj (); ObjIter o, next; for (o = contains.begin(); o != contains.end(); o = next) { obj_content = *o; next = ++o; obj_content->extract_obj(); } deepobnext = object_list.erase(find(object_list.begin(), object_list.end(), this)); AffIter af; for (af = affected.begin(); af != affected.end(); af++) { delete *af; } affected.clear(); std::list<ExtraDescription *>::iterator ed; for (ed = extra_descr.begin(); ed != extra_descr.end(); ed++) { delete *ed; } extra_descr.clear(); --pIndexData->count; delete this; return; } /* * Write an object and its contents. */ void Object::fwrite_obj (Character * ch, std::ofstream & fp, int iNest) { /* * Castrate storage characters. */ if (ch->level < level || item_type == ITEM_KEY || item_type == ITEM_POTION) return; fp << "#OBJECT\n"; fp << "Nest " << iNest << "\n"; fp << "Name " << name << "~\n"; fp << "ShortDescr " << short_descr << "~\n"; fp << "Description " << description << "~\n"; fp << "Vnum " << pIndexData->vnum << "\n"; fp << "ExtraFlags " << extra_flags << "\n"; fp << "WearFlags " << wear_flags << "\n"; fp << "WearLoc " << wear_loc << "\n"; fp << "ItemType " << item_type << "\n"; fp << "Weight " << weight << "\n"; fp << "Level " << level << "\n"; fp << "Timer " << timer << "\n"; fp << "Cost " << cost << "\n"; fp << "Values " << value[0] << " " << value[1] << " " << value[2] << " " << value[3] << "\n"; switch (item_type) { case ITEM_POTION: case ITEM_SCROLL: if (value[1] > 0) { fp << "Spell 1 '" << skill_table[value[1]].name << "'\n"; } if (value[2] > 0) { fp << "Spell 2 '" << skill_table[value[2]].name << "'\n"; } if (value[3] > 0) { fp << "Spell 3 '" << skill_table[value[3]].name << "'\n"; } break; case ITEM_PILL: case ITEM_STAFF: case ITEM_WAND: if (value[3] > 0) { fp << "Spell 3 '" << skill_table[value[3]].name << "'\n"; } break; } AffIter af; for (af = affected.begin(); af != affected.end(); af++) { fp << "Affect " << (*af)->type << " " << (*af)->duration << " " << (*af)->modifier << " " << (*af)->location << " " << (*af)->bitvector << "\n"; } std::list<ExtraDescription *>::iterator ed; for (ed = extra_descr.begin(); ed != extra_descr.end(); ed++) { fp << "ExtraDescr " << (*ed)->keyword << "~ " << (*ed)->description << "~\n"; } fp << "End\n\n"; std::list<Object*>::reverse_iterator o; for (o = contains.rbegin(); o != contains.rend(); o++) (*o)->fwrite_obj (ch, fp, iNest + 1); return; } bool Object::fread_obj (Character * ch, std::ifstream & fp) { std::string word; int iNest = 0; bool fMatch; bool fNest = false; bool fVnum = true; for (;;) { word = fp.eof() ? std::string("End") : fread_word (fp); fMatch = false; switch (toupper (word[0])) { case '*': fMatch = true; fread_to_eol (fp); break; case 'A': if (!str_cmp (word, "Affect")) { Affect *paf; paf = new Affect(); paf->type = fread_number (fp); paf->duration = fread_number (fp); paf->modifier = fread_number (fp); paf->location = fread_number (fp); paf->bitvector = fread_number (fp); affected.push_back(paf); fMatch = true; break; } break; case 'C': KEY ("Cost", cost, fread_number (fp)); break; case 'D': KEY ("Description", description, fread_string (fp)); break; case 'E': KEY ("ExtraFlags", extra_flags, fread_number (fp)); if (!str_cmp (word, "ExtraDescr")) { ExtraDescription *ed; ed = new ExtraDescription(); ed->keyword = fread_string (fp); ed->description = fread_string (fp); extra_descr.push_back(ed); fMatch = true; } if (!str_cmp (word, "End")) { if (!fNest || !fVnum) { bug_printf ("Fread_obj: incomplete object."); return false; } else { object_list.push_back(this); pIndexData->count++; if (iNest == 0 || rgObjNest[iNest] == NULL) obj_to_char (ch); else obj_to_obj (rgObjNest[iNest - 1]); return true; } } break; case 'I': KEY ("ItemType", item_type, fread_number (fp)); break; case 'L': KEY ("Level", level, fread_number (fp)); break; case 'N': KEY ("Name", name, fread_string (fp)); if (!str_cmp (word, "Nest")) { iNest = fread_number (fp); if (iNest < 0 || iNest >= MAX_NEST) { bug_printf ("Fread_obj: bad nest %d.", iNest); } else { rgObjNest[iNest] = this; fNest = true; } fMatch = true; } break; case 'S': KEY ("ShortDescr", short_descr, fread_string (fp)); if (!str_cmp (word, "Spell")) { int iValue; int sn; iValue = fread_number (fp); sn = skill_lookup (fread_word (fp)); if (iValue < 0 || iValue > 3) { bug_printf ("Fread_obj: bad iValue %d.", iValue); } else if (sn < 0) { bug_printf ("Fread_obj: unknown skill."); } else { value[iValue] = sn; } fMatch = true; break; } break; case 'T': KEY ("Timer", timer, fread_number (fp)); break; case 'V': if (!str_cmp (word, "Values")) { value[0] = fread_number (fp); value[1] = fread_number (fp); value[2] = fread_number (fp); value[3] = fread_number (fp); fMatch = true; break; } if (!str_cmp (word, "Vnum")) { int vnum; vnum = fread_number (fp); if ((pIndexData = get_obj_index (vnum)) == NULL) bug_printf ("Fread_obj: bad vnum %d.", vnum); else fVnum = true; fMatch = true; break; } break; case 'W': KEY ("WearFlags", wear_flags, fread_number (fp)); KEY ("WearLoc", wear_loc, fread_number (fp)); KEY ("Weight", weight, fread_number (fp)); break; } if (!fMatch) { bug_printf ("Fread_obj: no match."); fread_to_eol (fp); } } return false; } std::string Object::format_obj_to_char (Character * ch, bool fShort) { std::string buf; if (is_obj_stat(ITEM_INVIS)) buf.append("(Invis) "); if (ch->is_affected (AFF_DETECT_EVIL) && is_obj_stat(ITEM_EVIL)) buf.append("(Red Aura) "); if (ch->is_affected (AFF_DETECT_MAGIC) && is_obj_stat(ITEM_MAGIC)) buf.append("(Magical) "); if (is_obj_stat(ITEM_GLOW)) buf.append("(Glowing) "); if (is_obj_stat(ITEM_HUM)) buf.append("(Humming) "); if (fShort) { if (!short_descr.empty()) buf.append(short_descr); } else { if (!description.empty()) buf.append(description); } return buf; }