/* * dmobj.cpp * Staff functions related to objects * ____ _ * | _ \ ___ __ _| |_ __ ___ ___ * | |_) / _ \/ _` | | '_ ` _ \/ __| * | _ < __/ (_| | | | | | | \__ \ * |_| \_\___|\__,_|_|_| |_| |_|___/ * * Copyright (C) 2007-2012 Jason Mitchell, Randi Mitchell * Contributions by Tim Callahan, Jonathan Hseu * Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman * */ #include "mud.h" #include "commands.h" #include "dm.h" #include "craft.h" #include "unique.h" #include "effects.h" #include <iomanip> //********************************************************************* // dmCreateObj //********************************************************************* // This function allows a DM to create an object that will appear // in their inventory. int dmCreateObj(Player* player, cmd* cmnd) { Object *object=0; CatRef cr; getCatRef(getFullstrText(cmnd->fullstr, 1), &cr, player); if(!player->checkBuilder(cr)) { player->print("Error: %s out of your allowed range.\n", cr.str().c_str()); return(0); } if(!loadObject(cr, &object)) { player->print("Error (%s)\n", cr.str().c_str()); return(0); } if(!object->getCName()[0] || object->getCName()[0] == ' ') { player->printColor("Error (%s)\n", cr.str().c_str()); delete object; return(0); } if(object->flagIsSet(O_RANDOM_ENCHANT)) object->randomEnchant(); player->printColor("%s^x added to your inventory.\n", object->getCName()); if(!player->isDm()) log_immort(false,player, "%s added %s to %s inventory.\n", player->getCName(), object->getCName(), player->hisHer()); object->setDroppedBy(player, "DmCreate"); player->addObj(object); return(0); } //********************************************************************* // statObj //********************************************************************* // Display information on object given to player given. bstring Object::statObj(int statFlags) { std::ostringstream objStr; Object* object=0; bstring str = ""; bstring objName = getName(); bstring objPlural = plural; objName.Replace("^", "^^"); objPlural.Replace("^", "^^"); if(objPlural == "") { objStr << "Name: " << objName << "^x\n"; } else { objStr << "Name: " << objName << "^x\n" << "Plural: " << objPlural << "^x\n"; } objStr << "CompStr: " << this->getCompareStr() << " "; objStr << "Id: " << getId() << " Registered(Obj/Svr): " << (isRegistered() ? "Y" : "N") << "/" << (gServer->lookupObjId(getId()) != NULL ? "Y" : "N") << "\n"; const Unique* unique = gConfig->getUnique(this); if(unique) objStr << "^y - Unique this (In Game: ^Y" << unique->getInGame() << "^y, Global Limit: ^Y" << unique->getGlobalLimit()<< "^y)^x\n"; objStr << "Index: " << info.str(); if(statFlags & ISDM && !droppedBy.name.empty()) objStr << "\nDropped By: " << droppedBy << "\n"; if(statFlags & ISCT) objStr << "\nLast modified by: " << lastMod; objStr << "\n"; objStr << "Desc: " << description.c_str() << "\n"; if(type == WEAPON) objStr << "Weapon type: " << getWeaponType().c_str() << "\n"; else if(type == ARMOR) objStr << "Armor type: " << getArmorType().c_str() << "\n"; objStr << "Use: " << use_output << "\n"; objStr << "Keys: [" << key[0] << "] [" << key[1] << "] [" << key[2] << "]\n\n"; if(use_attack[0]) objStr << "Attack string: " << use_attack << "\n"; if(deed.high || deed.low.id) objStr << "Deed Room Range: " << deed.str() << "\n"; if(type != BANDAGE) objStr << "Hit: " << damage.str(); else objStr << "Heals: " << damage.str() << " hit points"; if(adjustment != 0) { objStr << " ("; if(adjustment > 0) objStr << "+"; objStr << adjustment << ")\n"; } else objStr << "\n"; if(type == WEAPON || (type == ARMOR && wearflag == FEET) || type == BANDAGE) { if(type != BANDAGE) objStr << "Damage: "; else objStr << "Healing: "; objStr << "low " << damage.low() << ", high " << damage.high() << " average: " << damage.average() << "\n"; if(type == WEAPON) { short num = numAttacks; if(numAttacks) objStr << "NumAttacks: " << numAttacks << "\n"; else num = 1; if(delay > 0) // TODO: This will need adjusting (formatting) objStr << "Delay: " << (delay/10.0) << " second(s)\n"; // Note: this equation is actually used backwards in Object::adjustWeapon // to compute weapon quality. objStr << "Damage per Second: " << ( (damage.average() + adjustment) * (1+num) / 2) / (getWeaponDelay()/10.0) << "\n"; } } objStr << "Shots: " << shotsCur << "/" << shotsMax << " "; if(chargesMax != 0) objStr << " Charges: " << chargesCur << "/" << chargesMax; objStr << "\n"; if(type == LIGHTSOURCE) objStr << "^WThis light source will last for approximately " << (MAX(1, shotsCur) * 20 - 10) << " seconds.^x\n"; if(compass) objStr << "Compass: ^y" << compass->str() << "^x\n"; if(recipe) objStr << "Recipe: ^y#" << recipe << "^x\n"; if(minStrength > 0) objStr << "^WMinimum " << minStrength << " strength required to use.^x\n"; objStr << "Type: " << obj_type(type) << " "; if(type == WEAPON) { if(magicpower > 0 && magicpower < MAXSPELL && flagIsSet(O_WEAPON_CASTS)) objStr << "Casts: " << magicpower << "(" << get_spell_name(magicpower - 1) << ")\n"; } else { switch (type) { case ARMOR: break; case POTION: case SCROLL: case WAND: if(magicpower > 0 && magicpower <= MAXSPELL) { objStr << "Spell: " << magicpower << "(" << get_spell_name(magicpower - 1) << ")"; if(magicpower-1 == S_ILLUSION) { const RaceData* race = 0; if(getExtra() > 0 && getExtra() < RACE_COUNT) race = gConfig->getRace(getExtra()); if(!race) objStr << "\n^R*set o " << key[0] << " extra <race>^x to choose a race for this potion."; else objStr << " (" << race->getName() << ")"; } objStr << "\n"; } break; case CONTAINER: objStr << " MaxBulk: "; if(maxbulk != 0) objStr << maxbulk; else objStr << bulk; objStr << "\n"; break; case KEY: objStr << " (" << getKey() << ")\n"; break; case LIGHTSOURCE: case MISC: case POISON: case BANDAGE: objStr << "\n"; break; case LOTTERYTICKET: objStr << "Lottery Cycle: " << lotteryCycle << " Ticket Info: " << lotteryNumbers[0] << " " << lotteryNumbers[1] << " " << lotteryNumbers[2] << " " << lotteryNumbers[3] << " " << lotteryNumbers[4] << " " << lotteryNumbers[5] << "\n"; break; case SONGSCROLL: if(magicpower > 0 && magicpower < gConfig->getMaxSong()) objStr << "Song #" << magicpower << "(Song of " << get_song_name(magicpower-1) << ")\n"; break; } } if(type == ARMOR || type == WEAPON) { objStr << "Wear location: " << getWearName() << "(" << wearflag << ").\n"; if(type == WEAPON && wearflag != WIELD) objStr << "^rThis object is a weapon and is not wieldable.^x\n"; if(type == ARMOR && (!wearflag || wearflag == HELD || wearflag == WIELD)) objStr << "^rThis object is a armor and is not wearable.^x\n"; } if(size) objStr << "Size: ^y" << getSizeName(size) << "^x\n"; if(material) objStr << "Material: ^g" << getMaterialName(material) << "^x\n"; if(type == ARMOR) objStr << "AC: " << armor; objStr << " Value(gp): " << value[GOLD]; objStr << " Weight: " << weight; objStr << " Bulk: " << bulk << " (" << getActualBulk() << ")"; if(type == CONTAINER) { objStr << "\nLoadable inside: [" << in_bag[0].str() << "] [" << in_bag[1].str() << "] [" << in_bag[2].str() << "]\n"; } if(flagIsSet(O_COIN_OPERATED_OBJECT) && coinCost) objStr << "\n\nCoin Operated Item: " << coinCost << "gp per use.\n"; if(shopValue) objStr << "\nShop Value: $" << shopValue; if(questnum && questnum <= numQuests) { objStr << " Quest: " << questnum << " - ("; if(gConfig->questTable[questnum-1]->name[0] != '\0') objStr << get_quest_name(questnum-1); else objStr << "Unknown"; objStr << ")\n"; } else objStr << "\n"; if(level) objStr << "Level: ^y" << level << "^x "; if(quality) objStr << "Quality: ^y" << (quality/10.0) << "^x "; if(requiredSkill) objStr << "Minimum Skill: ^y" << requiredSkill << "^x "; if(level || requiredSkill || quality > 0) objStr << "\n"; if(special) { objStr << "Special: "; switch (special) { case SP_MAPSC: objStr << "Map or Scroll.\n"; break; case SP_COMBO: objStr << "Combo Lock.\n"; break; default: objStr << "Unknown.\n"; } } if(effect != "") { objStr << "^yEffect: " << effect << "^x\n" << " Duration: "; if(effect == "poison" && !effectDuration) objStr << "Standard poison duratin.\n"; else objStr << effectDuration << " seconds.\n"; objStr << " Strength: " << effectStrength << ".\n"; if(flagIsSet(O_ENVENOMED)) { objStr << "Time remaining: " << timestr(MAX(0,(lasttime[LT_ENVEN].ltime+lasttime[LT_ENVEN].interval-time(0)))) << "\n"; } } if(flagIsSet(O_EQUIPPING_BESTOWS_EFFECT) && !Effect::objectCanBestowEffect(effect)) objStr << "^yObject is flagged as bestowing effect \"" << effect << "\" that cannot be bestowed.^x\n"; objStr << "Flags set: "; int loop = 0, numFlags = 0; for(loop=0; loop<MAX_OBJECT_FLAGS; loop++) { if(flagIsSet(loop)) { if(numFlags++ != 0) objStr << ", "; objStr << get_oflag(loop) << "(" << loop+1 << ")"; } } if(numFlags == 0) objStr << "None."; else objStr << "."; objStr << "\n"; if(randomObjects.size()) { objStr << "^WRandomObjects:^x this item will turn into these random objects:\n"; std::list<CatRef>::const_iterator it; for(it = randomObjects.begin(); it != randomObjects.end(); it++) { loadObject(*it, &object); objStr << " " << std::setw(14) << (*it).str("", 'y') << " ^y::^x " << (object ? object->getCName() : "") << "\n"; if(object) { delete object; object = 0; } } } if(increase) { objStr << "^cWhen studied, this object will increase:\n"; if(increase->type == SkillIncrease) { const SkillInfo* skill = gConfig->getSkill(increase->increase); if(!skill) objStr << "^rThe skill set on this object is not a valid skill.^x\n"; else objStr << "^W Skill:^x " << skill->getDisplayName() << "\n"; objStr << "^W Can Add If Not Known:^x " << (increase->canAddIfNotKnown ? "Yes" : "No") << "\n"; } else if(increase->type == LanguageIncrease) { int lang = atoi(increase->increase.c_str()); if(lang < 1 || lang > LANGUAGE_COUNT) objStr << "^rThe language set on this object is not a valid language.^x\n"; else objStr << "^W Language:^x " << get_language_adj(lang-1) << "\n"; } else { objStr << "^rThe increase type set on this object is not a valid increase type.^x\n"; } if(increase->type != LanguageIncrease) objStr << "^W Amount:^x " << increase->amount << "\n"; objStr << "^W Only Once:^x " << (increase->onlyOnce ? "Yes" : "No") << "\n"; } if(questOwner != "") objStr << "^gOwner:^x " << questOwner << "\n"; if(made) { str = ctime(&made); str.trim(); objStr << "Made: " << str << "\n"; } objStr << showAlchemyEffects() << hooks.display(); bstring toReturn = objStr.str(); return(toReturn); } int stat_obj(Player* player, Object* object) { if(!player->canBuildObjects()) return(cmdNoAuth(player)); if(object->info.id && !player->checkBuilder(object->info)) { player->print("Error: object not in any of your alotted ranges.\n"); return(0); } if(!player->isDm()) log_immort(false,player, "%s statted object %s(%s).\n", player->getCName(), object->getCName(), object->info.str().c_str()); int statFlags = 0; if(player->isCt()) statFlags |= ISCT; if(player->isDm()) statFlags |= ISDM; player->printColor("%s\n", object->statObj(statFlags).c_str()); return(0); } //********************************************************************* // setWhich //********************************************************************* int setWhich(const Player* player, bstring options) { options.Replace(",", "^x,^W"); player->printColor("Which do you wish to set: ^W%s^x?\n", options.c_str()); return(0); } //********************************************************************* // dmSetObj //********************************************************************* int dmSetObj(Player* player, cmd* cmnd) { Creature* creature=0; Monster* mTarget=0; BaseRoom* room = player->getRoomParent(); Object *object=0; int n=0, match=0, test=0; long num=0; double dNum=0.0; char flags[25], objname[200]; //temp3[80], objfile[80], ; //FILE *filename; if(!player->canBuildObjects()) return(cmdNoAuth(player)); if(cmnd->num < 4) { player->print("Syntax: *set o <name> [<crt>] <ad|ar|dn|ds|dp|f|m|sm|s|t|v|wg|wr|q> [<value>]\n"); return(0); } strcpy(objname, ""); // make an exception when we're setting certain flags if( cmnd->num == 4 || (cmnd->num == 5 && ( !strcmp(cmnd->str[3], "size") || !strcmp(cmnd->str[3], "sub") || !strcmp(cmnd->str[3], "ra") || !strcmp(cmnd->str[3], "material") || !strcmp(cmnd->str[3], "effect") || !strcmp(cmnd->str[3], "eff") || !strcmp(cmnd->str[3], "wear") ) ) ) { strcpy(flags, cmnd->str[3]); num = cmnd->val[3]; dNum = atof(getFullstrText(cmnd->fullstr, 4).c_str()); object = player->findObject(player, cmnd, 2); if(!object) object = room->findObject(player, cmnd, 2); if(!object) { player->print("Object not found.\n"); return(0); } if(Unique::isUnique(object)) player->printColor("^yCaution:^x this will remove the object's unique status.\n"); } else if(cmnd->num == 5) { strncpy(flags, cmnd->str[4], 24); num = cmnd->val[4]; dNum = atof(getFullstrText(cmnd->fullstr, 5).c_str()); cmnd->str[3][0] = up(cmnd->str[3][0]); creature = gServer->findPlayer(cmnd->str[3]); if(!creature) { cmnd->str[3][0] = low(cmnd->str[3][0]); creature = room->findCreature(player, cmnd, 3); } if(!creature || !player->canSee(creature)) { player->print("Creature not found.\n"); return(0); } object = creature->findObject(player, cmnd, 2); if(!object || !cmnd->val[2]) { for(n = 0; n < MAXWEAR; n++) { if(!creature->ready[n]) continue; if(keyTxtEqual(creature->ready[n], cmnd->str[2])) match++; else continue; if(cmnd->val[1] == match || !cmnd->val[2]) { object = creature->ready[n]; break; } } } if(!object) { player->print("Object not found.\n"); return(0); } if(Unique::isUnique(object)) { player->printColor("^yCannot change object %s^y owned by %s.\n", object->getCName(), creature->getCName()); player->print("This will remove the object's uniqueness and distort the object count.\n"); player->printColor("Use ^W*take^x or ^Wsteal^x to remove the object from their inventory first.\n"); return(0); } if(Lore::isLore(object)) { player->printColor("^yCannot change object %s^y owned by %s.\n", object->getCName(), creature->getCName()); player->print("This will remove the object's loreness and distort the object count.\n"); player->printColor("Use ^W*take^x or ^Wsteal^x to remove the object from their inventory first.\n"); return(0); } sprintf(objname, "%s's ", creature->getCName()); } // because float variables suck dNum += 0.0001; if(!object) { player->print("Object not found.\n"); return(0); } // make the green broadcast stay green strcat(objname, object->getCName()); if(player->isDm() || player->isCt()) strcat(objname, "^g"); else strcat(objname, "^G"); if(player->getClass() == BUILDER) { if(creature) { if(!player->canBuildMonsters()) { player->print("Error: you do not have authorization to modify monsters.\n"); return(PROMPT); } mTarget = creature->getAsMonster(); if(!mTarget) { player->print("Error: you are not allowed to modify players.\n"); return(0); } else if(mTarget->info.id && !player->checkBuilder(mTarget->info)) { player->print("Creature number is not in any of your alotted ranges.\n"); return(0); } } if(object->info.id && !player->checkBuilder(object->info, false)) { player->print("Error: object not in any of your alotted ranges.\n"); return(0); } } short result = 0; bstring resultTxt = ""; bstring setType = ""; // Save this object as a full object until *saved object->setFlag(O_SAVE_FULL); switch (flags[0]) { case 'a': switch (flags[1]) { case 'd': object->setAdjustment(num); result = object->getAdjustment(); setType = "Adjustment"; break; case 'r': if(object->getType() != ARMOR) { player->printColor("Please set %P to type 6(armor) first.\n", object); return(PROMPT); } object->setArmor(num); result = object->getArmor(); setType = "Armor"; break; default: return(setWhich(player, "adjustment, armor")); } break; case 'b': if(flags[1] == 'u' || !flags[1]) { if(num > 100 || num < 0) { player->print("Bulk must be greater than or equal to 0 and less than or equal to 100.\n"); return(PROMPT); } object->setBulk(num); result = object->getBulk(); setType = "Bulk"; } else { return(setWhich(player, "bulk")); } break; case 'c': if(flags[1] == 'o') { if( flags[2] == 's' || flags[2] == 'i' ) { if(num > 100000 || num < 0) { player->print("Nothing is going to cost more than 100000gp.\n"); return(PROMPT); } object->setCoinCost(num); result = object->getCoinCost(); setType = "Coin Use Cost"; } else if(flags[2] == 'm') { MapMarker mapmarker; CatRef cr; getDestination(getFullstrText(cmnd->fullstr, cmnd->num+cmnd->val[2]-1), &mapmarker, &cr, player); Area *area=0; if(mapmarker.getArea()) area = gConfig->getArea(mapmarker.getArea()); if(!area) { if(object->compass) { player->print("Deleting compass.\n"); delete object->compass; object->compass = 0; log_immort(2, player, "%s cleared %s's %s.\n", player->getCName(), objname, "compass"); } else player->print("That's not a valid location.\n"); } else { if(!object->compass) object->compass = new MapMarker; *object->compass = *&mapmarker; player->print("Compass set to location %s.\n", mapmarker.str().c_str()); log_immort(2, player, "%s set %s's %s to %s.\n", player->getCName(), objname, "compass", mapmarker.str().c_str()); } } else { return(setWhich(player, "coin cost, compass")); } } else { return(setWhich(player, "coin cost, compass")); } break; case 'd': switch(flags[1]) { case 'a': case 'l': case 'h': player->printColor("Use the following commands to set deed range:\n"); player->printColor(" ^W*set o <object> ra <area>\n"); player->printColor(" ^W*set o <object> rl <low #>\n"); player->printColor(" ^W*set o <object> rh <high #>\n"); break; case 'e': { if(dNum < 0.0) { player->print("Attack delay cannot be negative.\n"); return(0); } object->setDelay((int)(dNum * 10.0)); player->print("Delay set to %.1f.\n", object->getDelay()/10.0); log_immort(2, player, "%s set %s's %s to %.1f.\n", player->getCName(), objname, "Delay", object->getDelay()/10.0); if(object->adjustWeapon() != -1) player->print("Weapon has been auto adusted to a mean damage of %.2f.\n", object->damage.getMean()); } break; case 'n': object->damage.setNumber(num); result = object->damage.getNumber(); setType = "Dice Number"; break; case 's': object->damage.setSides(num); result = object->damage.getSides(); setType = "Dice Sides"; break; case 'p': object->damage.setPlus(num); result = object->damage.getPlus(); setType = "Dice Plus"; break; default: return(setWhich(player, "delay, dn, ds, dp")); } break; case 'e': switch(flags[1]) { case 'x': object->setExtra(num); result = object->getExtra(); setType = "Extra"; break; case 'f': { if(cmnd->num < 5) { player->print("Set what effect to what?\n"); return(0); } long duration = -1; int strength = 1; bstring txt = getFullstrText(cmnd->fullstr, 5); if(txt != "") duration = atoi(txt.c_str()); txt = getFullstrText(cmnd->fullstr, 6); if(txt != "") strength = atoi(txt.c_str()); if(duration > EFFECT_MAX_DURATION || duration < -1) { player->print("Duration must be between -1 and %d.\n", EFFECT_MAX_DURATION); return(0); } if(strength < 0 || strength > EFFECT_MAX_STRENGTH) { player->print("Strength must be between 0 and %d.\n", EFFECT_MAX_STRENGTH); return(0); } bstring effectStr = cmnd->str[4]; if(duration == 0) { player->print("Effect '%s' removed.\n", object->getEffect().c_str()); object->clearEffect(); log_immort(2, player, "%s cleared %s's effect.\n", player->getCName(), objname); } else { object->setEffect(effectStr); object->setEffectDuration(duration); object->setEffectStrength(strength); player->print("Effect '%s' added with duration %d and strength %d.\n", effectStr.c_str(), duration, strength); log_immort(2, player, "%s set %s's effect to %s with duration %d and strength %d.\n", player->getCName(), objname, effectStr.c_str(), duration, strength); } } break; default: return(setWhich(player, "extra, effect")); } break; case 'f': if(flags[1] == 'l' || !flags[1]) { if(num < 1 || num > MAX_OBJECT_FLAGS) { player->print("Error: flag out of range.\n"); return(PROMPT); } if(num-1 == O_UNIQUE) { if(player->getClass() == BUILDER) player->printColor("You will need to get a CT to set this object as unique using the ^y*unique^x command.\n"); else player->printColor("Use the ^y*unique^x command to modify the uniqueness of this object.\n"); return(0); } if(num-1 == O_LORE) { if(player->getClass() == BUILDER) player->printColor("You may have a CT use ^y*set o [object] lore #^x to specify how many of this object may be in game.\n"); else player->printColor("You may use ^y*set o [object] lore #^x to specify how many of this object may be in game.\n"); } if(object->flagIsSet(num - 1)) { object->clearFlag(num - 1); player->printColor("%O's flag #%d off.\n", object, num); test=0; } else { object->setFlag(num - 1); player->printColor("%O's flag #%d on.\n", object, num); test=1; } log_immort(2, player, "%s turned %s's flag %ld(%s) %s.\n", player->getCName(), objname, num, get_oflag(num-1), test == 1 ? "On" : "Off"); } else { return(setWhich(player, "flag")); } break; case 'k': if(flags[1] == 'e' || !flags[1]) { if(object->getType() != KEY) { player->print("Object is not a key. *set to object type 12.\n"); return(PROMPT); } if(num < 0 || num > 256) { player->print("Error: key out of range.\n"); return(PROMPT); } object->setKey(num); result = object->getKey(); setType = "Key Value"; } else { return(setWhich(player, "key")); } break; case 'l': if(flags[1] == 'e') { if(num < 0 || num > MAXALVL) { player->print("Error: level out of range.\n"); return(PROMPT); } if(num > 0 && (object->getType() == ARMOR || object->getType() == WEAPON)) player->printColor("^yConsider using a minimum-skill requirement instead of a level requirement.\n"); object->setLevel(num); result = object->getLevel(); setType = "Level"; } else if(flags[1] == 'o') { if(!object->info.id) { player->print("Object must be saved to an index to set lore amount on it.\n"); return(0); } num = MIN(50, MAX(1, num)); if(num == 1) gConfig->delLore(object->info); else { Lore* l = gConfig->getLore(object->info); if(l) l->setLimit(num); else gConfig->addLore(object->info, num); } gConfig->saveLimited(); player->printColor("Object lore set to ^y%d^x.\n", num); if(num == 1) player->print("To remove lore, clear the object's lore flag and resave.\n"); else player->print("To remove lore, set lore amount to 1 and clear the object's lore flag and resave.\n"); return(0); } else { return(setWhich(player, "level, lore")); } break; case 'm': if(flags[1] == 'a' && flags[2] == 't') { if(num > (MAX_MATERIAL-1) || num < NO_MATERIAL) { player->print("Error: material out of range.\n"); return(PROMPT); } object->setMaterial((Material)num); result = object->getMaterial(); resultTxt = getMaterialName(object->getMaterial()); setType = "Material"; } else if(flags[1] == 'b') { if(num > 100 || num < 0) { player->print("Max bulk must be greater than or equal to 0 and less than or equal to 100.\n"); return(0); } object->setMaxbulk(num); result = object->getMaxbulk(); setType = "Max Bulk"; } else if(flags[1] == 'a') { if(num < 0 || num > MAXSPELL) { player->print("Error: spell out of range.\n"); return(0); } object->setMagicpower(num); if(object->getMagicpower()) { if(object->getType() == SONGSCROLL) { player->print("Magic power set to %d - (Song of %s).\n", num, get_song_name(num-1)); log_immort(2, player, "%s set %s's %s to %ld - (Song of %s).\n", player->getCName(), objname, "Song", num, get_song_name(num-1)); } else { player->print("Magic power set to %d - (%s).\n",num, get_spell_name(num-1)); log_immort(2, player, "%s set %s's %s to %ld - (%s).\n", player->getCName(), objname, "Spell", num,get_spell_name(num-1)); } } else { player->print("Magic power cleared.\n"); log_immort(2, player, "%s cleared %s's %s.\n", player->getCName(), objname, "Spell"); } } else { return(setWhich(player, "material, maxbulk, magic")); } break; case 'n': if(flags[1] == 'u' || !flags[1]) { if(object->getType() != WEAPON) { player->print("Error: numAttacks can only be set on weapons.\n"); return(PROMPT); } if(num > 100 || num < 1) { player->print("Number of attacks must be greater than 0 and less than or equal to 100.\n"); return(0); } object->setNumAttacks(num); result = object->getNumAttacks(); setType = "numAttacks"; if(object->adjustWeapon() != -1) player->print("Weapon has been auto adusted to a mean damage of %.2f.\n", object->damage.getMean()); } else { return(setWhich(player, "numAttacks")); } break; case 'o': if(flags[1] == 'b' || !flags[1]) { if(object->getType() != CONTAINER) { player->print("Object must be a container.\n"); return(0); } num = atoi(&cmnd->str[3][1]); object->in_bag[num-1].id = cmnd->val[3]; object->setShotsMax(MAX(num, object->getShotsMax())); player->print("Loadable container object %s set to item number %s.\n", object->info.str().c_str(), object->in_bag[num-1].str().c_str()); log_immort(2, player, "%s set container %s(%s) to load object %s.\n", player->getCName(), objname, object->info.str().c_str(), object->in_bag[num-1].str().c_str()); } else { return(setWhich(player, "objects")); } break; case 'q': if(flags[1] == 'u' && flags[2] == 'a') { if(object->getType() == ARMOR || object->getType() == WEAPON) { if(dNum < 0.0 || dNum > MAXALVL+0.0001) { player->print("Error: quality out of range. (0-%d)\n", MAXALVL); return(PROMPT); } } else { if(dNum < 0.0 || dNum > 1000.0) { player->print("Error: quality out of range.(0-1000)\n"); return(PROMPT); } } object->setQuality(dNum*10.0); player->print("Quality set to %.1f.\n", dNum); log_immort(2, player, "%s set %s's %s to %.1f.\n", player->getCName(), objname, "Quality", dNum); if(object->adjustArmor() != -1) player->print("Armor has been auto adusted to %d.\n", object->getArmor()); if(object->adjustWeapon() != -1) player->print("Weapon has been auto adusted to a mean damage of %.2f.\n", object->damage.getMean()); break; } else if(flags[1] == 'u' && flags[2] == 'e') { if(num < 0 || num > 64) { player->print("Quest number must be greater than or equal to 0 and less than or equal to 64.\n"); return(0); } object->setQuestnum(num); result = object->getQuestnum(); resultTxt = get_quest_name(object->getQuestnum() - 1); setType = "Quest"; } else { return(setWhich(player, "quality, quest")); } break; case 'r': if(low(cmnd->str[3][1]) == 'l') { object->deed.low.id = (int)cmnd->val[3]; result = object->deed.low.id; setType = "Low Deed Room boundary"; } else if(low(cmnd->str[3][1]) == 'h') { object->deed.high = (int)cmnd->val[3]; result = object->deed.high; setType = "High Deed Room boundary"; } else if(low(cmnd->str[3][1]) == 'a') { object->deed.low.setArea(cmnd->str[4]); player->print("Deed Area: %s\n", object->deed.low.area.c_str()); log_immort(2, player, "%s set %s's %s to %s.\n", player->getCName(), objname, "Deed Area", object->deed.low.area.c_str()); } else if(low(cmnd->str[3][1]) == 'e') { Recipe* recipe = gConfig->getRecipe((int)cmnd->val[3]); if(!recipe) { player->print("That recipe does not exist.\n"); return(0); } if(!recipe->canBeEdittedBy(player)) { player->print("You are not allowed to set that recipe on an object.\n"); return(0); } object->setRecipe(recipe->getId()); result = object->getRecipe(); resultTxt = recipe->getResultName(); setType = "Recipe"; } else { return(setWhich(player, "rl (room low), rh (room high), ra (room area), recipe")); } break; case 's': if(flags[1] == 'i') { object->setSize(getSize(cmnd->str[4])); player->print("Size set to %s.\n", getSizeName(object->getSize()).c_str()); log_immort(2, player, "%s set %s's %s to %s.\n", player->getCName(), objname, "Size", getSizeName(object->getSize()).c_str()); } else if(flags[1] == 'm') { num = MAX(0, MIN(num,5000)); object->setShotsMax(num); result = object->getShotsMax(); setType = "Max Shots"; } else if(flags[1] == 'p') { num=MAX(0, MIN(num, MAX_SP)); object->setSpecial(num); result = object->getSpecial(); setType = "Special"; } else if(flags[1] == 't') { num=MAX(0, MIN(num, 280)); object->setMinStrength(num); result = object->getMinStrength(); setType = "MinStrength"; } else if(flags[1] == 'u') { bstring subType = cmnd->str[4]; if(object->getType() == WEAPON) object->setWeaponType(subType); else if(object->getType() == ARMOR) { object->setArmorType(subType); if(object->adjustArmor() != -1) player->print("Armor has been auto adusted to %d.\n", object->getArmor()); } else { object->setSubType(subType); } player->print("Object subtype set to %s.\n", object->getSubType().c_str()); log_immort(2, player, "%s set %s's %s to %s.\n", player->getCName(), objname, "Subtype", object->getSubType().c_str()); } else if(flags[1] == 'h' || flags[1] == 'v') { object->setShopValue(num); player->print("Shop value set.\n"); log_immort(2, player, "%s set %s's %s to %ld.\n", player->getCName(), objname, "shopValue", object->getShopValue()); } else if(flags[1] == 'k') { if(num < 0 || num > MAXALVL*10) { player->print("Error: required skill out of range.\n"); return(PROMPT); } object->setRequiredSkill(num); result = object->getRequiredSkill(); setType = "Required Skill"; } else if(flags[1] == 'c' || !flags[1]) { num=MAX(0, MIN(num, 5000)); object->setShotsCur(num); result = object->getShotsCur(); setType = "Current Shots"; } else { return(setWhich(player, "size, shots, sm (shots max), special, strength, subtype, shopvalue, skill")); } break; case 't': if(flags[1] == 'y' || !flags[1]) { if((num < 0 || num > MAX_OBJ_TYPE) && !player->isDm()) return(PROMPT); if(num > MAX_OBJ_TYPE) { object->setType(MISC); } else { object->setType(num); } result = object->getType(); resultTxt = obj_type(num); setType = "Type"; } else { return(setWhich(player, "type")); } break; case 'v': if(flags[1] == 'a' || !flags[1]) { if(!player->isDm()) num=MAX(0, MIN(num, 500000)); else num=MAX(0, MIN(num, 20000000)); object->value.set(num, GOLD); result = num; setType = "Value"; } else { return(setWhich(player, "value")); } break; case 'w': if(flags[1] == 'g' || (flags[1] == 'e' && flags[2] == 'i')) { num=MAX(0, MIN(num, 5000)); object->setWeight(num); result = object->getWeight(); setType = "Weight"; } else if(flags[1] == 'r' || (flags[1] == 'e' && flags[2] == 'a')) { bstring wear = cmnd->str[4]; if(!isdigit(cmnd->str[4][0])) { if(wear == "body") num = 1; else if(wear == "arm" || wear == "arms" || wear == "sleeve" || wear == "sleeves") num = 2; else if(wear == "leg" || wear == "legs" || wear == "pant" || wear == "pants") num = 3; else if(wear == "neck") num = 4; else if(wear == "belt" || wear == "waist") num = 5; else if(wear == "hand" || wear == "hands" || wear == "glove" || wear == "gloves") num = 6; else if(wear == "head" || wear == "helmet" || wear == "hat") num = 7; else if(wear == "feet" || wear == "shoe" || wear == "shoes" || wear == "boot" || wear == "boots") num = 8; else if(wear == "finger" || wear == "ring") num = 9; else if(wear == "held" || wear == "hold") num = 17; else if(wear == "shield") num = 18; else if(wear == "face" || wear == "mask" || wear == "visor") num = 19; else if(wear == "wield" || wear == "weapon") num = 20; } if(num < 0 || num > 64) { player->print("Use a valid wear location.\n"); break; } if((num > 9) && (num < 16)) { player->print("Use wear location 9 for rings.\n"); break; } object->setWearflag(num); result = object->getWearflag(); resultTxt = object->getWearName(); setType = "Wear Location"; if(object->adjustArmor() != -1) player->print("Armor has been auto adusted to %d.\n", object->getArmor()); } else { return(setWhich(player, "wear, weight")); } break; default: player->print("Invalid option.\n"); return(PROMPT); } if(setType != "") { if(resultTxt != "") { player->printColor("%s set to %ld(%s).\n", setType.c_str(), result, resultTxt.c_str()); log_immort(2, player, "%s set %s's %s to %ld(%s^g).\n", player->getCName(), objname, setType.c_str(), result, resultTxt.c_str()); } else { player->print("%s set to %ld.\n", setType.c_str(), result); log_immort(2, player, "%s set %s's %s to %ld.\n", player->getCName(), objname, setType.c_str(), result); } } if(Unique::isUnique(object)) { player->printColor("^yUnique status of %s^y has been removed.\n", object->getCName()); player->print("If the object is saved to a new index, the unique flag will be removed.\n"); player->print("If the object is resaved to the unique range, it will become unique again.\n"); object->clearFlag(O_UNIQUE); } if(Lore::isLore(object)) { player->printColor("^yLore status of %s^y has been removed.\n", object->getCName()); player->print("If the object is resaved to any index, it will become lore again.\n"); } // Reset object index object->info.id = 0; object->escapeText(); object->track(player); return(0); } //********************************************************************* // dmObjName //********************************************************************* // the dmObjName command allows a dm/ caretaker to modify an already // existing object's name, description, wield description, and key // words. This command does not save the changes to the object to the // object data base. This is used to edit an object that may or may // not be saved to the database using the dmSaveObj function. int dmObjName(Player* player, cmd* cmnd) { Object *object=0; int i=0, num=0; char which=0; bstring text = ""; if(cmnd->num < 2) { player->print("\nRename what object to what?\n"); player->print("*oname <object> [#] [-adok] <name>\n"); return(PROMPT); } // parse the full command string for the start of the description // (pass command, object, obj #, and possible flag). The object // number has to be interpreted separately, and with the normal // command parse (cmnd->val), due to problems caused having // the object number followed by a "-" while(isspace(cmnd->fullstr[i])) i++; while(!isspace(cmnd->fullstr[i])) i++; while(isspace(cmnd->fullstr[i])) i++; while(isalpha(cmnd->fullstr[i])) i++; while(isspace(cmnd->fullstr[i])) i++; cmnd->val[1]= 1; if(isdigit(cmnd->fullstr[i])) cmnd->val[1] = atoi(&cmnd->fullstr[i]); object = player->findObject(player, cmnd, 1); if(!object) object = player->getRoomParent()->findObject(player, cmnd, 1); if(!object) { player->print("Item not found.\n"); return(0); } while(isdigit(cmnd->fullstr[i])) i++; while(isspace(cmnd->fullstr[i])) i++; // parse flag if(cmnd->fullstr[i] == '-') { if(cmnd->fullstr[i+1] == 'd') { which =1; i += 2; } else if(cmnd->fullstr[i+1] == 'o') { which =2; i += 2; } else if(cmnd->fullstr[i+1] == 'a') { which =3; i += 2; } else if(cmnd->fullstr[i+1] == 'k') { i += 2; which = 4; num = atoi(&cmnd->fullstr[i]); if(num <1 || num > 3) num = 0; while(isdigit(cmnd->fullstr[i])) i++; } while(isspace(cmnd->fullstr[i])) i++; } // no description given if(cmnd->fullstr[i] == 0) return(PROMPT); text = &cmnd->fullstr[i]; // handle object modification switch(which) { case 0: if(text.getLength() > 79) text = text.left(79); if(Pueblo::is(text)) { player->print("That object name is not allowed.\n"); return(0); } object->setName( text.c_str()); player->print("\nName "); break; case 1: if(text == "0" && object->description != "") { object->description = ""; player->print("Item description cleared.\n"); return(0); } else if(Pueblo::is(text)) { player->print("That object description is not allowed.\n"); return(0); } else { object->description = text; object->description.Replace("*CR*", "\n"); } player->print("\nDescription "); break; case 2: if(text == "0" && object->use_output[0]) { zero(object->use_output, sizeof(object->use_output)); player->print("Item output string cleared.\n"); return(0); } else if(Pueblo::is(text)) { player->print("That object output string is not allowed.\n"); return(0); } else { if(text.getLength() > 79) text = text.left(79); strcpy(object->use_output, text.c_str()); player->print("\nOutput String "); } break; case 3: if(text == "0" && object->use_attack[0]) { zero(object->use_attack, sizeof(object->use_attack)); player->print("Item attack string cleared.\n"); return(0); } else { if(text.getLength() > 49) text = text.left(49); strcpy(object->use_attack, text.c_str()); player->print("\nAttack String "); } break; case 4: if(num) { if(text == "0" && object->key[num-1][0]) { zero(object->key[num-1], sizeof(object->key[num-1])); player->print("Key #%d string cleared.\n", num); return(0); } else { if(text.getLength() > OBJ_KEY_LENGTH-1) text = text.left(OBJ_KEY_LENGTH-1); strcpy(object->key[num-1], text.c_str()); player->print("\nKey "); } } break; } object->escapeText(); player->print("done.\n"); return(0); } //********************************************************************* // dmAddObj //********************************************************************* int dmAddObj(Player* player, cmd* cmnd) { Object *newObj=0; if(!player->canBuildObjects()) return(cmdNoAuth(player)); if(cmnd->val[1] < 1) { player->print("Add what?\n"); return(0); } newObj = new Object; if(!newObj) { merror("dmAddObj", NONFATAL); player->print("Cannot allocate object.\n"); return(0); } log_immort(true, player, "%s made a new Object!\n", player->getCName()); newObj->setName( "small clay ball"); strcpy(newObj->key[0], "ball"); strcpy(newObj->key[1], "clay"); newObj->setWearflag(HELD); newObj->setType(MISC); newObj->setWeight(1); newObj->setFlag(O_SAVE_FULL); player->addObj(newObj); player->print("Generic object added to your inventory.\n"); return(0); } //********************************************************************* // dmSaveObj //********************************************************************* void dmSaveObj(Player* player, cmd* cmnd, CatRef cr) { char file[80]; Object* object=0; if(!player->canBuildObjects()) { cmdNoAuth(player); return; } object = player->findObject(player, cmnd->str[2], 1); if(!object) object = player->getRoomParent()->findObject(player, cmnd->str[2], 1); if(!object) { player->print("Object not found.\n"); return; } if(!validObjId(cr)) { player->print("Index error: object number invalid.\n"); return; } if(object->info.id && !player->checkBuilder(object->info, false)) { player->print("Error: %s out of your allowed range.\n", object->info.str().c_str()); return; } if(!player->checkBuilder(cr, false)) { player->print("Error: %s out of your allowed range.\n", cr.str().c_str()); return; } object->clearFlag(O_BEING_PREPARED); object->clearFlag(O_SAVE_FULL); logn("log.bane", "%s saved %s to %s.\n", player->getCName(), object->getCName(), cr.str().c_str()); object->info = cr; sprintf(file, "%s", objectPath(object->info)); if(file_exists(file)) player->print("Object might already exist.\n"); dmResaveObject(player, object); } //********************************************************************* // dmResaveObject //********************************************************************* void dmResaveObject(const Player* player, Object* object, bool flush) { if(object->saveToFile() != 0) { loge("Error saving object in dmResaveObject()"); player->print("Error: object was not saved.\n"); } else player->print("Object %s updated.\n", object->info.str().c_str()); // swap this new Object if its in the queue if(flush || player->flagIsSet(P_NO_FLUSHCRTOBJ)) gConfig->replaceObjectInQueue(object->info, object); } //********************************************************************* // dmSize //********************************************************************* int dmSize(Player* player, cmd* cmnd) { if(cmnd->num < 2) { player->print("Syntax: *size <object> <size>\n"); return(0); } std::ostringstream oStr; oStr << "*set o " << cmnd->str[1] << " " << cmnd->val[1] << " size " << cmnd->str[2]; cmnd->fullstr = oStr.str(); parse(cmnd->fullstr, cmnd); return(dmSetObj(player, cmnd)); } //********************************************************************* // makeWeapon //********************************************************************* void makeWeapon(Player *player, CatRef* cr, Object* object, Object *random, const bstring& sub, const bstring& descBase, const bstring& descAll, bool twoHanded, int weight, double value, int bulk, short numAttacks) { Object* newObj = 0; bool addToInventory = true; if(sub == object->getSubType()) { // the object already exists newObj = object; addToInventory = false; } else { // create one if it doesn't newObj = new Object; if(!newObj) { merror("makeWeapon", NONFATAL); player->print("Cannot allocate object.\n"); return; } *newObj = *object; } if(!newObj->key[2][0]) { strcpy(newObj->key[1], sub.c_str()); newObj->setName(bstring(newObj->key[0]) + sub); //sprintf(newObj->name, "%s %s", newObj->key[0], sub.c_str()); } else { strcpy(newObj->key[2], sub.c_str()); newObj->setName(bstring(newObj->key[0]) + newObj->key[1] + sub); //sprintf(newObj->name, "%s %s %s", newObj->key[0], newObj->key[1], sub.c_str()); } newObj->setWeight(MAX(1, weight)); newObj->setBulk(MAX(1, bulk)); newObj->setNumAttacks(numAttacks); //newObj->setBulk(bulk); value = MAX(1, value); newObj->value.set((long)value, GOLD); newObj->setWearflag(WIELD); // The random item should represent the total value, weight, and bulk of the item lists // this is useful in trading - if they can carry the random object, then they can carry // all of the objects in the list. random->value.set(random->value[GOLD] + newObj->value[GOLD], GOLD); random->setWeight(random->getWeight() + newObj->getActualWeight()); random->setBulk(random->getBulk() + newObj->getActualBulk()); newObj->description = descBase + " " + descAll; newObj->setWeaponType(sub); newObj->adjustWeapon(); newObj->info = *cr; random->randomObjects.push_back(newObj->info); if(twoHanded) newObj->setFlag(O_TWO_HANDED); else newObj->clearFlag(O_TWO_HANDED); player->printColor("Saving %s to %s... ", newObj->getCName(), cr->str("", 'W').c_str()); dmResaveObject(player, newObj); log_immort(2, player, "%s cloned %s into %s.\n", player->getCName(), newObj->getCName(), cr->str().c_str()); if(addToInventory) player->addObj(newObj); cr->id++; } //********************************************************************* // makeArmor //********************************************************************* void makeArmor(Player *player, CatRef* cr, Object* object, Object *random, int wear, const bstring& base, const bstring& descBase, const bstring& descAll, long value, int weight, int bulk, bool somePrefix=false) { Object* newObj = 0; bool addToInventory = true; if(wear == object->getWearflag()) { // the object already exists newObj = object; addToInventory = false; } else { // create one if it doesn't newObj = new Object; if(!newObj) { merror("makeArmor", NONFATAL); player->print("Cannot allocate object.\n"); return; } *newObj = *object; } if(!newObj->key[2][0]) { strcpy(newObj->key[1], base.c_str()); newObj->setName(bstring(newObj->key[0]) + base); //sprintf(newObj->name, "%s %s", newObj->key[0], base.c_str()); } else { strcpy(newObj->key[2], base.c_str()); newObj->setName(bstring(newObj->key[0]) + newObj->key[1] + base); //sprintf(newObj->name, "%s %s %s", newObj->key[0], newObj->key[1], base.c_str()); } if(somePrefix) newObj->setFlag(O_SOME_PREFIX); else newObj->clearFlag(O_SOME_PREFIX); newObj->setWeight(weight); newObj->setBulk(bulk); newObj->value.set(value, GOLD); newObj->setWearflag(wear); // The random item should represent the total value, weight, and bulk of the item lists // this is useful in trading - if they can carry the random object, then they can carry // all of the objects in the list. random->value.set(random->value[GOLD] + value, GOLD); random->setWeight(random->getWeight() + weight); random->setBulk(random->getBulk() + bulk); newObj->adjustArmor(); newObj->description = descBase + " " + descAll; newObj->info = *cr; random->randomObjects.push_back(newObj->info); player->printColor("Saving %s to %s... ", newObj->getCName(), cr->str("", 'W').c_str()); dmResaveObject(player, newObj); log_immort(2, player, "%s cloned %s into %s.\n", player->getCName(), newObj->getCName(), cr->str().c_str()); if(addToInventory) player->addObj(newObj); cr->id++; } //********************************************************************* // dmClone //********************************************************************* // given an object, this code will create a set of armor int dmClone(Player* player, cmd* cmnd) { Object* object=0, *random=0; bool isArmor=false, isWeapon = false; if(cmnd->num == 1) { player->printColor("^WArmor:^x This command will take a single piece of armor and create a set of armor out of it.\n"); player->print(" It will save the items starting at <area.id> and will use between 10 and 11 spaces.\n"); player->printColor("^WWeapons:^x This command will take a weapon and create one weapon for every weapon type.\n"); player->print(" It will save the items starting at <area.id> and will use 19 spaces.\n"); player->print("The final item can be used to randomly become any of the items.\n"); player->printColor("Syntax: ^c*clone <object> <area.id> <partial desc>\n"); player->print("The partial description should complete the sentence, \"It's a <item> _____\".\n"); return(0); } object = player->findObject(player, cmnd->str[1], 1); if(!object) { player->print("Object not found.\n"); player->printColor("Syntax: ^c*clone <object> <area.id> <partial desc>\n"); return(0); } player->printColor("^yCloning %s.\n", object->getCName()); if(object->info.id && !player->checkBuilder(object->info, false)) { player->print("Error: %s out of your allowed range.\n", object->info.str().c_str()); return(0); } bstring sub = object->getSubType(); if(sub == "cloth" || sub == "leather" || sub == "chain" || sub == "plate") { isArmor = true; } else if(sub == "sword" || sub == "great-sword" || sub == "polearm" || sub == "whip" || sub == "axe" || sub == "great-axe" || sub == "rapier" || sub == "spear" || sub == "dagger" || sub == "staff" || sub == "mace" || sub == "great-mace" || sub == "club" || sub == "hammer" || sub == "great-hammer" || sub == "bow" || sub == "crossbow" || sub == "thrown" ) { isWeapon = true; } else { player->print("The object subtype \"%s\" is not an armor or a weapon subtype!\n", sub.c_str()); return(0); } CatRef cr; getCatRef(getFullstrText(cmnd->fullstr, 2), &cr, player); if(!validObjId(cr)) { player->print("Index error: object number invalid.\n"); player->printColor("Syntax: ^c*clone <object> <area.id> <partial desc>\n"); return(0); } if(!player->checkBuilder(cr, false)) { player->print("Error: %s out of your allowed range.\n", cr.str().c_str()); return(0); } bstring desc = getFullstrText(cmnd->fullstr, 3); if(desc == "") { player->printColor("Syntax: ^c*clone <object> <area.id> <partial desc>\n"); player->print("The partial description should complete the sentence, \"It's a <item> _____\".\n"); return(0); } // create a random object container for this suit of armor random = new Object; if(!random) { merror("dmClone", NONFATAL); player->print("Cannot allocate object.\n"); return(0); } strcpy(random->key[0], "random"); strcpy(random->key[1], object->key[0]); if(!object->key[2][0] && !isWeapon) { random->setName(bstring("random ") + random->key[1]); //sprintf(random->name, "random %s", random->key[1]); } else { if(!object->key[2][0]) strcpy(random->key[2], "weapon"); else strcpy(random->key[2], object->key[1]); random->setName(bstring("random ") + random->key[1] + random->key[2]); //sprintf(random->name, "random %s %s", random->key[1], random->key[2]); } if(isArmor) { long value = object->value[GOLD]; // makeArmor expects the value to be the body armor's value. If we're cloning // a non-body item, modify the value switch(object->getWearflag()) { case 17: value *= 2; break; case 3: case 19: value *= 3; break; case 2: case 5: case 6: case 7: case 8: value *= 4; break; case 4: value *= 5; break; default: break; } if(sub == "cloth") { object->setMaterial(CLOTH); makeArmor(player, &cr, object, random, BODY, "tunic", "It's a tunic", desc, value, 3, 5); makeArmor(player, &cr, object, random, ARMS, "sleeves", "They're some sleeves", desc, value/4, 1, 3, true); makeArmor(player, &cr, object, random, LEGS, "pants", "They're some pants", desc, value/3, 2, 4, true); makeArmor(player, &cr, object, random, NECK, "scarf", "It's a scarf", desc, value/5, 1, 3); makeArmor(player, &cr, object, random, BELT, "belt", "It's a belt", desc, value/4, 1, 3); makeArmor(player, &cr, object, random, HANDS, "gloves", "They're some gloves", desc, value/4, 1, 3, true); makeArmor(player, &cr, object, random, HEAD, "hat", "It's a hat", desc, value/4, 1, 3); makeArmor(player, &cr, object, random, FEET, "shoes", "They're some shoes", desc, value/4, 2, 4, true); makeArmor(player, &cr, object, random, FACE, "mask", "It's a mask", desc, value/3, 1, 3); } else if(sub == "leather") { object->setMaterial(LEATHER); makeArmor(player, &cr, object, random, BODY, "armor", "It's armor", desc, value, 5, 8, true); makeArmor(player, &cr, object, random, ARMS, "sleeves", "They're some sleeves", desc, value/4, 3, 5, true); makeArmor(player, &cr, object, random, LEGS, "leggings", "They're some leggings", desc, value/3, 4, 6, true); makeArmor(player, &cr, object, random, NECK, "neckguard", "It's a neckguard", desc, value/5, 3, 5); makeArmor(player, &cr, object, random, BELT, "belt", "It's a belt", desc, value/4, 3, 5); makeArmor(player, &cr, object, random, HANDS, "gloves", "They're some gloves", desc, value/4, 3, 5, true); makeArmor(player, &cr, object, random, HEAD, "cap", "It's a cap", desc, value/4, 3, 5); makeArmor(player, &cr, object, random, FEET, "boots", "They're some boots", desc, value/4, 3, 5, true); makeArmor(player, &cr, object, random, FACE, "faceguard", "It's a faceguard", desc, value/3, 2, 4); makeArmor(player, &cr, object, random, SHIELD, "buckler", "It's a buckler", desc, value/3, 4, 6); } else if(sub == "chain") { makeArmor(player, &cr, object, random, BODY, "armor", "It's armor", desc, value, 7, 9, true); makeArmor(player, &cr, object, random, ARMS, "sleeves", "They're some sleeves", desc, value/4, 5, 7, true); makeArmor(player, &cr, object, random, LEGS, "leggings", "They're some leggings", desc, value/3, 5, 7, true); makeArmor(player, &cr, object, random, NECK, "neckguard", "It's a neckguard", desc, value/5, 4, 6); makeArmor(player, &cr, object, random, BELT, "waistguard", "It's a waistguard", desc, value/4, 4, 6); makeArmor(player, &cr, object, random, HANDS, "gloves", "They're some gloves", desc, value/4, 4, 6, true); makeArmor(player, &cr, object, random, HEAD, "hood", "It's a hood", desc, value/4, 4, 6); makeArmor(player, &cr, object, random, FEET, "boots", "They're some boots", desc, value/4, 4, 6, true); makeArmor(player, &cr, object, random, FACE, "faceguard", "It's a faceguard", desc, value/3, 3, 5); makeArmor(player, &cr, object, random, SHIELD, "shield", "It's a shield", desc, value/3, 6, 8); } else if(sub == "plate") { makeArmor(player, &cr, object, random, BODY, "chestplate", "It's armor", desc, value, 10, 15); makeArmor(player, &cr, object, random, ARMS, "sleeves", "They're some sleeves", desc, value/4, 6, 8, true); makeArmor(player, &cr, object, random, LEGS, "leggings", "They're some leggings", desc, value/3, 6, 8, true); makeArmor(player, &cr, object, random, NECK, "neckguard", "It's a neckguard", desc, value/5, 5, 7); makeArmor(player, &cr, object, random, BELT, "waistguard", "It's a waistguard", desc, value/4, 5, 7); makeArmor(player, &cr, object, random, HANDS, "gauntlets", "They're some gauntlets", desc, value/4, 5, 7, true); makeArmor(player, &cr, object, random, HEAD, "helmet", "It's a helmet", desc, value/4, 5, 7); makeArmor(player, &cr, object, random, FEET, "boots", "They're some boots", desc, value/4, 5, 7, true); makeArmor(player, &cr, object, random, FACE, "faceguard", "It's a faceguard", desc, value/3, 4, 6); makeArmor(player, &cr, object, random, SHIELD, "shield", "It's a shield", desc, value/3, 10, 15); } } else if(isWeapon) { double value = object->value[GOLD]; int baseWeight = object->getActualWeight(); short numAttacks = object->getNumAttacks(); if(numAttacks < 1) numAttacks = 1; // bows get more attacks, so lower it for everyone else if(object->getSubType() == "bow" && numAttacks == 2) numAttacks = 1; if( sub == "great-sword" || sub == "polearm" || sub == "great-axe" || sub == "great-mace" || sub == "great-hammer" ) { value *= 0.8; baseWeight -= 2; } else if(sub == "whip" || sub == "dagger") { value *= 1.2; baseWeight += 2; } else if(sub == "bow" || sub == "crossbow") { baseWeight += 1; } makeWeapon(player, &cr, object, random, "sword", "It's a sword", desc, false, baseWeight, value, 4, numAttacks); makeWeapon(player, &cr, object, random, "great-sword", "It's a great sword", desc, true, baseWeight+2, value/0.8, 6, numAttacks); makeWeapon(player, &cr, object, random, "polearm", "It's a polearm", desc, true, baseWeight+2, value/0.8, 6, numAttacks); makeWeapon(player, &cr, object, random, "whip", "It's a whip", desc, false, baseWeight-2, value/1.2, 2, numAttacks); makeWeapon(player, &cr, object, random, "axe", "It's an axe", desc, false, baseWeight, value, 4, numAttacks); makeWeapon(player, &cr, object, random, "great-axe", "It's a great axe", desc, true, baseWeight+2, value/0.8, 6, numAttacks); makeWeapon(player, &cr, object, random, "rapier", "It's a rapier", desc, false, baseWeight, value, 3, numAttacks); makeWeapon(player, &cr, object, random, "spear", "It's a spear", desc, true, baseWeight, value, 5, numAttacks); makeWeapon(player, &cr, object, random, "dagger", "It's a dagger", desc, false, baseWeight-2, value/1.2, 2, numAttacks); makeWeapon(player, &cr, object, random, "staff", "It's a staff", desc, true, baseWeight, value, 5, numAttacks); makeWeapon(player, &cr, object, random, "mace", "It's a mace", desc, false, baseWeight, value, 4, numAttacks); makeWeapon(player, &cr, object, random, "great-mace", "It's a great mace", desc, true, baseWeight+2, value/0.8, 6, numAttacks); makeWeapon(player, &cr, object, random, "club", "It's a club", desc, false, baseWeight, value, 4, numAttacks); makeWeapon(player, &cr, object, random, "hammer", "It's a hammer", desc, false, baseWeight, value, 4, numAttacks); makeWeapon(player, &cr, object, random, "great-hammer", "It's a great hammer", desc, true, baseWeight+2, value/0.8, 6, numAttacks); makeWeapon(player, &cr, object, random, "bow", "It's a bow", desc, true, baseWeight-1, value, 6, numAttacks == 1 ? 2 : numAttacks); makeWeapon(player, &cr, object, random, "crossbow", "It's a crossbow", desc, false, baseWeight-1, value, 4, numAttacks); } random->info = cr; random->setType(MISC); random->setAdjustment(object->getAdjustment()); player->printColor("Saving %s to %s... ", random->getCName(), cr.str("", 'W').c_str()); dmResaveObject(player, random); log_immort(2, player, "%s cloned %s into %s.\n", player->getCName(), random->getCName(), cr.str().c_str()); player->addObj(random); player->printColor("^YDone!\n"); return(0); }