/* * command4.cpp * Command handling/parsing routines. * ____ _ * | _ \ ___ __ _| |_ __ ___ ___ * | |_) / _ \/ _` | | '_ ` _ \/ __| * | _ < __/ (_| | | | | | | \__ \ * |_| \_\___|\__,_|_|_| |_| |_|___/ * * 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 "version.h" #include "commands.h" #include "clans.h" #include "calendar.h" #include "magic.h" #include "effects.h" #include <sstream> #include <iomanip> #include <locale> //********************************************************************* // cmdScore //********************************************************************* // This function shows a player their current hit points, magic points, // experience, gold and level. int cmdScore(Player* player, cmd* cmnd) { Player *target = player; player->clearFlag(P_AFK); if(player->isBraindead()) { player->print("You are brain-dead. You can't do that.\n"); return(0); } if(player->isBlind()) { player->printColor("^CYou're blind!\n"); return(0); } player->clearFlag(P_AFK); if(player->isCt()) { if(cmnd->num > 1) { cmnd->str[1][0] = up(cmnd->str[1][0]); target = gServer->findPlayer(cmnd->str[1]); if(!target || (target->isDm() && !player->isDm())) { player->print("That player is not logged on.\n"); return(0); } } } target->score(player); return(0); } //********************************************************************* // score //********************************************************************* // This function shows a player their current hit points, magic points, // experience, gold and level. void Player::score(const Player* viewer) { const EffectInfo* eff=0; int i=0; std::ostringstream oStr; viewer->print("%s the %s (level %d)", name, getTitle().c_str(), getLevel()); if(getFishing()) oStr << " ^c*Fishing*"; if(flagIsSet(P_HIDDEN)) oStr << " ^c*Hidden*"; if(isEffected("courage")) oStr << " ^r*Brave*"; if(isEffected("fear")) oStr << " ^b*Fearful*"; if(flagIsSet(P_SITTING)) oStr << " ^x*Sitting*"; if(flagIsSet(P_MISTED)) oStr << " ^c*Misted*"; if(isEffected("armor")) oStr << " ^y*Armor Spell*"; if(flagIsSet(P_BERSERKED)) oStr << " ^r*Berserked*"; if(flagIsSet(P_RUNNING)) oStr << " ^c*Running*"; if(isPoisoned()) oStr << " ^g^#*Poisoned*"; if(isEffected("haste")) oStr << " ^c*Hasted*"; if(isEffected("slow")) oStr << " ^g*Slowed*"; if(isEffected("strength")) oStr << " ^y*Strength*"; if(isEffected("enfeeblement")) oStr << " ^y*Enfeeblement*"; if(isEffected("insight")) oStr << " ^y*Insight*"; if(isEffected("feeblemind")) oStr << " ^y*Feeblemind*"; if(isEffected("fortitude")) oStr << " ^c*Fortitude*"; if(isEffected("weakness")) oStr << " ^g*Weakness*"; if(isEffected("prayer")) oStr << " ^y*Prayer*"; if(isEffected("damnation")) oStr << " ^y*Damnation*"; eff = getEffect("drunkenness"); if(eff) oStr << " ^o*" << eff->getDisplayName() << "^o*"; if(isEffected("confusion")) oStr << " ^b^#*Confused*"; if(flagIsSet(P_CHARMED)) oStr << " ^C*Charmed*"; if(flagIsSet(P_FOCUSED)) oStr << " ^c*Focused*"; if(isEffected("silence")) oStr << " ^m^#*Muted*"; if(isDiseased()) oStr << " ^r^#*Diseased*"; if(isEffected("camouflage")) oStr << " ^g*Camouflaged*"; if(isEffected("petrification")) oStr << " ^c*Petrified*"; if(isEffected("hold-person")) oStr << " ^c*Magically Held*"; if(flagIsSet(P_PRAYED)) oStr << " ^y*Prayed*"; if(flagIsSet(P_UNCONSCIOUS)) { if(flagIsSet(P_SLEEPING)) oStr << " ^c*Sleeping*"; else oStr << " ^c*Unconscious*"; } if(isBraindead()) oStr << " ^y*Brain-dead*"; if(isEffected("wounded")) oStr << " ^r*Wounded*"; viewer->printColor(oStr.str().c_str()); viewer->printColor("\n ^g%3d/%3d Hit Points", hp.getCur(), hp.getMax()); if(getClass() == FIGHTER && flagIsSet(P_PTESTER)) viewer->printColor(" ^g%3d/%3d Focus Points", focus.getCur(), focus.getMax()); else if(hasMp()) viewer->printColor(" ^g%3d/%3d Magic Points", mp.getCur(), mp.getMax()); viewer->printColor(" ^rArmor: %d (%.0f%%)\n", getArmor(), (getDamageReduction(this)*100.0)); viewer->printColor(" ^y%7ld Experience %7ld Gold Piece%s XP Needed: %7s\n", getExperience(), coins[GOLD], coins[GOLD] != 1 ? "s" : "", expToLevel(false).c_str()); viewer->printColor("\n^MBank Balance: %ld gold coin%s.\n", bank[GOLD], bank[GOLD] != 1 ? "s" : ""); viewer->printColor("Total Inventory Assets: %ld gold.\n", getInventoryValue()); if(getRoom()->isWinter()) viewer->printColor("Winter Protection: ^c%d%%\n", (int)(20 * winterProtection()) * 5); viewer->print("\n"); viewer->printColor("Your size is: ^y%s^x.\n", getSizeName(getSize()).c_str()); // show spells under also spellsUnder(viewer, this, false); if(getWarnings()) { viewer->printColor("\n^BWarnings: "); for(i=0; i<getWarnings(); i++) viewer->print("* "); viewer->print("\n"); } switch(getSock()->getMccp()) { case 1: viewer->printColor("^yMCCP V1 Enabled\n"); break; case 2: viewer->printColor("^yMCCP V2 Enabled\n"); break; default: viewer->printColor("^rMCCP Disabled\n"); break; } if(!statsAddUp()) viewer->printColor("^RError:^x Your stats do not add up.\n"); } //********************************************************************* // cmdDaily //********************************************************************* int cmdDaily(Player* player, cmd* cmnd) { int loop=0; player->clearFlag(P_AFK); if(player->isBraindead()) { player->print("You are brain-dead. You can't do that.\n"); return(0); } while(loop++<=DAILYLAST) update_daily(&player->daily[loop]); player->print("Daily actions remaining:\n\n"); player->print("Broadcasts: %d of %d remaining.\n", player->daily[DL_BROAD].cur,player->daily[DL_BROAD].max); if( player->isCt() || (player->getClass() == CLERIC && player->getClass() != 12 && player->spellIsKnown(S_HEAL)) ) { player->print("Heals: %d of %d remaining.\n", player->daily[DL_FHEAL].cur,player->daily[DL_FHEAL].max); } if( player->isCt() || ((player->getClass() == RANGER || player->getClass() == DRUID) && player->spellIsKnown(S_TRACK)) ) { player->print("Tracks: %d of %d remaining.\n", player->daily[DL_TRACK].cur,player->daily[DL_TRACK].max); } if( player->isCt() || ((player->getClass() == LICH || player->getClass() == MAGE) && player->getLevel() >= 10) ) { player->print("Enchants: %d of %d remaining.\n", player->daily[DL_ENCHA].cur,player->daily[DL_ENCHA].max); } if( player->isCt() || (player->getClass() == MAGE && player->getLevel() >= 10)) { player->print("Transmutes: %d of %d remaining.\n", player->daily[DL_RCHRG].cur,player->daily[DL_RCHRG].max); } if( player->isCt() || (player->getLevel() >= 9 && player->spellIsKnown(S_TELEPORT))) { player->print("Teleports: %d of %d remaining.\n", player->daily[DL_TELEP].cur,player->daily[DL_TELEP].max); } if( player->isCt() || (player->getLevel() >= 16 && player->getClass() == PALADIN)) { player->print("Lay on Hands: %d of %d remaining.\n", player->daily[DL_HANDS].cur,player->daily[DL_HANDS].max); } if( player->isCt() || (player->getLevel() >= 16 && player->getClass() == DEATHKNIGHT)) { player->print("Harm touches: %d of %d remaining.\n", player->daily[DL_HANDS].cur,player->daily[DL_HANDS].max); } if( player->isDm() || (player->getLevel() >= 22 && player->getClass() == CLERIC && player->getDeity() == ARAMON && !player->getSecondClass())) { player->print("Bloodfusions: %d of %d remaining.\n", player->daily[DL_RESURRECT].cur,player->daily[DL_RESURRECT].max); } if( player->isDm() || (player->getLevel() >= 19 && player->getClass() == CLERIC && player->getDeity() == CERIS)) { player->print("Resurrections: %d of %d remaining.\n", player->daily[DL_RESURRECT].cur,player->daily[DL_RESURRECT].max); } /* if( player->isCt() || (player->getLevel() >= 13 && player->spellIsKnown(S_ETHREAL_TRAVEL))) { player->print("E-Travels: %d of %d remaining.\n", player->daily[DL_ETRVL].cur,player->daily[DL_ETRVL].max); } */ player->print("\n"); player->print("Can defecate? %s\n", player->canDefecate() ? "Yes" : "No"); player->print("Can be resurrected? %s\n", (player->daily[DL_RESURRECT].cur > 0) ? "Yes" : "No"); return(0); } //********************************************************************* // cmdHelp //********************************************************************* // This function allows a player to get help in general, or help for a // specific command. If help is typed by itself, a list of commands // is produced. Otherwise, help is supplied for the command specified int cmdHelp(Player* player, cmd* cmnd) { char file[80]; player->clearFlag(P_AFK); if(player->isBraindead()) { player->print("You are brain-dead. You can't do that.\n"); return(0); } strcpy(file, DOCPATH); if(cmnd->num < 2) { strcat(file, "/helpfile.txt"); viewFile(player->getSock(), file); return(DOPROMPT); } if(!checkWinFilename(player->getSock(), cmnd->str[1])) return(0); if(strchr(cmnd->str[1], '/')!=NULL) { player->print("You may not use backslashes.\n"); return(0); } sprintf(file, "%s/%s.txt", DOCPATH, cmnd->str[1]); viewFile(player->getSock(), file); return(DOPROMPT); } //********************************************************************* // cmdWelcome //********************************************************************* // Outputs welcome file to user, giving them info on how to play // the game int cmdWelcome(Player* player, cmd* cmnd) { char file[80]; player->clearFlag(P_AFK); if(player->isBraindead()) { player->print("You are brain-dead. You can't do that.\n"); return(0); } sprintf(file, "%s/welcomerealms.txt", DOCPATH); viewFile(player->getSock(), file); return(0); } //********************************************************************* // getTimePlayed //********************************************************************* bstring Player::getTimePlayed() const { std::ostringstream oStr; long played = lasttime[LT_AGE].interval; if(played > 86400L) oStr << (played / 86400) << " Day" << ((played / 86400 == 1) ? ", " : "s, "); if(played > 3600L) oStr << (played % 86400L) / 3600L << " Hour" << ((played % 86400L) / 3600L == 1 ? ", " : "s, "); oStr << (played % 3600L) / 60L << " Minute" << ((played % 3600L) / 60L == 1 ? "" : "s"); return(oStr.str()); } //********************************************************************* // showAge //********************************************************************* void Player::showAge(const Player* viewer) const { if(birthday) { viewer->printColor("^gAge:^x %d\n^gBorn:^x the %s of %s, the %s month of the year,\n ", getAge(), getOrdinal(birthday->getDay()).c_str(), gConfig->getCalendar()->getMonth(birthday->getMonth())->getName().c_str(), getOrdinal(birthday->getMonth()).c_str()); if(birthday->getYear()==0) viewer->print("the year the Kingdom of Bordia fell.\n"); else viewer->print("%d year%s %s the fall of the Kingdom of Bordia.\n", abs(birthday->getYear()), abs(birthday->getYear())==1 ? "" : "s", birthday->getYear() > 0 ? "after" : "before"); if(gConfig->getCalendar()->isBirthday(this)) { if(viewer == this) viewer->printColor("^yToday is your birthday!\n"); else viewer->printColor("^yToday is %s's birthday!\n", name); } } else viewer->printColor("^gAge:^x unknown\n"); viewer->print("\n"); bstring str = getCreatedStr(); if(str != "") viewer->printColor("^gCharacter Created:^x %s\n", str.c_str()); viewer->printColor("^gTime Played:^x %s\n\n", getTimePlayed().c_str()); } //********************************************************************* // cmdAge //********************************************************************* int cmdAge(Player* player, cmd* cmnd) { Player *target = player; player->clearFlag(P_AFK); if(player->isBraindead()) { player->print("You are brain-dead. You can't do that.\n"); return(0); } if(player->isCt()) { if(cmnd->num > 1) { cmnd->str[1][0] = up(cmnd->str[1][0]); target = gServer->findPlayer(cmnd->str[1]); if(!target || (target->isDm() && !player->isDm())) { player->print("That player is not logged on.\n"); return(0); } } } player->print("%s the %s (level %d)\n", target->name, target->getTitle().c_str(), target->getLevel()); player->print("\n"); target->showAge(player); return(0); } //********************************************************************* // cmdVersion //********************************************************************* // Shows the players the version of the mud and last compile time int cmdVersion(Player* player, cmd* cmnd) { player->print("Mud Version: " VERSION "\nLast compiled " __TIME__ " on " __DATE__ ".\n"); return(0); } //********************************************************************* // cmdStatistics //********************************************************************* int cmdStatistics(Player* player, cmd* cmnd) { Player* target=0; if(!strcmp(cmnd->str[1], "reset")) { player->statistics.reset(); player->print("Your statistics have been reset.\n"); player->print("Note that player kill statistics are always tracked and cannot be reset.\n"); return(0); } if(player->isDm() && cmnd->num > 1) { cmnd->str[1][0] = up(cmnd->str[1][0]); target = gServer->findPlayer(cmnd->str[1]); if(!target || (target->isDm() && !player->isDm())) { player->print("That player is not logged on.\n"); return(0); } player->printColor("^W%s's Statistics\n", target->name); } else { target = player; } target->statistics.display(player); if(target == player) { player->printColor("You may type ^Wstats reset^x to reset your statistic counts to zero.\n"); player->print("You may use the set, clear, and toggle commands to control tracking of statistics.\n"); } return(0); } //********************************************************************* // cmdInfo //********************************************************************* int cmdInfo(Player* player, cmd* cmnd) { Player *target = player; player->clearFlag(P_AFK); if(player->isBraindead()) { player->print("You are brain-dead. You can't do that.\n"); return(0); } if(player->isCt()) { if(cmnd->num > 1) { cmnd->str[1][0] = up(cmnd->str[1][0]); target = gServer->findPlayer(cmnd->str[1]); if(!target || (target->isDm() && !player->isDm())) { player->print("That player is not logged on.\n"); return(0); } target->information(player); return(0); } } target->information(); return(0); } //********************************************************************* // showSavingThrow //********************************************************************* // formatted saving throws bstring showSavingThrow(const Player* viewer, const Player* player, bstring text, int st) { char str[100]; if( (viewer && viewer->isCt()) || player->isCt() ) { sprintf(str, "(%3d%%)", player->saves[st].chance); text += str; } if( st==POI && player->immuneToPoison() && player->immuneToDisease() ) { text += "^WN/A^x"; } else { int save = MIN((1+player->saves[st].chance)/10, MAX_SAVE_COLOR-1); sprintf(str, "^%c%s^x", get_save_color(save), get_save_string(save)); text += str; } return(text); } //********************************************************************* // information //********************************************************************* // This function displays a player's entire list of information, including // player stats, proficiencies, level and class. void Player::information(const Player* viewer, bool online) { int numItems=0; long i=0; bool auth = viewer && viewer->isCt(); std::ostringstream oStr; bstring txt = ""; if(!auth) update(); oStr.setf(std::ios::left, std::ios::adjustfield); // no commas when displaying staff screens oStr.imbue(std::locale(isStaff() ? "C" : "")); oStr << std::setfill(' ') << "+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+\n"; if(lastPassword != "" && viewer && viewer->isDm()) oStr << "| Last Password: " << std::setw(14) << lastPassword << " ^W|\\^x |\n"; else oStr << "| ^W|\\^x |\n"; if(clan && auth) oStr << "+ Clan: " << std::setw(21) << gConfig->getClan(clan)->getName() << " ^W<<\\ _^x +\n"; else oStr << "+ ^W<<\\ _^x +\n"; txt = name; txt += " the "; txt += getTitle(); // use i to center the title for us i = 47 - txt.length(); oStr << "| ^W/ \\ //^x |\n" << "+ ^W.------------------------------------------------------------{o}______/|^x +\n" << "|^W<^x " << std::setw((int)i/2) << " " << txt << std::setw(i-(int)i/2) << " " << " ^W=====:::{*}///////////]^x |\n" << "+ ^W`------------------------------------------------------------{o}~~~~~~\\|^x +\n"; if(auth) { oStr << "| Password: " << std::setw(14) << password << " Pkills (in/won): "; oStr.setf(std::ios::right, std::ios::adjustfield); oStr << std::setw(5) << statistics.getPkwon(); oStr.setf(std::ios::left, std::ios::adjustfield); oStr << "/" << std::setw(5) << statistics.getPkin() << " ("; oStr.setf(std::ios::right, std::ios::adjustfield); oStr << std::setw(3) << statistics.pkRank(); oStr << "%) ^W\\ / \\\\^x |\n"; oStr.setf(std::ios::left, std::ios::adjustfield); } else oStr << "| ^W\\ / \\\\^x |\n"; oStr << "+ ^W__________________________________ <</ ~^x +\n" << "|^W/\\ \\ |/^x |\n" << "+^W\\_|^x Level: " << std::setw(2) << level << " Race: " << std::setw(13) << gConfig->getRace(race)->getName(12) << "^W| _________________________________^x +\n"; txt = !cClass2 ? get_class_string(cClass) : getClassName(this); if(deity) { txt += ", "; txt += gConfig->getDeity(deity)->getName(); } oStr << "| ^W|^x Class: " << std::setw(23) << txt << " ^W| /\\ \\^x |\n" << "+ ^W|^x Alignment: "; oStr.setf(std::ios::right, std::ios::adjustfield); oStr << std::setw(7) << (flagIsSet(P_CHAOTIC) ? "Chaotic" : "Lawful"); oStr.setf(std::ios::left, std::ios::adjustfield); txt = "Neutral"; if(getAdjustedAlignment() < NEUTRAL) txt = "Evil"; else if(getAdjustedAlignment() > NEUTRAL) txt = "Good"; for(i=0; i<MAXWEAR; i++) if(ready[i]) numItems++; numItems += count_bag_inv(this); oStr << " " << std::setw(13) << txt << "^W| \\_|^x Total Experience : " << std::setw(11) << experience << "^W|^x +\n" << "| ^W|^x Time Played: ^W| |^x Experience Needed: " << std::setw(11) << expToLevel(false) << "^W|^x |\n" << "+ ^W|^x "; oStr.setf(std::ios::right, std::ios::adjustfield); oStr << std::setw(31) << getTimePlayed(); oStr.setf(std::ios::left, std::ios::adjustfield); oStr << " ^W| |^x Gold : " << std::setw(11) << coins[GOLD] << "^W|^x +\n" << "| ^W| ______________________________|_ |^x Inventory Weight : " << std::setw(4) << getWeight() << " ^W|^x |\n" << "+ ^W\\_/_______________________________/ |^x Inventory Bulk : " << std::setw(3) << getTotalBulk() << "(" << std::setw(3) << getMaxBulk() << ") ^W|^x +\n" << "| ^W|^x Total Items : " << std::setw(4) << numItems << " ^W|^x |\n" << "+ Hit Points : "; oStr.setf(std::ios::right, std::ios::adjustfield); // no more commas oStr.imbue(std::locale("C")); oStr << std::setw(5) << hp.getCur() << "/" << std::setw(5) << hp.getMax() << " ^W| ____________________________|_^x +\n" << "| "; if(cClass == FIGHTER && !cClass2 && flagIsSet(P_PTESTER)) oStr << "Focus Points : " << std::setw(5) << focus.getCur() << "/" << std::setw(5) << focus.getMax(); else if(hasMp()) oStr << "Magic Points : " << std::setw(5) << mp.getCur() << "/" << std::setw(5) << mp.getMax(); else { oStr.setf(std::ios::left, std::ios::adjustfield); oStr << "Armor : " << std::setw(9) << armor; } oStr.setf(std::ios::left, std::ios::adjustfield); oStr << " ^W\\_/______________________________/^x|\n"; if(!hasMp()) oStr << "+ +\n"; else oStr << "+ Armor : " << std::setw(9) << armor << " +\n"; oStr << "| |\n" << "+^W /\\ ^x _ ^WSaving Throws^x +\n" << "|^W____/_ \\____ ^x Str: " << (strength.getCur() < 100 ? " " : "") << strength.getCur() << "^W |\\_\\\\-\\^x " << std::setw(41) << showSavingThrow(viewer, this, "Poison/Disease: ", POI) << "|\n" << "+^W\\ ___\\ \\ /^x Dex: " << (dexterity.getCur() < 100 ? " " : "") << dexterity.getCur() << "^W | \\\\-|^x " << std::setw(41) << showSavingThrow(viewer, this, "Death/Traps: ", DEA) << "+\n" << "|^W \\/ / \\/ / ^x Con: " << (constitution.getCur() < 100 ? " " : "") << constitution.getCur() << "^W \\ /~\\\\^x " << std::setw(41) << showSavingThrow(viewer, this, "Breath/Explosions: ", BRE) << "|\n" << "+^W / /\\__/_/\\ ^x Int: " << (intelligence.getCur() < 100 ? " " : "") << intelligence.getCur() << "^W ` \\\\^x " << std::setw(41) << showSavingThrow(viewer, this, "Mental Attacks: ", MEN) << "+\n" << "|^W/__\\ \\_____\\^x Pie: " << (piety.getCur() < 100 ? " " : "") << piety.getCur() << "^W \\\\^x " << std::setw(41) << showSavingThrow(viewer, this, "Spells: ", SPL) << "|\n" << "+^W \\ / \\^x +\n" << "|^W \\/ `^x |\n" << "+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+-=-+\n"; if(!auth && !isStaff()) oStr << "^WMore Information:^x age, daily, effects, factions, forum, languages, property,\n" << " quests, recipes, score/health, skills, spells, statistics\n"; if(viewer) viewer->printColor("%s\n", oStr.str().c_str()); else { printColor("%s", oStr.str().c_str()); hasNewMudmail(); print("\n"); } if(!statsAddUp()) { if(viewer) viewer->printColor("^RError:^x %s's stats do not add up.\n", name); else printColor("^RError:^x Your stats do not add up.\n"); } if(auth) { showAge(viewer); viewer->print("Bank: %-10lu \n", bank[GOLD]); if(getRoom()) viewer->print("Room: %s \n", getRoom()->fullName().c_str()); else viewer->print("Room: %s \n", room.str().c_str()); if(!online) viewer->print("Last login: \n%s", ctime(&lastLogin)); else viewer->print("Currently logged on.\n"); } }