/* * command5.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 "login.h" #include "commands.h" #include "guilds.h" #include "web.h" #include "calendar.h" //********************************************************************* // who //********************************************************************* // This function outputs a list of all the players who are currently // logged into the game. int cmdWho(Player* player, cmd* cmnd) { int cClass=0, chaos=0, clan=0, pledge=0; int race=0, cls=0, law=0, guild=0; bool found=false; 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); } if(cmnd->num > 1) { lowercize(cmnd->str[1],0); switch (cmnd->str[1][0]) { case 'a': switch (cmnd->str[1][1]) { case 'd': cClass = -2; break; case 's': cClass = ASSASSIN; break; default: player->print("Parameter not unique.\n"); return(0); break; } break; break; case 'b': switch (cmnd->str[1][3]) { case 'b': race = BARBARIAN; break; case 's': cClass = BERSERKER; break; case 'd': cClass = BARD; break; default: player->print("Parameter not unique.\n"); return(0); break; } break; case 'c': switch (cmnd->str[1][1]) { case 'a': switch(cmnd->str[1][2]) { case 'm': race = CAMBION; break; case 'r': if(!player->isCt()) { player->print("You do not currently have that privilege.\n"); return(0); } else cClass = CARETAKER; break; default: player->print("Parameter not unique.\n"); return(0); break; } break; case 'h': chaos = 1; break; case 'l': switch (cmnd->str[1][2]) { case 'e': cClass = CLERIC; break; case 'a': switch(cmnd->str[1][3]) { case 's': cClass = player->getClass(); break; case 'n': clan = 1; break; } break; default: player->print("Parameter not unique.\n"); return(0); break; } break; default: player->print("Parameter not unique.\n"); return(0); break; } break; case 'd': switch(cmnd->str[1][1]) { case 'a': race = DARKELF; break; case 'e': cClass = DEATHKNIGHT; break; case 'r': cClass = DRUID; break; case 'w': race = DWARF; break; case 'u': if(!player->isDm()) { player->print("You do not currently have that privilege.\n"); return(0); } else cClass = DUNGEONMASTER; break; default: player->print("Parameter not unique.\n"); return(0); break; } break; case 'e': race = ELF; break; case 'f': cClass = FIGHTER; break; case 'g': switch(cmnd->str[1][1]) { case 'n': race = GNOME; break; case 'o': race = GOBLIN; break; case 'u': guild = 1; break; default: player->print("Parameter not unique.\n"); return(0); break; } break; case 'h': switch(cmnd->str[1][1]) { case 'u': race = HUMAN; break; case 'a': switch(cmnd->str[1][4]) { case 'e': race = HALFELF; break; case 'g': race = HALFGIANT; break; case 'l': race = HALFLING; break; case 'o': race = HALFORC; break; default: player->print("Parameter not unique.\n"); return(0); break; } break; default: player->print("Parameter not unique.\n"); return(0); break; } break; case 'k': switch(cmnd->str[1][1]) { case 'a': race = KATARAN; break; case 'o': race = KOBOLD; break; default: player->print("Parameter not unique.\n"); return(0); break; } break; case 'l': switch(cmnd->str[1][1]) { case 'a': law = 1; break; case 'i': cClass = LICH; break; default: player->print("Parameter not unique.\n"); return(0); break; } break; case 'm': switch(cmnd->str[1][1]) { case 'a': cClass = MAGE; break; case 'i': race = MINOTAUR; break; case 'o': cClass = MONK; break; default: player->print("Unknown parameter.\n"); return(0); break; } break; case 'o': switch(cmnd->str[1][1]) { case 'g': race = OGRE; break; case 'r': race = ORC; break; default: player->print("Unknown parameter.\n"); return(0); break; } break; case 'p': switch(cmnd->str[1][1]) { case 'a': cClass = PALADIN; break; case 'l': pledge = 1; break; default: player->print("Parameter not unique.\n"); return(0); break; } break; case 'r': switch(cmnd->str[1][1]) { case 'a': cClass = RANGER; break; case 'o': cClass = ROGUE; break; default: player->print("Parameter not unique.\n"); return(0); break; } break; case 's': race = SERAPH; break; case 't': switch(cmnd->str[1][1]) { case 'h': cClass = THIEF; break; case 'r': race = TROLL; break; case 'i': race = TIEFLING; break; default: player->print("Parameter not unique.\n"); return(0); break; } break; case 'v': switch (cmnd->str[1][1]) { case 'a': cClass = VAMPIRE; break; case 'e': cClass = -3; break; default: player->print("Parameter not unique.\n"); return(0); break; } break; break; case 'w': switch(cmnd->str[1][1]) { case 'a': cClass = -1; break; case 'e': cClass = WEREWOLF; break; default: player->print("Parameter not unique.\n"); return(0); break; } break; case '.': cls = 1; break; default: player->print("Parameter not unique.\n"); return(0); break; }// end main switch } // end if cmnd->num > 1 std::ostringstream whoStr; bstring curStr; whoStr << "\n^BPlayers currently online:\n"; whoStr << "-------------------------------------------------------------------------------^x\n"; std::pair<bstring, Player*> p; Player* target=0; foreach(p, gServer->players) { target = p.second; if(!target->isConnected()) continue; if(!player->canSee(target)) continue; if(cls == 1) if(target->getClass() != player->getClass()) continue; if(clan == 1) if(!target->getClan()) continue; if(guild == 1) if(player->getGuild() && target->getGuild() != player->getGuild()) continue; if(chaos == 1) if(!target->flagIsSet(P_CHAOTIC)) continue; if(law == 1) if(target->flagIsSet(P_CHAOTIC)) continue; if(pledge == 1) if((target->getClan() && target->getClan() == player->getClan()) || !target->getClan()) continue; if(race > 0) if((player->willIgnoreIllusion() ? target->getRace() : target->getDisplayRace()) != race) continue; if(cClass == -1) if(!target->isPublicWatcher()) continue; if(cClass == -2) if(!target->flagIsSet(P_ADULT)) continue; if(cClass == -3) if(!target->flagIsSet(P_VETERAN)) continue; if(cClass > 0) if(target->getClass() != cClass) continue; if(target->flagIsSet(P_MISTED) && !player->isEffected("true-sight") && !player->isCt() ) continue; if(target->isInvisible() && !player->isEffected("detect-invisible") && !player->isCt() ) continue; if(target->flagIsSet(P_GLOBAL_GAG) && player != target && !player->isCt()) continue; found = true; curStr = target->getWhoString(false, true, player->willIgnoreIllusion()); whoStr << curStr; } if(!found) player->print("Nobody found!\n"); else { curStr = whoStr.str(); player->printColor("%s\n", curStr.c_str()); } return(0); } //********************************************************************* // classwho //********************************************************************* // This function outputs a list of all the players who are currently // logged into the game which are the same class as the player doing // the command. int cmdClasswho(Player* player, cmd* cmnd) { cmnd->num = 2; strcpy(cmnd->str[0], "who"); strcpy(cmnd->str[1], "class"); return(cmdWho(player, cmnd)); } //********************************************************************* // cmdWhois //********************************************************************* // The whois function displays a selected player's name, class, level // title, age and gender int cmdWhois(Player* player, cmd* cmnd) { Player *target=0; player->clearFlag(P_AFK); if(player->isBraindead()) { player->print("You are brain-dead. You can't do that.\n"); return(0); } if(cmnd->num < 2) { player->print("Whois who?\n"); return(0); } lowercize(cmnd->str[1], 1); target = gServer->findPlayer(cmnd->str[1]); if(!target || !player->canSee(target)) { player->print("That player is not logged on.\n"); return(0); } player->printColor("%s", target->getWhoString(true, true, player->willIgnoreIllusion()).c_str()); return(0); } //********************************************************************* // cmdSuicide //********************************************************************* // This function is called whenever the player explicitly asks to // commit suicide. int cmdSuicide(Player* player, cmd* cmnd) { if(!player->ableToDoCommand()) return(0); if(player->flagIsSet(P_NO_SUICIDE)) { player->print("You cannot suicide right now. You are in a 24 hour cooling-off period.\n"); return(0); } // Prevents players from suiciding in jail if(player->inJail()) { player->print("You attempt to kill yourself and fail. It sure hurts though!\n"); broadcast(player->getSock(), player->getRoom(),"%M tries to kill %sself.", player, player->himHer()); return(0); } if(cmnd->num < 2 || strcasecmp(cmnd->str[1], "yes")) { player->printColor("^rWARNING:^x This will completely erase your character!\n"); player->print("To prevent accidental suicides you must confirm you want to suicide;\nto do so type 'suicide yes'\n"); if(player->getGuild() && player->getGuildRank() == GUILD_MASTER) player->printColor("^yNote:^x if you want to control who takes over your guild after you suicide,\nbe sure to abdicate leadership first.\n"); return(0); } //if(player->getLevel() > 2 && !player->isStaff()) broadcast("### %s committed suicide! We'll miss %s dearly.", player->name, player->himHer()); //else // broadcast(isWatcher, "^C### %s committed suicide! We'll miss %s dearly.", player->name, player->himHer()); logn("log.suicide", "%s(%s)-%d (%s)\n", player->name, player->getPassword().c_str(), player->getLevel(), player->getSock()->getHostname().c_str()); deletePlayer(player); return(0); } //********************************************************************* // deletePlayer //********************************************************************* // Does a true delete of a player and their files void deletePlayer(Player* player) { char file[80]; bool hardcore = player->isHardcore(); // cache the name because we will be deleting the player object bstring name = player->name; gConfig->deleteUniques(player); player->clearEnemyPlayer(); // remove minions before backup, since this affects other players as well player->clearMinions(); // they are no longer the owner of any effects they have created gServer->removeEffectsOwner(player); // unassociate if(player->getForum() != "") { player->setForum(""); webUnassociate(name); } // take the player out of any guilds updateGuild(player, GUILD_REMOVE); // save a backup - this will be the only copy of the player! if(player->getLevel() >= 7) player->save(false, LS_BACKUP); if(player->flagIsSet(P_CREATING_GUILD)) { // If they are the founder, this will return text, and we // need go no further. Otherwise, they are a supporter, and we // have to search for them. if(gConfig->removeGuildCreation(name) != "") { std::list<GuildCreation*>::iterator gcIt; for(gcIt = gConfig->guildCreations.begin(); gcIt != gConfig->guildCreations.end(); gcIt++) { // they were supporting this guild - stop if((*gcIt)->removeSupporter(name)) break; } gConfig->saveGuilds(); } } // this deletes the player object Socket* sock = player->getSock(); player->uninit(); free_crt(player); zero(player, sizeof(player)); gServer->clearPlayer(name); sock->setPlayer(NULL); // get rid of any files the player was using sprintf(file, "%s/%s.xml", PLAYERPATH, name.c_str()); unlink(file); sprintf(file, "%s/%s.txt", BANKDIR, name.c_str()); unlink(file); sprintf(file, "%s/%s.txt", POSTPATH, name.c_str()); unlink(file); sprintf(file, "%s/%s.txt", HISTPATH, name.c_str()); unlink(file); // handle removing and property this player owned gConfig->destroyProperties(name); if(hardcore) sock->reconnect(true); else sock->disconnect(); } //********************************************************************* // cmdConvert //********************************************************************* // This function allows a player to convert from chaotic to lawful alignment. int cmdConvert(Player* player, cmd* cmnd) { if(!player->ableToDoCommand()) return(0); if(!player->flagIsSet(P_CHAOTIC)) { player->print("You cannot convert. You're lawful.\n"); return(0); } else if(player->getRace() == TIEFLING) { player->print("Tieflings are required to be chaotic.\n"); return(0); } else if(player->isNewVampire()) { player->print("Vampires are required to be chaotic.\n"); return(0); } if(cmnd->num < 2 || strcasecmp(cmnd->str[1], "yes")) { player->print("To prevent accidental conversion you must confirm you want to convert,\n"); player->print("to do so type 'convert yes'\n"); player->print("Remember, you will NEVER be able to be chaotic again.\n"); return(0); } if(player->getClass() == BUILDER) { broadcast(isStaff, "^G### %s just converted to lawful alignment.", player->getName()); logn("log.convert","%s converted to lawful.", player->getName()); } else broadcast("^G### %s just converted to lawful alignment.", player->getName()); player->clearFlag(P_CHAOTIC); if(player->getClass() == CLERIC) player->clearFlag(P_PLEDGED); return(0); } // having a pref that starts with a hyphen (-) is instead a category typedef struct prefInfo { bstring name; int flag; bool (*canUse)(const Creature *); bstring desc; bool invert; // reverses the language } prefInfo, *prefPtr; prefInfo prefList[] = { // name flag canUse desc { "-Staff Preferences", 0, isStaff, "", 0 }, { "eaves", P_EAVESDROPPER, isCt, "eavesdropper mode", 0 }, { "supereaves", P_SUPER_EAVESDROPPER, isCt, "super eavesdropper mode", 0 }, { "msg", P_NO_MSG, isCt, "*msg channel", true }, { "mobtick", P_NO_TICK_MSG, isCt, "See mob tick broadcasts", true }, { "mobaggro", P_NO_AGGRO_MSG, isCt, "See mob aggro broadcasts", true }, { "mobdeath", P_NO_DEATH_MSG, isCt, "See mob death broadcasts", true }, { "ttobound", P_T_TO_BOUND, isStaff,"*t to bound room", 0 }, { "wts", P_NO_WTS, isCt, "*wts channel", true }, { "zones", P_VIEW_ZONES, isCt, "view overland zones", 0 }, { "-Color", 0, 0, "", 0 }, { "mirc", P_MIRC, 0, "mirc colors", 0 }, { "ansi", P_ANSI_COLOR, 0, "ansi colors", 0 }, { "langcolor", P_LANGUAGE_COLORS, 0, "language colors", 0 }, { "extracolor", P_NO_EXTRA_COLOR, 0, "extra color options", true }, { "areacolor", P_INVERT_AREA_COLOR, 0, "invert area colors", 0 }, { "mxpcolors", P_MXP_ENABLED, 0, "use MXP for more than 16 colors", 0 }, { "-Channels", 0, 0, "", 0 }, { "cls", P_IGNORE_CLASS_SEND, 0, "class channel", true }, { "race", P_IGNORE_RACE_SEND, 0, "race channel", true }, { "broad", P_NO_BROADCASTS, 0, "broadcast channel", true }, { "newbie", P_IGNORE_NEWBIE_SEND, 0, "newbie channel", true }, { "gossip", P_IGNORE_GOSSIP, 0, "gossip channel", true }, { "clan", P_IGNORE_CLAN, 0, "clan channel", true }, { "tells", P_NO_TELLS, 0, "send/tell/whisper/sign", true }, { "sms", P_IGNORE_SMS, 0, "receive text messages", true }, { "ignore", 0, 0, "ignore all channels", 0 }, // do something with P_IGNORE_ALL { "-Notifications", 0, 0, "", 0 }, { "duel", P_NO_DUEL_MESSAGES, 0, "duel messages", true }, { "login", P_NO_LOGIN_MESSAGES, 0, "login messages", true }, { "shopprofit", P_DONT_SHOW_SHOP_PROFITS,0, "shop profit notifications",true }, { "mail", P_NO_SHOW_MAIL, 0, "mudmail notifications", true }, { "permdeath", P_PERM_DEATH, 0, "perm death broadcasts", 0 }, { "auction", P_NO_AUCTIONS, 0, "player auctions", true }, { "notifications",0, 0, "show all notifications", 0 }, { "-Combat", 0, 0, "", 0 }, { "autoattack", P_NO_AUTO_ATTACK, 0, "auto attack", true }, { "lagprotect", P_LAG_PROTECTION_SET, 0, "lag protection", 0 }, { "lagrecall", P_NO_LAG_HAZY, 0, "recall potion if below half hp",true }, { "wimpy", P_WIMPY, 0, "flee when HP below this number",0 }, { "killaggros", P_KILL_AGGROS, 0, "attack aggros first", 0 }, { "mobnums", P_NO_NUMBERS, 0, "monster ordinal numbers", true }, { "-Group", 0, 0, "", 0 }, { "group", P_IGNORE_GROUP_BROADCAST,0, "group combat messages", true }, { "xpsplit", P_XP_DIVIDE, 0, "group experience split", 0 }, { "split", P_GOLD_SPLIT, 0, "split gold among group", 0 }, { "stats", P_NO_SHOW_STATS, 0, "show group your stats", true }, { "follow", P_NO_FOLLOW, 0, "can be followed", true }, { "-Miscellaneous", 0, 0, "", 0 }, { "autowear", P_NO_AUTO_WEAR, 0, "wear all on login", true }, { "short", P_NO_SHORT_DESCRIPTION, 0, "short description", true }, { "long", P_NO_LONG_DESCRIPTION, 0, "long description", true }, { "prompt", P_PROMPT, 0, "descriptive prompt", 0 }, { "nlprompt", P_NEWLINE_AFTER_PROMPT, 0, "newline after prompt", 0 }, { "summon", P_NO_SUMMON, 0, "can be summoned", true }, { "xpprompt", P_SHOW_XP_IN_PROMPT, 0, "show exp in prompt", 0 }, //{ "pkill", P_NO_PKILL_PERCENT, 0, "show pkill percentage", true }, { "afk", P_AFK, 0, "away from keyboard", 0 }, { "statistics", P_NO_TRACK_STATS, 0, "track statistics", true }, { "skillprogress", P_SHOW_SKILL_PROGRESS,0, "show skill progress bar", false }, // handle wimpy below // handle afk below { "", 0, 0, "" } }; //********************************************************************* // cmdPrefs //********************************************************************* int cmdPrefs(Player* player, cmd* cmnd) { prefPtr pref = NULL; int i=0, match=0, len=strlen(cmnd->str[1]); bool set = cmnd->str[0][0]=='s'; bool toggle = cmnd->str[0][0]=='t' || cmnd->str[0][0]=='p'; bool show=false, all = !strcmp(cmnd->str[1], "-all"); bstring prefName=""; if(!player->ableToDoCommand()) return(0); // display a list of preferences if(cmnd->num == 1 || cmnd->str[1][0] == '-') { if(!len) { player->print("Below is a list of preference categories. To view a cateogry, type\n"); player->print("\"pref -[category]\". To view all preferences, type \"pref -all\".\n\n"); } while(prefList[i].name != "") { if(!prefList[i].canUse || prefList[i].canUse(player)) { if(prefList[i].name.at(0) == '-') { // previous category was shown? newline if(show) player->print("\n"); // no parameters? indent if(!len) player->print(" "); prefName = prefList[i].name; show = len && (all || !strncmp(cmnd->str[1], prefName.toLower().c_str(), len)); player->printColor("^%s%s^w\n", show ? "C" : "c", prefList[i].name.substr(1, prefList[i].name.length() - 1).c_str()); } else { if(!show) { i++; continue; } player->print(" %-13s :: %-31s :: ", prefList[i].name.c_str(), prefList[i].desc.c_str()); // wimpy gets its own special format if(prefList[i].name == "wimpy" && player->flagIsSet(prefList[i].flag)) player->print("%d", player->getWimpy()); // print everything exp ignore else if(prefList[i].flag) player->printColor("%s^w", player->flagIsSet(prefList[i].flag) ^ !prefList[i].invert ? "^roff" : "^gon"); player->print("\n"); } } i++; } player->print("\n"); return(0); } // everyone is used to nosummon - let them keep it that way if(!strcmp(cmnd->str[1], "nosummon")) { if(!toggle) set = !set; strcpy(cmnd->str[1], "summon"); } // we're setting or clearing a preference // find out which one while(prefList[i].name != "") { if( prefList[i].name.at(0) != '-' && (!prefList[i].canUse || prefList[i].canUse(player)) ) { if(!strcmp(cmnd->str[1], prefList[i].name.c_str())) { match = 1; pref = &prefList[i]; break; } else if(!strncmp(cmnd->str[1], prefList[i].name.c_str(), len)) { match++; pref = &prefList[i]; } } i++; } if(match > 1) { player->print("Preference not unique.\n"); return(0); } if(!pref) { player->print("Unknown preference.\n"); return(0); } // if any channels are being ignored, toggle = stop ignorning if(toggle && pref->name == "ignore") { toggle = false; set = (!player->flagIsSet(P_IGNORE_CLASS_SEND) && !player->flagIsSet(P_IGNORE_RACE_SEND) && !player->flagIsSet(P_NO_BROADCASTS) && !player->flagIsSet(P_IGNORE_NEWBIE_SEND) && !player->flagIsSet(P_IGNORE_GOSSIP) && !player->flagIsSet(P_IGNORE_CLAN) && !player->flagIsSet(P_NO_TELLS) ); } // if any notifications are off, toggle = turn them all one if(toggle && pref->name == "notifications") { toggle = false; set = (player->flagIsSet(P_NO_DUEL_MESSAGES) || player->flagIsSet(P_NO_LOGIN_MESSAGES) || player->flagIsSet(P_DONT_SHOW_SHOP_PROFITS) || player->flagIsSet(P_NO_SHOW_MAIL) || player->flagIsSet(P_IGNORE_GROUP_BROADCAST) || !player->flagIsSet(P_PERM_DEATH) || player->flagIsSet(P_NO_AUCTIONS) ); } // set //--------------- //NORMAL // toggle // !flag // toggle // invert && flag // are we setting or clearing? if( ((set ^ pref->invert) && !toggle) || (toggle && !player->flagIsSet(pref->flag)) ) { if(pref->flag == P_MXP_ENABLED) { if(!player->getSock()->getMxp()) { player->print("Your client does not support MXP!\nYou will not be able to view extra colors.\n"); return(0); } player->defineMXP(); } if(pref->name == "ignore") { player->setFlag(P_IGNORE_CLASS_SEND); player->setFlag(P_IGNORE_RACE_SEND); player->setFlag(P_NO_BROADCASTS); player->setFlag(P_IGNORE_NEWBIE_SEND); player->setFlag(P_IGNORE_GOSSIP); player->setFlag(P_IGNORE_CLAN); player->setFlag(P_NO_TELLS); } else if(pref->name == "notifications") { player->clearFlag(P_NO_DUEL_MESSAGES); player->clearFlag(P_NO_LOGIN_MESSAGES); player->clearFlag(P_DONT_SHOW_SHOP_PROFITS); player->clearFlag(P_NO_SHOW_MAIL); player->clearFlag(P_IGNORE_GROUP_BROADCAST); player->setFlag(P_PERM_DEATH); player->clearFlag(P_NO_AUCTIONS); } else player->setFlag(pref->flag); if(pref->name == "afk") { // broadcast for going afk if(!player->flagIsSet(P_DM_INVIS)) broadcast(player->getSock(), player->getRoom(), "%M has gone afk.", player); else broadcast(isCt, player->getSock(), player->getRoom(), "*DM* %M has gone afk.", player); } if(pref->name == "wimpy") { player->setWimpy(cmnd->val[1] == 1L ? 10 : cmnd->val[1]); player->setWimpy(MAX(player->getWimpy(), 2)); } set = true; } else { if(pref->name == "ignore") { player->clearFlag(P_IGNORE_CLASS_SEND); player->clearFlag(P_IGNORE_RACE_SEND); player->clearFlag(P_NO_BROADCASTS); player->clearFlag(P_IGNORE_NEWBIE_SEND); player->clearFlag(P_IGNORE_GOSSIP); player->clearFlag(P_IGNORE_CLAN); player->clearFlag(P_NO_TELLS); } else if(pref->name == "notifications") { player->setFlag(P_NO_DUEL_MESSAGES); player->setFlag(P_NO_LOGIN_MESSAGES); player->setFlag(P_DONT_SHOW_SHOP_PROFITS); player->setFlag(P_NO_SHOW_MAIL); player->setFlag(P_IGNORE_GROUP_BROADCAST); player->clearFlag(P_PERM_DEATH); player->setFlag(P_NO_AUCTIONS); } else player->clearFlag(pref->flag); if(pref->name == "wimpy") player->setWimpy(0); set = false; } // give them the message player->print("Preference : %s : ", pref->desc.c_str()); if(pref->name == "wimpy" && player->flagIsSet(pref->flag)) player->print("%d", player->getWimpy()); else player->printColor("%s^w", set ^ !pref->invert ? "^roff" : "^gon"); player->print(".\n"); if(pref->flag == P_NO_TRACK_STATS) player->print("Note that player kill statistics are always tracked and cannot be reset.\n"); return(0); } //********************************************************************* // cmdQuit //********************************************************************* // This function checks to see if a player is allowed to quit yet. It // checks to make sure the player isn't in the middle of combat, and if // so, the player is not allowed to quit (and 0 is returned). int cmdQuit(Player* player, cmd* cmnd) { long i=0, t=0; if(!player->ableToDoCommand()) return(0); t = time(0); if(player->inCombat()) i = player->getLTAttack() + 20; else i = player->getLTAttack() + 2; if(t < i) { player->pleaseWait(i-t); return(0); } if(player->inCombat()) i = LT(player, LT_SPELL) + 20; else i = LT(player, LT_SPELL) + 2; if(t < i) { player->pleaseWait(i-t); return(0); } player->update(); return(DISCONNECT); } //********************************************************************* // changeStats //********************************************************************* int cmdChangeStats(Player* player, cmd* cmnd) { player->changeStats(); return(0); } void Player::changeStats() { int a=0; if(!flagIsSet(P_CAN_CHANGE_STATS) && !isCt()) { print("You cannot change your stats at this time.\n"); return; } else { for(a=0;a<5;a++) { tnum[a] = 0; tstat.num[a] = 0; } tstat.hp = 0; tstat.mp = 0; tstat.pp = 0; tstat.rp = 0; tstat.race = 0; tstat.cls = 0; tstat.cls2 = 0; tstat.level = 0; broadcast(::isCt, "^y### %s is choosing new stats.", name); printColor("^yPlease enter a new set of initial stats (56 points):\n"); getSock()->setState(CON_CHANGING_STATS); } } //******************************************************************** // changingStats //******************************************************************** // This function allows a player to change their stats void changingStats(Socket* sock, char *str) { sock->getPlayer()->changingStats(str); } void Player::changingStats(char *str) { int a, n, i, k, l, sum=0; int vnum[5]; vstat nstat, sendStat; switch(getSock()->getState()) { case CON_CHANGING_STATS: n = strlen(str); l = 0; k = 0; for(i=0; i<=n; i++) { if(str[i]==' ' || str[i]==0) { str[i] = 0; vnum[k++] = atoi(&str[l]); l = i+1; } if(k>4) break; } if(k<5) { print("Please enter all 5 numbers.\n"); print("Aborted.\n"); getSock()->setState(CON_PLAYING); return; } sum = 0; for(i=0; i<5; i++) { if(vnum[i] < 3 || vnum[i] > 18) { print("No stats < 3 or > 18 please.\n"); print("Aborted.\n"); getSock()->setState(CON_PLAYING); return; } sum += vnum[i]; } if(sum != 56) { print("Stat total must equal 56 points.\n"); print("Aborted.\n"); getSock()->setState(CON_PLAYING); return; } for(a=0;a<5;a++) tnum[a] = vnum[a]; if(race == HUMAN) { print("Raise which stat?:\n[A] Strength, [B] Dexterity, [C] Constitution, [D] Intelligence, or [E] Piety.\n"); getSock()->setState(CON_CHANGING_STATS_RAISE); return; } print("Your stats have been calculated.\n"); print("Please press [ENTER].\n"); getSock()->setState(CON_CHANGING_STATS_CALCULATE); return; break; case CON_CHANGING_STATS_CALCULATE: for(a=0;a<5;a++) { sendStat.num[a] = tnum[a]; } calcStats(sendStat, &nstat); print("Your resulting stats will be as follows:\n"); print("STR: %d DEX: %d CON: %d INT: %d PIE: %d\n", nstat.num[0], nstat.num[1], nstat.num[2], nstat.num[3], nstat.num[4]); print("Hit Points: %d\n", nstat.hp); print("Are these the stats you want? (Y/N)\n"); for(a=0; a<5; a++) tstat.num[a] = nstat.num[a]; tstat.hp = nstat.hp; getSock()->setState(CON_CHANGING_STATS_CONFIRM); // confirm y/n break; case CON_CHANGING_STATS_CONFIRM: if(low(str[0]) == 'y') { broadcast(::isCt, "^y### %s has chosen %s stats.", name, hisHer()); print("New stats set.\n"); strength.setCur((short)tstat.num[0]); dexterity.setCur((short)tstat.num[1]); constitution.setCur((short)tstat.num[2]); intelligence.setCur((short)tstat.num[3]); piety.setCur((short)tstat.num[4]); hp.setMax(tstat.hp); clearFlag(P_CAN_CHANGE_STATS); getSock()->setState(CON_PLAYING); return; } else { broadcast(::isCt,"^y### %s aborted choosing new stats.", name); print("Aborted.\n"); getSock()->setState(CON_PLAYING); return; } break; case CON_CHANGING_STATS_RAISE: switch (low(str[0])) { case 'a': tnum[0]++; break; case 'b': tnum[1]++; break; case 'c': tnum[2]++; break; case 'd': tnum[3]++; break; case 'e': tnum[4]++; break; default: print("\nPlease choose one.\n"); return; break; } print("Lower which stat?:\n[A] Strength, [B] Dexterity, [C] Constitution, [D] Intelligence, or [E] Piety.\n"); getSock()->setState(CON_CHANGING_STATS_LOWER); return; break; case CON_CHANGING_STATS_LOWER: switch (low(str[0])) { case 'a': tnum[0]--; tnum[0] = MAX(1, tnum[0]); break; case 'b': tnum[1]--; tnum[1] = MAX(1, tnum[1]); break; case 'c': tnum[2]--; tnum[2] = MAX(1, tnum[2]); break; case 'd': tnum[3]--; tnum[3] = MAX(1, tnum[3]); break; case 'e': tnum[4]--; tnum[4] = MAX(1, tnum[4]); break; default: print("\nPlease choose one."); return; break; } print("Your stats have been calculated.\n"); print("Please press [ENTER].\n"); getSock()->setState(CON_CHANGING_STATS_CALCULATE); break; } } //********************************************************************* // doTrain //********************************************************************* void doTrain(Player* player) { player->upLevel(); player->setFlag(P_JUST_TRAINED); broadcast("### %s just made a level!", player->name); player->print("Congratulations, you made a level!\n\n"); if(player->canChooseCustomTitle()) { player->setFlag(P_CAN_CHOOSE_CUSTOM_TITLE); player->print("You may now choose a custom title. Type ""help title"" for more details.\n"); } logn("log.train", "%s just trained to level %d in room %s.\n", player->name, player->getLevel(), player->getRoom()->fullName().c_str()); } //********************************************************************* // cmdTrain //********************************************************************* // This function allows a player to train if they are in the correct // training location and has enough gold and experience. If so, the // character goes up a level. int cmdTrain(Player* player, cmd* cmnd) { unsigned long goldneeded=0, expneeded=0, bankneeded=0, maxgold=0; if(player->getClass() == BUILDER) { player->print("You don't need to do that!\n"); return(0); } if(!player->ableToDoCommand()) return(0); if(player->isBlind()) { player->printColor("^CYou can't do that! You're blind!\n"); return(0); } if(!player->flagIsSet(P_SECURITY_CHECK_OK)) { player->print("You are not allowed to do that.\n"); return(0); } if(!player->flagIsSet(P_PASSWORD_CURRENT)) { player->print("Your password is no longer current.\n"); player->print("In order to train, you must change it.\n"); player->print("Use the \"password\" command to do this.\n"); return(0); } if(!player->flagIsSet(P_CHOSEN_ALIGNMENT) && player->getLevel() == ALIGNMENT_LEVEL) { player->print("You must choose your alignment before you can train to level %d.\n", ALIGNMENT_LEVEL+1); player->print("Use the 'alignment' command to do so. HELP ALIGNMENT.\n"); return(0); } if(player->getNegativeLevels()) { player->print("To train, all of your life essence must be present.\n"); return(0); } expneeded = gConfig->expNeeded(player->getLevel()); if(player->getLevel() < 19) maxgold = 750000; else if(player->getLevel() < 22) maxgold = 2000000; else maxgold = ((player->getLevel()-22)*500000) + 3000000; goldneeded = MIN(maxgold, expneeded / 2L); if(player->getRace() == HUMAN) goldneeded += goldneeded/3/10; // Humans have +10% training costs. // Leveling cost temporarily suspended. -TC if(player->getLevel() <= 3) // Free for levels 1-3 to train. goldneeded = 0; if(expneeded > player->getExperience()) { player->print("You need %s more experience.\n", player->expToLevel(false).c_str()); return(0); } if((goldneeded > (player->coins[GOLD] + player->bank[GOLD])) && !player->flagIsSet(P_FREE_TRAIN)) { player->print("You don't have enough gold.\n"); player->print("You need %ld gold to train.\n", goldneeded); return(0); } if(player->getRoom()->whatTraining() != player->getClass()) { player->print("This is not your training location.\n"); return(0); } if(player->getLevel() >= MAXALVL) { player->print("You couldn't possibly train any more!\n"); return(0); } // Prevent power leveling! if(player->flagIsSet(P_JUST_TRAINED)) { player->print("You just trained! You must leave the room and re-enter.\n"); return(0); } if(cmnd->num >= 2 && !strcmp(cmnd->str[1], "dispel")) { player->print("Dispelling stat-modifying magic and abilities.\nPlease wait one moment.\n"); player->removeEffect("strength"); player->removeEffect("haste"); player->removeEffect("fortitude"); player->removeEffect("insight"); player->removeEffect("prayer"); player->loseRage(); player->loseFrenzy(); player->losePray(); return(0); } if( player->underStatSpell() || player->flagIsSet(P_BERSERKED) || player->flagIsSet(P_FRENZY) || player->flagIsSet(P_PRAYED) ) { player->print("You cannot train while under the effects of stat-modifying magic or abilities.\n"); player->print("Type \"train dispel\" to dispel this magic.\n"); return(0); } if(!player->flagIsSet(P_FREE_TRAIN)) { if(goldneeded > player->coins[GOLD]) { bankneeded = goldneeded - player->coins[GOLD]; player->coins.set(0, GOLD); player->bank.sub(bankneeded, GOLD); player->print("You use %ld gold coins from your bank account.\n", bankneeded); banklog(player->name, "WITHDRAW (train) %ld [Balance: %ld]\n", bankneeded, player->bank[GOLD]); } else player->coins.sub(goldneeded, GOLD); } doTrain(player); return(0); } //********************************************************************* // timestr //********************************************************************* char *timestr(long t) { static char buf[BUFSIZ]; if(t >= 60) { sprintf(buf, "%01ld:%02ld", t / 60, t % 60); } else { sprintf(buf, "%ld seconds", t); } return(buf); } #define TIMELEFT(name,ltflag) \ tmp = MAX(0,(LT(player, (ltflag)) - t)); \ player->print("Time left on current %s: %s.\n", name, timestr(tmp)); #define TIMEUNTIL(name,ltflag,time) \ u = (time) - t + player->lasttime[(ltflag)].ltime;\ if(u < 0) u = 0;\ player->print("Time left before next %s: %s.\n", name, timestr(u)); //********************************************************************* // showAbility //********************************************************************* void showAbility(Player* player, const char *skill, const char *display, int lt, int tu, int flag = -1) { long t = time(0), u=0, tmp=0; if(player->knowsSkill(skill)) { if(flag != -1 && player->flagIsSet(flag)) { TIMELEFT(display, lt); } else { TIMEUNTIL(display, lt, tu); } } } //********************************************************************* // cmdTime //********************************************************************* // This function outputs the time of day (realtime) to the player. int cmdTime(Player* player, cmd* cmnd) { long t = time(0), u=0, tmp=0, i=0; ctag *cp=0; const CatRefInfo* cri = gConfig->getCatRefInfo(player->getRoom(), 1); bstring world = ""; if(cri && cri->worldName != "") { world += " of "; world += cri->worldName; } player->clearFlag(P_AFK); if(player->isBraindead()) { player->print("You are brain-dead. You can't do that.\n"); return(0); } player->printColor("^cThe current time in the world%s:\n", world.c_str()); gConfig->getCalendar()->printtime(player); if(gConfig->getCalendar()->isBirthday(player)) player->printColor("^yToday is your birthday!\n"); if(player->flagIsSet(P_PTESTER)) player->print("Tick Interval: %d.\n", player->lasttime[LT_TICK].interval); if(cmnd->num < 2) { // for ceris/aramon when they resurrect dead people tmp = MAX(0,(LT(player, LT_NOMPTICK) - t)); if(tmp > 0) player->print("Time until vitality is restored: %s.\n", timestr(tmp)); // CT+ doesn't need to see all this info if(!player->isCt()) { if(player->getClass() == BARD && player->getLevel() >= 4) { TIMEUNTIL("bard song", LT_SING, player->lasttime[LT_SING].interval); } showAbility(player, "barkskin", "barkskin", LT_BARKSKIN, 600); showAbility(player, "berserk", "berserk", LT_BERSERK, 600, P_BERSERKED); showAbility(player, "bite", "bite", LT_PLAYER_BITE, player->lasttime[LT_PLAYER_BITE].interval); showAbility(player, "bloodsac", "blood sacrifice", LT_BLOOD_SACRIFICE, 600, P_BLOODSAC); showAbility(player, "commune", "commune", LT_PRAY, 45); showAbility(player, "charm", "charm", LT_HYPNOTIZE, player->lasttime[LT_HYPNOTIZE].interval); showAbility(player, "creeping-doom", "creeping-doom", LT_SMOTHER, player->lasttime[LT_SMOTHER].interval); showAbility(player, "disarm", "disarm", LT_DISARM, player->lasttime[LT_DISARM].interval); showAbility(player, "drain", "drain life", LT_DRAIN_LIFE, player->lasttime[LT_DRAIN_LIFE].interval); showAbility(player, "smother", "earth-smother", LT_SMOTHER, player->lasttime[LT_SMOTHER].interval); showAbility(player, "enthrall", "enthrall", LT_HYPNOTIZE, player->lasttime[LT_HYPNOTIZE].interval); showAbility(player, "focus", "focus", LT_FOCUS, 600, P_FOCUSED); showAbility(player, "frenzy", "frenzy", LT_FRENZY, 600, P_FRENZY); showAbility(player, "harm", "harm touch", LT_LAY_HANDS, player->lasttime[LT_LAY_HANDS].interval); showAbility(player, "holyword", "holyword", LT_SMOTHER, player->lasttime[LT_SMOTHER].interval); showAbility(player, "howl", "howl", LT_HOWLS, 240); showAbility(player, "hypnotize", "hypnotize", LT_HYPNOTIZE, player->lasttime[LT_HYPNOTIZE].interval); if( player->knowsSkill("identify") || player->canBuildObjects() ) { TIMEUNTIL("identify", LT_IDENTIFY, player->lasttime[LT_IDENTIFY].interval); } showAbility(player, "hands", "lay on hands", LT_LAY_HANDS, player->lasttime[LT_LAY_HANDS].interval); showAbility(player, "maul", "maul", LT_KICK, player->lasttime[LT_KICK].interval); showAbility(player, "meditate", "meditate", LT_MEDITATE, 90); showAbility(player, "mistbane", "mistbane", LT_FOCUS, 600, P_MISTBANE); showAbility(player, "poison", "poison", LT_DRAIN_LIFE, player->lasttime[LT_DRAIN_LIFE].interval); showAbility(player, "pray", "pray", LT_PRAY, 600, P_PRAYED); showAbility(player, "regenerate", "regenerate", LT_REGENERATE, player->lasttime[LT_REGENERATE].interval); showAbility(player, "renounce", "renounce", LT_RENOUNCE, player->lasttime[LT_RENOUNCE].interval); showAbility(player, "touch", "touch of death", LT_TOUCH_OF_DEATH, player->lasttime[LT_TOUCH_OF_DEATH].interval); showAbility(player, "turn", "turn undead", LT_TURN, player->lasttime[LT_TURN].interval); showAbility(player, "scout", "scout", LT_SCOUT, player->lasttime[LT_SCOUT].interval); } if(player->flagIsSet(P_OUTLAW)) { i = LT(player, LT_OUTLAW); player->print("Outlaw time remaining: "); if(i - t > 3600) player->print("%02d:%02d:%02d more hours.\n",(i - t) / 3600L, ((i - t) % 3600L) / 60L, (i - t) % 60L); else if((i - t > 60) && (i - t < 3600)) player->print("%d:%02d more minutes.\n", (i - t) / 60L, (i - t) % 60L); else player->print("%d more seconds.\n", MAX((i - t),0)); } if(player->flagIsSet(P_JAILED)) { if( player->parent_rom && player->parent_rom->flagIsSet(R_MOB_JAIL) ) i = LT(player, LT_MOB_JAILED); else i = LT(player, LT_JAILED); player->print("NOTE: 0 Seconds means you're out any second.\n"); player->print("Jailtime remaining(Approx): "); if(i - t > 3600) player->print("%02d:%02d:%02d more hours.\n",(i - t) / 3600L, ((i - t) % 3600L) / 60L, (i - t) % 60L); else if((i - t > 60) && (i - t < 3600)) player->print("%d:%02d more minutes.\n", (i - t) / 60L, (i - t) % 60L); else player->print("%d more seconds.\n", MAX((i - t),0)); } // All those confusing defines, i'll make up my own code i = 0; cp = player->first_fol; while(cp) { if(cp->crt->isMonster() && cp->crt->isPet()) { i = 1; if(cp->crt->isUndead()) player->print("Time left before creature following you leaves/fades: %s\n", timestr(cp->crt->lasttime[LT_ANIMATE].ltime+cp->crt->lasttime[LT_ANIMATE].interval-t)); else player->print("Time left before creature following you leaves/fades: %s\n", timestr(cp->crt->lasttime[LT_INVOKE].ltime+cp->crt->lasttime[LT_INVOKE].interval-t)); //TIMEUNTIL("hire",LT_INVOKE,player->lasttime[LT_INVOKE].interval); } cp = cp->next_tag; } // only show how long until next if they don't have a pet already if(!i) { if( player->getClass() == DRUID || (player->getClass() == CLERIC && player->getDeity() == GRADIUS) ) { TIMEUNTIL("conjure", LT_INVOKE, player->lasttime[LT_INVOKE].interval); } if( player->getClass() == CLERIC && player->getDeity() == ARAMON && player->getAdjustedAlignment() <= REDDISH ) { TIMEUNTIL("animate dead", LT_ANIMATE, player->lasttime[LT_ANIMATE].interval); } } } return(0); } //********************************************************************* // cmdSave //********************************************************************* // This is the function that is called when a players types save // It calls save() (the real save function) and then tells the user // the player was saved. See save() for more details. int cmdSave(Player* player, cmd* cmnd) { ASSERTLOG( player ); player->clearFlag(P_AFK); if(player->isBraindead()) { player->print("You are brain-dead. You can't do that.\n"); return(0); } player->save(true); // Save storage rooms if(player->parent_rom && player->parent_rom->info.isArea("stor")) gConfig->resaveRoom(player->parent_rom->info); player->print("Player saved.\n"); return(0); }