/* * 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-2009 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 <signal.h> #include <dirent.h> #include <iomanip> const char* sepType = " "; #define RSWAP_QUEUE_LIMIT 100 //********************************************************************* // 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(bstring text, int wrap) { 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 //********************************************************************* void expand_exit_name(char *name) { if(!strcmp(name, "n")) strcpy(name, "north"); else if(!strcmp(name, "s")) strcpy(name, "south"); else if(!strcmp(name, "e")) strcpy(name, "east"); else if(!strcmp(name, "w")) strcpy(name, "west"); else if(!strcmp(name, "sw")) strcpy(name, "southwest"); else if(!strcmp(name, "nw")) strcpy(name, "northwest"); else if(!strcmp(name, "se")) strcpy(name, "southeast"); else if(!strcmp(name, "ne")) strcpy(name, "northeast"); else if(!strcmp(name, "d")) strcpy(name, "door"); else if(!strcmp(name, "o")) strcpy(name, "out"); else if(!strcmp(name, "p")) strcpy(name, "passage"); else if(!strcmp(name, "t")) strcpy(name, "trap door"); else if(!strcmp(name, "a")) strcpy(name, "arch"); else if(!strcmp(name, "g")) strcpy(name, "gate"); else if(!strcmp(name, "st")) strcpy(name, "stairs"); } //********************************************************************* // opposite_exit_name //********************************************************************* int opposite_exit_name(const char *name, char *name2) { if(!strcmp(name, "south")) strcpy(name2, "north"); else if(!strcmp(name, "north")) strcpy(name2, "south"); else if(!strcmp(name, "west")) strcpy(name2, "east"); else if(!strcmp(name, "east")) strcpy(name2, "west"); else if(!strcmp(name, "northeast")) strcpy(name2, "southwest"); else if(!strcmp(name, "southeast")) strcpy(name2, "northwest"); else if(!strcmp(name, "northwest")) strcpy(name2, "southeast"); else if(!strcmp(name, "southwest")) strcpy(name2, "northeast"); else if(!strcmp(name, "up")) strcpy(name2, "down"); else if(!strcmp(name, "down")) strcpy(name2, "up"); else return(0); return(1); } //********************************************************************* // dmPurge //********************************************************************* // This function allows staff to purge a room of all its objects and // monsters. int dmPurge(Player* player, cmd* cmnd) { ctag *cp=0, *fol=0, *ctemp=0, *pet=0; otag *op=0, *otemp=0; BaseRoom* room = player->getRoom(); if(!player->canBuildMonsters() && !player->canBuildObjects()) return(cmdNoAuth(player)); if(!player->checkBuilder(player->parent_rom)) { player->print("Error: this room is out of your range; you cannot *purge here.\n"); return(0); } cp = room->first_mon; room->first_mon = 0; while(cp) { ctemp = cp->next_tag; if(cp->crt->isPet()) { player->print("Skipping %N.\n", cp->crt); // don't kill pets if(!room->first_mon) { room->first_mon = cp; pet = room->first_mon; } else { pet->next_tag = cp; pet = pet->next_tag; } pet->next_tag = 0; cp = ctemp; continue; } if(cp->crt->flagIsSet(M_DM_FOLLOW)) { if(cp->crt->following) { Player* master = cp->crt->following->getPlayer(); master->clearFlag(P_ALIASING); master->setAlias(0); master->print("%1M's soul was purged.\n", cp->crt); fol = master->first_fol; if(fol->crt == cp->crt) { master->first_fol = fol->next_tag; delete fol; } else { while(fol) { if(fol->crt == cp->crt) { //folprev = fol->next_tag; delete fol; break; } //folprev = fol; fol = fol->next_tag; } } } } free_crt(cp->crt); delete cp; cp = ctemp; } op = room->first_obj; room->first_obj = 0; while(op) { otemp = op->next_tag; if(!op->obj->flagIsSet(O_TEMP_PERM)) { delete op->obj; delete op; } op = otemp; } player->print("Purged.\n"); if(!player->isDm()) log_immort(false,player, "%s purged room %s.\n", player->name, player->getRoom()->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->parent_rom)) { player->print("Error: room number not in any of your alotted 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->name, player->getRoom()->fullName().c_str(), text.c_str()); broadcast(NULL, player->getRoom(), "%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->parent_rom)) { player->print("Error: this room is out of your range; you cannot reload this room.\n"); return(0); } if(gConfig->reloadRoom(player->getRoom())) 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; Room *room = player->parent_rom; //long temp_obj[10], temp_mon[10]; if(!needUniqueRoom(player)) return(0); if(!player->checkBuilder(player->parent_rom)) { 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->name, player->getRoom()->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) { xtag *xp=0; Exit *exit=0; char str[1024], temp[25], tempstr[32]; int i=0, flagcount=0; Room* uRoom = room->getUniqueRoom(); if(room->first_ext) player->print("Exits:\n"); xp = room->first_ext; while(xp) { exit = xp->ext; xp = xp->next_tag; if(!exit->getLevel()) player->print(" %s: ", exit->name); else player->print(" %s(L%d): ", exit->name, 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->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->print(" Owner: %s Uses: %d\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()) player->print(" Size: %s\n", getSizeName(exit->getSize()).c_str()); if(exit->effects.list.size()) player->printColor(" Effects:\n%s", exit->effects.getEffectsString(player).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()); } //********************************************************************* // show //********************************************************************* void WanderInfo::show(const Player* player, bstring area) const { std::map<int, CatRef>::const_iterator it; Monster* monster=0; player->print("Traffic: %d%%\n", traffic); player->print("Random Monsters:\n"); for(it = random.begin(); it != random.end() ; it++) { loadMonster((*it).second, &monster); player->printColor("^c%2d) ^x%14s ^c::^x %s\n", (*it).first+1, (*it).second.str("", 'c').c_str(), monster ? monster->name : ""); if(monster) { free_crt(monster); monster = 0; } } } //********************************************************************* // 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->name, player->getRoom()->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(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.list.size()) player->printColor("Effects:\n%s", room->effects.getEffectsString(player).c_str()); stat_rom_exits(player, room); return(0); } //********************************************************************* // stat_rom //********************************************************************* int stat_rom(Player* player, Room* room) { std::map<int, crlasttime>::iterator it; crlasttime* crtm=0; CatRef cr; Monster* monster=0; Object* object=0; if(!player->checkBuilder(room)) return(0); if(player->getClass() == CARETAKER) log_immort(false,player, "%s statted room %s.\n", player->name, player->getRoom()->fullName().c_str()); player->printColor("Room: %s", room->info.str("", 'y').c_str()); if(gConfig->moveRoomInQueue(room->info, 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->name); 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", (*it).first+1, crtm->cr.str("", 'y').c_str(), object ? object->name : "", crtm->interval); if(room->flagIsSet(R_SHOP_STORAGE) && object) player->printColor(" ^yCost:^x %s", object->value.str().c_str()); player->print("\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\n", (*it).first+1, crtm->cr.str("", 'm').c_str(), monster ? monster->name : "", crtm->interval); 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)) { 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 relog room number.\n"); } 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->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.list.size()) player->printColor("Effects:\n%s", room->effects.getEffectsString(player).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) { Room *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); } 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, roomPath(cr)); if(file_exists(file)) { player->print("Room already exists.\n"); return(0); } newRoom = new Room; if(!newRoom) merror("dmAddRoom", FATAL); newRoom->info = cr; newRoom->setFlag(R_CONSTRUCTION); sprintf(newRoom->name, "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->name, cr.str().c_str()); player->print("Room %s created.\n", cr.str().c_str()); 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->getRoom(); 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->parent_rom)) { 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->parent_rom) { 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->parent_rom->setLowLevel(cmnd->val[2]); player->print("Low level boundary %d\n", player->parent_rom->getLowLevel()); } else if(low(cmnd->str[2][1]) == 'h') { player->parent_rom->setHighLevel(cmnd->val[2]); player->print("Upper level boundary %d\n", player->parent_rom->getHighLevel()); } break; case 'd': if(!player->area_room) { player->print("Error: You need to be in an area room to do that.\n"); return(0); } if(!player->area_room->unique.id) { player->print("Error: The area room must have the unique field set [*set r unique #].\n"); return(0); } player->area_room->setDecCompass(!player->area_room->getDecCompass()); player->printColor("DecCompass toggled, set to %s^x.\n", player->area_room->getDecCompass() ? "^gYes" : "^rNo"); log_immort(true, player, "%s set decCompass to %s in room %s.\n", player->name, player->area_room->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->getEffect(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, true) == true) { 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->parent_rom) { player->print("Error: You need to be in a unique room to do that.\n"); return(0); } player->parent_rom->setRoomExperience(cmnd->val[2]); player->print("Room experience set to %d.\n", player->parent_rom->getRoomExperience()); log_immort(true, player, "%s set roomExp to %d in room %s.\n", player->name, player->parent_rom->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->parent_rom->setFishing(""); player->print("Fishing list cleared.\n"); log_immort(true, player, "%s cleared fishing list in room %s.\n", player->name, 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->parent_rom->setFishing(cmnd->str[3]); player->print("Fishing list set to %s.\n", player->parent_rom->getFishingStr().c_str()); log_immort(true, player, "%s set fishing list to %s in room %s.\n", player->name, player->parent_rom->getFishingStr().c_str(), room->fullName().c_str()); } } else if(low(cmnd->str[2][1]) == 'a') { if(!player->parent_rom) { 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->parent_rom->setFaction(""); player->print("Faction cleared.\n"); log_immort(true, player, "%s cleared faction in room %s.\n", player->name, room->fullName().c_str()); return(0); } Property* p = gConfig->getProperty(player->parent_rom->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->parent_rom->setFaction(faction->getName()); player->print("Faction set to %s.\n", player->parent_rom->getFaction().c_str()); log_immort(true, player, "%s set faction to %s in room %s.\n", player->name, player->parent_rom->getFaction().c_str(), room->fullName().c_str()); break; } else { if(!player->parent_rom) { 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->parent_rom->clearFlag(a); player->print("All room flags cleared.\n"); log_immort(true, player, "%s cleared all flags in room %s.\n", player->name, room->fullName().c_str()); break; } if(player->parent_rom->flagIsSet(num - 1)) { player->parent_rom->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->name, 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->parent_rom->whatTraining(num-1)) { player->print("You are setting training for a class that does not exist.\n"); return(0); } } player->parent_rom->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->name, 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_UNDERGROUND) && player->parent_rom->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 && !strcmp(player->parent_rom->name, "New Room") && !player->parent_rom->first_ext ) { cr = player->parent_rom->info; Room* 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->parent_rom->setTrapExit(cr); player->printColor("^y * ^xCreating exit ""out"" to %s...\n", cr.str().c_str()); link_rom(player->parent_rom, cr, "out"); player->parent_rom->setTrapExit(cr); player->printColor("^y * ^xNaming this room...\n"); storageName += shop->name; player->printColor("^y * ^xNaming this room...\n"); strcpy(player->parent_rom->name, storageName.c_str()); if(player->parent_rom->flagIsSet(R_CONSTRUCTION)) { player->printColor("^y * ^xClearing construction...\n"); player->parent_rom->clearFlag(R_CONSTRUCTION); } player->print("Done!\n"); } } } } break; case 'l': if(!player->parent_rom) { 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->parent_rom->lastPly, ""); strcpy(player->parent_rom->lastPlyTime, ""); player->print("Last-arrived info cleared.\n"); break; case 'm': if(!player->parent_rom) { player->print("Error: You need to be in a unique room to do that.\n"); return(0); } player->parent_rom->setMaxMobs(cmnd->val[2]); if(!player->parent_rom->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->parent_rom->getMaxMobs(), player->parent_rom->getMaxMobs() != 1 ? "s" : ""); log_immort(true, player, "%s set max %d mobs in room %s.\n", player->name, player->parent_rom->getMaxMobs(), room->fullName().c_str()); break; case 'n': if(!player->area_room) { player->print("Error: You need to be in an area room to do that.\n"); return(0); } if(!player->area_room->unique.id) { player->print("Error: The area room must have the unique field set [*set r unique #].\n"); return(0); } player->area_room->setNeedsCompass(!player->area_room->getNeedsCompass()); player->printColor("NeedsCompass toggled, set to %s^x.\n", player->area_room->getNeedsCompass() ? "^gYes" : "^rNo"); log_immort(true, player, "%s set needsCompass to %s in room %s.\n", player->name, player->area_room->getNeedsCompass() ? "true" : "false", room->fullName().c_str()); break; case 'r': if(!player->parent_rom) { 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->parent_rom->wander.random.erase(num-1); player->print("Random #%d has been cleared.\n", num); } else { player->parent_rom->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->name, num, cr.str().c_str(), room->fullName().c_str()); break; case 's': if(!player->parent_rom) { player->print("Error: You need to be in a unique room to do that.\n"); return(0); } player->parent_rom->setSize(getSize(cmnd->str[3])); player->print("Size set to %s.\n", getSizeName(player->parent_rom->getSize()).c_str()); log_immort(true, player, "%s set room %s's %s to %s.\n", player->name, room->fullName().c_str(), "Size", getSizeName(player->parent_rom->getSize()).c_str()); break; case 't': if(!player->parent_rom) { player->print("Error: You need to be in a unique room to do that.\n"); return(0); } player->parent_rom->wander.setTraffic(cmnd->val[2]); log_immort(true, player, "%s set room %s's traffic to %ld.\n", player->name, player->parent_rom->info.str().c_str(), player->parent_rom->wander.getTraffic()); player->print("Traffic is now %d%%.\n", player->parent_rom->wander.getTraffic()); break; case 'x': if(!player->parent_rom) { 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->parent_rom->setTrapExit(cr); player->print("Room's trap exit is now %s.\n", player->parent_rom->getTrapExit().str().c_str()); log_immort(true, player, "%s set trapexit to %s in room %s.\n", player->name, player->parent_rom->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->parent_rom->setTrapWeight(num); player->print("Room's trap weight is now %d.\n", player->parent_rom->getTrapWeight()); log_immort(true, player, "%s set trapweight to %d in room %s.\n", player->name, player->parent_rom->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->parent_rom->setTrapStrength(num); player->print("Room's trap strength is now %d.\n", player->parent_rom->getTrapStrength()); log_immort(true, player, "%s set trapstrength to %d in room %s.\n", player->name, player->parent_rom->getTrapStrength(), room->fullName().c_str()); } else { player->parent_rom->setTrap(cmnd->val[2]); player->print("Room has trap #%d set.\n", player->parent_rom->getTrap()); log_immort(true, player, "%s set trap #%d in room %s.\n", player->name, player->parent_rom->getTrap(), room->fullName().c_str()); } break; case 'u': if(!player->area_room) { 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->area_room->unique = cr; player->print("Unique room set to %s.\n", player->area_room->unique.str().c_str()); if(player->area_room->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->name, player->area_room->unique.str().c_str(), room->fullName().c_str()); break; default: player->print("Invalid option.\n"); return(0); } if(player->parent_rom) player->parent_rom->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->getRoom(); int num=0; //char orig_exit[30]; short n=0; xtag *xp=0; if(!player->checkBuilder(player->parent_rom)) { 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); } xp = room->first_ext; while(xp) { if( !strcmp(xp->ext->name, cmnd->str[2]) && !xp->ext->flagIsSet(X_NO_SEE) ) break; xp = xp->next_tag; } if(!xp) { player->print("Exit not found.\n"); return(0); } switch(cmnd->str[1][1]) { 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 = xp->ext->getEffect(effectStr)) { // We have an existing effect we're modifying if(duration == 0) { // Duration is 0, so remove it xp->ext->removeEffect(toSet, true, room); 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(xp->ext->addEffect(effectStr, duration, strength, true, room) == true) { 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 { xp->ext->setEnter(getFullstrText(cmnd->fullstr, 3)); if(xp->ext->getEnter() == "" || Pueblo::is(xp->ext->getEnter())) { xp->ext->setEnter(""); player->print("OnEnter cleared.\n"); log_immort(true, player, "%s cleared %s's %s.\n", player->name, xp->ext->name, "OnEnter"); } else { player->print("OnEnter set to \"%s\".\n", xp->ext->getEnter().c_str()); log_immort(true, player, "%s set %s's %s to \"%s\".\n", player->name, xp->ext->name, "OnEnter", xp->ext->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(xp->ext->flagIsSet(num - 1)) { xp->ext->clearFlag(num - 1); player->print("%s exit flag #%d off.\n", xp->ext->name, num); log_immort(true, player, "%s cleared %s exit flag #%d(%s) in room %s.\n", player->name, xp->ext->name, num, get_xflag(num-1), room->fullName().c_str()); } else { xp->ext->setFlag(num - 1); player->print("%s exit flag #%d on.\n", xp->ext->name, num); log_immort(true, player, "%s turned on %s exit flag #%d(%s) in room %s.\n", player->name, xp->ext->name, num, get_xflag(num-1), room->fullName().c_str()); } break; case 'k': if(cmnd->str[1][2] == 'a') { xp->ext->setKeyArea(cmnd->str[3]); if(xp->ext->getKeyArea() == "") { player->print("Key Area cleared.\n"); log_immort(true, player, "%s cleared %s's %s.\n", player->name, xp->ext->name, "Key Area"); } else { player->print("Key Area set to \"%s\".\n", xp->ext->getKeyArea().c_str()); log_immort(true, player, "%s set %s's %s to \"%s\".\n", player->name, xp->ext->name, "Key Area", xp->ext->getKeyArea().c_str()); } } else { if(cmnd->val[2] > 255 || cmnd->val[2] < 0) { player->print("Error: key out of range.\n"); return(0); } xp->ext->setKey(cmnd->val[2]); player->print("Exit %s key set to %d.\n", xp->ext->name, xp->ext->getKey()); log_immort(true, player, "%s set %s's %s to %ld.\n", player->name, xp->ext->name, "Key", xp->ext->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); } xp->ext->setLevel(cmnd->val[2]); player->print("Exit %s's level is now set to %d.\n", xp->ext->name, xp->ext->getLevel()); log_immort(true, player, "%s set %s's %s to %ld.\n", player->name, xp->ext->name, "Pick Level", xp->ext->getLevel()); break; case 'o': xp->ext->setOpen(getFullstrText(cmnd->fullstr, 3)); if(xp->ext->getOpen() == "" || Pueblo::is(xp->ext->getOpen())) { xp->ext->setOpen(""); player->print("OnOpen cleared.\n"); log_immort(true, player, "%s cleared %s's %s.\n", player->name, xp->ext->name, "OnOpen"); } else { player->print("OnOpen set to \"%s\".\n", xp->ext->getOpen().c_str()); log_immort(true, player, "%s set %s's %s to \"%s\".\n", player->name, xp->ext->name, "OnOpen", xp->ext->getOpen().c_str()); } break; case 'p': if(low(cmnd->str[1][2]) == 'p') { xp->ext->setPassPhrase(getFullstrText(cmnd->fullstr, 3)); if(xp->ext->getPassPhrase() == "") { player->print("Passphrase cleared.\n"); log_immort(true, player, "%s cleared %s's %s.\n", player->name, xp->ext->name, "Passphrase"); } else { player->print("Passphrase set to \"%s\".\n", xp->ext->getPassPhrase().c_str()); log_immort(true, player, "%s set %s's %s to \"%s\".\n", player->name, xp->ext->name, "Passphrase", xp->ext->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; xp->ext->setPassLanguage(n); player->print("Pass language %s.\n", n ? "set" : "cleared"); log_immort(true, player, "%s set %s's %s to %s(%ld).\n", player->name, xp->ext->name, "Passlang", n ? get_language_adj(n) : "Nothing", n+1); } else { player->print("Passphrase (xpp) or passlang (xpl)?\n"); return(0); } break; case 's': xp->ext->setSize(getSize(cmnd->str[3])); player->print("%s's %s set to %s.\n", xp->ext->name, "Size", getSizeName(xp->ext->getSize()).c_str()); log_immort(true, player, "%s set %s %s's %s to %s.\n", player->name, "exit", xp->ext->name, "Size", getSizeName(xp->ext->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); } xp->ext->setToll(n); player->print("Exit %s's toll is now set to %d.\n", xp->ext->name, xp->ext->getToll()); log_immort(true, player, "%s set %s's %s to %ld.\n", player->name, xp->ext->name, "Toll", xp->ext->getToll()); break; default: player->print("Invalid syntax.\n"); return(0); } if(player->parent_rom) player->parent_rom->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; Room *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(del_exit(room, cmnd->str[2])) player->print("Exit %s deleted.\n", cmnd->str[2]); //} else if( // strcmp(orig_exit, cmnd->str[2]) && // del_exit(room, orig_exit) //) // player->print("Exit %s not found.\nExit %s deleted.\n", cmnd->str[2], orig_exit); 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; } cmnd->str[2][24] = 0; // strcpy(orig_exit, cmnd->str[2]); expand_exit_name(cmnd->str[2]); if(returnExit != "") { if(returnExit == ".") { strcpy(cmnd->str[0], returnExit.c_str()); if(!opposite_exit_name(cmnd->str[2], cmnd->str[0])) strcpy(cmnd->str[0], cmnd->str[2]); returnExit = cmnd->str[0]; } if(cr.id) { link_rom(room, cr, cmnd->str[2]); if(player->parent_rom) link_rom(uRoom, player->parent_rom->info, returnExit); else link_rom(uRoom, &player->area_room->mapmarker, returnExit); gConfig->resaveRoom(cr); } else { link_rom(room, &mapmarker, cmnd->str[2]); if(player->parent_rom) link_rom(aRoom, player->parent_rom->info, returnExit); else link_rom(aRoom, &player->area_room->mapmarker, returnExit); aRoom->save(); } log_immort(true, player, "%s linked room %s to room %s in %s direction, both ways.\n", player->name, room->fullName().c_str(), room2->fullName().c_str(), cmnd->str[2]); player->print("Room %s linked to room %s in %s direction, both ways.\n", room->fullName().c_str(), room2->fullName().c_str(), cmnd->str[2]); } else { if(cr.id) link_rom(room, cr, cmnd->str[2]); else link_rom(room, &mapmarker, cmnd->str[2]); player->print("Room %s linked to room %s in %s direction.\n", room->fullName().c_str(), room2->fullName().c_str(), cmnd->str[2]); log_immort(true, player, "%s linked room %s to room %s in %s direction.\n", player->name, room->fullName().c_str(), room2->fullName().c_str(), cmnd->str[2]); } if(player->parent_rom) gConfig->resaveRoom(player->parent_rom->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->parent_rom) return(0); strcpy(player->parent_rom->last_mod, player->name); strcpy(player->parent_rom->lastModTime, ctime(&t)); return(0); } //********************************************************************* // dmReplace //********************************************************************* // this command lets staff replace words or phrases in a room description int dmReplace(Player* player, cmd* cmnd) { Room *room = player->parent_rom; int n=0, skip=0, skPos=0; int unsigned i=0, pos=0; char delim = ' '; bool sdesc=false, ldesc=false; bstring search = "", temp = ""; if(!needUniqueRoom(player)) return(0); if(!player->checkBuilder(player->parent_rom)) { 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 strcpy(cmnd->fullstr, &cmnd->fullstr[i+1]); // we search until we find the deliminator we're looking for pos=0; i = strlen(cmnd->fullstr); 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]); if(delim != ' ') { if(cmnd->fullstr[strlen(cmnd->fullstr)-1] != delim) { player->print("Deliminators do not match up.\n"); return(0); } cmnd->fullstr[strlen(cmnd->fullstr)-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) { Room *room = player->parent_rom; 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->parent_rom)) { 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 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 += strlen(cmnd->fullstr); // 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 + strlen(cmnd->fullstr), room->getShortDescription().length())); else room->setLongDescription(room->getLongDescription().substr(0, pos) + room->getLongDescription().substr(pos + strlen(cmnd->fullstr), room->getLongDescription().length())); } } // phrase && after } // *del -A log_immort(true, player, "%s deleted description in room %s.\n", player->name, player->parent_rom->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->parent_rom)) { 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); strcpy(player->parent_rom->name, name.c_str()); log_immort(true, player, "%s renamed room %s.\n", player->name, player->getRoom()->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) { Room *room = player->parent_rom; int unsigned i=0; bool sdesc=false, newline=false; if(!needUniqueRoom(player)) return(0); if(!player->checkBuilder(player->parent_rom)) { 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; strcpy(cmnd->fullstr, &cmnd->fullstr[i+1]); if(strstr(cmnd->fullstr, " ")) 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) strcat(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) strcat(cmnd->fullstr, "\n"); room->setLongDescription(cmnd->fullstr + room->getLongDescription()); } player->print("Long description %s.\n", append ? "appended" : "prepended"); } player->parent_rom->escapeText(); log_immort(true, player, "%s descripted in room %s.\n", player->name, player->parent_rom->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->name << " " << "[" << 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->parent_rom)) { 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->parent_rom) showMobList(player, &player->parent_rom->wander, "room"); else if(player->area_room) { Area* area = player->area_room->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->area_room->mapmarker)) { player->print("Zone: %s\n", zone->name.c_str()); showMobList(player, &zone->wander, "zone"); } } TileInfo* tile = area->getTile(area->getTerrain(0, &player->area_room->mapmarker, 0, 0, 0, true), area->getSeasonFlags(&player->area_room->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) { Room *room = player->parent_rom; int wrap=0; bool err=false, which=false; bstring text = ""; if(!needUniqueRoom(player)) return(0); if(!player->checkBuilder(player->parent_rom)) { 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->parent_rom->escapeText(); log_immort(false, player, "%s wrapped the description in room %s.\n", player->name, player->getRoom()->fullName().c_str()); return(0); } //********************************************************************* // dmDeleteAllExits //********************************************************************* int dmDeleteAllExits(Player* player, cmd* cmnd) { xtag *xp=0, *prev = 0; xp = player->getRoom()->first_ext; if(!xp) { player->print("No exits to delete.\n"); return(0); } player->getRoom()->first_ext = 0; while(xp) { prev = xp; xp = xp->next_tag; delete prev; } // sorry, can't delete exits in overland if(player->area_room) player->area_room->updateExits(); player->print("All exits deleted.\n"); log_immort(true, player, "%s deleted all exits in room %s.\n", player->name, player->getRoom()->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(char *exit1, 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 //********************************************************************* void BaseRoom::arrangeExits(Player* player) { xtag *xp=0, *prev=0, *sxp=0; xp = first_ext; if(!xp || !xp->next_tag) { if(player) player->print("No exits to rearrange!\n"); return; } // start at the 2nd one prev = xp; xp = xp->next_tag; while(xp) { if(player) player->print("Checking exit %s vs %s...%s\n", xp->ext->name, prev->ext->name, exit_ordering(prev->ext->name, xp->ext->name) ? "" : "ok."); // we're looking at an exit, we've got a pointer to the previous exit if(exit_ordering(prev->ext->name, xp->ext->name)) { // if xp goes before prev, start rearranging! if( prev->ext == first_ext->ext || exit_ordering(first_ext->ext->name, xp->ext->name) ) { // if it should go before the FIRST exit.. if(player) player->print(" Moving %s to the front...\n", xp->ext->name); prev->next_tag = xp->next_tag; xp->next_tag = first_ext; first_ext = xp; xp = prev->next_tag; } else { // otherwise, start over from the top: // find where xp belongs! if(player) player->print(" Finding a spot for %s...\n", xp->ext->name); sxp = first_ext; while(!exit_ordering(sxp->next_tag->ext->name, xp->ext->name)) sxp = sxp->next_tag; if(player) player->print(" Spot found after: %s.\n", sxp->ext->name); // ok we found it, time to do some magic prev->next_tag = xp->next_tag; xp->next_tag = sxp->next_tag; sxp->next_tag = xp; xp = prev->next_tag; } } else { prev = xp; xp = xp->next_tag; } } if(player) player->print("Exits rearranged!\n"); } int dmArrangeExits(Player* player, cmd* cmnd) { if(!player->checkBuilder(player->parent_rom)) { player->print("Error: Room number not inside any of your alotted ranges.\n"); return(0); } player->getRoom()->arrangeExits(player); return(0); } //********************************************************************* // link_rom //********************************************************************* // from this room to unique room void link_rom(BaseRoom* room, Location l, bstring str) { Exit *exit=0; xtag *xp=0, *prev=0, *temp=0; const char* dir = str.c_str(); xp = room->first_ext; while(xp) { exit = xp->ext; prev = xp; xp = xp->next_tag; if(!strcmp(exit->name, dir)) { strcpy(exit->name, dir); exit->target = l; return; } } temp = new xtag; exit = new Exit; strcpy(exit->name, dir); exit->target = l; temp->next_tag = 0; temp->ext = exit; if(prev) prev->next_tag = temp; else room->first_ext = temp; } 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); } //********************************************************************* // del_exit //********************************************************************* int del_exit(BaseRoom* room, Exit *exit) { xtag *xp = room->first_ext, *prev=0; while(xp) { if(xp->ext == exit) { if(prev) prev->next_tag = xp->next_tag; else room->first_ext = xp->next_tag; delete xp->ext; delete xp; return(1); } prev = xp; xp = xp->next_tag; } return(0); } int del_exit(BaseRoom* room, const char *dir) { xtag *xp = room->first_ext, *prev=0; while(xp) { if(!strcmp(xp->ext->name, dir)) { if(prev) prev->next_tag = xp->next_tag; else room->first_ext = xp->next_tag; delete xp->ext; delete xp; return(1); } prev = xp; xp = xp->next_tag; } return(0); } //********************************************************************* // 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); } for(i=strlen(exit->name); i>0; i--) { if(exit->name[i] == find) { exit->name[i] = replace; fixed = true; } } if(fixed) { log_immort(true, player, "%s %sed the exit '%s' in room %s.\n", player->name, name.c_str(), exit->name, player->getRoom()->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; char newName[20]; if(!player->checkBuilder(player->parent_rom)) { 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); } if(strlen(cmnd->str[2]) > 20) { player->print("New exit name must be 20 characters or less in length.\n"); return(0); } strcpy(newName, cmnd->str[2]); player->print("Exit \"%s\" renamed to \"%s\".\n", exit->name, newName); log_immort(false, player, "%s renamed exit %s to %s in room %s.\n", player->name, exit->name, newName, player->getRoom()->fullName().c_str()); room_track(player); strcpy(exit->name, newName); return(0); } //********************************************************************* // dmDestroyRoom //********************************************************************* int dmDestroyRoom(Player* player, cmd* cmnd) { if(!player->parent_rom) { player->print("Error: You need to be in a unique room to do that.\n"); return(0); } if(!player->checkBuilder(player->parent_rom)) { player->print("Room is not in any of your alotted room ranges.\n"); return(0); } if( ( player->parent_rom->info.isArea(gConfig->defaultArea) && player->parent_rom->info.id == ROOM_BUILDER_PERM_LOW ) || player->bound.room == player->room ) { player->print("Sorry, you cannot destroy this room.\n"); return(0); } std::map<bstring, StartLoc*>::iterator sIt; for(sIt = gConfig->start.begin() ; sIt != gConfig->start.end() ; sIt++) { if( player->parent_rom->info == (*sIt).second->getBind().room || player->parent_rom->info == (*sIt).second->getRequired().room ) { player->print("Sorry, you cannot destroy this room.\n"); return(0); } } std::list<CatRefInfo*>::const_iterator crIt; for(crIt = gConfig->catRefInfo.begin() ; crIt != gConfig->catRefInfo.end() ; crIt++) { if( player->parent_rom->info.isArea((*crIt)->area) && ( (*crIt)->limbo == player->parent_rom->info.id || (*crIt)->recall == player->parent_rom->info.id ) ) { player->print("Sorry, you cannot destroy this room.\n"); return(0); } } log_immort(true, player, "%s destroyed room %s.\n", player->name, player->getRoom()->fullName().c_str()); player->parent_rom->destroy(); return(0); } //********************************************************************* // moveRoom //********************************************************************* // The move room process works like this. // 1. Player requests to swap current room with another. // a. Checks to make sure current room can be swapped. // 2. If an area is specified, fork and find the next available room in that area. // 3. Checks to make sure target room can be swapped. // 4. Fork to find all players/unique rooms/area rooms affected. // a. The fork sends the info to the main mud as soon as it finds it. // b. On the main mud, any player that is saved or any unique room/area room that // is saved or modified from start to finish of this process will be put in // the queue for inspection. // 5. As the main mud receives info from the fork, it puts it into the queue. // a. Unique rooms received will be loaded into memory immediately to prevent // many rooms loading at once at the end of the process. // 6. Once the fork finishes its search, it loops through everything found as well // as everything already in memory: // a. Areas (zones) // b. StartLocs // c. Ships // d. CatRefInfo // e. Online players // Everything is updated and saved to disk. // Property is not examined because all rooms belong to restricted ranges. // // If another roomswap is attempted, it will enter a queue. Once the first process is // complete, the next one will execute. // //********************************************************************* // dmMoveRoom //********************************************************************* int dmMoveRoom(Player* player, cmd* cmnd) { bstring str = getFullstrText(cmnd->fullstr, 1); bstring name=""; CatRef origin, target; int queueSize = gConfig->moveRoomQueueSize(); if(str == "") { player->print("Commands:\n"); player->printColor(" ^e*rswap [area] ^x- move to next open room in [area].\n"); player->printColor(" ^e*rswap [area.id] ^x- move to specific room (will swap if room exists).\n"); player->printColor(" ^e*rswap [id] ^x- move to specific room (will swap if room exists).\n"); player->printColor(" ^e*rswap [^x-range source target loop^e]\n"); player->printColor(" ^e[^x-range source.low:high target^e]\n"); player->print(" - swap a range of rooms.\n"); player->printColor(" ^e*rswap [^x-info^e] ^x- print roomswap info.\n"); player->printColor(" ^e*rswap [^x-cancel #^e] ^x- cancel a roomswap job, # is 1 by default.\n"); player->printColor(" ^e*rswap [^x-abort^e] ^x- abort all roomswap jobs (empty queue).\n"); return(0); } else if(str == "-info") { gConfig->moveRoomInfo(player); gServer->moveRoomInfo(player); return(0); } else if(str.left(6) == "-range") { bstring o = getFullstrText(cmnd->fullstr, 2); getCatRef(o, &origin, 0); getCatRef(getFullstrText(cmnd->fullstr, 3), &target, 0); player->printColor("^YRS: ^xLooking to swap ranges starting at %s to %s.\n", origin.rstr().c_str(), target.id == -1 ? target.area.c_str() : target.rstr().c_str()); int loop=0; bstring::size_type pos = o.Find(":"); if(pos != bstring::npos) { // *rswap -range misc.100:120 test.1 loop = atoi(o.substr(pos+1).c_str()) - origin.id; } else { // *rswap -range misc.100 test.1 20 loop = atoi(getFullstrText(cmnd->fullstr, 4).c_str()); } loop = MAX(0, loop); if(!loop) { player->printColor("^YRS: ^RError: ^xNo upper bound found: which rooms would you like to loop over?\n"); return(0); } if(!gConfig->moveRoomChecks(player, target, origin)) return(0); loop++; player->printColor("^YRS: ^xAdding %d job%s to the queue... ", loop, loop != 1 ? "s" : ""); if(loop + queueSize > RSWAP_QUEUE_LIMIT) { player->printColor("\n^YRS: ^RError: ^xThe queue has a limit of %d rooms; you may only add %d more.\n", RSWAP_QUEUE_LIMIT, RSWAP_QUEUE_LIMIT - queueSize); return(0); } loop = origin.id + loop; for(; origin.id < loop; origin.id++) { gConfig->moveRoomAddQueue(player->name, origin, target); if(target.id != -1) target.id++; } player->print("done.\n"); // begin if nothing has started! if(!gConfig->isMovingRoom()) gConfig->moveRoomNextInQueue(); return(0); } if(gConfig->isMovingRoom()) { name = gServer->moveRoomName(); if(str == "-abort") { broadcast(isStaff, "^YRS: Room move queue has been cleared."); gConfig->moveRoomAbort(); return(0); } if(str.left(7) == "-cancel") { int id = atoi(getFullstrText(cmnd->fullstr, 2).c_str()); if(id <= 1) id = 1; player->printColor("^YRS: ^eRoom swap canceled.\n"); if(name != player->name && name != "Someone") { Player* p = gServer->findPlayer(name.c_str()); if(p) player->printColor("^RRS: ^eRoom swap canceled by %s.\n", player->name); } if(id==1) gServer->endMoveRoom(); gConfig->endMoveRoom(id); return(0); } } if(str.getAt(0) == '-') { player->printColor("^YRS: ^RError: ^xFlag not understood.\n"); return(0); } if(!needUniqueRoom(player)) return(0); if(!player->checkBuilder(player->parent_rom)) { player->printColor("^YRS: ^RError: ^xRoom number not inside any of your alotted ranges.\n"); return(0); } origin = player->parent_rom->info; getCatRef(str, &target, player); // these checks done here for convenience of user, // not to ensure data validity: this is why the checks // are run again in Server::moveRoom if(!gConfig->moveRoomChecks(player, target, origin)) return(0); if(!target.isArea(origin.area) && getFullstrText(cmnd->fullstr, 2) != "confirm") { xtag *xp = player->parent_rom->first_ext; while(xp) { if(xp->ext->flagIsSet(X_LOCKABLE) && xp->ext->getKey()) { player->printColor("^YRS: ^RError: ^xthis room contains a lockable exit and is being moved to a different area.\n"); player->printColor(" To continue, type ^W*rswap %s confirm^x. Make sure all keys work correctly.\n", target.area.c_str()); return(0); } xp = xp->next_tag; } } if(player->parent_rom->flagIsSet(R_SHOP)) player->printColor("^YRS: ^GThis room is a shop - don't forget to swap the storage room: %s.\n", shopStorageRoom(player->parent_rom).rstr().c_str()); else if(player->parent_rom->getTrapExit().id) player->printColor("^YRS: ^GThis room has a trap exit set: %s.\n", player->parent_rom->getTrapExit().rstr().c_str()); if(gConfig->isMovingRoom()) { player->printColor("^YRS: ^x%s is currently moving rooms.\n", name.c_str()); if(!gConfig->moveRoomInQueue(origin)) { if(queueSize >= RSWAP_QUEUE_LIMIT) { player->printColor("^YRS: ^RError: ^xThe queue has a limit of %d rooms; you cannot add any more.\n", RSWAP_QUEUE_LIMIT); return(0); } player->printColor("^YRS: Your request has been added to the queue.\n"); gConfig->moveRoomAddQueue(player->name, origin, target); } else player->printColor("^YRS: ^RError: ^xThat room is already in the queue.\n"); } else gServer->moveRoom(player->name, origin, target); return(0); } //********************************************************************* // moveRoom //********************************************************************* bool Server::moveRoom(bstring mover, CatRef origin, CatRef target) { Player *player = gServer->findPlayer(mover.c_str()); gConfig->setMovingRoom(origin, target); // check validity here if(!gConfig->moveRoomChecks(player, origin, target)) { gConfig->endMoveRoom(); return(false); } // find the room ourselves! if(target.id == -1) { // only one forked process at a time if(gServer->moveRoomName() != "Someone") return(false); // prepare to split the mud process int fds[2]; if(pipe(fds) == -1) { printf("RS: Error with pipe!\n"); abort(); } int pid = fork(); if(!pid) { // this is the child process // Close the reading end, we'll only be writing close(fds[0]); // Remap stdout to fds[1] so cout will print to fds[1] and we can // read it in from the mud if(dup2(fds[1], STDOUT_FILENO) != STDOUT_FILENO) { std::cout << "RS: Error with dup2.\n"; return(false); } std::cout << gConfig->findNextEmpty(target.area).rstr(); exit(0); } else { // this is the parent process // Close the writing end, we'll only be reading close(fds[1]); nonBlock(fds[0]); std::cout << "Watching Child MoveRoom Find for(" << mover << ") running with pid " << pid << " reading from fd " << fds[0] << std::endl; // Let the server know we're monitoring this child process gServer->addChild(pid, CHILD_MOVEROOM_FIND, fds[0], mover); if(player) player->printColor("^YRS: ^eBeginning search for next empty room in area \"%s\".\n", target.area.c_str()); } } else gConfig->finishMoveRoom(mover); return(true); } //********************************************************************* // simpleChildRead //********************************************************************* bstring Server::simpleChildRead(Server::childProcess &child) { char tmpBuf[4096]; bstring toProcess; int n; for(;;) { // read in all of the data memset(tmpBuf, '\0', sizeof(tmpBuf)); n = read(child.fd, tmpBuf, sizeof(tmpBuf)-1); if(n <= 0) break; toProcess += tmpBuf; } return(toProcess.trim()); } //********************************************************************* // findNextEmpty //********************************************************************* // searches for the next empty room in the area CatRef Config::findNextEmpty(bstring area) { CatRef cr; Room* uRoom=0; cr.setArea(area); for(cr.id = 1; cr.id < RMAX; cr.id++) if(!loadRoom(cr, &uRoom)) return(cr); cr.id = -1; return(cr); } // gets output from findNextEmpty void Config::findNextEmpty(Server::childProcess &child, bool onReap) { if(!movingRoom) return; Player* player = gServer->findPlayer(child.extra.c_str()); // a target has not yet been found if(mrTarget.id == -1) { bstring toProcess = gServer->simpleChildRead(child); if(toProcess != "") { getCatRef(toProcess, &mrTarget, 0); if(player) player->printColor("^YRS: ^eRoom found: %s.\n", mrTarget.rstr().c_str()); } } if(onReap) { if(mrTarget.id == -1) { if(player) player->printColor("^YRS: No empty rooms were found!\n"); endMoveRoom(); } else { Room* uRoom=0; // did we actually get a room where we were expecting none? if(loadRoom(mrTarget, &uRoom)) { if(roomSearchFailure) { // we're only allowed 1 failure per go if(player) player->printColor("^RRS: ^xMove search failed; aborting this job.\n"); endMoveRoom(); } else { roomSearchFailure = true; if(player) { player->printColor("^RRS: ^xMove search failed; this room is not empty.\n"); player->printColor("^RRS: ^xAttempting room search again.\n"); } mrTarget.id = -1; uRoom->saveToFile(0); gServer->moveRoom(gServer->moveRoomName(), mrOrigin, mrTarget); } return; } finishMoveRoom(child.extra); } } } //********************************************************************* // finishMoveRoom //********************************************************************* void Config::finishMoveRoom(bstring mover) { Player* player = gServer->findPlayer(mover.c_str()); bool online=true; if(!player) { if(!loadPlayer(mover.c_str(), &player)) { broadcast(isStaff, "^YRS: ^RError: ^xNon-existent player %s attempting to move rooms.\n", mover.c_str()); endMoveRoom(); return; } online=false; player->fd = -1; } // this range is restricted if(moveRoomRestrictedArea(mrTarget.area)) { if(online) player->printColor("^YRS: ^RError: ^x""%s"" is a restricted range. You cannot swap unique rooms into or out that area.\n", mrTarget.area.c_str()); else free_crt(player); endMoveRoom(); return; } if(!player->checkBuilder(mrTarget)) { if(online) player->printColor("^YRS: ^RError: ^xRoom number not inside any of your alotted ranges.\n"); else free_crt(player); endMoveRoom(); return; } // no moving the builder waiting room! if(mrOrigin.isArea(gConfig->defaultArea) && mrOrigin.id == ROOM_BUILDER_PERM_LOW) { if(online) player->printColor("^YRS: ^RError: ^xSorry, you cannot swap this room (%s) (Builder Waiting Room).\n", mrOrigin.str().c_str()); else free_crt(player); endMoveRoom(); return; } if(mrTarget.isArea(gConfig->defaultArea) && mrTarget.id == ROOM_BUILDER_PERM_LOW) { if(online) player->printColor("^YRS: ^RError: ^xSorry, you cannot swap that room (%s) (Builder Waiting Room).\n", mrTarget.str().c_str()); else free_crt(player); endMoveRoom(); return; } // no moving special rooms out of their areas! if(!mrTarget.isArea(mrOrigin.area)) { // endMoveRoom() is handled inside these functions if(!checkSpecialArea(mrOrigin, mrTarget, &CatRefInfo::recall, player, online, "Recall")) return; if(!checkSpecialArea(mrOrigin, mrTarget, &CatRefInfo::limbo, player, online, "Limbo")) return; if(!checkSpecialArea(mrTarget, mrOrigin, &CatRefInfo::recall, player, online, "Recall")) return; if(!checkSpecialArea(mrTarget, mrOrigin, &CatRefInfo::limbo, player, online, "Limbo")) return; } player->printColor("^YRS: ^eSwapping room %s with room %s.\n", mrOrigin.str().c_str(), mrTarget.str().c_str()); gServer->finishMoveRoom(player, online, mrOrigin, mrTarget); } void Server::finishMoveRoom(Player* player, bool online, CatRef origin, CatRef target) { // only one forked process at a time if(gServer->moveRoomName() != "Someone") { if(!online) free_crt(player); return; } log_immort(true, player, "%s has begun swapping %s with %s.\n", player->name, origin.str().c_str(), target.str().c_str()); // prepare to split the mud process int fds[2]; if(pipe(fds) == -1) { printf("RS: Error with pipe!\n"); abort(); } int pid = fork(); if(!pid) { if(!online) free_crt(player); // this is the child process // Close the reading end, we'll only be writing close(fds[0]); // Remap stdout to fds[1] so cout will print to fds[1] and we can // read it in from the mud if(dup2(fds[1], STDOUT_FILENO) != STDOUT_FILENO) { std::cout << "RS: Error with dup2.\n"; return; } gConfig->offlineMoveRoom(); exit(0); } else { // this is the parent process // Close the writing end, we'll only be reading close(fds[1]); nonBlock(fds[0]); std::cout << "Watching Child MoveRoom Finish for(" << player->name << ") running with pid " << pid << " reading from fd " << fds[0] << std::endl; // Let the server know we're monitoring this child process addChild(pid, CHILD_MOVEROOM_FINISH, fds[0], player->name); if(online) { player->printColor("^YRS: ^eBeginning offline search sequence.\n"); player->printColor("^YRS: ^eThis may take several minutes.\n"); } else free_crt(player); gConfig->moveRoomLog((bstring)"r" + origin.rstr(), false); gConfig->moveRoomLog((bstring)"r" + target.rstr(), false); } } //********************************************************************* // offlineMoveRoom //********************************************************************* // the offline search function void Config::offlineMoveRoom() { std::list<bstring> updates; std::list<Area*>::iterator aIt; std::map<bstring, AreaRoom*>::iterator rIt; struct dirent *dirp=0, *dirq=0; DIR *dir=0, *subdir=0; bstring filename = ""; Room* uRoom=0; AreaRoom* aRoom=0; Player* player=0; Monster* monster=0; // id = -1 tells the loadFromFile functions to rely on the monster/room CatRef placeholder; placeholder.id = -1; // get a list of all players that need updating if((dir = opendir(PLAYERPATH)) != NULL) { while((dirp = readdir(dir)) != NULL) { if(dirp->d_name[0] == '.') continue; if(!isupper(dirp->d_name[0])) continue; dirp->d_name[strlen(dirp->d_name)-4] = 0; if(!loadPlayer(dirp->d_name, &player)) continue; if(player->moveRoom(mrOrigin, mrTarget)) { std::cout << "p" << player->name << sepType; fflush(stdout); } free_crt(player); } } // check player backups if((dir = opendir(BACKUPPATH)) != NULL) { while((dirp = readdir(dir)) != NULL) { if(dirp->d_name[0] == '.') continue; if(!isupper(dirp->d_name[0])) continue; dirp->d_name[strlen(dirp->d_name)-8] = 0; if(!loadPlayer(dirp->d_name, &player, LS_BACKUP)) continue; if(player->moveRoom(mrOrigin, mrTarget)) { std::cout << "b" << player->name << sepType; fflush(stdout); } free_crt(player); } } // get a list of all unique rooms if((dir = opendir(ROOMPATH)) != NULL) { while((dirp = readdir(dir)) != NULL) { if(dirp->d_name[0] == '.') continue; filename = ROOMPATH; filename += dirp->d_name; filename += "/"; if((subdir = opendir(filename.c_str())) != NULL) { while((dirq = readdir(subdir)) != NULL) { if(dirq->d_name[0] != 'r') continue; filename = ROOMPATH; filename += dirp->d_name; filename += "/"; filename += dirq->d_name; if(!loadRoomFromFile(placeholder, &uRoom, filename)) continue; // we check origin and target already, so forget about it here if( uRoom->info != mrOrigin && uRoom->info != mrTarget && uRoom->moveRoom(mrOrigin, mrTarget) ) { std::cout << "r" << uRoom->info.rstr() << sepType; fflush(stdout); } } } } } // get a list of all monsters if((dir = opendir(MONPATH)) != NULL) { while((dirp = readdir(dir)) != NULL) { if(dirp->d_name[0] == '.') continue; filename = MONPATH; filename += dirp->d_name; filename += "/"; if((subdir = opendir(filename.c_str())) != NULL) { while((dirq = readdir(subdir)) != NULL) { if(dirq->d_name[0] != 'r') continue; filename = MONPATH; filename += dirp->d_name; filename += "/"; filename += dirq->d_name; if(!loadMonsterFromFile(placeholder, &monster, filename)) continue; // we check origin and target already, so forget about it here if(monster->moveRoom(mrOrigin, mrTarget)) { std::cout << "m" << monster->info.rstr() << sepType; fflush(stdout); } free_crt(monster); } } } } // get a list of all area rooms for(aIt = areas.begin(); aIt != areas.end() ; aIt++) { for(rIt = (*aIt)->rooms.begin(); rIt != (*aIt)->rooms.end() ; rIt++) { aRoom = (*rIt).second; if(aRoom->moveRoom(mrOrigin, mrTarget)) { std::cout << "a" << aRoom->mapmarker.str() << sepType; fflush(stdout); } } } } // gets output from offlineMoveRoom void Config::offlineMoveRoom(Server::childProcess &child, bool onReap) { if(!movingRoom) return; Player* player = gServer->findPlayer(child.extra.c_str()); bstring toProcess = gServer->simpleChildRead(child); if(toProcess != "") { Room *uRoom=0; Monster *monster=0; CatRef cr; bstring input; charTokenizer::iterator it; boost::char_separator<char> sep(sepType); charTokenizer tok(toProcess, sep); // load the rooms as we go // last one will always be loaded in target for(it = tok.begin() ; it != tok.end() ; it++) { input = *it; moveRoomLog(input); if(input.getAt(0) == 'r') { getCatRef(input.right(input.getLength()-1), &cr, 0); // this will put rooms in the queue loadRoom(cr, &uRoom); } else if(input.getAt(0) == 'm') { getCatRef(input.right(input.getLength()-1), &cr, 0); // this will put monsters in the queue if(loadMonster(cr, &monster)) free_crt(monster); } } } if(onReap) moveRoom(player, child.extra); } //********************************************************************* // moveRoom //********************************************************************* void Config::moveRoom(Player* player, bstring name) { std::map<bstring, rsparse>::iterator rIt; std::list<bstring>::iterator bIt; std::list<RoomSwap>::iterator qIt; Room *uOrigin=0, *uTarget=0; bool found=false; if(player) player->printColor("^YRS: ^eSearch complete. Beginning final sequence.\n"); // clear this now or it interferes with saving below movingRoom = false; // loop through each area found = false; std::list<Area*>::iterator aIt; for(aIt = areas.begin() ; aIt != areas.end() ; aIt++) { if((*aIt)->moveRoom(mrOrigin, mrTarget)) found = true; } if(found) saveAreas(false); // loop through each starting location found = false; std::map<bstring, StartLoc*>::iterator lIt; for(lIt = start.begin() ; lIt != start.end() ; lIt++) { if((*lIt).second->moveRoom(mrOrigin, mrTarget)) { if(player) player->printColor("^GRS: Be sure to update the starting locations file for %s.\n", (*lIt).second->getName().c_str()); found = true; } } if(found) saveStartLocs(); // loop through each ship // TODO: Dom: midnight ship file? found = false; std::list<Ship*>::iterator sIt; for(sIt = ships.begin() ; sIt != ships.end() ; sIt++) { if((*sIt)->moveRoom(mrOrigin, mrTarget)) { if(player) player->printColor("^GRS: Be sure to update the midnight ship file for %s.\n", (*sIt)->name.c_str()); found = true; } } if(found) saveShips(); // loop through catrefinfo found = false; std::list<CatRefInfo*>::iterator cIt; for(cIt = catRefInfo.begin() ; cIt != catRefInfo.end() ; cIt++) { if((*cIt)->moveRoom(mrOrigin, mrTarget)) { if(player) player->printColor("^GRS: Be sure to update the catrefinfo file for %s.\n", (*cIt)->area.c_str()); found = true; } } if(found) saveCatRefInfo(); // check all players online std::pair<bstring, Player*> p; Player* ply=0; foreach(p, gServer->players) { ply = p.second; if(ply->moveRoom(mrOrigin, mrTarget)) ply->save(true); moveRoomList.remove((bstring)"p" + ply->name); } // remove the swapped rooms from the queue if(roomInQueue(mrOrigin)) { getRoomQueue(mrOrigin, &uOrigin); delRoomQueue(mrOrigin); } if(roomInQueue(mrTarget)) { getRoomQueue(mrTarget, &uTarget); delRoomQueue(mrTarget); } else { // the original room won't exist anymore unlink(roomPath(mrOrigin)); } // readd them to the queue under their new names // DO NOT update now: the loop just after this will do it if(uOrigin) addRoomQueue(mrTarget, &uOrigin); if(uTarget) addRoomQueue(mrOrigin, &uTarget); // go through players, rooms, and arearooms saved while the offline search // was running, also includes results of the offline search for(bIt = moveRoomList.begin() ; bIt != moveRoomList.end() ; bIt++) moveRoom(*bIt); for(qIt = moveRoomQueue.begin() ; qIt != moveRoomQueue.end() ; qIt++) (*qIt).moveRoom(mrOrigin, mrTarget); found = false; if(player) { if(player->room == mrOrigin || player->room == mrTarget) display_rom(player); player->printColor("^YRS: Room swap complete.\n"); found = true; } else loadPlayer(name.c_str(), &player); if(player) log_immort(true, player, "%s has finished swapping %s with %s.\n", name.c_str(), mrOrigin.str().c_str(), mrTarget.str().c_str()); else broadcast(isStaff, "^y%s has finished swapping %s with %s.", name.c_str(), mrOrigin.str().c_str(), mrTarget.str().c_str()); if(!found && player) free_crt(player); endMoveRoom(); } //********************************************************************* // RoomSwap //********************************************************************* RoomSwap::RoomSwap() { player = ""; } bool RoomSwap::moveRoom(CatRef o, CatRef t) { bool found=false; if(origin == o) { origin = t; found = true; } else if(origin == t) { origin = t; found = true; } if(target == o) { target = t; found = true; } else if(target == t) { target = t; found = true; } return(found); } //********************************************************************* // moveRoomChecks //********************************************************************* bool Config::moveRoomChecks(Player* player, CatRef origin, CatRef target) { if(moveRoomRestrictedArea(origin.area)) { if(player) player->printColor("^YRS: ^RError: ^x""%s"" is a restricted range. You cannot swap unique rooms into or out of that area.\n", origin.area.c_str()); return(false); } if(moveRoomRestrictedArea(target.area)) { if(player) player->printColor("^YRS: ^RError: ^x""%s"" is a restricted range. You cannot swap unique rooms into or out of that area.\n", target.area.c_str()); return(false); } if(target == origin) { if(player) player->printColor("^YRS: ^RError: ^xYou cannot swap a room with itself!\n"); return(false); } if(!origin.id) { if(player) player->printColor("^YRS: ^RError: ^xYou cannot move The Void (room 0).\n"); return(false); } if(!target.id) { if(player) player->printColor("^YRS: ^RError: ^xYou cannot swap a room with The Void (room 0).\n"); return(false); } return(true); } //********************************************************************* // checkSpecialArea //********************************************************************* bool Config::checkSpecialArea(CatRef origin, CatRef target, int (CatRefInfo::*toCheck), Player* player, bool online, bstring type) { Location l = getSpecialArea(toCheck, origin); bool t = origin == l.room; if(t || target == l.room) { if(online) { player->printColor("^YRS: ^RError: ^xRoom (%s) room is set as a %s Room under CatRefInfo.\n", t ? origin.str().c_str() : target.str().c_str(), type.c_str()); player->print("It cannot be moved out of its area.\n"); } else free_crt(player); endMoveRoom(); return(false); } return(true); } //********************************************************************* // moveRoom //********************************************************************* void Config::moveRoom(bstring str) { char type = str.getAt(0); str = str.right(str.getLength()-1); if(type == 'p' || type == 'b') { // at this point, the player will always be offline Player* player=0; LoadType saveType = type == 'p' ? LS_NORMAL : LS_BACKUP; if(!loadPlayer(str.c_str(), &player, saveType)) return; if(player->moveRoom(mrOrigin, mrTarget)) player->save(false, saveType); free_crt(player); } else if(type == 'm') { // the monster should have been loaded into the queue by now Monster* monster=0; CatRef cr; getCatRef(str, &cr, 0); if(!loadMonster(cr, &monster)) return; if(monster->moveRoom(mrOrigin, mrTarget)) monster->saveToFile(); free_crt(monster); } else if(type == 'r') { // the room should have been loaded into the queue by now Room* uRoom=0; CatRef cr; getCatRef(str, &cr, 0); if(!loadRoom(cr, &uRoom)) return; if(uRoom->moveRoom(mrOrigin, mrTarget)) uRoom->saveToFile(0); } else if(type == 'a') { // arearooms are always in memory Area *area=0; AreaRoom* aRoom=0; MapMarker m; m.load(str); area = gConfig->getArea(m.getArea()); if(!area) return; aRoom = area->loadRoom(0, &m, false); if(!aRoom) return; if(aRoom->moveRoom(mrOrigin, mrTarget)) aRoom->save(); } } //********************************************************************* // moveRoomLog //********************************************************************* // record players and rooms that are saved during roomMove void Config::moveRoomLog(const bstring log, bool external) { char type = log.getAt(0); if(type == 'b' || type == 'p' || type == 'm' || type == 'r' || type == 'a') { Player* player = gServer->findPlayer(gServer->moveRoomName().c_str()); if(player) player->printColor("^%cRS: ^eReceiving %s%s%s.\n", external ? 'M' : 'Y', type == 'm' ? "Monster " : "", log.right(log.getLength()-1).c_str(), type == 'b' ? " (backup)" : ""); moveRoomList.remove(log); moveRoomList.push_back(log); } } bool Config::moveRoomRestrictedArea(bstring area) const { return(area == "area" || area == "stor" || area == "shop" || area == "guild"); } //********************************************************************* // movingRoom functions //********************************************************************* bool Config::isMovingRoom() const { return(movingRoom); } void Config::setMovingRoom(CatRef o, CatRef t) { movingRoom = true; mrOrigin = o; mrTarget = t; } //********************************************************************* // moveRoomName //********************************************************************* bstring Server::moveRoomName() { foreach(childProcess & child, children) if(child.type == CHILD_MOVEROOM_FIND || child.type == CHILD_MOVEROOM_FINISH) return(child.extra); return("Someone"); } //********************************************************************* // endMoveRoom //********************************************************************* void Server::endMoveRoom() { std::list<childProcess>::iterator it; for(it = children.begin(); it != children.end() ;) { if((*it).type == CHILD_MOVEROOM_FIND || (*it).type == CHILD_MOVEROOM_FINISH) { close((*it).fd); kill((*it).pid, 9); it = children.erase(it); } else it++; } } void Config::endMoveRoom(int id) { if(id <= 1) { roomSearchFailure = false; movingRoom = false; moveRoomList.clear(); mrTarget.id = 0; moveRoomNextInQueue(); return; } std::list<RoomSwap>::iterator qIt; int i=1; for(qIt = moveRoomQueue.begin() ; qIt != moveRoomQueue.end() ; qIt++) { if(++i==id) { moveRoomQueue.erase(qIt); return; } } } //********************************************************************* // moveRoomInfo //********************************************************************* void Config::moveRoomInfo(Player* player) { player->printColor("^WRoomswap Config Info\n"); player->printColor(" Moving Room: %s\n", movingRoom ? "^gYes" : "^rNo"); player->printColor(" Queue Size: ^c%d\n", RSWAP_QUEUE_LIMIT); player->print(" Data In Memory:\n"); std::list<bstring>::iterator bIt; for(bIt = moveRoomList.begin() ; bIt != moveRoomList.end() ; bIt++) { player->printColor(" ^e%s%s\n", (*bIt).right((*bIt).getLength()-1).c_str(), (*bIt).getAt(0) == 'b' ? " (backup)" : ""); } std::list<RoomSwap>::iterator qIt; int id=1; player->print(" The Queue:\n"); for(qIt = moveRoomQueue.begin() ; qIt != moveRoomQueue.end() ; qIt++) { player->printColor(" %d) Player: ^e%s^x Origin: ^e%s^x Target: ^e%s\n", ++id, (*qIt).player.c_str(), (*qIt).origin.str().c_str(), (*qIt).target.id == -1 ? (*qIt).target.area.c_str() : (*qIt).target.str().c_str()); } } void Server::moveRoomInfo(Player* player) { player->printColor("^WRoomswap Server Info\n"); player->print(" Child Processes Being Watched:\n"); foreach(childProcess & child, children) { if(child.type == CHILD_MOVEROOM_FIND || child.type == CHILD_MOVEROOM_FINISH) { player->printColor(" Player: ^e%s^x Pid: ^e%d^x Fd: ^e%d^x Purpose: ^e%s\n", child.extra.c_str(), child.pid, child.fd, child.type == CHILD_MOVEROOM_FIND ? "Finding next empty room." : "Finding things that need updating."); } } } //********************************************************************* // moveRoom queue functions //********************************************************************* void Config::moveRoomEmptyQueue() { moveRoomQueue.clear(); } int Config::moveRoomQueueSize() { return(moveRoomQueue.size()); } void Config::moveRoomNextInQueue() { if(moveRoomQueue.empty()) return; RoomSwap rs = moveRoomQueue.front(); moveRoomQueue.pop_front(); gServer->moveRoom(rs.player, rs.origin, rs.target); } void Config::moveRoomAddQueue(bstring mover, CatRef origin, CatRef target) { RoomSwap rs; rs.player = mover; rs.origin = origin; rs.target = target; moveRoomQueue.push_back(rs); } bool Config::moveRoomInQueue(CatRef origin, bool checkTarget) { std::list<RoomSwap>::iterator it; for(it = moveRoomQueue.begin() ; it != moveRoomQueue.end() ; it++) { if(origin == (*it).origin) return(true); if(checkTarget && origin == (*it).target) return(true); } return(false); } //********************************************************************* // moveRoomAbort //********************************************************************* void Config::moveRoomAbort() { moveRoomEmptyQueue(); gServer->endMoveRoom(); endMoveRoom(); } //********************************************************************* // moveRoom for various classes //********************************************************************* // update everything on the player when moving a room bool Player::moveRoom(CatRef origin, CatRef target) { bool found=false; if(bound.room == origin) { bound.room = target; found = true; } else if(bound.room == target) { bound.room = origin; found = true; } if(room == origin) { room = target; found = true; } else if(room == target) { room = origin; found = true; } for(int i=0; i<MAX_DIMEN_ANCHORS; i++) { if(anchor[i]) { if(anchor[i]->getRoom() == origin) { anchor[i]->setRoom(target); found = true; } else if(anchor[i]->getRoom() == target) { anchor[i]->setRoom(origin); found = true; } } } std::list<CatRef>::iterator it; for(it = roomExp.begin() ; it != roomExp.end() ; it++) { if(*it == origin) { *it = target; found = true; } else if(*it == target) { *it = origin; found = true; } } return(found); } // update everything on the player when moving a room bool Monster::moveRoom(CatRef origin, CatRef target) { bool found=false; if(jail == origin) { jail = target; found = true; } else if(jail == target) { jail = origin; found = true; } if(room == origin) { room = target; found = true; } else if(room == target) { room = origin; found = true; } return(found); } // update any room with links to the origin room (including the origin) bool Room::moveRoom(CatRef origin, CatRef target) { bool found=false; if(info == origin || info == target) { CatRef nOrigin, nTarget; if(info == origin) { nOrigin = origin; nTarget = target; } else { nOrigin = target; nTarget = origin; } // if shop relies on next room for storage if(flagIsSet(R_SHOP) && !trapexit.id) { // manually set trapexit = info; trapexit.id++; } info = nTarget; found = true; } Monster* monster=0; ctag* cp = first_mon; while(cp) { monster = cp->crt->getMonster(); cp = cp->next_tag; if(monster->moveRoom(origin, target)) found = true; } if(trapexit == origin) { trapexit = target; found = true; } else if(trapexit == target) { trapexit = origin; found = true; } xtag *xp = first_ext; while(xp) { if(xp->ext->target.room == origin) { xp->ext->target.room = target; found = true; } else if(xp->ext->target.room == target) { xp->ext->target.room = origin; found = true; } xp = xp->next_tag; } return(found); } // update any arearoom with links to the origin bool AreaRoom::moveRoom(CatRef origin, CatRef target) { bool found=false; if(unique == origin) { unique = target; found = true; } else if(unique == target) { unique = origin; found = true; } xtag *xp = first_ext; while(xp) { if(xp->ext->target.room == origin) { xp->ext->target.room = target; found = true; } else if(xp->ext->target.room == target) { xp->ext->target.room = origin; found = true; } xp = xp->next_tag; } Monster* monster=0; ctag* cp = first_mon; while(cp) { monster = cp->crt->getMonster(); cp = cp->next_tag; if(monster->moveRoom(origin, target)) found = true; } return(found); } // update any zones that link to the origin bool AreaZone::moveRoom(CatRef origin, CatRef target) { bool found=false; if(unique == origin) { unique = target; found = true; } else if(unique == target) { unique = origin; found = true; } return(found); } // handle all zones in the area bool Area::moveRoom(CatRef origin, CatRef target) { std::map<bstring, AreaRoom*>::iterator rIt; std::list<AreaZone*>::iterator zIt; bool found=false; for(zIt = zones.begin() ; zIt != zones.end() ; zIt++) { if((*zIt)->moveRoom(origin, target)) found = true; } return(found); } // handle all the exits at this raid bool ShipRaid::moveRoom(CatRef origin, CatRef target) { bool found=false; if(prison == origin) { prison = target; found = true; } else if(prison == target) { prison = origin; found = true; } if(dump == origin) { dump = target; found = true; } else if(dump == target) { dump = origin; found = true; } return(found); } // handle all the exits at this ship exit bool ShipExit::moveRoom(CatRef o, CatRef t) { bool found=false; if(origin.room == o) { origin.room = t; found = true; } else if(origin.room == t) { origin.room = o; found = true; } if(target.room == o) { target.room = t; found = true; } else if(target.room == t) { target.room = o; found = true; } return(found); } // handle all exits at stop, as well as raids bool ShipStop::moveRoom(CatRef origin, CatRef target) { std::list<ShipExit*>::iterator it; bool found=false; for(it = exits.begin() ; it != exits.end() ; it++) { if((*it)->moveRoom(origin, target)) found = true; } if(raid && raid->moveRoom(origin, target)) found = true; return(found); } // handle all stops the ship makes bool Ship::moveRoom(CatRef origin, CatRef target) { std::list<ShipStop*>::iterator it; bool found=false; for(it = stops.begin() ; it != stops.end() ; it++) { if((*it)->moveRoom(origin, target)) found = true; } return(found); } bool StartLoc::moveRoom(CatRef origin, CatRef target) { bool found=false; if(bind.room == origin) { bind.room = target; found = true; } else if(bind.room == target) { bind.room = origin; found = true; } if(required.room == origin) { required.room = target; found = true; } else if(required.room == target) { required.room = origin; found = true; } return(found); } bool CatRefInfo::moveRoom(CatRef origin, CatRef target) { bool found=false; if(origin.isArea(area) && limbo == origin.id) { limbo = target.id; found = true; } else if(target.isArea(area) && limbo == target.id) { limbo = origin.id; found = true; } if(origin.isArea(area) && recall == origin.id) { recall = target.id; found = true; } else if(target.isArea(area) && recall == target.id) { recall = origin.id; found = true; } return(found); }