/*
* 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();
}