/* * dmroom.cpp * Staff functions related to rooms. * ____ _ * | _ \ ___ __ _| |_ __ ___ ___ * | |_) / _ \/ _` | | '_ ` _ \/ __| * | _ < __/ (_| | | | | | | \__ \ * |_| \_\___|\__,_|_|_| |_| |_|___/ * * Permission to use, modify and distribute is granted via the * Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License * http://creativecommons.org/licenses/by-nc-sa/3.0/ * * 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 "factions.h" #include "property.h" #include "ships.h" #include "tokenizer.h" #include "effects.h" #include "traps.h" #include <signal.h> #include <dirent.h> #include <iomanip> //********************************************************************* // checkTeleportRange //********************************************************************* void checkTeleportRange(const Player* player, CatRef cr) { // No warning for the test range if(cr.isArea("test")) return; const CatRefInfo* cri = gConfig->getCatRefInfo(cr.area); if(!cri) { player->printColor("^yNo CatRefInfo zone found for this room's area. Contact a dungeonmaster to fix this.\n"); return; } if(cr.id > cri->getTeleportWeight()) { player->printColor("^yThis room is outside the CatRefInfo zone's teleport range.\n"); return; } } //********************************************************************* // isCardinal //********************************************************************* bool isCardinal(bstring xname) { return( xname == "north" || xname == "east" || xname == "south" || xname == "west" || xname == "northeast" || xname == "northwest" || xname == "southeast" || xname == "southwest" ); } //********************************************************************* // wrapText //********************************************************************* bstring wrapText(const bstring& text, int wrap) { if(text == "") return(""); bstring wrapped = ""; int len = text.length(), i=0, sp=0, spLast=0, spLen=0; char ch, chLast; // find our starting position while(text.at(i) == ' ' || text.at(i) == '\n' || text.at(i) == '\r') i++; for(; i < len; i++) { ch = text.at(i); // convert linebreaks to spaces if(ch == '\r') ch = ' '; if(ch == '\n') ch = ' '; // skiping 2x spacing (or greater) if(ch == ' ' && chLast == ' ') { do { i++; } while(i+1 < len && (text.at(i+1) == ' ' || text.at(i+1) == '\n' || text.at(i+1) == '\r')); if(i < len) ch = text.at(i); } // don't add trailing spaces if(ch != ' ' || i+1 < len) { // If there is color in the room description, the color characters // shouldn't count toward string length. if(ch == '^') spLen += 2; // wrap if(ch == ' ') { // We went over! spLast points to the last non-overboard space. if(wrap <= (sp - spLen)) { wrapped.replace(spLast, 1, "\n"); spLen = spLast; } spLast = sp; } wrapped += ch; sp++; chLast = ch; } } return(wrapped); } //********************************************************************* // expand_exit_name //********************************************************************* bstring expand_exit_name(const bstring& name) { if(name == "n") return("north"); if(name == "s") return("south"); if(name == "e") return("east"); if(name == "w") return("west"); if(name == "sw") return("southwest"); if(name == "nw") return("northwest"); if(name == "se") return("southeast"); if(name == "ne") return("northeast"); if(name == "d") return("door"); if(name == "o") return("out"); if(name == "p") return("passage"); if(name == "t") return("trap door"); if(name == "a") return("arch"); if(name == "g") return("gate"); if(name == "st") return("stairs"); return(name); } //********************************************************************* // opposite_exit_name //********************************************************************* bstring opposite_exit_name(const bstring& name) { if(name == "south") return("north"); if(name == "north") return("south"); if(name == "west") return("east"); if(name == "east") return("west"); if(name == "northeast") return("southwest"); if(name == "southeast") return("northwest"); if(name == "northwest") return("southeast"); if(name == "southwest") return("northeast"); if(name == "up") return("down"); if(name == "down") return("up"); return(name); } //********************************************************************* // dmPurge //********************************************************************* // This function allows staff to purge a room of all its objects and // monsters. int dmPurge(Player* player, cmd* cmnd) { BaseRoom* room = player->getRoomParent(); if(!player->canBuildMonsters() && !player->canBuildObjects()) return(cmdNoAuth(player)); if(!player->checkBuilder(player->getUniqueRoomParent())) { player->print("Error: this room is out of your range; you cannot *purge here.\n"); return(0); } room->purge(false); player->print("Purged.\n"); if(!player->isDm()) log_immort(false,player, "%s purged room %s.\n", player->getCName(), player->getRoomParent()->fullName().c_str()); return(0); } //********************************************************************* // dmEcho //********************************************************************* // This function allows a staff specified by the socket descriptor in // the first parameter to echo the rest of their command line to all // the other people in the room. int dmEcho(Player* player, cmd* cmnd) { if(!player->checkBuilder(player->getUniqueRoomParent())) { player->print("Error: room number not in any of your allotted ranges.\n"); return(0); } bstring text = getFullstrText(cmnd->fullstr, 1); if(text == "" || Pueblo::is(text)) { player->print("Echo what?\n"); return(0); } if(!player->isCt()) broadcast(isStaff, "^G*** %s (%s) echoed: %s", player->getCName(), player->getRoomParent()->fullName().c_str(), text.c_str()); broadcast(NULL, player->getRoomParent(), "%s", text.c_str()); return(0); } //********************************************************************* // dmReloadRoom //********************************************************************* // This function allows a staff to reload a room from disk. int dmReloadRoom(Player* player, cmd* cmnd) { if(!player->checkBuilder(player->getUniqueRoomParent())) { player->print("Error: this room is out of your range; you cannot reload this room.\n"); return(0); } if(gConfig->reloadRoom(player->getRoomParent())) player->print("Ok.\n"); else player->print("Reload failed.\n"); return(0); } //********************************************************************* // resetPerms //********************************************************************* // This function allows a staff to reset perm timeouts in the room int dmResetPerms(Player* player, cmd* cmnd) { std::map<int, crlasttime>::iterator it; crlasttime* crtm=0; std::map<int, long> tempMonsters; std::map<int, long> tempObjects; UniqueRoom *room = player->getUniqueRoomParent(); //long temp_obj[10], temp_mon[10]; if(!needUniqueRoom(player)) return(0); if(!player->checkBuilder(player->getUniqueRoomParent())) { player->print("Error: this room is out of your range; you cannot reload this room.\n"); return(0); } for(it = room->permMonsters.begin(); it != room->permMonsters.end() ; it++) { crtm = &(*it).second; tempMonsters[(*it).first] = crtm->interval; crtm->ltime = time(0); crtm->interval = 0; } for(it = room->permObjects.begin(); it != room->permObjects.end() ; it++) { crtm = &(*it).second; tempObjects[(*it).first] = crtm->interval; crtm->ltime = time(0); crtm->interval = 0; } player->print("Permanent object and creature timeouts reset.\n"); room->addPermCrt(); for(it = room->permMonsters.begin(); it != room->permMonsters.end() ; it++) { crtm = &(*it).second; crtm->interval = tempMonsters[(*it).first]; crtm->ltime = time(0); } for(it = room->permObjects.begin(); it != room->permObjects.end() ; it++) { crtm = &(*it).second; crtm->interval = tempObjects[(*it).first]; crtm->ltime = time(0); } log_immort(true, player, "%s reset perm timeouts in room %s\n", player->getCName(), player->getRoomParent()->fullName().c_str()); if(gConfig->resaveRoom(room->info) < 0) player->print("Room fail saved.\n"); else player->print("Room saved.\n"); return(0); } //********************************************************************* // stat_rom_exits //********************************************************************* // Display information on room given to staff. void stat_rom_exits(Creature* player, BaseRoom* room) { char str[1024], temp[25], tempstr[32]; int i=0, flagcount=0; UniqueRoom* uRoom = room->getAsUniqueRoom(); if(room->exits.empty()) return; player->print("Exits:\n"); for(Exit* exit : room->exits) { if(!exit->getLevel()) player->print(" %s: ", exit->getCName()); else player->print(" %s(L%d): ", exit->getCName(), exit->getLevel()); if(!exit->target.mapmarker.getArea()) player->printColor("%s ", exit->target.room.str(uRoom ? uRoom->info.area : "", 'y').c_str()); else player->print(" A:%d X:%d Y:%d Z:%d ", exit->target.mapmarker.getArea(), exit->target.mapmarker.getX(), exit->target.mapmarker.getY(), exit->target.mapmarker.getZ()); *str = 0; strcpy(str, "Flags: "); for(i=0; i<MAX_EXIT_FLAGS; i++) { if(exit->flagIsSet(i)) { sprintf(tempstr, "%s(%d), ", get_xflag(i), i+1); strcat(str, tempstr); flagcount++; } } if(flagcount) { str[strlen(str) - 2] = '.'; str[strlen(str) - 1] = 0; } if(flagcount) player->print("%s", str); if(exit->flagIsSet(X_LOCKABLE)) { player->print(" Key#: %d ", exit->getKey()); if(exit->getKeyArea() != "") player->printColor(" Area: ^y%s^x ", exit->getKeyArea().c_str()); } if(exit->flagIsSet(X_TOLL_TO_PASS)) player->print(" Toll: %d ", exit->getToll()); player->print("\n"); if(exit->getDescription() != "") player->print(" Description: \"%s\"\n", exit->getDescription().c_str()); if( (exit->flagIsSet(X_CAN_LOOK) || exit->flagIsSet(X_LOOK_ONLY)) && exit->flagIsSet(X_NO_SCOUT) ) player->printColor("^rExit is flagged as no-scout, but it flagged as lookable.\n"); if(exit->flagIsSet(X_PLEDGE_ONLY)) { for(i=1; i<15; i++) if(exit->flagIsSet(i+40)) { sprintf(temp, "Clan: %d, ",i); strcat(str, temp); } player->print(" Clan: %s\n", temp); } if(exit->flagIsSet(X_PORTAL)) { player->printColor(" Owner: ^c%s^x Uses: ^c%d^x\n", exit->getPassPhrase().c_str(), exit->getKey()); } else if(exit->getPassPhrase() != "") { player->print(" Passphrase: \"%s\"\n", exit->getPassPhrase().c_str()); if(exit->getPassLanguage()) player->print(" Passlang: %s\n", get_language_adj(exit->getPassLanguage())); } if(exit->getEnter() != "") player->print(" OnEnter: \"%s\"\n", exit->getEnter().c_str()); if(exit->getOpen() != "") player->print(" OnOpen: \"%s\"\n", exit->getOpen().c_str()); if(exit->getSize() || exit->getDirection()) { if(exit->getSize()) player->print(" Size: %s", getSizeName(exit->getSize()).c_str()); if(exit->getDirection()) { player->print(" Direction: %s", getDirName(exit->getDirection()).c_str()); if(getDir(exit->getName()) != NoDirection) player->printColor("\n^rThis exit has a direction set, but the exit is a cardinal exit."); } player->print("\n"); } if(exit->effects.effectList.size()) player->printColor(" Effects:\n%s", exit->effects.getEffectsString(player).c_str()); player->printColor("%s", exit->hooks.display().c_str()); } } //********************************************************************* // trainingFlagSet //********************************************************************* bool trainingFlagSet(const BaseRoom* room, const TileInfo *tile, const AreaZone *zone, int flag) { return( (room && room->flagIsSet(flag)) || (tile && tile->flagIsSet(flag)) || (zone && zone->flagIsSet(flag)) ); } //********************************************************************* // whatTraining //********************************************************************* // determines what class can train here int whatTraining(const BaseRoom* room, const TileInfo *tile, const AreaZone *zone, int extra) { int i = 0; if(R_TRAINING_ROOM - 1 == extra || trainingFlagSet(room, tile, zone, R_TRAINING_ROOM - 1)) i += 16; if(R_TRAINING_ROOM == extra || trainingFlagSet(room, tile, zone, R_TRAINING_ROOM)) i += 8; if(R_TRAINING_ROOM + 1 == extra || trainingFlagSet(room, tile, zone, R_TRAINING_ROOM + 1)) i += 4; if(R_TRAINING_ROOM + 2 == extra || trainingFlagSet(room, tile, zone, R_TRAINING_ROOM + 2)) i += 2; if(R_TRAINING_ROOM + 3 == extra || trainingFlagSet(room, tile, zone, R_TRAINING_ROOM + 3)) i += 1; return(i > CLASS_COUNT - 1 ? 0 : i); } int BaseRoom::whatTraining(int extra) const { return(::whatTraining(this, (const TileInfo*)0, (const AreaZone*)0, extra)); } //********************************************************************* // showRoomFlags //********************************************************************* void showRoomFlags(const Player* player, const BaseRoom* room, const TileInfo *tile, const AreaZone *zone) { bool flags=false; int i=0; std::ostringstream oStr; oStr << "^@Flags set: "; for(; i<MAX_ROOM_FLAGS; i++) { if(i >=2 && i <= 6) // skips training flags continue; if( (room && room->flagIsSet(i)) || (tile && tile->flagIsSet(i)) || (zone && zone->flagIsSet(i)) ) { if(flags) oStr << ", "; flags = true; oStr << get_rflag(i) << "(" << (int)(i+1) << ")"; } } if(!flags) oStr << "None"; oStr << ".^x\n"; i = whatTraining(room, tile, zone, 0); if(i) oStr << "^@Training: " << get_class_string(i) << "^x\n"; player->printColor("%s", oStr.str().c_str()); // inform user of redundant flags if(room && room->getAsConstUniqueRoom()) { int whatTraining = room->whatTraining(); bool limboOrCoven = room->flagIsSet(R_LIMBO) || room->flagIsSet(R_VAMPIRE_COVEN); if(room->flagIsSet(R_NO_TELEPORT)) { if( limboOrCoven || room->flagIsSet(R_JAIL) || room->flagIsSet(R_ETHEREAL_PLANE) || whatTraining ) player->printColor("^rThis room does not need flag 13-No Teleport set.\n"); } if(room->flagIsSet(R_NO_SUMMON_OUT)) { if( room->flagIsSet(R_IS_STORAGE_ROOM) || room->flagIsSet(R_LIMBO) ) player->printColor("^rThis room does not need flag 29-No Summon Out set.\n"); } if(room->flagIsSet(R_NO_LOGIN)) { if( room->flagIsSet(R_LOG_INTO_TRAP_ROOM) || whatTraining ) player->printColor("^rThis room does not need flag 34-No Log set.\n"); } if(room->flagIsSet(R_NO_CLAIR_ROOM)) { if(limboOrCoven) player->printColor("^rThis room does not need flag 43-No Clair set.\n"); } if(room->flagIsSet(R_NO_TRACK_TO)) { if( limboOrCoven || room->flagIsSet(R_IS_STORAGE_ROOM) || room->flagIsSet(R_NO_TELEPORT) || room->whatTraining() ) player->printColor("^rThis room does not need flag 52-No Track To set.\n"); } if(room->flagIsSet(R_NO_SUMMON_TO)) { if( limboOrCoven || room->flagIsSet(R_NO_TELEPORT) || room->flagIsSet(R_ONE_PERSON_ONLY) || whatTraining ) player->printColor("^rThis room does not need flag 54-No Summon To set.\n"); } if(room->flagIsSet(R_NO_TRACK_OUT)) { if( room->flagIsSet(R_LIMBO) || room->flagIsSet(R_ETHEREAL_PLANE) ) player->printColor("^rThis room does not need flag 54-No Summon To set.\n"); } if(room->flagIsSet(R_OUTLAW_SAFE)) { if( limboOrCoven || whatTraining ) player->printColor("^rThis room does not need flag 57-Outlaw Safe set.\n"); } if(room->flagIsSet(R_LOG_INTO_TRAP_ROOM)) { if(whatTraining) player->printColor("^rThis room does not need flag 63-Log To Trap Exit set.\n"); } if(room->flagIsSet(R_LIMBO)) { if(room->flagIsSet(R_POST_OFFICE)) player->printColor("^rThis room does not need flag 11-Post Office set.\n"); if(room->flagIsSet(R_FAST_HEAL)) player->printColor("^rThis room does not need flag 14-Fast Heal set.\n"); if(room->flagIsSet(R_NO_POTION)) player->printColor("^rThis room does not need flag 32-No Potion set.\n"); if(room->flagIsSet(R_NO_CAST_TELEPORT)) player->printColor("^rThis room does not need flag 38-No Cast Teleport set.\n"); if(room->flagIsSet(R_NO_FLEE)) player->printColor("^rThis room does not need flag 44-No Flee set.\n"); if(room->flagIsSet(R_BANK)) player->printColor("^rThis room does not need flag 58-Bank set.\n"); if(room->flagIsSet(R_MAGIC_MONEY_MACHINE)) player->printColor("^rThis room does not need flag 59-Magic Money Machine set.\n"); } } } //********************************************************************* // stat_rom //********************************************************************* int stat_rom(Player* player, AreaRoom* room) { std::list<AreaZone*>::iterator it; AreaZone* zone=0; TileInfo* tile=0; if(!player->checkBuilder(0)) return(0); if(player->getClass() == CARETAKER) log_immort(false,player, "%s statted room %s.\n", player->getCName(), player->getRoomParent()->fullName().c_str()); player->print("Room: %s %s\n\n", room->area->name.c_str(), room->fullName().c_str()); tile = room->area->getTile(room->area->getTerrain(0, &room->mapmarker, 0, 0, 0, true), false); for(it = room->area->zones.begin() ; it != room->area->zones.end() ; it++) { zone = (*it); if(zone->inside(room->area, &room->mapmarker)) { player->printColor("^yZone:^x %s\n", zone->name.c_str()); if(zone->wander.getTraffic()) { zone->wander.show(player); } else { player->print(" No monsters come in this zone.\n"); } player->print("\n"); } } if(room->getSize()) player->printColor("Size: ^y%s\n", getSizeName(room->getSize()).c_str()); if(tile->wander.getTraffic()) tile->wander.show(player); player->print("Terrain: %c\n", tile->getDisplay()); if(room->isWater()) player->printColor("Water: ^gyes\n"); if(room->isRoad()) player->printColor("Road: ^gyes\n"); player->printColor("Generic Room: %s\n", room->canSave() ? "^rNo" : "^gYes"); if(room->unique.id) { player->printColor("Links to unique room ^y%s^x.\n", room->unique.str().c_str()); player->printColor("needsCompass: %s^x decCompass: %s", room->getNeedsCompass() ? "^gYes" : "^rNo", room->getDecCompass() ? "^gYes" : "^rNo"); } player->print("\n"); showRoomFlags(player, room, 0, 0); if(room->effects.effectList.size()) player->printColor("Effects:\n%s", room->effects.getEffectsString(player).c_str()); player->printColor("%s", room->hooks.display().c_str()); stat_rom_exits(player, room); return(0); } //********************************************************************* // validateShop //********************************************************************* void validateShop(const Player* player, const UniqueRoom* shop, const UniqueRoom* storage) { // basic checks if(!shop) { player->printColor("^rThe shop associated with this storage room does not exist.\n"); return; } if(!storage) { player->printColor("^rThe storage room associated with this shop does not exist.\n"); return; } if(shop->info == storage->info) { player->printColor("^rThe shop and the storage room cannot be the same room. Set the shop's trap exit appropriately.\n"); return; } CatRef cr = shopStorageRoom(shop); if(shop->info == cr) { player->printColor("^rThe shop and the storage room cannot be the same room. Set the shop's trap exit appropriately.\n"); return; } bstring name = "Storage: "; name += shop->getName(); if(cr != storage->info) player->printColor("^rThe shop's storage room of %s does not match the storage room %s.\n", cr.str().c_str(), storage->info.str().c_str()); if(storage->getTrapExit() != shop->info) player->printColor("^yThe storage room's trap exit of %s does not match the shop room %s.\n", storage->info.str().c_str(), shop->info.str().c_str()); if(!shop->flagIsSet(R_SHOP)) player->printColor("^rThe shop's flag 1-Shoppe is not set.\n"); if(!storage->flagIsSet(R_SHOP_STORAGE)) player->printColor("^rThe storage room's flag 97-Shop Storage is not set.\n"); // what DOESN'T the storage room need? if(storage->flagIsSet(R_NO_LOGIN)) player->printColor("^rThe storage room does not need flag 34-No Log set.\n"); if(storage->flagIsSet(R_LOG_INTO_TRAP_ROOM)) player->printColor("^rThe storage room does not need flag 63-Log To Trap Exit set.\n"); if(storage->flagIsSet(R_NO_TELEPORT)) player->printColor("^rThe storage room does not need flag 13-No Teleport set.\n"); if(storage->flagIsSet(R_NO_SUMMON_TO)) player->printColor("^rThe storage room does not need flag 54-No Summon To set.\n"); if(storage->flagIsSet(R_NO_TRACK_TO)) player->printColor("^rThe storage room does not need flag 52-No Track To set.\n"); if(storage->flagIsSet(R_NO_CLAIR_ROOM)) player->printColor("^rThe storage room does not need flag 43-No Clair set.\n"); if(storage->exits.empty()) { player->printColor("^yThe storage room does not have an out exit pointing to the shop.\n"); } else { const Exit* exit = storage->exits.front(); if( exit->target.room != shop->info || exit->getName() != "out") player->printColor("^yThe storage room does not have an out exit pointing to the shop.\n"); else if(storage->exits.size() > 1) player->printColor("^yThe storage room has more than one exit - it only needs one out exit pointing to the shop.\n"); } } //********************************************************************* // stat_rom //********************************************************************* int stat_rom(Player* player, UniqueRoom* room) { std::map<int, crlasttime>::iterator it; crlasttime* crtm=0; CatRef cr; Monster* monster=0; Object* object=0; UniqueRoom* shop=0; time_t t = time(0); if(!player->checkBuilder(room)) return(0); if(player->getClass() == CARETAKER) log_immort(false,player, "%s statted room %s.\n", player->getCName(), player->getRoomParent()->fullName().c_str()); player->printColor("Room: %s", room->info.str("", 'y').c_str()); if(gConfig->inSwapQueue(room->info, SwapRoom, true)) player->printColor(" ^eThis room is being swapped."); player->print("\nTimes People have entered this room: %d\n", room->getBeenHere()); player->print("Name: %s\n", room->getCName()); Property *p = gConfig->getProperty(room->info); if(p) { player->printColor("Property Belongs To: ^y%s^x\nProperty Type: ^y%s\n", p->getOwner().c_str(), p->getTypeStr().c_str()); } if(player->isCt()) { if(room->last_mod[0]) player->printColor("^cLast modified by: %s on %s\n", room->last_mod, stripLineFeeds(room->lastModTime)); if(room->lastPly[0]) player->printColor("^cLast player here: %s on %s\n", room->lastPly, stripLineFeeds(room->lastPlyTime)); } else player->print("\n"); if(room->getSize()) player->printColor("Size: ^y%s\n", getSizeName(room->getSize()).c_str()); if(room->getRoomExperience()) player->print("Experience for entering this room: %d\n", room->getRoomExperience()); if(room->getFaction() != "") player->printColor("Faction: ^g%s^x\n", room->getFaction().c_str()); if(room->getFishingStr() != "") player->printColor("Fishing: ^g%s^x\n", room->getFishingStr().c_str()); if(room->getMaxMobs() > 0) player->print("Max mob allowance: %d\n", room->getMaxMobs()); room->wander.show(player, room->info.area); player->print("\n"); player->print("Perm Objects:\n"); for(it = room->permObjects.begin(); it != room->permObjects.end() ; it++) { crtm = &(*it).second; loadObject((*it).second.cr, &object); player->printColor("^y%2d) ^x%14s ^y::^x %-30s ^yInterval:^x %-5d ^yTime Until Spawn:^x %-5d", (*it).first+1, crtm->cr.str("", 'y').c_str(), object ? object->getCName() : "", crtm->interval, tMAX<long>(0, crtm->ltime + crtm->interval-t)); if(room->flagIsSet(R_SHOP_STORAGE) && object) player->printColor(" ^yCost:^x %s", object->value.str().c_str()); player->print("\n"); // warning about deeds in improper areas if(object && object->deed.low.id && !object->deed.isArea(room->info.area)) player->printColor(" ^YCaution:^x this object's deed area does not match the room's area.\n"); if(object) { delete object; object = 0; } } player->print("\n"); player->print("Perm Monsters:\n"); for(it = room->permMonsters.begin(); it != room->permMonsters.end() ; it++) { crtm = &(*it).second; loadMonster((*it).second.cr, &monster); player->printColor("^m%2d) ^x%14s ^m::^x %-30s ^mInterval:^x %d ^yTime until Spawn:^x %-5d\n", (*it).first+1, crtm->cr.str("", 'm').c_str(), monster ? monster->getCName() : "", crtm->interval, tMAX<long>(0, crtm->ltime + crtm->interval-t)); if(monster) { free_crt(monster); monster = 0; } } player->print("\n"); if(room->track.getDirection() != "" && room->flagIsSet(R_PERMENANT_TRACKS)) player->print("Perm Tracks: %s.\n", room->track.getDirection().c_str()); if(room->getLowLevel() || room->getHighLevel()) { player->print("Level Boundary: "); if(room->getLowLevel()) player->print("%d+ level ", room->getLowLevel()); if(room->getHighLevel()) player->print("%d- level ", room->getHighLevel()); player->print("\n"); } if( room->flagIsSet(R_LOG_INTO_TRAP_ROOM) || room->flagIsSet(R_SHOP_STORAGE) || room->whatTraining() ) { if(room->getTrapExit().id) player->print("Players will relog into room %s from here.\n", room->getTrapExit().str(room->info.area).c_str()); else player->printColor("^rTrap exit needs to be set to %s room number.\n", room->flagIsSet(R_SHOP_STORAGE) ? "shop" : "relog"); } if( room->getSize() == NO_SIZE && ( room->flagIsSet(R_INDOORS) || room->flagIsSet(R_UNDERGROUND) ) ) player->printColor("^yThis room does not have a size set.\n"); checkTeleportRange(player, room->info); // isShopValid if(room->flagIsSet(R_SHOP)) { cr = shopStorageRoom(room); player->print("Shop storage room: %s (%s)\n", cr.str().c_str(), cr.id == room->info.id+1 && cr.isArea(room->info.area) ? "default" : "trapexit"); if(room->getFaction() == "" && room->info.area != "shop") player->printColor("^yThis shop does not have a faction set.\n"); loadRoom(cr, &shop); validateShop(player, room, shop); } else if(room->flagIsSet(R_PAWN_SHOP)) { if(room->getFaction() == "") player->printColor("^yThis pawn shop does not have a faction set.\n"); } if(room->flagIsSet(R_SHOP_STORAGE)) { loadRoom(room->getTrapExit(), &shop); validateShop(player, shop, room); } if(room->getTrap()) { if(room->getTrapWeight()) player->print("Trap weight: %d/%d lbs\n", room->getWeight(), room->getTrapWeight()); player->print("Trap type: "); switch(room->getTrap()) { case TRAP_PIT: player->print("Pit Trap (exit rm %s)\n", room->getTrapExit().str(room->info.area).c_str()); break; case TRAP_DART: player->print("Poison Dart Trap\n"); break; case TRAP_BLOCK: player->print("Falling Block Trap\n"); break; case TRAP_MPDAM: player->print("MP Damage Trap\n"); break; case TRAP_RMSPL: player->print("Negate Spell Trap\n"); break; case TRAP_NAKED: player->print("Naked Trap\n"); break; case TRAP_TPORT: player->print("Teleport Trap\n"); break; case TRAP_ARROW: player->print("Arrow Trap\n"); break; case TRAP_SPIKED_PIT: player->print("Spiked Pit Trap (exit rm %s)\n", room->getTrapExit().str(room->info.area).c_str()); break; case TRAP_WORD: player->print("Word of Recall Trap\n"); break; case TRAP_FIRE: player->print("Fire Trap\n"); break; case TRAP_FROST: player->print("Frost Trap\n"); break; case TRAP_ELEC: player->print("Electricity Trap\n"); break; case TRAP_ACID: player->print("Acid Trap\n"); break; case TRAP_ROCKS: player->print("Rockslide Trap\n"); break; case TRAP_ICE: player->print("Icicle Trap\n"); break; case TRAP_SPEAR: player->print("Spear Trap\n"); break; case TRAP_CROSSBOW: player->print("Crossbow Trap\n"); break; case TRAP_GASP: player->print("Poison Gas Trap\n"); break; case TRAP_GASB: player->print("Blinding Gas Trap\n"); break; case TRAP_GASS: player->print("Stun Gas Trap\n"); break; case TRAP_MUD: player->print("Mud Trap\n"); break; case TRAP_DISP: player->print("Room Displacement Trap (exit rm %s)\n", room->getTrapExit().str(room->info.area).c_str()); break; case TRAP_FALL: player->print("Deadly Fall Trap (exit rm %s)\n", room->getTrapExit().str(room->info.area).c_str()); break; case TRAP_CHUTE: player->print("Chute Trap (exit rm %s)\n", room->getTrapExit().str(room->info.area).c_str()); break; case TRAP_ALARM: player->print("Alarm Trap (guard rm %s)\n", room->getTrapExit().str(room->info.area).c_str()); break; case TRAP_BONEAV: player->print("Bone Avalanche Trap (exit rm %s)\n", room->getTrapExit().str(room->info.area).c_str()); break; case TRAP_PIERCER: player->print("Piercer trap (%d piercers)\n", room->getTrapStrength()); break; case TRAP_ETHEREAL_TRAVEL: player->print("Ethereal travel trap.\n"); break; case TRAP_WEB: player->print("Sticky spider web trap.\n"); break; default: player->print("Invalid trap #\n"); break; } } if(room->flagIsSet(R_CAN_SHOPLIFT)) player->print("Store guardroom: rm %s\n", cr.str(room->info.area).c_str()); showRoomFlags(player, room, 0, 0); if(room->effects.effectList.size()) player->printColor("Effects:\n%s", room->effects.getEffectsString(player).c_str()); player->printColor("%s", room->hooks.display().c_str()); stat_rom_exits(player, room); return(0); } //********************************************************************* // dmAddRoom //********************************************************************* // This function allows staff to add a new, empty room to the current // database of rooms. int dmAddRoom(Player* player, cmd* cmnd) { UniqueRoom *newRoom=0; char file[80]; int i=1; if(!strcmp(cmnd->str[1], "c") && (cmnd->num > 1)) { dmAddMob(player, cmnd); return(0); } if(!strcmp(cmnd->str[1], "o") && (cmnd->num > 1)) { dmAddObj(player, cmnd); return(0); } CatRef cr; bool extra = !strcmp(cmnd->str[1], "r"); getCatRef(getFullstrText(cmnd->fullstr, extra ? 2 : 1), &cr, player); if(cr.id < 1) { player->print("Index error: please specify room number.\n"); return(0); } if(!player->checkBuilder(cr, false)) { player->print("Error: Room number not inside any of your alotted ranges.\n"); return(0); } if(gConfig->moveRoomRestrictedArea(cr.area)) { player->print("Error: ""%s"" is a restricted range. You cannot create unique rooms in that area.\n"); return(0); } Path::checkDirExists(cr.area, roomPath); if(!strcmp(cmnd->str[extra ? 3 : 2], "loop")) i = MAX(1, MIN(100, cmnd->val[extra ? 3 : 2])); for(; i; i--) { if(!player->checkBuilder(cr, false)) { player->print("Error: Room number not inside any of your alotted ranges.\n"); return(0); } sprintf(file, "%s", roomPath(cr)); if(file_exists(file)) { player->print("Room already exists.\n"); return(0); } newRoom = new UniqueRoom; if(!newRoom) merror("dmAddRoom", FATAL); newRoom->info = cr; newRoom->setFlag(R_CONSTRUCTION); newRoom->setName("New Room"); if(newRoom->saveToFile(0) < 0) { player->print("Write failed.\n"); return(0); } delete newRoom; log_immort(true, player, "%s created room %s.\n", player->getCName(), cr.str().c_str()); player->print("Room %s created.\n", cr.str().c_str()); checkTeleportRange(player, cr); cr.id++; } return(0); } //********************************************************************* // dmSetRoom //********************************************************************* // This function allows staff to set a characteristic of a room. int dmSetRoom(Player* player, cmd* cmnd) { BaseRoom *room = player->getRoomParent(); int a=0, num=0; CatRef cr; if(cmnd->num < 3) { player->print("Syntax: *set r [option] [<value>]\n"); return(0); } if(!player->checkBuilder(player->getUniqueRoomParent())) { player->print("Error: Room number not inside any of your alotted ranges.\n"); return(0); } switch(low(cmnd->str[2][0])) { case 'b': if(!player->inUniqueRoom()) { player->print("Error: You need to be in a unique room to do that.\n"); return(0); } if(low(cmnd->str[2][1]) == 'l') { player->getUniqueRoomParent()->setLowLevel(cmnd->val[2]); player->print("Low level boundary %d\n", player->getUniqueRoomParent()->getLowLevel()); } else if(low(cmnd->str[2][1]) == 'h') { player->getUniqueRoomParent()->setHighLevel(cmnd->val[2]); player->print("Upper level boundary %d\n", player->getUniqueRoomParent()->getHighLevel()); } break; case 'd': if(!player->inAreaRoom()) { player->print("Error: You need to be in an area room to do that.\n"); return(0); } if(!player->getAreaRoomParent()->unique.id) { player->print("Error: The area room must have the unique field set [*set r unique #].\n"); return(0); } player->getAreaRoomParent()->setDecCompass(!player->getAreaRoomParent()->getDecCompass()); player->printColor("DecCompass toggled, set to %s^x.\n", player->getAreaRoomParent()->getDecCompass() ? "^gYes" : "^rNo"); log_immort(true, player, "%s set decCompass to %s in room %s.\n", player->getCName(), player->getAreaRoomParent()->getDecCompass() ? "true" : "false", room->fullName().c_str()); break; case 'e': if(cmnd->str[2][1] == 'f') { if(cmnd->num < 4) { player->print("Set what effect to what?\n"); return(0); } long duration = -1; int strength = 1; bstring txt = getFullstrText(cmnd->fullstr, 4); if(txt != "") duration = atoi(txt.c_str()); txt = getFullstrText(cmnd->fullstr, 5); 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[3]; EffectInfo* toSet = 0; if((toSet = room->getExactEffect(effectStr))) { // We have an existing effect we're modifying if(duration == 0) { // Duration is 0, so remove it room->removeEffect(toSet, true); player->print("Effect '%s' (room) removed.\n", effectStr.c_str()); } else { // Otherwise modify as appropriate toSet->setDuration(duration); if(strength != -1) toSet->setStrength(strength); player->print("Effect '%s' (room) set to duration %d and strength %d.\n", effectStr.c_str(), toSet->getDuration(), toSet->getStrength()); } break; } else { // No existing effect, add a new one if(strength == -1) strength = 1; if(room->addEffect(effectStr, duration, strength, 0, true) != NULL){ player->print("Effect '%s' (room) added with duration %d and strength %d.\n", effectStr.c_str(), duration, strength); } else { player->print("Unable to add effect '%s' (room)\n", effectStr.c_str()); } break; } } else if(cmnd->str[2][1] == 'x') { if(!player->inUniqueRoom()) { player->print("Error: You need to be in a unique room to do that.\n"); return(0); } player->getUniqueRoomParent()->setRoomExperience(cmnd->val[2]); player->print("Room experience set to %d.\n", player->getUniqueRoomParent()->getRoomExperience()); log_immort(true, player, "%s set roomExp to %d in room %s.\n", player->getCName(), player->getUniqueRoomParent()->getRoomExperience(), room->fullName().c_str()); } else { player->print("Invalid option.\n"); return(0); } break; case 'f': if(low(cmnd->str[2][1]) == 'i') { if(!strcmp(cmnd->str[3], "")) { player->getUniqueRoomParent()->setFishing(""); player->print("Fishing list cleared.\n"); log_immort(true, player, "%s cleared fishing list in room %s.\n", player->getCName(), room->fullName().c_str()); } else { const Fishing* list = gConfig->getFishing(cmnd->str[3]); if(!list) { player->print("Fishing list \"%s\" does not exist!\n", cmnd->str[3]); return(0); } player->getUniqueRoomParent()->setFishing(cmnd->str[3]); player->print("Fishing list set to %s.\n", player->getUniqueRoomParent()->getFishingStr().c_str()); log_immort(true, player, "%s set fishing list to %s in room %s.\n", player->getCName(), player->getUniqueRoomParent()->getFishingStr().c_str(), room->fullName().c_str()); } } else if(low(cmnd->str[2][1]) == 'a') { if(!player->inUniqueRoom()) { player->print("Error: You need to be in a unique room to do that.\n"); return(0); } if(cmnd->num < 3) { player->print("Set faction to what?\n"); return(0); } else if(cmnd->num == 3) { player->getUniqueRoomParent()->setFaction(""); player->print("Faction cleared.\n"); log_immort(true, player, "%s cleared faction in room %s.\n", player->getCName(), room->fullName().c_str()); return(0); } Property* p = gConfig->getProperty(player->getUniqueRoomParent()->info); if(p && p->getType() == PROP_SHOP) { player->print("You can't set room faction on player shops!\n"); return(0); } const Faction* faction = gConfig->getFaction(cmnd->str[3]); if(!faction) { player->print("'%s' is an invalid faction.\n", cmnd->str[3]); return(0); } player->getUniqueRoomParent()->setFaction(faction->getName()); player->print("Faction set to %s.\n", player->getUniqueRoomParent()->getFaction().c_str()); log_immort(true, player, "%s set faction to %s in room %s.\n", player->getCName(), player->getUniqueRoomParent()->getFaction().c_str(), room->fullName().c_str()); break; } else { if(!player->inUniqueRoom()) { player->print("Error: You need to be in a unique room to do that.\n"); return(0); } num = cmnd->val[2]; if(num < 1 || num > MAX_ROOM_FLAGS) { player->print("Error: outside of range.\n"); return(0); } if(!player->isCt() && num == R_CONSTRUCTION+1) { player->print("Error: you cannot set/clear that flag.\n"); return(0); } if(!strcmp(cmnd->str[3], "del")) { for(a=0;a<MAX_ROOM_FLAGS;a++) player->getUniqueRoomParent()->clearFlag(a); player->print("All room flags cleared.\n"); log_immort(true, player, "%s cleared all flags in room %s.\n", player->getCName(), room->fullName().c_str()); break; } if(player->getUniqueRoomParent()->flagIsSet(num - 1)) { player->getUniqueRoomParent()->clearFlag(num - 1); player->print("Room flag #%d(%s) off.\n", num, get_rflag(num-1)); log_immort(true, player, "%s cleared flag #%d(%s) in room %s.\n", player->getCName(), num, get_rflag(num-1), room->fullName().c_str()); } else { if(num >= R_TRAINING_ROOM && num - 4 <= R_TRAINING_ROOM) { // setting a training flag - do we let them? if(!player->getUniqueRoomParent()->whatTraining(num-1)) { player->print("You are setting training for a class that does not exist.\n"); return(0); } } player->getUniqueRoomParent()->setFlag(num - 1); player->print("Room flag #%d(%s) on.\n", num, get_rflag(num-1)); log_immort(true, player, "%s set flag #%d(%s) in room %s.\n", player->getCName(), num, get_rflag(num-1), room->fullName().c_str()); if(num-1 == R_SHOP) player->printColor("^YNote:^x you must set the Shop Storage (97) to use this room as a shop.\n"); if((num-1 == R_INDOORS || num-1 == R_VAMPIRE_COVEN || num-1 == R_UNDERGROUND) && player->getUniqueRoomParent()->getSize() == NO_SIZE) player->printColor("^YNote:^x don't forget to set the size for this room.\n"); } // try and be smart if( num-1 == R_SHOP_STORAGE && player->getUniqueRoomParent()->getName() == "New Room" && player->getUniqueRoomParent()->exits.empty()) { cr = player->getUniqueRoomParent()->info; UniqueRoom* shop=0; bstring storageName = "Storage: "; cr.id--; if(loadRoom(cr, &shop)) { if( shop->flagIsSet(R_SHOP) && (!shop->getTrapExit().id || shop->getTrapExit() == cr) ) { player->printColor("^ySetting up this storage room for you...\n"); player->printColor("^y * ^xSetting the trap exit to %s...\n", cr.str().c_str()); player->getUniqueRoomParent()->setTrapExit(cr); player->printColor("^y * ^xCreating exit ""out"" to %s...\n", cr.str().c_str()); link_rom(player->getUniqueRoomParent(), cr, "out"); player->getUniqueRoomParent()->setTrapExit(cr); player->printColor("^y * ^xNaming this room...\n"); storageName += shop->getName(); player->getUniqueRoomParent()->setName(storageName); player->print("Done!\n"); } } } } break; case 'l': if(!player->inUniqueRoom()) { player->print("Error: You need to be in a unique room to do that.\n"); return(0); } if(strcmp(cmnd->str[3], "clear")) { player->print("Are you sure?\nType \"*set r last clear\" to clear last-arrived info.\n"); return(0); } strcpy(player->getUniqueRoomParent()->lastPly, ""); strcpy(player->getUniqueRoomParent()->lastPlyTime, ""); player->print("Last-arrived info cleared.\n"); break; case 'm': if(!player->inUniqueRoom()) { player->print("Error: You need to be in a unique room to do that.\n"); return(0); } player->getUniqueRoomParent()->setMaxMobs(cmnd->val[2]); if(!player->getUniqueRoomParent()->getMaxMobs()) player->print("The limit on the number of creatures that can be here has been removed.\n"); else player->print("Only %d creature%s can now be in here at a time.\n", player->getUniqueRoomParent()->getMaxMobs(), player->getUniqueRoomParent()->getMaxMobs() != 1 ? "s" : ""); log_immort(true, player, "%s set max %d mobs in room %s.\n", player->getCName(), player->getUniqueRoomParent()->getMaxMobs(), room->fullName().c_str()); break; case 'n': if(!player->inAreaRoom()) { player->print("Error: You need to be in an area room to do that.\n"); return(0); } if(!player->getAreaRoomParent()->unique.id) { player->print("Error: The area room must have the unique field set [*set r unique #].\n"); return(0); } player->getAreaRoomParent()->setNeedsCompass(!player->getAreaRoomParent()->getNeedsCompass()); player->printColor("NeedsCompass toggled, set to %s^x.\n", player->getAreaRoomParent()->getNeedsCompass() ? "^gYes" : "^rNo"); log_immort(true, player, "%s set needsCompass to %s in room %s.\n", player->getCName(), player->getAreaRoomParent()->getNeedsCompass() ? "true" : "false", room->fullName().c_str()); break; case 'r': if(!player->inUniqueRoom()) { player->print("Error: You need to be in a unique room to do that.\n"); return(0); } num = atoi(&cmnd->str[2][1]); if(num < 1 || num > NUM_RANDOM_SLOTS) { player->print("Error: outside of range.\n"); return(PROMPT); } getCatRef(getFullstrText(cmnd->fullstr, 3), &cr, player); if(!cr.id) { player->getUniqueRoomParent()->wander.random.erase(num-1); player->print("Random #%d has been cleared.\n", num); } else { player->getUniqueRoomParent()->wander.random[num-1] = cr; player->print("Random #%d is now %s.\n", num, cr.str().c_str()); } log_immort(false,player, "%s set mob slot %d to mob %s in room %s.\n", player->getCName(), num, cr.str().c_str(), room->fullName().c_str()); break; case 's': if(!player->inUniqueRoom()) { player->print("Error: You need to be in a unique room to do that.\n"); return(0); } player->getUniqueRoomParent()->setSize(getSize(cmnd->str[3])); player->print("Size set to %s.\n", getSizeName(player->getUniqueRoomParent()->getSize()).c_str()); log_immort(true, player, "%s set room %s's %s to %s.\n", player->getCName(), room->fullName().c_str(), "Size", getSizeName(player->getUniqueRoomParent()->getSize()).c_str()); break; case 't': if(!player->inUniqueRoom()) { player->print("Error: You need to be in a unique room to do that.\n"); return(0); } player->getUniqueRoomParent()->wander.setTraffic(cmnd->val[2]); log_immort(true, player, "%s set room %s's traffic to %ld.\n", player->getCName(), player->getUniqueRoomParent()->info.str().c_str(), player->getUniqueRoomParent()->wander.getTraffic()); player->print("Traffic is now %d%%.\n", player->getUniqueRoomParent()->wander.getTraffic()); break; case 'x': if(!player->inUniqueRoom()) { player->print("Error: You need to be in a unique room to do that.\n"); return(0); } if(low(cmnd->str[2][1]) == 'x') { getCatRef(getFullstrText(cmnd->fullstr, 3), &cr, player); if(!player->checkBuilder(cr)) { player->print("Trap's exit must be within an assigned range.\n"); return(0); } player->getUniqueRoomParent()->setTrapExit(cr); player->print("Room's trap exit is now %s.\n", player->getUniqueRoomParent()->getTrapExit().str().c_str()); log_immort(true, player, "%s set trapexit to %s in room %s.\n", player->getCName(), player->getUniqueRoomParent()->getTrapExit().str().c_str(), room->fullName().c_str()); } else if(low(cmnd->str[2][1]) == 'w') { num = (int)cmnd->val[2]; if(num < 0 || num > 5000) { player->print("Trap weight cannot be less than 0 or greater than 5000.\n"); return(0); } player->getUniqueRoomParent()->setTrapWeight(num); player->print("Room's trap weight is now %d.\n", player->getUniqueRoomParent()->getTrapWeight()); log_immort(true, player, "%s set trapweight to %d in room %s.\n", player->getCName(), player->getUniqueRoomParent()->getTrapWeight(), room->fullName().c_str()); } else if(low(cmnd->str[2][1]) == 's') { num = (int)cmnd->val[2]; if(num < 0 || num > 5000) { player->print("Trap strength cannot be less than 0 or greater than 5000.\n"); return(0); } player->getUniqueRoomParent()->setTrapStrength(num); player->print("Room's trap strength is now %d.\n", player->getUniqueRoomParent()->getTrapStrength()); log_immort(true, player, "%s set trapstrength to %d in room %s.\n", player->getCName(), player->getUniqueRoomParent()->getTrapStrength(), room->fullName().c_str()); } else { player->getUniqueRoomParent()->setTrap(cmnd->val[2]); player->print("Room has trap #%d set.\n", player->getUniqueRoomParent()->getTrap()); log_immort(true, player, "%s set trap #%d in room %s.\n", player->getCName(), player->getUniqueRoomParent()->getTrap(), room->fullName().c_str()); } break; case 'u': if(!player->inAreaRoom()) { player->print("Error: You need to be in an area room to do that.\n"); return(0); } getCatRef(getFullstrText(cmnd->fullstr, 3), &cr, player); player->getAreaRoomParent()->unique = cr; player->print("Unique room set to %s.\n", player->getAreaRoomParent()->unique.str().c_str()); if(player->getAreaRoomParent()->unique.id) player->print("You'll need to use *teleport to get to this room in the future.\n"); log_immort(true, player, "%s set unique room to %s in room %s.\n", player->getCName(), player->getAreaRoomParent()->unique.str().c_str(), room->fullName().c_str()); break; default: player->print("Invalid option.\n"); return(0); } if(player->inUniqueRoom()) player->getUniqueRoomParent()->escapeText(); room_track(player); return(0); } //********************************************************************* // dmSetExit //********************************************************************* // This function allows staff to set a characteristic of an exit. int dmSetExit(Player* player, cmd* cmnd) { BaseRoom* room = player->getRoomParent(); int num=0; //char orig_exit[30]; short n=0; if(!player->checkBuilder(player->getUniqueRoomParent())) { player->print("Error: Room number not inside any of your alotted ranges.\n"); return(0); } // setting something on the exit if(cmnd->str[1][1]) { if(cmnd->num < 3) { player->print("Invalid syntax.\n"); return(0); } Exit* exit = findExit(player, cmnd->str[2], 1); if(!exit) { player->print("Exit not found.\n"); return(0); } switch(cmnd->str[1][1]) { case 'd': { if(cmnd->str[1][2] == 'i') { Direction dir = getDir(cmnd->str[3]); if(getDir(exit->getName()) != NoDirection && dir != NoDirection) { player->print("This exit does not need a direction set on it.\n"); return(0); } exit->setDirection(dir); player->printColor("%s^x's %s set to %s.\n", exit->getCName(), "Direction", getDirName(exit->getDirection()).c_str()); log_immort(true, player, "%s set %s %s^g's %s to %s.\n", player->getCName(), "exit", exit->getCName(), "Direction", getDirName(exit->getDirection()).c_str()); } else if(cmnd->str[1][2] == 'e') { bstring desc = getFullstrText(cmnd->fullstr, 3); desc.Replace("*CR*", "\n"); exit->setDescription(desc); if(exit->getDescription() == "") { player->print("Description cleared.\n"); log_immort(true, player, "%s cleared %s^g's %s.\n", player->getCName(), exit->getCName(), "Description"); } else { player->print("Description set to \"%s\".\n", exit->getDescription().c_str()); log_immort(true, player, "%s set %s^g's %s to \"%s\".\n", player->getCName(), exit->getCName(), "Description", exit->getDescription().c_str()); } } else { player->print("Description or direction?\n"); return(0); } break; } case 'e': if(cmnd->str[1][2] == 'f') { if(cmnd->num < 4) { player->print("Set what effect to what?\n"); return(0); } long duration = -1; int strength = 1; bstring txt = getFullstrText(cmnd->fullstr, 4); if(txt != "") duration = atoi(txt.c_str()); txt = getFullstrText(cmnd->fullstr, 5); 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[3]; EffectInfo* toSet = 0; if((toSet = exit->getExactEffect(effectStr))) { // We have an existing effect we're modifying if(duration == 0) { // Duration is 0, so remove it exit->removeEffect(toSet, true); player->print("Effect '%s' (exit) removed.\n", effectStr.c_str()); } else { // Otherwise modify as appropriate toSet->setDuration(duration); if(strength != -1) toSet->setStrength(strength); player->print("Effect '%s' (exit) set to duration %d and strength %d.\n", effectStr.c_str(), toSet->getDuration(), toSet->getStrength()); } } else { // No existing effect, add a new one if(strength == -1) strength = 1; if(exit->addEffect(effectStr, duration, strength, 0, true) != NULL) { player->print("Effect '%s' (exit) added with duration %d and strength %d.\n", effectStr.c_str(), duration, strength); } else { player->print("Unable to add effect '%s' (exit)\n", effectStr.c_str()); } } break; } else { exit->setEnter(getFullstrText(cmnd->fullstr, 3)); if(exit->getEnter() == "" || Pueblo::is(exit->getEnter())) { exit->setEnter(""); player->print("OnEnter cleared.\n"); log_immort(true, player, "%s cleared %s^g's %s.\n", player->getCName(), exit->getCName(), "OnEnter"); } else { player->print("OnEnter set to \"%s\".\n", exit->getEnter().c_str()); log_immort(true, player, "%s set %s^g's %s to \"%s\".\n", player->getCName(), exit->getCName(), "OnEnter", exit->getEnter().c_str()); } } break; case 'f': num = cmnd->val[2]; if(num < 1 || num > MAX_EXIT_FLAGS) { player->print("Error: flag out of range.\n"); return(PROMPT); } if(exit->flagIsSet(num - 1)) { exit->clearFlag(num - 1); player->printColor("%s^x exit flag #%d off.\n", exit->getCName(), num); log_immort(true, player, "%s cleared %s^g exit flag #%d(%s) in room %s.\n", player->getCName(), exit->getCName(), num, get_xflag(num-1), room->fullName().c_str()); } else { exit->setFlag(num - 1); player->printColor("%s^x exit flag #%d on.\n", exit->getCName(), num); log_immort(true, player, "%s turned on %s^g exit flag #%d(%s) in room %s.\n", player->getCName(), exit->getCName(), num, get_xflag(num-1), room->fullName().c_str()); } break; case 'k': if(cmnd->str[1][2] == 'a') { exit->setKeyArea(cmnd->str[3]); if(exit->getKeyArea() == "") { player->print("Key Area cleared.\n"); log_immort(true, player, "%s cleared %s^g's %s.\n", player->getCName(), exit->getCName(), "Key Area"); } else { player->print("Key Area set to \"%s\".\n", exit->getKeyArea().c_str()); log_immort(true, player, "%s set %s^g's %s to \"%s\".\n", player->getCName(), exit->getCName(), "Key Area", exit->getKeyArea().c_str()); } } else { if(cmnd->val[2] > 255 || cmnd->val[2] < 0) { player->print("Error: key out of range.\n"); return(0); } exit->setKey(cmnd->val[2]); player->printColor("Exit %s^x key set to %d.\n", exit->getCName(), exit->getKey()); log_immort(true, player, "%s set %s^g's %s to %ld.\n", player->getCName(), exit->getCName(), "Key", exit->getKey()); } break; case 'l': if(cmnd->val[2] > MAXALVL || cmnd->val[2] < 0) { player->print("Level must be from 0 to %d.\n", MAXALVL); return(0); } exit->setLevel(cmnd->val[2]); player->printColor("Exit %s^x's level is now set to %d.\n", exit->getCName(), exit->getLevel()); log_immort(true, player, "%s set %s^g's %s to %ld.\n", player->getCName(), exit->getCName(), "Pick Level", exit->getLevel()); break; case 'o': exit->setOpen(getFullstrText(cmnd->fullstr, 3)); if(exit->getOpen() == "" || Pueblo::is(exit->getOpen())) { exit->setOpen(""); player->print("OnOpen cleared.\n"); log_immort(true, player, "%s cleared %s^g's %s.\n", player->getCName(), exit->getCName(), "OnOpen"); } else { player->print("OnOpen set to \"%s\".\n", exit->getOpen().c_str()); log_immort(true, player, "%s set %s^g's %s to \"%s\".\n", player->getCName(), exit->getCName(), "OnOpen", exit->getOpen().c_str()); } break; case 'p': if(low(cmnd->str[1][2]) == 'p') { exit->setPassPhrase(getFullstrText(cmnd->fullstr, 3)); if(exit->getPassPhrase() == "") { player->print("Passphrase cleared.\n"); log_immort(true, player, "%s cleared %s^g's %s.\n", player->getCName(), exit->getCName(), "Passphrase"); } else { player->print("Passphrase set to \"%s\".\n", exit->getPassPhrase().c_str()); log_immort(true, player, "%s set %s^g's %s to \"%s\".\n", player->getCName(), exit->getCName(), "Passphrase", exit->getPassPhrase().c_str()); } } else if(low(cmnd->str[1][2]) == 'l') { n = cmnd->val[2]; if(n < 0 || n > LANGUAGE_COUNT) { player->print("Error: pass language out of range.\n"); return(0); } n--; if(n < 0) n = 0; exit->setPassLanguage(n); player->print("Pass language %s.\n", n ? "set" : "cleared"); log_immort(true, player, "%s set %s^g's %s to %s(%ld).\n", player->getCName(), exit->getCName(), "Passlang", n ? get_language_adj(n) : "Nothing", n+1); } else { player->print("Passphrase (xpp) or passlang (xpl)?\n"); return(0); } break; case 's': exit->setSize(getSize(cmnd->str[3])); player->printColor("%s^x's %s set to %s.\n", exit->getCName(), "Size", getSizeName(exit->getSize()).c_str()); log_immort(true, player, "%s set %s %s^g's %s to %s.\n", player->getCName(), "exit", exit->getCName(), "Size", getSizeName(exit->getSize()).c_str()); break; case 't': n = (short)cmnd->val[2]; if(n > 30000 || n < 0) { player->print("Must be between 0-30000.\n"); return(0); } exit->setToll(n); player->printColor("Exit %s^x's toll is now set to %d.\n", exit->getCName(), exit->getToll()); log_immort(true, player, "%s set %s^g's %s to %ld.\n", player->getCName(), exit->getCName(), "Toll", exit->getToll()); break; default: player->print("Invalid syntax.\n"); return(0); } if(player->inUniqueRoom()) player->getUniqueRoomParent()->escapeText(); room_track(player); return(0); } // otherwise, we have other plans for this function if(cmnd->num < 3) { player->print("Syntax: *set x <name> <#> [. or name]\n"); return(0); } // we need more variables to continue our work MapMarker mapmarker; BaseRoom* room2=0; AreaRoom* aRoom=0; UniqueRoom *uRoom=0; Area *area=0; CatRef cr; bstring returnExit = getFullstrText(cmnd->fullstr, 4); getDestination(getFullstrText(cmnd->fullstr, 3).c_str(), &mapmarker, &cr, player); if(!mapmarker.getArea() && !cr.id) { // if the expanded exit wasnt found // and the exit was expanded, check to delete the original if(room->delExit(cmnd->str[2])) player->print("Exit %s deleted.\n", cmnd->str[2]); else player->print("Exit %s not found.\n", cmnd->str[2]); return(0); } if(cr.id) { if(!player->checkBuilder(cr)) return(0); if(!loadRoom(cr, &uRoom)) { player->print("Room %s does not exist.\n", cr.str().c_str()); return(0); } room2 = uRoom; } else { if(player->getClass() == BUILDER) { player->print("Sorry, builders cannot link exits to the overland.\n"); return(0); } area = gConfig->getArea(mapmarker.getArea()); if(!area) { player->print("Area does not exist.\n"); return(0); } aRoom = area->loadRoom(0, &mapmarker, false); room2 = aRoom; } bstring newName = getFullstrText(cmnd->fullstr, 2, ' ', false, true); if(newName.getLength() > 20) { player->print("Exit names must be 20 characters or less in length.\n"); return(0); } newName = expand_exit_name(newName); if(returnExit != "") { if(returnExit == ".") returnExit = opposite_exit_name(newName); if(cr.id) { link_rom(room, cr, newName); if(player->inUniqueRoom()) link_rom(uRoom, player->getUniqueRoomParent()->info, returnExit); else link_rom(uRoom, &player->getAreaRoomParent()->mapmarker, returnExit); gConfig->resaveRoom(cr); } else { link_rom(room, &mapmarker, newName); if(player->inUniqueRoom()) link_rom(aRoom, player->getUniqueRoomParent()->info, returnExit); else link_rom(aRoom, &player->getAreaRoomParent()->mapmarker, returnExit); aRoom->save(); } log_immort(true, player, "%s linked room %s to room %s in %s^g direction, both ways.\n", player->getCName(), room->fullName().c_str(), room2->fullName().c_str(), newName.c_str()); player->printColor("Room %s linked to room %s in %s^x direction, both ways.\n", room->fullName().c_str(), room2->fullName().c_str(), newName.c_str()); } else { if(cr.id) link_rom(room, cr, newName); else link_rom(room, &mapmarker, newName); player->printColor("Room %s linked to room %s in %s^x direction.\n", room->fullName().c_str(), room2->fullName().c_str(), newName.c_str()); log_immort(true, player, "%s linked room %s to room %s in %s^g direction.\n", player->getCName(), room->fullName().c_str(), room2->fullName().c_str(), newName.c_str()); } if(player->inUniqueRoom()) gConfig->resaveRoom(player->getUniqueRoomParent()->info); if(aRoom && aRoom->canDelete()) area->remove(aRoom); room_track(player); return(0); } //********************************************************************* // room_track //********************************************************************* int room_track(Creature* player) { long t = time(0); if(player->isMonster() || !player->inUniqueRoom()) return(0); strcpy(player->getUniqueRoomParent()->last_mod, player->getCName()); strcpy(player->getUniqueRoomParent()->lastModTime, ctime(&t)); return(0); } //********************************************************************* // dmReplace //********************************************************************* // this command lets staff replace words or phrases in a room description int dmReplace(Player* player, cmd* cmnd) { UniqueRoom *room = player->getUniqueRoomParent(); int n=0, skip=0, skPos=0; bstring::size_type i=0, pos=0; char delim = ' '; bool sdesc=false, ldesc=false; bstring search = "", temp = ""; if(!needUniqueRoom(player)) return(0); if(!player->checkBuilder(player->getUniqueRoomParent())) { player->print("Room is not in any of your alotted room ranges.\n"); return(0); } if(cmnd->num < 3) { player->print("syntax: *replace [-SL#<num>] <search> <replace>\n"); return(0); } // we have flags! // let's find out what they are if(cmnd->str[1][0] == '-') { i=1; while(i < strlen(cmnd->str[1])) { switch(cmnd->str[1][i]) { case 'l': ldesc = true; break; case 's': sdesc = true; break; case '#': skip = atoi(&cmnd->str[1][++i]); break; default: break; } i++; } } // we need to get fullstr into a nicer format i = strlen(cmnd->str[0]); if(ldesc || sdesc || skip) i += strlen(cmnd->str[1]) + 1; // which deliminator should we use? if(cmnd->fullstr[i+1] == '\'' || cmnd->fullstr[i+1] == '"' || cmnd->fullstr[i+1] == '*') { delim = cmnd->fullstr[i+1]; i++; } // fullstr is now our search text and replace text seperated by a space cmnd->fullstr = cmnd->fullstr.substr(i+1); //strcpy(cmnd->fullstr, &cmnd->fullstr[i+1]); // we search until we find the deliminator we're looking for pos=0; i = cmnd->fullstr.length(); while(pos < i) { if(cmnd->fullstr[pos] == delim) break; pos++; } if(pos == i) { if(delim != ' ') player->print("Deliminator not found.\n"); else player->print("No replace text found.\n"); return(0); } // cut the string apart cmnd->fullstr[pos] = 0; search = cmnd->fullstr; // if it's not a space, we need to add 2 to get rid of the space and // next deliminator if(delim != ' ') { pos += 2; // although we don't have to, we're enforcing that the deliminators // equal each other so people are consistent with the usage of this function if(cmnd->fullstr[pos] != delim) { player->print("Deliminators do not match up.\n"); return(0); } } // fullstr now has our replace text //strcpy(cmnd->fullstr, &cmnd->fullstr[pos+1]); cmnd->fullstr = cmnd->fullstr.substr(pos+1); if(delim != ' ') { if(cmnd->fullstr[cmnd->fullstr.length()-1] != delim) { player->print("Deliminators do not match up.\n"); return(0); } cmnd->fullstr[cmnd->fullstr.length()-1] = 0; } // the text we are searching for is in "search" // the text we are replacing it with is in "fullstr" // we will use i to help us reuse code // 0 = sdesc, 1 = ldesc i = 0; // if only long desc, skip short desc if(ldesc && !sdesc) i++; // loop for the short and long desc do { // loop for skip do { if(!i) n = room->getShortDescription().find(search.c_str(), skPos); else n = room->getLongDescription().find(search.c_str(), skPos); if(n >= 0) { if(--skip > 0) skPos = n + 1; else { if(!i) { temp = room->getShortDescription().substr(0, n); temp += cmnd->fullstr; temp += room->getShortDescription().substr(n + search.length(), room->getShortDescription().length()); room->setShortDescription(temp); } else { temp = room->getLongDescription().substr(0, n); temp += cmnd->fullstr; temp += room->getLongDescription().substr(n + search.length(), room->getLongDescription().length()); room->setLongDescription(temp); } player->print("Replaced.\n"); room->escapeText(); return(0); } } } while(n >= 0 && skip); // if we're on long desc (i=1), we'll stop after this, so no worries // if we're on short desc and not doing long desc, we need to stop if(sdesc && !ldesc) i++; i++; } while(i<2); player->print("Pattern not found.\n"); return(0); } //********************************************************************* // dmDelete //********************************************************************* // Allows staff to delete some/all of the room description int dmDelete(Player* player, cmd* cmnd) { UniqueRoom *room = player->getUniqueRoomParent(); int pos=0; int unsigned i=0; bool sdesc=false, ldesc=false, phrase=false, after=false; if(!needUniqueRoom(player)) return(0); if(!player->checkBuilder(player->getUniqueRoomParent())) { player->print("Room is not in any of your alotted room ranges.\n"); return(0); } if(cmnd->num < 2) { player->print("syntax: *delete [-ASLPE] <delete_word>\n"); return(0); } // take care of the easy one if(!strcmp(cmnd->str[1], "-a")) { room->setShortDescription(""); room->setLongDescription(""); } else { // determine our flags i=1; while(i < strlen(cmnd->str[1])) { switch(cmnd->str[1][i]) { case 'l': ldesc = true; break; case 's': sdesc = true; break; case 'p': phrase = true; break; case 'e': after = true; break; default: break; } i++; } // a simple delete operation if(!phrase && !after) { if(sdesc) room->setShortDescription(""); if(ldesc) room->setLongDescription(""); if(!sdesc && !ldesc) { player->print("Invalid syntax.\n"); return(0); } } else { // we need to figure out what our phrase is // turn fullstr into what we want to delete i = strlen(cmnd->str[0]) + strlen(cmnd->str[1]) + 1; // fullstr is now our phrase cmnd->fullstr = cmnd->fullstr.substr(i+1); //strcpy(cmnd->fullstr, &cmnd->fullstr[i+1]); // we will use i to help us reuse code // 0 = sdesc, 1 = ldesc i = 0; // if only long desc, skip short desc if(ldesc && !sdesc) i++; // loop! do { if(!i) pos = room->getShortDescription().find(cmnd->fullstr); else pos = room->getLongDescription().find(cmnd->fullstr); if(pos >= 0) break; // if we're on long desc (i=1), we'll stop after this, so no worries // if we're on short desc and not doing long desc, we need to stop if(sdesc && !ldesc) i++; i++; } while(i<2); // did we find it? if(pos < 0) { player->print("Pattern not found.\n"); return(0); } // we delete everything after the phrase if(after) { if(!phrase) pos += cmnd->fullstr.length(); // if it's in the short desc, and they wanted to delete // from both short and long, then delete all of long if(!i && !(sdesc ^ ldesc)) room->setLongDescription(""); if(!i) room->setShortDescription(room->getShortDescription().substr(0, pos)); else room->setLongDescription(room->getLongDescription().substr(0, pos)); // only delete the phrase } else { if(!i) room->setShortDescription(room->getShortDescription().substr(0, pos) + room->getShortDescription().substr(pos + cmnd->fullstr.length(), room->getShortDescription().length())); else room->setLongDescription(room->getLongDescription().substr(0, pos) + room->getLongDescription().substr(pos + cmnd->fullstr.length(), room->getLongDescription().length())); } } // phrase && after } // *del -A log_immort(true, player, "%s deleted description in room %s.\n", player->getCName(), player->getUniqueRoomParent()->info.str().c_str()); player->print("Deleted.\n"); return(0); } //********************************************************************* // dmNameRoom //********************************************************************* int dmNameRoom(Player* player, cmd* cmnd) { if(!needUniqueRoom(player)) return(0); if(!player->checkBuilder(player->getUniqueRoomParent())) { player->print("Room is not in any of your alotted room ranges.\n"); return(0); } bstring name = getFullstrText(cmnd->fullstr, 1); if(name == "" || Pueblo::is(name)) { player->print("Rename room to what?\n"); return(0); } if(name.getLength() > 79) name = name.left(79); player->getUniqueRoomParent()->setName(name); log_immort(true, player, "%s renamed room %s.\n", player->getCName(), player->getRoomParent()->fullName().c_str()); player->print("Done.\n"); return(0); } //********************************************************************* // dmDescription //********************************************************************* // Allows a staff to add the given text to the room description. int dmDescription(Player* player, cmd* cmnd, bool append) { UniqueRoom *room = player->getUniqueRoomParent(); int unsigned i=0; bool sdesc=false, newline=false; if(!needUniqueRoom(player)) return(0); if(!player->checkBuilder(player->getUniqueRoomParent())) { player->print("Room is not in any of your alotted room ranges.\n"); return(0); } if(cmnd->num < 2) { player->print("syntax: *%s [-sn] <text>\n", append ? "append" : "prepend"); return(0); } // turn fullstr into what we want to append i = strlen(cmnd->str[0]); sdesc = cmnd->str[1][0] == '-' && (cmnd->str[1][1] == 's' || cmnd->str[1][2] == 's'); newline = !(cmnd->str[1][0] == '-' && (cmnd->str[1][1] == 'n' || cmnd->str[1][2] == 'n')); // keep chopping if(sdesc || !newline) i += strlen(cmnd->str[1]) + 1; cmnd->fullstr = cmnd->fullstr.substr(i+1); // strcpy(cmnd->fullstr, &cmnd->fullstr[i+1]); if(cmnd->fullstr.find(" ") != cmnd->fullstr.npos) player->printColor("Do not use double spaces in room descriptions! Use ^W*wrap^x to fix this.\n"); if(sdesc) { // short descriptions newline = newline && room->getShortDescription() != ""; if(append) { room->appendShortDescription(newline ? "\n" : ""); room->appendShortDescription(cmnd->fullstr); } else { if(newline) cmnd->fullstr += "\n"; room->setShortDescription(cmnd->fullstr + room->getShortDescription()); } player->print("Short description %s.\n", append ? "appended" : "prepended"); } else { // long descriptions newline = newline && room->getLongDescription() != ""; if(append) { room->appendLongDescription(newline ? "\n" : ""); room->appendLongDescription(cmnd->fullstr); } else { if(newline) cmnd->fullstr += "\n"; room->setLongDescription(cmnd->fullstr + room->getLongDescription()); } player->print("Long description %s.\n", append ? "appended" : "prepended"); } player->getUniqueRoomParent()->escapeText(); log_immort(true, player, "%s descripted in room %s.\n", player->getCName(), player->getUniqueRoomParent()->info.str().c_str()); return(0); } //********************************************************************* // dmAppend //********************************************************************* int dmAppend(Player* player, cmd* cmnd) { return(dmDescription(player, cmnd, true)); } //********************************************************************* // dmPrepend //********************************************************************* int dmPrepend(Player* player, cmd* cmnd) { return(dmDescription(player, cmnd, false)); } //********************************************************************* // dmMobList //********************************************************************* // Display information about what mobs will randomly spawn. void showMobList(Player* player, WanderInfo *wander, bstring type) { std::map<int, CatRef>::iterator it; Monster *monster=0; bool found=false, maybeAggro=false; std::ostringstream oStr; for(it = wander->random.begin(); it != wander->random.end() ; it++) { if(!found) oStr << "^cTraffic = " << wander->getTraffic() << "\n"; found=true; if(!(*it).second.id) continue; if(!loadMonster((*it).second, &monster)) continue; if(monster->flagIsSet(M_AGGRESSIVE)) oStr << "^r"; else { maybeAggro = monster->flagIsSet(M_AGGRESSIVE_EVIL) || monster->flagIsSet(M_AGGRESSIVE_GOOD) || monster->flagIsSet(M_AGGRESSIVE_AFTER_TALK) || monster->flagIsSet(M_CLASS_AGGRO_INVERT) || monster->flagIsSet(M_RACE_AGGRO_INVERT) || monster->flagIsSet(M_DEITY_AGGRO_INVERT); if(!maybeAggro) { std::map<int, RaceData*>::iterator rIt; for(rIt = gConfig->races.begin() ; rIt != gConfig->races.end() ; rIt++) { if(monster->isRaceAggro((*rIt).second->getId(), false)) { maybeAggro = true; break; } } } if(!maybeAggro) { for(int n=1; n<STAFF; n++) { if(monster->isClassAggro(n, false)) { maybeAggro = true; break; } } } if(!maybeAggro) { std::map<int, DeityData*>::iterator dIt; for(dIt = gConfig->deities.begin() ; dIt != gConfig->deities.end() ; dIt++) { if(monster->isDeityAggro((*dIt).second->getId(), false)) { maybeAggro = true; break; } } } if(maybeAggro) oStr << "^y"; else oStr << "^g"; } oStr << "Slot " << std::setw(2) << (*it).first+1 << ": " << monster->getName() << " " << "[" << monType::getName(monster->getType()) << ":" << monType::getHitdice(monster->getType()) << "HD]\n" << " ^x[I:" << monster->info.str() << " L:" << monster->getLevel() << " X:" << monster->getExperience() << " G:" << monster->coins[GOLD] << " H:" << monster->hp.getMax() << " M:" << monster->mp.getMax() << " N:" << (monster->getNumWander() ? monster->getNumWander() : 1) << (monster->getAlignment() > 0 ? "^g" : "") << (monster->getAlignment() < 0 ? "^r" : "") << " A:" << monster->getAlignment() << "^x D:" << monster->damage.average() << "]\n"; free_crt(monster); } if(!found) oStr << " No random monsters currently come in this " << type << "."; player->printColor("%s\n", oStr.str().c_str()); } int dmMobList(Player* player, cmd* cmnd) { if(!player->checkBuilder(player->getUniqueRoomParent())) { player->print("Error: Room number not inside any of your alotted ranges.\n"); return(0); } player->print("Random monsters which come in this room:\n"); if(player->inUniqueRoom()) showMobList(player, &player->getUniqueRoomParent()->wander, "room"); else if(player->inAreaRoom()) { Area* area = player->getAreaRoomParent()->area; std::list<AreaZone*>::iterator it; AreaZone *zone=0; for(it = area->zones.begin() ; it != area->zones.end() ; it++) { zone = (*it); if(zone->inside(area, &player->getAreaRoomParent()->mapmarker)) { player->print("Zone: %s\n", zone->name.c_str()); showMobList(player, &zone->wander, "zone"); } } TileInfo* tile = area->getTile(area->getTerrain(0, &player->getAreaRoomParent()->mapmarker, 0, 0, 0, true), area->getSeasonFlags(&player->getAreaRoomParent()->mapmarker)); if(tile && tile->wander.getTraffic()) { player->print("Tile: %s\n", tile->getName().c_str()); showMobList(player, &tile->wander, "tile"); } } return(0); } //********************************************************************* // dmWrap //********************************************************************* // dmWrap will either wrap the short or long desc of a room to the // specified length, for sanity, a range of 60 - 78 chars is the limit. int dmWrap(Player* player, cmd* cmnd) { UniqueRoom *room = player->getUniqueRoomParent(); int wrap=0; bool err=false, which=false; bstring text = ""; if(!needUniqueRoom(player)) return(0); if(!player->checkBuilder(player->getUniqueRoomParent())) { player->print("Room is not in any of your alotted room ranges.\n"); return(0); } // parse the input command for syntax/range problems if(cmnd->num < 2) err = true; else { switch(cmnd->str[1][0]) { case 'l': which = true; text = room->getLongDescription(); break; case 's': which = false; text = room->getShortDescription(); break; default: err = true; break; } if(!err) { wrap = cmnd->val[1]; if(wrap < 60 || wrap > 78) err = true; } } if(err) { player->print("*wrap <s | l> <len> where len is between 60 and 78 >\n"); return(0); } if((!which && room->getShortDescription() == "") || (which && room->getLongDescription() == "")) { player->print("No text to wrap!\n"); return(0); } // adjust! wrap++; // replace! if(!which) room->setShortDescription(wrapText(room->getShortDescription(), wrap)); else room->setLongDescription(wrapText(room->getLongDescription(), wrap)); player->print("Text wrapped.\n"); player->getUniqueRoomParent()->escapeText(); log_immort(false, player, "%s wrapped the description in room %s.\n", player->getCName(), player->getRoomParent()->fullName().c_str()); return(0); } //********************************************************************* // dmDeleteAllExits //********************************************************************* int dmDeleteAllExits(Player* player, cmd* cmnd) { if(player->getRoomParent()->exits.empty()) { player->print("No exits to delete.\n"); return(0); } player->getRoomParent()->clearExits(); // sorry, can't delete exits in overland if(player->inAreaRoom()) player->getAreaRoomParent()->updateExits(); player->print("All exits deleted.\n"); log_immort(true, player, "%s deleted all exits in room %s.\n", player->getCName(), player->getRoomParent()->fullName().c_str()); room_track(player); return(0); } //********************************************************************* // exit_ordering //********************************************************************* // 1 mean exit2 goes in front of exit1 // 0 means keep looking int exit_ordering(const char *exit1, const char *exit2) { // always skip if they're the same name if(!strcmp(exit1, exit2)) return(0); // north east south west if(!strcmp(exit1, "north")) return(0); if(!strcmp(exit2, "north")) return(1); if(!strcmp(exit1, "east")) return(0); if(!strcmp(exit2, "east")) return(1); if(!strcmp(exit1, "south")) return(0); if(!strcmp(exit2, "south")) return(1); if(!strcmp(exit1, "west")) return(0); if(!strcmp(exit2, "west")) return(1); // northeast northwest southeast southwest if(!strcmp(exit1, "northeast")) return(0); if(!strcmp(exit2, "northeast")) return(1); if(!strcmp(exit1, "northwest")) return(0); if(!strcmp(exit2, "northwest")) return(1); if(!strcmp(exit1, "southeast")) return(0); if(!strcmp(exit2, "southeast")) return(1); if(!strcmp(exit1, "southwest")) return(0); if(!strcmp(exit2, "southwest")) return(1); if(!strcmp(exit1, "up")) return(0); if(!strcmp(exit2, "up")) return(1); if(!strcmp(exit1, "down")) return(0); if(!strcmp(exit2, "down")) return(1); // alphabetic return strcmp(exit1, exit2) > 0 ? 1 : 0; } //********************************************************************* // dmArrangeExits //********************************************************************* bool exitCompare( const Exit* left, const Exit* right ){ return(exit_ordering(left->getCName(), right->getCName())); } void BaseRoom::arrangeExits(Player* player) { if(exits.size() <= 1) { if(player) player->print("No exits to rearrange!\n"); return; } exits.sort(exitCompare); if(player) player->print("Exits rearranged!\n"); } int dmArrangeExits(Player* player, cmd* cmnd) { if(!player->checkBuilder(player->getUniqueRoomParent())) { player->print("Error: Room number not inside any of your alotted ranges.\n"); return(0); } player->getRoomParent()->arrangeExits(player); return(0); } //********************************************************************* // link_rom //********************************************************************* // from this room to unique room void link_rom(BaseRoom* room, Location l, bstring str) { const char* dir = str.c_str(); for(Exit* ext : room->exits) { if(ext->getName() == dir) { ext->target = l; return; } } Exit* exit = new Exit; exit->setRoom(room); exit->setName( dir); exit->target = l; room->exits.push_back(exit); } void link_rom(BaseRoom* room, short tonum, bstring str) { Location l; l.room.id = tonum; link_rom(room, l, str); } void link_rom(BaseRoom* room, CatRef cr, bstring str) { Location l; l.room = cr; link_rom(room, l, str); } void link_rom(BaseRoom* room, MapMarker *mapmarker, bstring str) { Location l; l.mapmarker = *mapmarker; link_rom(room, l, str); } //********************************************************************* // dmFix //********************************************************************* int dmFix(Player* player, cmd* cmnd, bstring name, char find, char replace) { Exit *exit=0; int i=0; bool fixed=false; if(cmnd->num < 2) { player->print("Syntax: *%sup <exit>\n", name.c_str()); return(0); } exit = findExit(player, cmnd); if(!exit) { player->print("You don't see that exit.\n"); return(0); } bstring newName = exit->getName(); for(i=newName.length(); i>0; i--) { if(newName[i] == find) { newName[i] = replace; fixed = true; } } if(fixed) { exit->setName(newName); log_immort(true, player, "%s %sed the exit '%s' in room %s.\n", player->getCName(), name.c_str(), exit->getCName(), player->getRoomParent()->fullName().c_str()); player->print("Done.\n"); } else player->print("Couldn't find any underscores.\n"); return(0); } //********************************************************************* // dmUnfixExit //********************************************************************* int dmUnfixExit(Player* player, cmd* cmnd) { return(dmFix(player, cmnd, "unfix", ' ', '_')); } //********************************************************************* // dmFixExit //********************************************************************* int dmFixExit(Player* player, cmd* cmnd) { return(dmFix(player, cmnd, "fix", '_', ' ')); } //********************************************************************* // dmRenameExit //********************************************************************* int dmRenameExit(Player* player, cmd* cmnd) { Exit *exit=0; if(!player->checkBuilder(player->getUniqueRoomParent())) { player->print("Room is not in any of your alotted room ranges.\n"); return(0); } if(cmnd->num < 3) { player->print("Syntax: *xrename <old exit>[#] <new exit>\n"); return(0); } exit = findExit(player, cmnd); if(!exit) { player->print("There is no exit here by that name.\n"); return(0); } bstring newName = getFullstrText(cmnd->fullstr, 2); if(newName.getLength() > 20) { player->print("New exit name must be 20 characters or less in length.\n"); return(0); } player->printColor("Exit \"%s^x\" renamed to \"%s^x\".\n", exit->getCName(), newName.c_str()); log_immort(false, player, "%s renamed exit %s^g to %s^g in room %s.\n", player->getCName(), exit->getCName(), newName.c_str(), player->getRoomParent()->fullName().c_str()); room_track(player); if(getDir(newName) != NoDirection) exit->setDirection(NoDirection); exit->setName( newName.c_str()); return(0); } //********************************************************************* // dmDestroyRoom //********************************************************************* int dmDestroyRoom(Player* player, cmd* cmnd) { if(!player->inUniqueRoom()) { player->print("Error: You need to be in a unique room to do that.\n"); return(0); } if(!player->checkBuilder(player->getUniqueRoomParent())) { player->print("Room is not in any of your alotted room ranges.\n"); return(0); } if( player->getUniqueRoomParent()->info.isArea("test") && player->getUniqueRoomParent()->info.id == 1 ) { player->print("Sorry, you cannot destroy this room.\n"); player->print("It is the Builder Waiting Room.\n"); return(0); } if(player->bound.room == player->currentLocation.room) { player->print("Sorry, you cannot destroy this room.\n"); player->print("It is your bound room.\n"); return(0); } std::map<bstring, StartLoc*>::iterator sIt; for(sIt = gConfig->start.begin() ; sIt != gConfig->start.end() ; sIt++) { if( player->getUniqueRoomParent()->info == (*sIt).second->getBind().room || player->getUniqueRoomParent()->info == (*sIt).second->getRequired().room ) { player->print("Sorry, you cannot destroy this room.\n"); player->print("It is important to starting locations.\n"); return(0); } } std::list<CatRefInfo*>::const_iterator crIt; for(crIt = gConfig->catRefInfo.begin() ; crIt != gConfig->catRefInfo.end() ; crIt++) { if(player->getUniqueRoomParent()->info.isArea((*crIt)->getArea())) { if((*crIt)->getLimbo() == player->getUniqueRoomParent()->info.id) { player->print("Sorry, you cannot destroy this room.\n"); player->print("It is a Limbo room.\n"); return(0); } if((*crIt)->getRecall() == player->getUniqueRoomParent()->info.id) { player->print("Sorry, you cannot destroy this room.\n"); player->print("It is a recall room.\n"); return(0); } } } log_immort(true, player, "%s destroyed room %s.\n", player->getCName(), player->getRoomParent()->fullName().c_str()); player->getUniqueRoomParent()->destroy(); return(0); } //********************************************************************* // findRoomsWithFlag //********************************************************************* void findRoomsWithFlag(const Player* player, Range range, int flag) { Async async; if(async.branch(player, CHILD_PRINT) == AsyncExternal) { std::ostringstream oStr; bool found = false; if(range.low.id <= range.high) { UniqueRoom* room=0; CatRef cr; int high = range.high; cr.setArea(range.low.area); cr.id = range.low.id; if(range.low.id == -1 && range.high == -1) { cr.id = 1; high = RMAX; } for(; cr.id < high; cr.id++) { if(!loadRoom(cr, &room)) continue; if(room->flagIsSet(flag)) { if(player->isStaff()) oStr << room->info.rstr() << " - "; oStr << room->getName() << "^x\n"; found = true; } } } printf("^YLocations found:^x\n"); if(!found) { printf("No available locations were found."); } else { bstring output = oStr.str(); printf("%s", output.c_str()); } exit(0); } } void findRoomsWithFlag(const Player* player, CatRef area, int flag) { Async async; if(async.branch(player, CHILD_PRINT) == AsyncExternal) { struct dirent *dirp=0; DIR *dir=0; std::ostringstream oStr; bool found = false; char filename[250]; UniqueRoom *room=0; // This tells us just to get the path, not the file, // and tells loadRoomFromFile to ignore the CatRef area.id = -1; bstring path = roomPath(area); if((dir = opendir(path.c_str())) != NULL) { while((dirp = readdir(dir)) != NULL) { // is this a room file? if(dirp->d_name[0] == '.') continue; sprintf(filename, "%s/%s", path.c_str(), dirp->d_name); if(!loadRoomFromFile(area, &room, filename)) continue; if(room->flagIsSet(flag)) { if(player->isStaff()) oStr << room->info.rstr() << " - "; oStr << room->getName() << "^x\n"; found = true; } // TODO: Memleak (even though it is forked), room is not deleted } } printf("^YLocations found:^x\n"); if(!found) { printf("No available locations were found."); } else { bstring output = oStr.str(); printf("%s", output.c_str()); } exit(0); } } //********************************************************************* // dmFind //********************************************************************* int dmFind(Player* player, cmd* cmnd) { bstring type = getFullstrText(cmnd->fullstr, 1); CatRef cr; if(player->inUniqueRoom()) cr = player->getUniqueRoomParent()->info; else cr.setArea("area"); if(type == "r") type = "room"; else if(type == "o") type = "object"; else if(type == "m") type = "monster"; if(type == "" || (type != "room" && type != "object" && type != "monster")) { if(type != "") player->print("\"%s\" is not a valid type.\n", type.c_str()); player->print("Search for next available of the following: room, object, monster.\n"); return(0); } if(!player->checkBuilder(cr)) { player->print("Error: this area is out of your range; you cannot *find here.\n"); return(0); } if(type == "monster" && !player->canBuildMonsters()) { player->print("Error: you cannot work with monsters.\n"); return(0); } if(type == "object" && !player->canBuildObjects()) { player->print("Error: you cannot work with objects.\n"); return(0); } Async async; if(async.branch(player, CHILD_PRINT) == AsyncExternal) { cr = findNextEmpty(type, cr.area); printf("^YNext available %s in area %s:^x\n", type.c_str(), cr.area.c_str()); if(cr.id == -1) printf("No empty %ss found.", type.c_str()); else { bstring output = cr.rstr(); printf("%s", output.c_str()); } exit(0); } else { player->printColor("Searching for next available %s in ^W%s^x.\n", type.c_str(), cr.area.c_str()); } return(0); } //********************************************************************* // findNextEmpty //********************************************************************* // searches for the next empty room/object/monster in the area CatRef findNextEmpty(bstring type, bstring area) { CatRef cr; cr.setArea(area); if(type == "room") { UniqueRoom* room=0; for(cr.id = 1; cr.id < RMAX; cr.id++) if(!loadRoom(cr, &room)) return(cr); } else if(type == "object") { Object *object=0; for(cr.id = 1; cr.id < OMAX; cr.id++) { if(!loadObject(cr, &object)) return(cr); else delete object; } } else if(type == "monster") { Monster *monster=0; for(cr.id = 1; cr.id < MMAX; cr.id++) { if(!loadMonster(cr, &monster)) return(cr); else free_crt(monster); } } // -1 indicates failure cr.id = -1; return(cr); }