/* * ships.c * Moving exits and such * ____ _ * | _ \ ___ __ _| |_ __ ___ ___ * | |_) / _ \/ _` | | '_ ` _ \/ __| * | _ < __/ (_| | | | | | | \__ \ * |_| \_\___|\__,_|_|_| |_| |_|___/ * * 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 "move.h" #include "ships.h" #include "calendar.h" #include "commands.h" #include <sstream> #define PIRATE_QUEST 54 - 1 // Notes: // If you mess up the data up, you'll never know what time the ship // will be at the docks. You will need to check that ALL of the time // spent at stops / time spent traveling adds up to some 24 hour // increment or divides into 24. // For example, if it adds up to 25, you'll get: // stop 1, day 1: 8am // stop 1, day 2: 9am // stop 1, day 3: 10am //********************************************************************* // shipBroadcastRange //********************************************************************* // given a ShipStop and a message, we'll announce it to the // mud (appropriate rooms) bool ShipStop::belongs(CatRef cr) { std::list<Range>::iterator rt; for(rt = announce.begin() ; rt != announce.end() ; rt++) if((*rt).belongs(cr)) return(true); return(false); } bool Ship::belongs(CatRef cr) { std::list<Range>::iterator rt; for(rt = ranges.begin() ; rt != ranges.end() ; rt++) if((*rt).belongs(cr)) return(true); return(false); } void shipBroadcastRange(Ship *ship, ShipStop *stop, bstring message) { if(message == "") return; // if our announce range isnt there, announce to everyone and quit if(stop->announce.empty()) { broadcast("%s", message.c_str()); return; } std::pair<bstring, Player*> p; Player* target=0; // otherwise go through each player foreach(p, gServer->players) { target = p.second; if(!target->isConnected()) continue; if(!target->parent_rom) continue; if( ship->belongs(target->parent_rom->info) || stop->belongs(target->parent_rom->info) ) target->print("%s\n", message.c_str()); } } //********************************************************************* // spawnRaiders //********************************************************************* // run through the exits declared as Raid and spawn some raiders! void ShipExit::spawnRaiders(ShipRaid* sRaid) { Monster *raider=0; BaseRoom *room=0; int l=0, total=0; if(name == "" || !raid || !origin.getId() || !target.getId()) return; if(!loadMonster(sRaid->getSearchMob(), &raider)) return; room = getRoom(false); if(!room) { free_crt(raider); return; } if(!raider->flagIsSet(M_CUSTOM)) raider->validateAc(); if(!raider->name[0] || raider->name[0] == ' ') { free_crt(raider); return; } total = mrand(sRaid->getMinSpawnNum(), sRaid->getMaxSpawnNum()); for(l=0; l<total;) { raider->initMonster(true, false); if(!l) raider->addToRoom(room, total); else raider->addToRoom(room, 0); raider->setFlag(M_PERMENANT_MONSTER); raider->setFlag(M_RAIDING); gServer->addActive(raider); l++; if(l < total) loadMonster(sRaid->getSearchMob(), &raider); } } //********************************************************************* // getRoom //********************************************************************* BaseRoom* ShipExit::getRoom(bool useOrigin) { if(useOrigin) return(origin.loadRoom()); return(target.loadRoom()); } //********************************************************************* // spawnRaiders //********************************************************************* // run through the exits declared as Raid and spawn some raiders! void ShipStop::spawnRaiders() { std::list<ShipExit*>::iterator xt; if(!raid || !raid->getSearchMob()) return; for(xt = exits.begin() ; xt != exits.end() ; xt++) (*xt)->spawnRaiders(raid); } //********************************************************************* // createExit //********************************************************************* // creates the exits for the ShipExit it's given // it also takes care of announcing the ship's arrival bool ShipExit::createExit() { xtag *xp=0; BaseRoom* newRoom=0; int i=0; if(name == "" || !origin.getId() || !target.getId()) return(false); newRoom = getRoom(true); if(!newRoom) return(false); link_rom(newRoom, target, name); xp = newRoom->first_ext; while(xp) { if(!strcmp(xp->ext->name, name.c_str())) { zero(xp->ext->flags, sizeof(xp->ext->flags)); // TODO: Dom: needs to use getFlags() and setFlags() for(i=sizeof(xp->ext->flags)-1; i>=0; i--) xp->ext->flags[i] = flags[i]; xp->ext->setFlag(X_MOVING); if(arrives != "") broadcast(NULL, newRoom, "%s", arrives.c_str()); return(true); } xp = xp->next_tag; } return(false); } // hand on that responsibility! // but do broadcasting and raider-spawning int shipSetExits(Ship *ship, ShipStop *stop) { std::list<ShipExit*>::iterator exit; bool broad = false; for(exit = stop->exits.begin() ; exit != stop->exits.end() ; exit++) broad = (*exit)->createExit() || broad; if(broad) shipBroadcastRange(ship, stop, stop->arrives); stop->spawnRaiders(); return(0); } //********************************************************************* // removeExit //********************************************************************* // Given a ship exits, it will delete the appropriate moving exits. // Will also cause raiders to wander away. void ShipExit::removeExit() { Monster *raider=0; ctag *cp=0; BaseRoom* newRoom=0; AreaRoom* aRoom=0; Exit *xt=0; xtag *xp=0; int i=0, n=0; newRoom = getRoom(true); if(!newRoom) return; // kill all raiders cp = newRoom->first_mon; while(cp) { raider = cp->crt->getMonster(); cp = cp->next_tag; if(raider && raider->flagIsSet(M_RAIDING)) { broadcast(NULL, newRoom, "%1M just %s away.", raider, Move::getString(raider).c_str()); gServer->delActive(raider); raider->deleteFromRoom(); raider->clearAsEnemy(); free_crt(raider); } } if(departs != "") broadcast(NULL, newRoom, "%s", departs.c_str()); aRoom = newRoom->getAreaRoom(); xp = newRoom->first_ext; while(xp) { xt = xp->ext; xp = xp->next_tag; // if we're given an exit, delete it // otherwise delete all exits if(xt->flagIsSet(X_MOVING) && !strcmp(xt->name, name.c_str()) ) { //oldPrintColor(4, "^rDeleting^w exit %s in room %d.\n", xt->name, room); if(i < 8 && aRoom) { // it's a cardinal direction, clear all flags for(n=0; n<MAX_EXIT_FLAGS; n++) xt->clearFlag(n); xt->target.room.id = 0; aRoom->updateExits(); } else del_exit(newRoom, xt->name); } i++; } } // hand on that responsibility! // but do broadcasting and kicking people off a raiding vessel int shipDeleteExits(Ship *ship, ShipStop *stop) { std::list<ShipExit*>::iterator exit; Monster *raider=0; Room *room=0, *newRoom=0; int found=1; char output[160]; if(stop->raid) { // record when the last pirate raid was if(stop->raid->getRecord()) gConfig->calendar->setLastPirate(ship->name); // kick people off the ship! if( stop->raid->getSearchMob() && (stop->raid->getDump().id || stop->raid->getPrison().id) && loadMonster(stop->raid->getSearchMob(), &raider) ) { std::pair<bstring, Player*> p; Player* ply; // otherwise go through each player foreach(p, gServer->players) { ply = p.second; if(!ply->isConnected()) continue; if(ply->isStaff()) continue; if(!ply->parent_rom) continue; if(!ship->belongs(ply->parent_rom->info)) continue; if(!loadRoom(ply->parent_rom->info, &room)) continue; if(!room->wander.getTraffic()) continue; found = 1; sprintf(output, "%s just arrived.\n", crt_str(raider, 1, 0 | CAP)); ply->print(output); ply->sendPrompt(); // you can't see me! if(!raider->canSee(ply)) found = 0; // if they're hidden - look for them! if(found && ply->flagIsSet(P_HIDDEN)) { found = 0; sprintf(output, "%s searches the room.\n", crt_str(raider, 0, 0 | CAP | NONUM)); ply->print(output); if(mrand(1,100) <= SHIP_SEARCH_CHANCE) { found = 1; ply->unhide(); sprintf(output, "%s found something!\n", raider->upHeShe()); ply->print(output); } ply->sendPrompt(); } if(!found) { sprintf(output, "%s wanders away.\n", crt_str(raider, 0, 0 | CAP | NONUM)); ply->print(output); ply->sendPrompt(); continue; } ply->wake("You awaken suddenly!"); if( stop->raid->getDump().id && !(ply->isUnconscious() && stop->raid->getUnconInPrison()) && loadRoom(stop->raid->getDump(), &newRoom) ) { if(stop->raid->getDumpTalk() != "") { sprintf(output, "%s says to you, \"%s\".\n", crt_str(raider, 0, 0 | CAP | NONUM), stop->raid->getDumpTalk().c_str()); ply->print(output); } if(stop->raid->getDumpAction() != "") { if(stop->raid->getDumpTalk() != "") ply->sendPrompt(); sprintf(output, stop->raid->getDumpAction().c_str(), crt_str(raider, 0, 0 | CAP | NONUM)); strcat(output, "\n"); ply->print(output); } ply->deleteFromRoom(); ply->addToRoom(newRoom); ply->doPetFollow(); } else if(stop->raid->getPrison().id && loadRoom(stop->raid->getPrison(), &newRoom) ) { if(stop->raid->getPrisonTalk() != "") { sprintf(output, "%s says to you, \"%s\".\n", crt_str(raider, 0, 0 | CAP | NONUM), stop->raid->getPrisonTalk().c_str()); ply->print(output); } if(stop->raid->getPrisonAction() != "") { if(stop->raid->getPrisonTalk() != "") ply->sendPrompt(); sprintf(output, stop->raid->getPrisonAction().c_str(), crt_str(raider, 0, 0 | CAP | NONUM)); strcat(output, "\n"); ply->print(output); } ply->deleteFromRoom(); ply->addToRoom(newRoom); ply->doPetFollow(); } broadcast(NULL, room, "%M was hauled off by %N.", ply, raider); } free_crt(raider); } } for(exit = stop->exits.begin() ; exit != stop->exits.end() ; exit++) (*exit)->removeExit(); shipBroadcastRange(ship, stop, stop->departs); return(0); } // ___...---...___...---...___...--- // ShipRaid // ___...---...___...---...___...--- ShipRaid::ShipRaid() { searchMob = raidMob = minSpawnNum = maxSpawnNum = record = 0; dumpTalk = prisonTalk = dumpAction = prisonAction = ""; unconInPrison = false; } void ShipRaid::load(xmlNodePtr curNode) { xmlNodePtr childNode = curNode->children; while(childNode) { if(NODE_NAME(childNode, "Record")) xml::copyToBool(record, childNode); else if(NODE_NAME(childNode, "SearchMob")) xml::copyToNum(searchMob, childNode); else if(NODE_NAME(childNode, "RaidMob")) xml::copyToNum(raidMob, childNode); else if(NODE_NAME(childNode, "MinSpawnNum")) xml::copyToNum(minSpawnNum, childNode); else if(NODE_NAME(childNode, "MaxSpawnNum")) xml::copyToNum(maxSpawnNum, childNode); else if(NODE_NAME(childNode, "Dump")) dump.load(childNode); else if(NODE_NAME(childNode, "Prison")) prison.load(childNode); else if(NODE_NAME(childNode, "DumpTalk")) xml::copyToBString(dumpTalk, childNode); else if(NODE_NAME(childNode, "PrisonTalk")) xml::copyToBString(prisonTalk, childNode); else if(NODE_NAME(childNode, "DumpAction")) xml::copyToBString(dumpAction, childNode); else if(NODE_NAME(childNode, "PrisonAction")) xml::copyToBString(prisonAction, childNode); else if(NODE_NAME(childNode, "UnconInPrison")) xml::copyToBool(unconInPrison, childNode); childNode = childNode->next; } minSpawnNum = MAX(0, minSpawnNum); if(maxSpawnNum < minSpawnNum) maxSpawnNum = minSpawnNum; } void ShipRaid::save(xmlNodePtr curNode) const { xml::saveNonZeroNum(curNode, "Record", record); xml::saveNonZeroNum(curNode, "SearchMob", searchMob); xml::saveNonZeroNum(curNode, "RaidMob", raidMob); xml::saveNonZeroNum(curNode, "MinSpawnNum", minSpawnNum); xml::saveNonZeroNum(curNode, "MaxSpawnNum", maxSpawnNum); dump.save(curNode, "Dump", false); prison.save(curNode, "Prison", false); xml::saveNonNullString(curNode, "DumpTalk", dumpTalk); xml::saveNonNullString(curNode, "PrisonTalk", prisonTalk); xml::saveNonNullString(curNode, "DumpAction", dumpAction); xml::saveNonNullString(curNode, "PrisonAction", prisonAction); xml::saveNonZeroNum(curNode, "UnconInPrison", unconInPrison); } // get functions int ShipRaid::getRecord() const { return(record); } int ShipRaid::getSearchMob() const { return(searchMob); } int ShipRaid::getRaidMob() const { return(raidMob); } int ShipRaid::getMinSpawnNum() const { return(minSpawnNum); } int ShipRaid::getMaxSpawnNum() const { return(maxSpawnNum); } CatRef ShipRaid::getDump() const { return(dump); } CatRef ShipRaid::getPrison() const { return(prison); } bstring ShipRaid::getDumpTalk() const { return(dumpTalk); } bstring ShipRaid::getPrisonTalk() const { return(prisonTalk); } bstring ShipRaid::getDumpAction() const { return(dumpAction); } bstring ShipRaid::getPrisonAction() const { return(prisonAction); } bool ShipRaid::getUnconInPrison() const { return(unconInPrison); } // ___...---...___...---...___...--- // ShipExit // ___...---...___...---...___...--- ShipExit::ShipExit() { raid = 0; zero(flags, sizeof(flags)); name = ""; arrives = ""; departs = ""; } bstring ShipExit::getName() const { return(name); } bool ShipExit::getRaid() const { return(raid); } bstring ShipExit::getArrives() const { return(arrives); } bstring ShipExit::getDeparts() const { return(departs); } const char *ShipExit::getFlags() const { return(flags); } void ShipExit::setFlags(char f) { int i = sizeof(flags); char tmp[i]; zero(tmp, i); *(tmp) = f; for(i--; i>=0; i--) flags[i] = tmp[i]; } void ShipExit::save(xmlNodePtr curNode) const { xml::saveNonNullString(curNode, "Name", name); origin.save(curNode, "Origin"); target.save(curNode, "Target"); saveBits(curNode, "Flags", MAX_EXIT_FLAGS, flags); xml::saveNonNullString(curNode, "Arrives", arrives); xml::saveNonNullString(curNode, "Departs", departs); xml::saveNonZeroNum(curNode, "Raid", raid); } void ShipExit::load(xmlNodePtr curNode) { xmlNodePtr childNode = curNode->children; while(childNode) { if(NODE_NAME(childNode, "Name")) { xml::copyToBString(name, childNode); } else if(NODE_NAME(childNode, "Origin")) origin.load(childNode); else if(NODE_NAME(childNode, "Target")) target.load(childNode); else if(NODE_NAME(childNode, "Arrives")) xml::copyToBString(arrives, childNode); else if(NODE_NAME(childNode, "Departs")) xml::copyToBString(departs, childNode); else if(NODE_NAME(childNode, "Flags")) loadBits(childNode, flags); else if(NODE_NAME(childNode, "Raid")) raid = true; childNode = childNode->next; } } // ___...---...___...---...___...--- // ShipStop // ___...---...___...---...___...--- ShipStop::ShipStop() { name = arrives = lastcall = departs = ""; to_next = in_dock = 0; raid = 0; } ShipStop::~ShipStop() { ShipExit* exit=0; if(raid) delete raid; while(!exits.empty()) { exit = exits.front(); delete exit; exits.pop_front(); } exits.clear(); } void ShipStop::load(xmlNodePtr curNode) { xmlNodePtr childNode = curNode->children; while(childNode) { if(NODE_NAME(childNode, "Name")) { xml::copyToBString(name, childNode); } else if(NODE_NAME(childNode, "Arrives")) { xml::copyToBString(arrives, childNode); } else if(NODE_NAME(childNode, "LastCall")) { xml::copyToBString(lastcall, childNode); } else if(NODE_NAME(childNode, "Departs")) { xml::copyToBString(departs, childNode); } else if(NODE_NAME(childNode, "ToNext")) xml::copyToNum(to_next, childNode); else if(NODE_NAME(childNode, "InDock")) xml::copyToNum(in_dock, childNode); else if(NODE_NAME(childNode, "Raid")) { raid = new ShipRaid; raid->load(childNode); } else if(NODE_NAME(childNode, "Exits")) loadExits(childNode); else if(NODE_NAME(childNode, "AnnounceRange")) { xmlNodePtr subNode = childNode->children; while(subNode) { if(NODE_NAME(subNode, "Range")) { Range r; r.load(subNode); announce.push_back(r); } subNode = subNode->next; } } childNode = childNode->next; } } void ShipStop::loadExits(xmlNodePtr curNode) { xmlNodePtr childNode = curNode->children; ShipExit *exit=0; while(childNode) { if(NODE_NAME(childNode, "Exit")) { exit = new ShipExit; exit->load(childNode); if(exit->origin.room.id || exit->origin.mapmarker.getArea()) exit->removeExit(); exits.push_back(exit); } childNode = childNode->next; } } void ShipStop::save(xmlNodePtr rootNode) const { xmlNodePtr curNode, childNode, xchildNode; curNode = xml::newStringChild(rootNode, "Stop"); xml::saveNonNullString(curNode, "Name", name); xml::saveNonZeroNum(curNode, "InDock", in_dock); xml::saveNonZeroNum(curNode, "ToNext", to_next); xml::saveNonNullString(curNode, "Arrives", arrives); xml::saveNonNullString(curNode, "LastCall", lastcall); xml::saveNonNullString(curNode, "Departs", departs); if(raid) { childNode = xml::newStringChild(curNode, "Raid"); raid->save(childNode); } childNode = xml::newStringChild(curNode, "Exits"); std::list<ShipExit*>::const_iterator exit; for(exit = exits.begin() ; exit != exits.end() ; exit++) { xchildNode = xml::newStringChild(childNode, "Exit"); (*exit)->save(xchildNode); } if(!announce.empty()) { childNode = xml::newStringChild(curNode, "AnnounceRange"); std::list<Range>::const_iterator rt; for(rt = announce.begin() ; rt != announce.end() ; rt++) (*rt).save(childNode, "Range"); } } // ___...---...___...---...___...--- // Ship // ___...---...___...---...___...--- Ship::Ship() { timeLeft = clan = 0; name = transit = movement = docked = ""; inPort = canQuery = false; } Ship::~Ship() { ShipStop* stop=0; while(!stops.empty()) { stop = stops.front(); delete stop; stops.pop_front(); } stops.clear(); } void Ship::load(xmlNodePtr curNode) { xmlNodePtr childNode = curNode->children; int at_stop=0, stop=0; while(childNode) { if(NODE_NAME(childNode, "Name")) xml::copyToBString(name, childNode); else if(NODE_NAME(childNode, "Clan")) xml::copyToNum(clan, childNode); else if(NODE_NAME(childNode, "Transit")) xml::copyToBString(transit, childNode); else if(NODE_NAME(childNode, "Movement")) xml::copyToBString(movement, childNode); else if(NODE_NAME(childNode, "Docked")) xml::copyToBString(docked, childNode); else if(NODE_NAME(childNode, "CanQuery")) xml::copyToBool(canQuery, childNode); else if(NODE_NAME(childNode, "InPort")) xml::copyToBool(inPort, childNode); else if(NODE_NAME(childNode, "TimeLeft")) xml::copyToNum(timeLeft, childNode); // at_stop is only used when loading - the cycling of the stops below // will put the stop pointed to by at_stop at the front. when it's saved, // it will load first else if(NODE_NAME(childNode, "AtStop")) xml::copyToNum(at_stop, childNode); else if(NODE_NAME(childNode, "BoatRange")) { xmlNodePtr subNode = childNode->children; while(subNode) { if(NODE_NAME(subNode, "Range")) { Range r; r.load(subNode); ranges.push_back(r); } subNode = subNode->next; } } else if(NODE_NAME(childNode, "Stops")) loadStops(childNode); childNode = childNode->next; } // now move what stop we're at to the front of the list while(stop < at_stop) { stop++; stops.push_back(stops.front()); stops.pop_front(); } } void Ship::loadStops(xmlNodePtr curNode) { xmlNodePtr childNode = curNode->children; ShipStop *stop=0; while(childNode) { if(NODE_NAME(childNode, "Stop")) { stop = new ShipStop; stop->load(childNode); stops.push_back(stop); } childNode = childNode->next; } } void Ship::save(xmlNodePtr rootNode) const { xmlNodePtr curNode, childNode; curNode = xml::newStringChild(rootNode, "Ship"); xml::saveNonNullString(curNode, "Name", name); xml::saveNonZeroNum(curNode, "Clan", clan); xml::saveNonZeroNum(curNode, "AtStop", 0); xml::saveNonZeroNum(curNode, "InPort", inPort); xml::saveNonZeroNum(curNode, "TimeLeft", timeLeft); xml::saveNonZeroNum(curNode, "CanQuery", canQuery); xml::saveNonNullString(curNode, "Transit", transit); xml::saveNonNullString(curNode, "Movement", movement); xml::saveNonNullString(curNode, "Docked", docked); if(!ranges.empty()) { childNode = xml::newStringChild(curNode, "BoatRange"); std::list<Range>::const_iterator rt; for(rt = ranges.begin() ; rt != ranges.end() ; rt++) (*rt).save(childNode, "Range"); } childNode = xml::newStringChild(curNode, "Stops"); std::list<ShipStop*>::const_iterator st; for(st = stops.begin() ; st != stops.end() ; st++) (*st)->save(childNode); } //********************************************************************* // shipPrintRange //********************************************************************* // used in dmQueryShips to print out the ranges void shipPrintRange(Player* player, std::list<Range>* list) { std::list<Range>::iterator rt; for(rt = list->begin() ; rt != list->end() ; rt++) player->print(" %s\n", (*rt).str().c_str()); } //********************************************************************* // dmQueryShips //********************************************************************* // dm command to show all information about ships int dmQueryShips(Player* player, cmd* cmnd) { int mod=0, id=0; std::list<Ship*>::iterator it; std::list<ShipStop*>::iterator st; std::list<ShipExit*>::iterator xt; Ship *ship=0; ShipStop *stop=0; ShipExit *exit=0; int shipID = atoi(getFullstrText(cmnd->fullstr, 1).c_str()); int stopID = atoi(getFullstrText(cmnd->fullstr, 2).c_str()); const Calendar* calendar = 0; if(!shipID) { calendar = gConfig->getCalendar(); player->print("Location of All Ships:\n"); player->printColor("^b-------------------------------------------------------------------------------\n"); id = 1; for(it = gConfig->ships.begin() ; it != gConfig->ships.end() ; it++) { ship = (*it); player->print(" %-25s %s", ship->name.c_str(), ship->inPort ? "Stopped at " : "In transit, going to "); st = ship->stops.begin(); stop = (*st); player->print("%s.\n #%-25dWill ", stop->name.c_str(), id); if(ship->inPort) { st++; stop = (*st); player->print("depart for %s", stop->name.c_str()); } else { player->print("arrive"); } player->print(" in "); mod = ship->timeLeft / 60; if(mod) player->print("%d hour%s%s", mod, mod==1 ? "" : "s", ship->timeLeft % 60 ? " " : ""); mod = ship->timeLeft % 60; if(mod) player->print("%d minute%s", mod, mod==1 ? "" : "s"); player->print(".\n"); id++; } player->print("\nType \"*ship [ship id]\" to view the details of a specific ship.\n"); player->printColor("Ship Updates: ^c%d^x / ^c%d^x Hour: ^c%d^x / ^c%d^x.\n", calendar->shipUpdates, gConfig->expectedShipUpdates(), calendar->shipUpdates % 60, gConfig->expectedShipUpdates() % 60); player->print("The last pirate raid was: %s\n\n", calendar->getLastPirate().c_str()); return(0); } mod = 1; // find the ship we're looking at for(it = gConfig->ships.begin() ; it != gConfig->ships.end() && mod != shipID ; it++) mod++; ship = (*it); if(!ship) { player->print("Invalid ship!\n"); return(0); } player->print("Information on %s:\n", ship->name.c_str()); player->printColor("^b-------------------------------------------------------------------------------\n"); stop = ship->stops.front(); player->print("In Port: %s\n", ship->inPort ? "Yes" : "No"); player->print("Time Left: %d minutes\n", ship->timeLeft); if(!stopID) { player->print("Can Query: %s\n", ship->canQuery ? "Yes" : "No"); if(ship->transit != "") player->print("Transit: %s\n", ship->transit.c_str()); if(ship->movement != "") player->print("Movement: %s\n", ship->movement.c_str()); if(ship->docked != "") player->print("Docked: %s\n", ship->docked.c_str()); player->print("\n"); // boat range player->print("Boat Ranges:\n"); shipPrintRange(player, &ship->ranges); player->print("\n"); player->print("Stops:\n"); id = 1; for(st = ship->stops.begin() ; st != ship->stops.end() ; st++) { stop = (*st); player->print("-----------------------\n"); player->print(" Stop: %d - %s\n", id, stop->name.c_str()); player->print(" Raid: %s\n", stop->raid ? "Yes" : "No"); player->print(" Exits:\n"); mod = 1; for(xt = stop->exits.begin() ; xt != stop->exits.end() ; xt++) { exit = (*xt); player->print(" Exit: %d - %s, room %s %s\n", mod, exit->getName().c_str(), exit->origin.room.str().c_str(), exit->origin.mapmarker.getArea() ? exit->origin.mapmarker.str().c_str() : ""); mod++; } player->print("\n"); id++; } player->print("Type \"*ship [ship id] [stop id]\" to view the details of a specific stop.\n\n"); } else { mod = 1; // find the stop we're looking at for(st = ship->stops.begin() ; st != ship->stops.end() && mod != stopID ; st++) mod++; stop = (*st); if(!stop) { player->print("Invalid stop!\n"); return(0); } player->print("Stop: %d - %s\n", id, stop->name.c_str()); player->print("In Dock: %d minutes\n", stop->in_dock); player->print("To Next: %d minutes\n\n", stop->to_next); if(stop->arrives != "") player->print("Arrives: %s\n", stop->arrives.c_str()); if(stop->lastcall != "") player->print("Last Call: %s\n", stop->lastcall.c_str()); if(stop->departs != "") player->print("Departs: %s\n", stop->departs.c_str()); if(stop->arrives != "" || stop->lastcall != "" || stop->departs != "") player->print("\n"); if(stop->raid) { player->print("Raid Info:\n-----------------------\n"); player->print("Record: %s\n", stop->raid->getRecord() ? "Yes" : "No"); player->print("Search Mob: %d\n", stop->raid->getSearchMob()); player->print("Dump Room: %s\n", stop->raid->getDump().str().c_str()); player->print("Prison Room: %s\n", stop->raid->getPrison().str().c_str()); if(stop->raid->getDumpTalk() != "") player->print("Dump Talk: %s\n", stop->raid->getDumpTalk().c_str()); if(stop->raid->getPrisonTalk() != "") player->print("Prison Talk: %s\n", stop->raid->getPrisonTalk().c_str()); if(stop->raid->getDumpAction() != "") player->print("Dump Action: %s\n", stop->raid->getDumpAction().c_str()); if(stop->raid->getPrisonAction() != "") player->print("Prison Action: %s\n", stop->raid->getPrisonAction().c_str()); player->print("Uncon In Prison: %s\n\n", stop->raid->getUnconInPrison() ? "Yes" : "No"); } // announce range player->print("Announce Ranges:\n"); shipPrintRange(player, &stop->announce); player->print("\n"); player->print("Exits:\n"); player->print("-----------------------\n"); mod = 1; for(xt = stop->exits.begin() ; xt != stop->exits.end() ; xt++) { exit = (*xt); player->print(" Exit: %d - %s\n", mod, exit->getName().c_str()); player->print(" uOrigin: %s aOrigin: %s\n", exit->origin.room.str().c_str(), exit->origin.mapmarker.str().c_str()); player->print(" uTarget: %s aTarget: %s\n", exit->target.room.str().c_str(), exit->target.mapmarker.str().c_str()); player->print(" Raid: %s\n", exit->getRaid() ? "Yes" : "No"); if(exit->getArrives() != "") player->print(" Arrives: %s\n", exit->getArrives().c_str()); if(exit->getDeparts() != "") player->print(" Departs: %s\n", exit->getDeparts().c_str()); player->print("\n"); mod++; } } return(0); } //********************************************************************* // cmdQueryShips //********************************************************************* // let the player see where ships are int cmdQueryShips(Player* player, cmd* cmnd) { int mod=0; std::list<Ship*>::iterator it; std::list<ShipStop*>::iterator st; Ship *ship=0; ShipStop *stop=0; if(!player->ableToDoCommand()) return(0); player->print("Location of Chartered Ships:\n"); player->printColor("^b-------------------------------------------------------------------------------\n"); for(it = gConfig->ships.begin() ; it != gConfig->ships.end() ; it++) { ship = (*it); // the wizard's eye tower can be viewed by clan members if(ship->canQuery || (ship->clan && ship->clan == player->getClan())) { player->print(" %-25s ", ship->name.c_str()); if(ship->inPort) player->print("%s at ", ship->docked.c_str()); else player->print("%s, %s to ", ship->transit.c_str(), ship->movement.c_str()); st = ship->stops.begin(); stop = (*st); player->print("%s.\n%-31sWill ", stop->name.c_str(), " "); if(ship->inPort) { st++; stop = (*st); player->print("depart for %s", stop->name.c_str()); } else player->print("arrive"); player->print(" in "); mod = ship->timeLeft / 60; if(mod) player->print("%d hour%s%s", mod, mod==1 ? "" : "s", ship->timeLeft % 60 ? " " : ""); mod = ship->timeLeft % 60; if(mod) player->print("%d minute%s", mod, mod==1 ? "" : "s"); player->print(".\n"); } } // Dont let staff cheat and set the quest on themselves // to see where the Marauder will be. if(player->isStaff() && !player->isDm()) return(0); if(player->questIsSet(PIRATE_QUEST) || player->isDm()) player->print("\nThe last pirate raid was: %s\n", gConfig->getCalendar()->getLastPirate().c_str()); return(0); } //********************************************************************* // saveShips //********************************************************************* void Config::saveShips() const { std::list<Ship*>::const_iterator it; xmlDocPtr xmlDoc; xmlNodePtr rootNode; char filename[80]; // we only save if we're up on the main port if(getPortNum() != 3333) return; xmlDoc = xmlNewDoc(BAD_CAST "1.0"); rootNode = xmlNewDocNode(xmlDoc, NULL, BAD_CAST "Ships", NULL); xmlDocSetRootElement(xmlDoc, rootNode); for(it = ships.begin() ; it != ships.end() ; it++) (*it)->save(rootNode); sprintf(filename, "%s/ships.xml", CONFPATH); xml::saveFile(filename, xmlDoc); xmlFreeDoc(xmlDoc); } //********************************************************************* // loadShips //********************************************************************* bool Config::loadShips() { char filename[80]; xmlDocPtr xmlDoc; xmlNodePtr rootNode; xmlNodePtr curNode; Ship *ship=0; std::list<Ship*>::iterator it; sprintf(filename, "%s/ships.xml", CONFPATH); if(!file_exists(filename)) return(false); if((xmlDoc = xml::loadFile(filename, "Ships")) == NULL) return(false); rootNode = xmlDocGetRootElement(xmlDoc); curNode = rootNode->children; clearShips(); while(curNode) { if(NODE_NAME(curNode, "Ship")) { ship = new Ship; ship->load(curNode); ships.push_back(ship); } curNode = curNode->next; } // exits have all been deleted - go and set the current ones for(it = ships.begin() ; it != ships.end() ; it++) { ship = (*it); // if at a stop, make the exits if(ship->inPort) shipSetExits(ship, ship->stops.front()); } xmlFreeDoc(xmlDoc); xmlCleanupParser(); return(true); } //********************************************************************* // clearShips //********************************************************************* void Config::clearShips() { Ship *ship=0; while(!ships.empty()) { ship = ships.front(); delete ship; ships.pop_front(); } ships.clear(); }