/*
* equipment.cpp
* Functions dealing with players equipment/inventory
* ____ _
* | _ \ ___ __ _| |_ __ ___ ___
* | |_) / _ \/ _` | | '_ ` _ \/ __|
* | _ < __/ (_| | | | | | | \__ \
* |_| \_\___|\__,_|_|_| |_| |_|___/
*
* 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-2012 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 "factions.h"
#include "commands.h"
#include "property.h"
#include "unique.h"
#include "calendar.h"
#include "quests.h"
#include "effects.h"
#include <sstream>
int cmdCompare(Player* player, cmd* cmnd) {
if(!player->ableToDoCommand())
return(0);
if(cmnd->num < 2) {
*player << "What would you like to compare?\n";
return(0);
}
Object* toCompare = 0;
Object* compareTo = 0;
// Attempt to compare to something we're wearing
toCompare = player->findObject(player, cmnd, 1);
if(!toCompare) {
*player << "You don't have that in your inventory.\n";
return(0);
}
if(cmnd->num == 2) {
for(int i=0; i<MAXWEAR; i++) {
if( player->ready[i] ) {
if( player->ready[i]->getType() == toCompare->getType()
&& player->ready[i]->getWearflag() == toCompare->getWearflag())
{
compareTo = player->ready[i];
break;
}
}
}
if(!compareTo) {
*player << "You're not wearing anything to compare it with!\n";
return(0);
}
} else {
// cmnd > 2
compareTo = player->findObject(player, cmnd, 2);
if(!compareTo) {
*player << "You don't have that in your inventory to compare with!\n";
return(0);
}
}
if(toCompare->getWearflag() != compareTo->getWearflag() ||
toCompare->getType() != compareTo->getType()) {
*player << ColorOn << "You don't know how to compare " << toCompare << " to " << compareTo << "!\n" << ColorOff;
return(0);
}
if(toCompare == compareTo) {
*player << ColorOn << "You compare " << compareTo << " to itself...it looks about the same.\n" << ColorOff;
return(0);
}
if(toCompare->getType() == WEAPON) {
*player << ColorOn << setf(CAP) << toCompare << " seems ";
if(toCompare->getDps() > compareTo->getDps()) {
*player << ColorOn << "^gbetter^x than ";
} else if(toCompare->getDps() < compareTo->getDps()) {
*player << ColorOn << "^rworse^x than ";
} else {
*player << "about the same as " << ColorOff;
}
*player << compareTo << ".\n";
} else if(toCompare->getType() == ARMOR) {
*player << ColorOn << setf(CAP) << toCompare << " seems ";
if(toCompare->getArmor() > compareTo->getArmor()) {
*player << ColorOn << "^gbetter^x than ";
} else if(toCompare->getArmor() < compareTo->getArmor()) {
*player << ColorOn << "^rworse^x than ";
} else {
*player << "about the same as ";
}
*player << compareTo << ".\n" << ColorOff;
} else {
*player << ColorOn << "You don't know how to compare " << toCompare << " to " << compareTo << "!\n" << ColorOff;
}
return(0);
}
// Rules for creating a new ownership object for unique items
// no - pet gets
// yes -get from normal room
// yes -get from normal container in room
// no - get from storage room
// no - get from storage container in room
// no - get from own container
//*********************************************************************
// equip
//*********************************************************************
bool Creature::equip(Object* object, bool showMessage) {
bool isWeapon = false;
switch(object->getWearflag()) {
case BODY:
case ARMS:
case LEGS:
case HANDS:
case HEAD:
case FEET:
case FACE:
case HELD:
case SHIELD:
case NECK:
case BELT:
// handle armor
ready[object->getWearflag()-1] = object;
break;
case FINGER:
// handle rings
for(int i=FINGER1; i<FINGER8+1; i++) {
if(!ready[i-1]) {
ready[i-1] = object;
break;
}
}
break;
case WIELD:
// handle weapons
if(!ready[WIELD-1]) {
// weapons going in the first hand
if(showMessage) {
printColor("You wield %1P.\n", object);
broadcast(getSock(), getRoomParent(), "%M wields %1P.", this, object);
}
ready[WIELD-1] = object;
} else if(!ready[HELD-1]) {
// weapons going in the off hand
if(showMessage) {
printColor("You wield %1P in your off hand.\n", object);
broadcast(getSock(), getRoomParent(), "%M wields %1P in %s off hand.",
this, object, hisHer());
}
ready[HELD-1] = object;
} else
return(false);
isWeapon = true;
break;
default:
return(false);
}
// message for armor/rings
if(!isWeapon && showMessage) {
printColor("You wear %1P.\n", object);
broadcast(getSock(), getRoomParent(), "%M wore %1P.", this, object);
}
if(showMessage && object->getType() != CONTAINER && object->use_output[0])
printColor("%s\n", object->use_output);
object->setFlag(O_WORN);
delObj(object, false, false, true, false, true);
if(object->flagIsSet(O_EQUIPPING_BESTOWS_EFFECT)) {
if(Effect::objectCanBestowEffect(object->getEffect())) {
if(!isEffected(object->getEffect())) {
// passing keepApplier = true, which means this effect will continue to point to this object
addEffect(object->getEffect(), object->getEffectDuration(), object->getEffectStrength(), object, true, this, true);
}
} else {
object->clearFlag(O_EQUIPPING_BESTOWS_EFFECT);
if(isStaff())
printColor("^MClearing flag EquipEffect flag from %s^M.\n", object->getCName());
}
}
return(true);
}
//*********************************************************************
// unequip
//*********************************************************************
Object* Creature::unequip(int wearloc, UnequipAction action, bool darkness, bool showEffect) {
wearloc--;
Object* object = ready[wearloc];
ready[wearloc] = 0;
if(object) {
object->clearFlag(O_WORN);
if(object->flagIsSet(O_EQUIPPING_BESTOWS_EFFECT))
removeEffect(object->getEffect(), showEffect, true, object);
// don't run checkDarkness if this isnt a dark item
if(!object->flagIsSet(O_DARKNESS))
darkness = false;
if(action == UNEQUIP_DELETE) {
Limited::remove(getAsPlayer(), object);
darkness = object->flagIsSet(O_DARKNESS);
delete object;
object = 0;
} else if(action == UNEQUIP_ADD_TO_INVENTORY) {
darkness = false;
addObj(object);
}
}
if(darkness)
checkDarkness();
return(object);
}
//*********************************************************************
// cmdUse
//*********************************************************************
// This function allows a player to use an item without specifying the
// special command for its type. Use determines which type of item
// it is, and calls the appropriate functions.
int cmdUse(Player* player, cmd* cmnd) {
Object *object=0;
BaseRoom* room = player->getRoomParent();
unsigned long amt=0;
player->clearFlag(P_AFK);
if(!player->ableToDoCommand())
return(0);
if(cmnd->num < 2) {
player->print("Use what?\n");
return(0);
}
if(!strcmp(cmnd->str[1], "all"))
return(cmdWear(player, cmnd));
object = player->findObject(player, cmnd, 1);
if(!object) {
object = room->findObject(player, cmnd, 1);
if(!object && player->ready[HELD-1]) {
object = player->ready[HELD-1];
} else if(!object || !object->flagIsSet(O_CAN_USE_FROM_FLOOR)) {
player->print("Use what?\n");
return(0);
} else if(object->flagIsSet(O_CAN_USE_FROM_FLOOR)) {
//onfloor = 1;
// cmnd->num = 2;
}
}
if(object->flagIsSet(O_COIN_OPERATED_OBJECT)) {
amt = object->getCoinCost();
if(amt <= 0) {
player->printColor("%O is currently out of order.\n", object);
return(0);
}
if(amt > player->coins[GOLD]) {
player->printColor("You don't have enough gold to use %P.\n", object);
return(0);
}
player->printColor("You spend %ld gold coin%s on %P.\n", amt,
amt != 1 ? "s" : "", object);
broadcast(player->getSock(), room, "%M puts some coins in %P.", player, object);
gServer->logGold(GOLD_OUT, player, Money(amt, GOLD), object, "CoinOperated");
player->coins.sub(amt, GOLD);
}
player->unhide();
if(object->flagIsSet(O_FISHING))
return(cmdHold(player, cmnd));
if(object->flagIsSet(O_EATABLE) || object->flagIsSet(O_DRINKABLE))
return(cmdConsume(player, cmnd));
switch(object->getType()) {
case WEAPON:
return(cmdReady(player, cmnd));
case ARMOR:
return(cmdWear(player, cmnd));
case POTION:
return(cmdConsume(player, cmnd));
case SCROLL:
return(cmdReadScroll(player, cmnd));
case WAND:
return(cmdUseWand(player, cmnd));
case KEY:
return(cmdUnlock(player, cmnd));
case LIGHTSOURCE:
return(cmdHold(player, cmnd));
default:
player->print("How does one use that?\n");
}
return(0);
}
//*********************************************************************
// doWear
//*********************************************************************
// actual code to wear object
bool doWear(Player* player, cmd* cmnd) {
Object *object=0;
player->clearFlag(P_AFK);
if(!player->ableToDoCommand())
return(false);
if(player->flagIsSet(P_SITTING)) {
player->print("You must stand to do that.\n");
return(false);
}
if(cmnd && cmnd->num < 2) {
player->print("Wear what?\n");
return(false);
}
player->unhide();
if(cmnd && !strcmp(cmnd->str[1], "all")) {
wearAll(player);
return(false);
}
if(cmnd)
object = player->findObject(player, cmnd, 1);
if(!object) {
player->print("You don't have that.\n");
return(false);
}
if(!player->canUse(object) || !player->canWear(object))
return(false);
if(object->getWearflag() == SHIELD && !player->canWield(object, SHIELDOBJ))
return(false);
object->clearFlag(O_JUST_BOUGHT);
// if cmnd is set, we want to pass true to resetUniqueId
player->equip(object, true);
player->computeAC();
return(true);
}
//*********************************************************************
// cmdWear
//*********************************************************************
// This function allows the player pointed to by the first parameter
// to wear an item specified in the pointer to the command structure
// in the second parameter. That is, if the item is wearable.
int cmdWear(Player* player, cmd* cmnd) {
doWear(player, cmnd);
return(0);
}
//*********************************************************************
// wearCursed
//*********************************************************************
void Player::wearCursed() {
Object *object=0;
ObjectSet::iterator it;
for( it = objects.begin() ; it != objects.end() ; ) {
object = (*it++);
if(object->flagIsSet(O_CURSED) && object->flagIsSet(O_WORN)) {
if(object->getShotsCur() < 1) {
object->clearFlag(O_WORN);
} else {
if( ready[WIELD-1] &&
object->getType() == WEAPON &&
object->flagIsSet(O_CURSED)
) {
if(ready[HELD-1]) {
ready[HELD-1] = 0;
object->clearFlag(O_WORN);
addObj(object);
}
delObj(object, false, false, true, false, true);
ready[HELD-1] = object;
object->setFlag(O_WORN);
if(object->getWeight() > ready[WIELD-1]->getWeight()) {
ready[HELD-1] = ready[WIELD-1];
ready[WIELD-1] = object;
}
} else {
equip(object, false);
}
}
}
}
}
//*********************************************************************
// wear_all
//*********************************************************************
// This function allows a player to wear everything in their inventory that
// they possibly can.
void wearAll(Player* player, bool login) {
char str[4096], str2[85];
bool found=false;
str[0] = 0;
if(!login) {
if(!player->ableToDoCommand()) return;
if(player->flagIsSet(P_SITTING)) {
player->print("You must stand to do that.\n");
return;
}
}
Object *object=0;
ObjectSet::iterator it;
for( it = player->objects.begin() ; it != player->objects.end() ; ) {
object = (*it++);
if(object->getWearflag() && object->getWearflag() != HELD && object->getWearflag() != WIELD) {
if(!player->canSee(object))
continue;
if(!player->canUse(object, true) || !player->canWear(object, true))
continue;
if(object->getWearflag() == SHIELD && player->ready[HELD-1] && !object->flagIsSet(O_SMALL_SHIELD))
continue;
if(object->getWearflag() == SHIELD && !player->canWield(object, SHIELDOBJ))
continue;
if(!login && object->use_output[0] && object->getType() != CONTAINER && object->getWearflag() != FINGER)
player->printColor("%s\n", object->use_output);
object->clearFlag(O_JUST_BOUGHT);
if(!login) {
sprintf(str2, "%s, ", object->getObjStr(NULL, 0, 1).c_str());
strcat(str, str2);
}
player->equip(object, false);
found = true;
}
}
if(found) {
player->computeAC();
if(!login) {
str[strlen(str)-2] = 0;
player->printColor("You wear %s.\n", str);
broadcast(player->getSock(), player->getParent(), "%M wears %s.", player, str);
}
} else
if(!login)
player->print("You have nothing you can wear.\n");
}
//*********************************************************************
// doRemoveObj
//*********************************************************************
// This function does the heavy lifting of removing objects
bool doRemoveObj(Player* player, cmd* cmnd ) {
Object *object=0, *second=0;
int found=0, match=0, i=0, jumped=0;
player->clearFlag(P_AFK);
if(!player->ableToDoCommand())
return(false);
if(cmnd && cmnd->num < 2) {
player->print("Remove what?\n");
return(false);
}
player->unhide();
i = 0;
if(!cmnd || cmnd->num > 1) {
if(cmnd && !strcmp(cmnd->str[1], "all")) {
remove_all(player);
return(false);
}
while(i<MAXWEAR) {
object = player->ready[i];
second = 0;
jumped=0;
if(!object) {
i++;
continue;
}
if(cmnd) {
if(keyTxtEqual(object, cmnd->str[1])) {
match++;
if(match == cmnd->val[1]) {
found = 1;
break;
}
}
}
i++;
}
if(!found) {
player->print("You aren't using that.\n");
return(false);
}
if( object->flagIsSet(O_CURSED) &&
object->getShotsCur() > 0 &&
!player->checkStaff("You can't. It's cursed!\n")
)
return(false);
if(i == (WIELD-1)) {
if(player->ready[HELD-1] && player->ready[HELD-1]->getType() == WEAPON) {
second = player->ready[HELD-1];
// if cmnd is set, pass true to resetUniqueId
player->addObj(second);
second->clearFlag(O_WORN);
player->ready[HELD-1] = 0;
}
}
player->doRemove(i);
player->computeAC();
player->computeAttackPower();
if( second &&
second->flagIsSet(O_CURSED) &&
second->flagIsSet(O_WORN) &&
i == (WIELD-1)
) {
player->ready[HELD-1] = 0;
player->ready[WIELD-1] = second;
player->computeAC();
player->computeAttackPower();
if(second->flagIsSet(O_NO_PREFIX)) {
player->printColor("%s jumped to your primary hand! It's cursed!\n", second->getCName());
broadcast(player->getSock(), player->getParent(), "%s jumped to %N's primary hand! It's cursed!",
second->getCName(), player);
} else {
player->printColor("The %s jumped to your primary hand! It's cursed!\n", second->getCName());
broadcast(player->getSock(), player->getParent(), "%M's %s jumped to %s primary hand! It's cursed!", player,
second->getCName(), player->hisHer());
}
jumped = 1;
}
player->printColor("You removed %1P.\n", object);
broadcast(player->getSock(), player->getParent(), "%M removed %1P.", player, object);
if(second && !jumped) {
player->printColor("You removed %1P.\n", second);
broadcast(player->getSock(), player->getParent(), "%M removed %1P.", player, second);
}
object->clearFlag(O_WORN);
}
return(true);
}
//*********************************************************************
// cmdRemoveObj
//*********************************************************************
// This function allows the player pointed to by the first parameter to/
// remove the item specified by the command structure in the second
// parameter from those things which they are wearing.
int cmdRemoveObj(Player* player, cmd* cmnd) {
doRemoveObj(player, cmnd);
return(0);
}
//*********************************************************************
// doRemove
//*********************************************************************
void Player::doRemove(int i) {
i++;
Object* object = unequip(i, UNEQUIP_NOTHING);
addObj(object);
if(i == FEET) {
// Takes some time to remove boots in combat and then kick.
if(inCombat()) {
lasttime[LT_KICK].ltime = time(0);
lasttime[LT_KICK].interval = (cClass == FIGHTER ? 12L:15L);
}
}
if(cClass == FIGHTER && cClass2 == THIEF && object->isHeavyArmor()) {
updateAttackTimer(true, 70);
lasttime[LT_STEAL].ltime = time(0);
lasttime[LT_STEAL].interval = 30;
lasttime[LT_PEEK].ltime = time(0);
lasttime[LT_PEEK].interval = 30;
}
}
//*********************************************************************
// remove_all
//*********************************************************************
// This function allows the player pointed to in the first parameter
// to remove everything they are wearing all at once.
void remove_all(Player* player) {
char str[4096], str2[85];
int i, found=0;
str[0] = 0;
if(!player->ableToDoCommand())
return;
if(player->flagIsSet(P_SITTING)) {
player->print("You must stand to do that.\n");
return;
}
for(i=0; i<MAXWEAR; i++) {
if(player->ready[i] && (!(player->ready[i]->flagIsSet(O_CURSED) && player->ready[i]->getShotsCur() > 0))) {
sprintf(str2,"%s, ", player->ready[i]->getObjStr(NULL, 0, 1).c_str());
strcat(str, str2);
player->ready[i]->clearFlag(O_WORN);
player->doRemove(i);
found = 1;
}
}
if(!found) {
player->print("You aren't wearing anything that can be removed.\n");
return;
}
player->computeAC();
player->computeAttackPower();
str[strlen(str)-2] = 0;
broadcast(player->getSock(), player->getParent(), "%M removes %s.", player, str);
player->printColor("You remove %s.\n", str);
}
//*********************************************************************
// cmdEquipment
//*********************************************************************
// This function outputs to the player all of the equipment that they are
// wearing/wielding/holding on their body.
int cmdEquipment(Player* player, cmd* cmnd) {
Player *target=0;
int i=0, found=0;
player->clearFlag(P_AFK);
if(!player->ableToDoCommand())
return(0);
if(player->isBlind()) {
player->printColor("^CYou can't see anything! You're blind!\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 || !player->canSee(target)) {
player->print("That player is not logged on.\n");
return(0);
}
for(i=0; i<MAXWEAR; i++)
if(target->ready[i])
found = 1;
if(!found) {
player->print("%s isn't wearing anything.\n", target->upHeShe());
return(0);
}
player->print("%s's worn equipment:\n", target->getCName());
target->printEquipList(player);
return(0);
}
}
for(i=0; i<MAXWEAR; i++)
if(player->ready[i])
found = 1;
if(!found) {
player->print("You aren't wearing anything.\n");
return(0);
}
player->printEquipList(player);
return(0);
}
//*********************************************************************
// printEquipList
//*********************************************************************
void Creature::printEquipList(const Player* viewer) {
if(ready[BODY-1])
viewer->printColor("On body: %1P\n", ready[BODY-1]);
if(ready[ARMS-1])
viewer->printColor("On arms: %1P\n", ready[ARMS-1]);
if(ready[LEGS-1])
viewer->printColor("On legs: %1P\n", ready[LEGS-1]);
if(ready[NECK-1])
viewer->printColor("On neck: %1P\n", ready[NECK-1]);
if(ready[HANDS-1])
viewer->printColor("On hands: %1P\n", ready[HANDS-1]);
if(ready[HEAD-1])
viewer->printColor("On head: %1P\n", ready[HEAD-1]);
if(ready[BELT-1])
viewer->printColor("On waist: %1P\n", ready[BELT -1]);
if(ready[FEET-1])
viewer->printColor("On feet: %1P\n", ready[FEET-1]);
if(ready[FACE-1])
viewer->printColor("On face: %1P\n", ready[FACE-1]);
if(ready[FINGER1-1])
viewer->printColor("On finger: %1P\n", ready[FINGER1-1]);
if(ready[FINGER2-1])
viewer->printColor("On finger: %1P\n", ready[FINGER2-1]);
if(ready[FINGER3-1])
viewer->printColor("On finger: %1P\n", ready[FINGER3-1]);
if(ready[FINGER4-1])
viewer->printColor("On finger: %1P\n", ready[FINGER4-1]);
if(ready[FINGER5-1])
viewer->printColor("On finger: %1P\n", ready[FINGER5-1]);
if(ready[FINGER6-1])
viewer->printColor("On finger: %1P\n", ready[FINGER6-1]);
if(ready[FINGER7-1])
viewer->printColor("On finger: %1P\n", ready[FINGER7-1]);
if(ready[FINGER8-1])
viewer->printColor("On finger: %1P\n", ready[FINGER8-1]);
// dual wield
if(ready[HELD-1]) {
if(ready[HELD-1]->getWearflag() != WIELD)
viewer->printColor("Holding: %1P\n", ready[HELD-1]);
else if(ready[HELD-1]->getWearflag() == WIELD)
viewer->printColor("In Hand: %1P\n", ready[HELD-1]);
}
if(ready[SHIELD-1])
viewer->printColor("Shield: %1P\n", ready[SHIELD-1]);
if(ready[WIELD-1])
viewer->printColor("Wielded: %1P\n", ready[WIELD-1]);
}
//*********************************************************************
// cmdReady
//*********************************************************************
// This function allows the player pointed to by the first parameter to
// ready a weapon specified in the second, if it is a weapon.
bool doWield(Player* player, cmd* cmnd) {
Object *object=0;
player->clearFlag(P_AFK);
if(cmnd && cmnd->num < 2) {
player->print("Wield what?\n");
return(false);
}
if(!player->ableToDoCommand())
return(false);
player->unhide();
if(!cmnd || cmnd->num > 1) {
if(cmnd)
object = player->findObject(player, cmnd, 1);
if(!object) {
player->print("You don't have that.\n");
return(false);
}
if(object->getWearflag() != WIELD) {
player->print("You can't wield that.\n");
return(false);
}
if(player->ready[WIELD-1]) {
player->print("You're already wielding something.\n");
return(false);
}
if(player->ready[HELD-1] && player->ready[HELD-1]->getWearflag() == WIELD) {
if(!player->isCt() && (object->getWeight() <= player->ready[HELD-1]->getWeight())) {
player->print("Your primary weapon must be heavier then your secondary weapon.\n");
return(false);
}
}
// these functions print out their reasons for denial
if(!player->canUse(object) || !player->canWield(object, WIELDOBJ))
return(false);
player->equip(object, true);
player->computeAttackPower();
object->clearFlag(O_JUST_BOUGHT);
}
return(true);
}
int cmdReady(Player* player, cmd* cmnd) {
doWield(player, cmnd);
return(0);
}
//*********************************************************************
// cmdHold
//*********************************************************************
// This function allows a player to hold an item if it is designated
// as a hold-able item.
int cmdHold(Player* player, cmd* cmnd) {
Object *object=0;
player->clearFlag(P_AFK);
if(!player->ableToDoCommand())
return(0);
if(cmnd->num < 2) {
player->print("Hold what?\n");
return(0);
}
player->unhide();
if(cmnd->num > 1) {
object = player->findObject(player, cmnd, 1);
if(!object) {
player->print("You don't have that.\n");
return(0);
}
if(object->getWearflag() != HELD) {
player->print("You can't hold that.\n");
return(0);
}
if(!player->canUse(object, false) || !player->canWield(object, HOLDOBJ))
return(0);
if(!player->willFit(object)) {
player->printColor("%O isn't the right size for you.\n", object);
return(0);
}
if(object->getMinStrength() > player->strength.getCur()) {
player->printColor("You are currently not strong enough to hold %P.\n", object);
return(0);
}
player->ready[HELD-1] = object;
player->delObj(object, false, false, true, true, true);
player->printColor("You hold %1P.\n", object);
broadcast(player->getSock(), player->getParent(), "%M holds %1P.", player, object);
if(object->use_output[0] && object->getType() != POTION && object->getType() != CONTAINER && object->getType() != WAND)
player->printColor("%s\n", object->use_output);
object->setFlag(O_WORN);
object->clearFlag(O_JUST_BOUGHT);
}
return(0);
}
//*********************************************************************
// canGetUnique
//*********************************************************************
bool canGetUnique(const Player* player, const Creature* creature, const Object* object, bool print) {
if(player != creature) {
// monsters
if(Unique::is(object)) {
if(print)
player->print("%M cannot get that item.\n", creature);
return(false);
}
} else {
// player
if(!Unique::canGet(player, object)) {
if(print)
player->print("You currently cannot take that limited object.\n");
return(false);
}
}
return(true);
}
//*********************************************************************
// doGetObject
//*********************************************************************
// Parameters: <object> The object bein taken
// <player> The player getting the item
// [doLimited=true] Limited item ownership
// [noSplit=false] Don't split gold items
// [noQuest=false] Don't do quest code
// [noMessage=false] Don't show "You now have xx gold pieces"
// Handles getting of objects
// 0 = normal
// 1 = killMortalObjects is run
// 2 = money
int doGetObject(Object* object, Creature* creature, bool doLimited, bool noSplit, bool noQuest, bool noMessage, bool saveOnLimited) {
// we're being sent either a player or a pet
// - creature will be the one getting the object
// - player will be the one getting the messages
Player *player = creature->getPlayerMaster();
int i = 0;
if(!player) {
creature->print("Unable to get item!\n");
object->addToRoom(creature->getRoomParent());
return(i);
}
if(doLimited) {
if(Limited::addOwner(player, object) == 2)
i = 1;
}
if(!noQuest)
fulfillQuest(player, object);
if(object->getType() == MONEY) {
Group* group = player->getGroup(true);
if(group && group->flagIsSet(GROUP_SPLIT_GOLD) && !noSplit) {
gServer->logGold(GOLD_IN, player, object->value, object, "GetObject-Split");
if(!player->autosplit(object->value[GOLD])) {
player->coins.add(object->value);
}
} else {
player->coins.add(object->value);
gServer->logGold(GOLD_IN, player, object->value, object, "GetObject");
}
delete object;
if(!noMessage)
player->print("You now have %s.\n", player->coins.str().c_str());
player->bug("%s now has %s.\n", player->getCName(), player->coins.str().c_str());
return(2);
} else {
if(saveOnLimited && Limited::is(object))
player->save(true);
creature->addObj(object);
}
return(i);
}
//*********************************************************************
// limitedInStorage
//*********************************************************************
bool limitedInStorage(const Player* player, const Object* object, const Property *p, bool print) {
if( object &&
p &&
Limited::is(object) &&
!p->isOwner(player->getName())
) {
if(print)
player->print("You may only handle limited objects in a storage room if you are the primary owner.\n");
return(false);
}
return(true);
}
//*********************************************************************
// storageProperty
//*********************************************************************
// runs checks to see if the player is allowed to get/drop/throw
bool storageProperty(const Player* player, const Object* object, Property **p) {
if(player->inUniqueRoom()) {
(*p) = gConfig->getProperty(player->getConstUniqueRoomParent()->info);
if(*p) {
// currently, we only care about storage rooms. we don't log gets
// in any other type of property
if((*p)->getType() != PROP_STORAGE)
(*p) = 0;
// are they allowed to get anything?
else if(!(*p)->isOwner(player->getName()) && !(*p)->isPartialOwner(player->getName()) &&
!player->checkStaff("You aren't allowed to do that; this is not your storage room.\n")
)
return(false);
if(!limitedInStorage(player, object, (*p), true))
return(false);
}
}
return(true);
}
//*********************************************************************
// getPermObj
//*********************************************************************
// This function is called whenever someone picks up a permanent item
// from a room. The item's room-permanent flag is cleared, and the
// inventory-permanent flag is set. Also, the room's permanent
// time for that item is updated.
void getPermObj(Object* object) {
std::map<int, crlasttime>::iterator it;
crlasttime* crtm=0;
Object *temp_obj;
UniqueRoom* room=0;
long t = time(0);
object->setFlag(O_PERM_INV_ITEM);
object->clearFlag(O_PERM_ITEM);
room = object->getUniqueRoomParent();
if(!room)
return;
for(it = room->permObjects.begin(); it != room->permObjects.end() ; it++) {
crtm = &(*it).second;
if(!crtm->cr.id)
continue;
if(crtm->ltime + crtm->interval > t)
continue;
if(!loadObject(crtm->cr, &temp_obj))
continue;
if(temp_obj->getName() == object->getName()) {
crtm->ltime = t;
delete temp_obj;
break;
}
delete temp_obj;
}
}
//*********************************************************************
// getAllObj
//*********************************************************************
// This function allows a player to get the entire contents from a
// container object. The player is pointed to by the first parameter and
// the container by the second.
void getAllObj(Creature* creature, Object *container) {
Player *player = creature->getPlayerMaster();
Property *p=0;
Object *object=0, *last_obj=0;
char str[2048];
const char *str2;
int n=1, found=0, heavy=0;
bool doUnique=false, saveLimited=false;
str[0] = 0;
// we're being sent either a player or a pet
// - creature will be the one getting the object
// - player will be the one getting the messages
if(!player) {
creature->print("Unable to get all!\n");
return;
}
if(!player->ableToDoCommand())
return;
// are they allowed to put objects from this storage room?
if(!storageProperty(player, 0, &p))
return;
doUnique = !container->inCreature() && !p;
ObjectSet::iterator it;
for( it = container->objects.begin() ; it != container->objects.end() ; ) {
object = (*it++);
if( !object->flagIsSet(O_SCENERY) && !object->flagIsSet(O_NO_TAKE) &&
!object->flagIsSet(O_HIDDEN) && player->canSee(object) )
{
found++;
if(player->getWeight() + object->getActualWeight() > player->maxWeight()) {
heavy++;
continue;
}
if(player->tooBulky(object->getActualBulk())) {
heavy++;
continue;
}
if(doUnique && !Lore::canHave(player, object)) {
heavy++;
continue;
}
// on ground and quest
if(!container->inCreature() && object->getQuestnum()) {
if(player->questIsSet(object->getQuestnum()-1)) {
heavy++;
continue;
} else
fulfillQuest(player, object);
}
if(!p && !canGetUnique(player, creature, object, false)) {
heavy++;
continue;
}
if(object->flagIsSet(O_TEMP_PERM)) {
object->clearFlag(O_PERM_INV_ITEM);
object->clearFlag(O_TEMP_PERM);
}
if(object->flagIsSet(O_PERM_ITEM))
getPermObj(object);
container->delObj(object);
if(last_obj && last_obj->showAsSame(player, object))
n++;
else if(last_obj) {
// BUGFIX: Assigning the c_str() of a bstring to a char, and it's still being accessed after the bstring goes out of scope (this line)
bstring lastObjStr = last_obj->getObjStr(NULL, 0, n);
str2 = lastObjStr.c_str();
if(strlen(str2)+strlen(str) < 2040) {
strcat(str, str2);
strcat(str, ", ");
n = 1;
}
}
if(object->getType() == MONEY) {
last_obj = 0;
} else {
last_obj = object;
}
// don't let doGetObject save the player, handle it right here
saveLimited = saveLimited || Limited::is(object);
// Ignore quest items
doGetObject(object, creature, doUnique, false, true, false, false);
}
}
if(found && last_obj) {
bstring objStr = object->getObjStr(NULL, 0, n);
if(objStr.length() +strlen(str) < 2040)
strcat(str, objStr.c_str());
} else if(!found) {
player->print("There's nothing in it.\n");
return;
}
if(heavy) {
if(creature == player)
player->print("You weren't able to carry everything.\n");
else
player->print("%M wasn't able to carry everything.\n", creature);
if(heavy == found)
return;
}
if(!strlen(str))
return;
broadcast(player->getSock(), player->getParent(), "%M gets %s from %1P.", creature, str, container);
player->bug("%s%s gets %s from %s.\n", player->getCName(), player != creature ? "'s pet" : "", str, container->getCName());
if(player == creature)
player->printColor("You get %s from %1P.\n", str, container);
else
player->printColor("%M gets %s from %1P.\n", creature, str, container);
if(p)
p->appendLog(player->getName(), "%s gets %s.", player->getCName(), str);
if(saveLimited)
player->save(true);
}
//*********************************************************************
// get_all_rom
//*********************************************************************
// This function will cause the creature pointed to by the first parameter
// to get everything they are able to see in the room.
void get_all_rom(Creature* creature, char *item) {
Player *player = creature->getPlayerMaster();
BaseRoom* room = creature->getRoomParent();
Object *object=0, *last_obj=0;
char str[2048];
const char *str2;
int n=1, found=0, heavy=0, dogoldmsg=0;
// we're being sent either a player or a pet
// - creature will be the one getting the object
// - player will be the one getting the messages
if(!player) {
creature->print("Unable to get all!\n");
return;
}
if(!player->ableToDoCommand())
return;
last_obj = 0;
str[0] = 0;
if(!player->isStaff()) {
for(Player* ply : room->players) {
if( ply != player &&
player->canSee(ply) &&
!ply->flagIsSet(P_HIDDEN) &&
!player->inSameGroup(ply) &&
!ply->isStaff())
{
player->print("You cannot do that when someone else is in the room.\n");
return;
}
}
}
ObjectSet::iterator it;
for( it = room->objects.begin() ; it != room->objects.end() && strlen(str) < 2040 ; ) {
object = (*it++);
if( !object->flagIsSet(O_SCENERY) && !object->flagIsSet(O_NO_TAKE) &&
!object->flagIsSet(O_HIDDEN) && player->canSee(object) )
{
found++;
if(item && !keyTxtEqual(object, item))
continue;
if(player->getWeight() + object->getActualWeight() > player->maxWeight()) {
heavy++;
continue;
}
if(player->tooBulky(object->getActualBulk())) {
heavy++;
continue;
}
if(!Lore::canHave(player, object)) {
heavy++;
continue;
}
if(object->getQuestnum() && player->questIsSet(object->getQuestnum()-1)) {
heavy++;
continue;
}
if(!canGetUnique(player, creature, object, false)) {
heavy++;
continue;
}
if(object->flagIsSet(O_TEMP_PERM)) {
object->clearFlag(O_PERM_INV_ITEM);
object->clearFlag(O_TEMP_PERM);
}
if(object->flagIsSet(O_PERM_ITEM))
getPermObj(object);
object->clearFlag(O_HIDDEN);
object->deleteFromRoom();
if(last_obj && last_obj->showAsSame(player, object))
n++;
else if(last_obj) {
bstring oStr = last_obj->getObjStr(NULL, 0, n);
str2 = oStr.c_str();
if(strlen(str2)+strlen(str) < 2040) {
strcat(str, str2);
strcat(str, ", ");
n=1;
}
}
if(object->getType() == MONEY) {
bstring strtmp = object->getObjStr(NULL, 0, 1);
str2 = strtmp.c_str();
if(strlen(str2)+strlen(str) < 2040) {
strcat(str, str2);
strcat(str, ", ");
}
last_obj = 0;
dogoldmsg = 1;
} else {
last_obj = object;
}
// Don't show "You now have xxx message
// if killMortalObjects is run, we need to use the previous tag
// because op might be pointing to invalid memory
if(doGetObject(object, creature, true, false, false, true) == 1) {
if(player == creature)
player->print("You are interrupted from getting anything else.\n");
else
player->print("%M was interrupted from getting anything else.\n", creature);
break;
}
}
}
if(found && last_obj) {
bstring objStr = last_obj->getObjStr(NULL, 0, n);
str2 = objStr.c_str();
if(strlen(str2)+strlen(str) < 2040)
strcat(str, str2);
} else if(!found) {
player->print("There's nothing here.\n");
return;
}
if(dogoldmsg && !last_obj)
str[strlen(str)-2] = 0;
if(heavy) {
if(creature == player)
player->print("You weren't able to carry everything.\n");
else
player->print("%M wasn't able to carry everything.\n", creature);
if(heavy == found)
return;
}
if(!strlen(str))
return;
broadcast(player->getSock(), room, "%M gets %s.", creature, str);
player->bug("%s%s gets %s.\n", player->getCName(), player != creature ? "'s pet" : "", str);
if(player == creature)
player->printColor("You get %s.\n", str);
else
player->printColor("%M gets %s.\n", creature, str);
if(dogoldmsg)
player->print("You now have %ld gold pieces.\n", player->coins[GOLD]);
}
//*********************************************************************
// cmdGet
//*********************************************************************
// This function allows players or pets to get things lying on the floor or
// inside another object.
int cmdGet(Creature* creature, cmd* cmnd) {
Player *player = creature->getPlayerMaster();
BaseRoom* room = creature->getRoomParent();
Object *object=0, *container=0;
int n=0, match=0, ground=0;
Monster *pet=0;
Property* p=0;
// we're being sent either a player or a pet
// - creature will be the one getting the object
// - player will be the one getting the messages
if(!player) {
creature->print("Unable to get!\n");
return(0);
}
if(!player->ableToDoCommand())
return(0);
player->clearFlag(P_AFK);
if(player->getClass() == BUILDER) {
if(!player->canBuildObjects()) {
player->print("You are not allowed get items.\n");
return(0);
}
if(!player->checkBuilder(player->getUniqueRoomParent())) {
player->print("Error: Room number not inside any of your alotted ranges.\n");
return(0);
}
}
if(cmnd->num < 2) {
player->print("Get what?\n");
return(0);
}
player->unhide();
if(cmnd->num == 2) {
if(!player->isStaff() && room->flagIsSet(R_SHOP_STORAGE)) {
player->print("You cannot get anything here.\n");
return(0);
}
if(isGuardLoot(room, player, "%M won't let you take anything.\n"))
return(0);
if(player->isBlind()) {
player->printColor("^CYou can't see to do that!\n");
return(0);
}
if(!strcmp(cmnd->str[1], "all")) {
if(cmnd->num == 3)
get_all_rom(creature, cmnd->str[2]);
else
get_all_rom(creature, 0);
return(0);
}
object = room->findObject(player, cmnd, 1);
if(!object) {
player->print("That isn't here.\n");
return(0);
}
if( !player->canSee(object) &&
!player->checkStaff("That isn't here.\n") )
return(0);
if( (object->flagIsSet(O_NO_TAKE) || object->flagIsSet(O_SCENERY)) &&
!player->checkStaff("You can't take that!\n") )
return(0);
// are they allowed to get objects from this storage room?
if(!storageProperty(player, object, &p))
return(0);
if(!canGetUnique(player, creature, object, true))
return(0);
if(!Lore::canHave(player, object, false)) {
player->print("You already have enough of those.\nYou cannot currently have any more.\n");
return(0);
}
if(!Lore::canHave(player, object, true)) {
player->print("You cannot get that item.\nIt contains a limited item that you cannot carry.\n");
return(0);
}
if(player->getLevel() < object->getLevel() && object->getQuestnum() > 0 &&
!player->checkStaff("You are not high enough level to pick that up yet.\n")
)
return(0);
if( (player->getWeight() + object->getActualWeight()) > player->maxWeight() &&
!player->checkStaff("You can't carry anymore.\n")
)
return(0);
if( player->tooBulky(object->getActualBulk()) &&
!player->checkStaff("That is too bulky to fit in your inventory right now.\n")
)
return(0);
if( object->getQuestnum() &&
player->questIsSet(object->getQuestnum()-1) &&
!player->checkStaff("You may not take that. You have already fulfilled that quest.\n")
)
return(0);
for(Object *obj : object->objects) {
if( obj->getQuestnum() && player->questIsSet(obj->getQuestnum()-1) &&
!player->checkStaff("You may not take that.\nIt contains an item for a quest you have already completed.\n"))
return(0);
}
if(object->flagIsSet(O_TEMP_PERM)) {
object->clearFlag(O_PERM_INV_ITEM);
object->clearFlag(O_TEMP_PERM);
}
if(object->flagIsSet(O_PERM_ITEM))
getPermObj(object);
if(player == creature && !player->isStaff()) {
// The following keeps misted vampires from
// stealing loot off the ground from people. -TC
player->unmist();
// Mist timer always reset when getting something
if(player->isEffected("vampirism")) {
player->lasttime[LT_MIST].ltime = time(0);
player->lasttime[LT_MIST].interval = 10L;
}
}
object->clearFlag(O_HIDDEN);
if(player == creature) {
player->printColor("You get %1P.\n", object);
} else
player->printColor("%M gets %1P.\n", creature, object);
player->bug("%s%s gets %s.\n", player->getCName(), player != creature ? "'s pet" : "", object->getCName());
if(object->flagIsSet(O_SILVER_OBJECT) && player->isEffected("lycanthropy")) {
if(player == creature)
player->printColor("%O burns you and you drop it!\n", object);
else
player->printColor("%O burns %N and %s drop it!\n", object, creature, creature->heShe());
broadcast(player->getSock(), room, "%M is burned by %P.", creature, object);
player->bug("%s%s burned %s and %s dropped it.\n",
player->getCName(), player != creature ? "'s pet" : "", object->getCName(), creature->heShe());
//player->delObj(object, false, true);
//object->addToRoom(room);
return(0);
}
object->deleteFromRoom();
broadcast(player->getSock(), room, "%M gets %1P.", creature, object);
doGetObject(object, creature);
} else {
container = creature->findObject(player, cmnd, 2);
if(!container) {
container = room->findObject(player, cmnd, 2);
if(container) {
if(!player->isStaff() && room->flagIsSet(R_SHOP_STORAGE)) {
player->print("You cannot get anything here.\n");
return(0);
}
ground = true;
}
}
// only check wear for players
if(player == creature && (!container || !cmnd->val[2])) {
for(n=0; n < MAXWEAR; n++) {
if(!player->ready[n])
continue;
if(keyTxtEqual(player->ready[n], cmnd->str[2]))
match++;
else
continue;
if(match == cmnd->val[2] || !cmnd->val[2]) {
container = player->ready[n];
break;
}
}
}
object = 0;
pet = 0;
if(!container && player == creature) {
// check for pets
pet = room->findMonster(player, cmnd, 2);
if(pet) {
if(!player->findPet(pet)) {
player->print("%M is not your pet!\n", pet);
return(0);
}
object = pet->findObject(pet, cmnd, 1);
if(!object) {
player->print("%M doesn't have %s.\n", pet, mrand(0, 1) ? "that" : "one of those");
return(0);
}
}
}
if(!object) {
pet = 0;
if(!container) {
player->print("That isn't here.\n");
return(0);
}
if(container->getType() != CONTAINER) {
player->print("That isn't a container.\n");
return(0);
}
if(ground && isGuardLoot(room, player, "%M won't let you take anything.\n"))
return(0);
if(!strcmp(cmnd->str[1], "all")) {
if(player->flagIsSet(P_NO_GET_ALL)) {
player->print("You have lost the privilage to get all for now.\n");
return(0);
}
getAllObj(creature, container);
return(0);
}
object = container->findObject(player, cmnd, 1);
if(!object) {
player->print("That isn't in there.\n");
return(0);
}
// are they allowed to put objects from this storage room?
if(!storageProperty(player, object, &p))
return(0);
}
bool doUnique = !p && !pet && ground;
if(doUnique && !canGetUnique(player, creature, object, true))
return(0);
// if the container is on the ground, we have to prevent them from
// getting quest items
if(ground && object->getQuestnum()) {
if(player->questIsSet(object->getQuestnum()-1)) {
if(!player->checkStaff("You may not take that. You have already fulfilled that quest.\n"))
return(0);
} else {
fulfillQuest(player, object);
}
}
// TODO: Dom: add monster weight check so we don't have monsters carrying tons of items!
// right now they are forced to obey player's weight/bulk rules
// Weight has already been taken into account if it's in a container in the inventory,
// but not if it is in the room or on the pet
if( player->getWeight() + object->getActualWeight() > player->maxWeight() &&
((container && container->inRoom()) || pet) &&
!player->checkStaff("You can't carry anymore.\n")
) return(0);
// Make sure it's not too bulky to fit in the player's inventory
if(player->tooBulky(object->getActualBulk()) &&
!player->checkStaff("That is too bulky to fit in your inventory right now.\n"))
return(0);
if(ground && !pet && !p) {
if(!Lore::canHave(player, object, false)) {
player->print("You already have enough of those.\nYou cannot currently have any more.\n");
return(0);
}
if(!Lore::canHave(player, object, true)) {
player->print("You cannot get that item.\nIt contains a limited item that you cannot carry.\n");
return(0);
}
}
if(object->flagIsSet(O_PERM_ITEM))
getPermObj(object);
if(pet) {
pet->delObj(object);
player->printColor("You get %1P from %N.\n", object, pet);
broadcast(player->getSock(), room, "%M gets %1P from %N.", player, object, pet);
} else {
container->delObj(object);
if(player == creature)
player->printColor("You get %1P from %1P.\n", object, container);
else
player->printColor("%M gets %1P from %1P.\n", creature, object, container);
broadcast(player->getSock(), room, "%M gets %1P from %1P.", creature, object, container);
player->bug("%s%s get's %s from %s.\n", player->getCName(), player != creature ? "'s pet" : "", object->getCName(), container->getCName());
}
if(p)
p->appendLog(player->getName(), "%s gets %s.", player->getCName(), object->getObjStr(player, player->displayFlags(), 1).c_str());
// Don't ignore split, Do ignore quest
doGetObject(object, creature, doUnique, false, true);
}
return(0);
}
//*********************************************************************
// cmdInventory
//*********************************************************************
// This function outputs the contents of a player's inventory.
int cmdInventory(Player* player, cmd* cmnd) {
Player *target = player;
int m=0, n=0, flags = player->displayFlags();
bool online=true;
std::ostringstream oStr;
player->clearFlag(P_AFK);
if(!player->ableToDoCommand())
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) {
online = false;
if(!loadPlayer(cmnd->str[1], &target)) {
player->print("Player does not exist.\n");
return(0);
}
}
if(target->isDm() && !player->isDm()) {
player->print("You are not allowed to do that.\n");
if(!online)
free_crt(target);
return(0);
}
if(cmnd->num > 2) {
peek_bag(player, target, cmnd, 1);
if(!online)
free_crt(target);
return(0);
}
}
}
if(target != player && player->isBlind()) {
player->printColor("^CYou can't do that! You're blind!\n");
return(0);
}
if(player == target)
oStr << "You have: ";
else
oStr << target->getName() << "'s inventory: ";
ObjectSet::iterator it;
Object* obj;
for( it = target->objects.begin() ; it != target->objects.end() ; ) {
obj = (*it++);
if(player->canSee(obj)) {
m = 1;
while( it != target->objects.end() ) {
if(obj->showAsSame(player, (*it))) {
m++;
it++;
} else
break;
}
if(n)
oStr << ", ";
oStr << obj->getObjStr(player, flags, m);
if(obj->flagIsSet(O_KEEP))
oStr << "(K)";
if(obj->flagIsSet(O_BEING_PREPARED))
oStr << "(P)";
n++;
}
}
if(!n)
oStr << "nothing";
oStr << ".\n";
player->printColor("%s", oStr.str().c_str());
if(!online)
free_crt(target);
return(0);
}
//*********************************************************************
// canDrop
//*********************************************************************
bool canDrop(const Player* player, const Object* object, const Property* p) {
if(!limitedInStorage(player, object, p, false))
return(false);
if(object->flagIsSet(O_NO_DROP) && !player->isStaff())
return(false);
if(object->flagIsSet(O_KEEP))
return(false);
for(Object* obj : object->objects ) {
if(!canDrop(player, obj, p))
return(false);
}
return(true);
}
//*********************************************************************
// delete_drop_obj
//*********************************************************************
bool delete_drop_obj(const BaseRoom* room, const Object* object, bool factionCanRecycle) {
if(room->flagIsSet(R_DUMP_ROOM) && factionCanRecycle)
return(true);
if(object->flagIsSet(O_BREAK_ON_DROP)) {
broadcast(NULL, room, "%O shattered and turned to dust!", object);
return(true);
}
return(false);
}
//*********************************************************************
// dropAllRoom
//*********************************************************************
void dropAllRoom(Creature* creature, Player *player, bool factionCanRecycle) {
Player *pCreature = creature->getAsPlayer();
int money=0, flags=0, m=0, n=0;
BaseRoom* room = creature->getRoomParent();
Object *object=0;
Property* p=0;
bool first=false;
bstring txt = "";
// we're being sent either a player or a pet
// - creature will be the one dropping the object
// - player will be the one getting the messages
if(!player) {
creature->print("Unable to drop all!\n");
return;
}
flags = player->displayFlags();
if(!storageProperty(player, 0, &p))
return;
if(room->isDropDestroy()) {
if(player == creature)
player->print("Surely you would lose your entire inventory if you did that here!\n");
else
player->print("Surely %N would lose %s entire inventory if %s did that here!\n",
creature, creature->hisHer(), creature->heShe());
return;
}
if(room->flagIsSet(R_DUMP_ROOM) && !factionCanRecycle) {
player->print("The shopkeeper refuses to recycle those for you.\n");
return;
}
ObjectSet::iterator it;
Object *obj;
for( it = creature->objects.begin() ; it != creature->objects.end() ; ) {
obj = (*it++);
if(!canDrop(player, obj, p)) {
continue;
}
if(player->canSee(obj)) {
m=1;
while(it != creature->objects.end()) {
if(obj->showAsSame(player, (*it)) && canDrop(player, obj, p)) {
m++;
(it++);
} else
break;
}
if(first)
txt += ", ";
first = true;
txt += obj->getObjStr(player, flags, m);
n++;
}
}
if(n) {
txt += ".";
} else {
if(player == creature)
player->print("You don't have anything you can drop.\n");
else
player->print("%M doesn't have anything %s can drop.\n", creature, creature->heShe());
return;
}
for( it = creature->objects.begin() ; it != creature->objects.end() ; ) {
object = (*it++);
if(!canDrop(player, object, p))
continue;
if(delete_drop_obj(room, object, factionCanRecycle)) {
if(room->flagIsSet(R_DUMP_ROOM))
money += 5;
creature->delObj(object, true, false, true, false);
// players save last pawn, monsters delete right away
if(pCreature)
pCreature->setLastPawn(object);
else
delete object;
} else {
// if in storage room, keep ownership
creature->delObj(object, false, true, true, false);
object->addToRoom(room);
}
}
creature->checkDarkness();
if(player == creature)
player->printColor("You drop: %s\n", txt.c_str());
else
player->printColor("%M drops: %s\n", creature, txt.c_str());
broadcast(player->getSock(), room, "%M drops %s", creature, txt.c_str());
if(money) {
player->coins.add(money, GOLD);
player->print("Thank you for recycling!\nYou now have %s.\n", player->coins.str().c_str());
gServer->logGold(GOLD_IN, player, Money(money, GOLD), NULL, "RecycleAll");
}
player->bug("%s%s dropped %s.\n", player->getCName(), player != creature ? "'s pet" : "", txt.c_str());
if(!player->isDm()) {
log_immort(false, player, "%s%s dropped %s in room %s\n", player->getCName(),
player != creature ? "'s pet" : "", txt.c_str(), room->fullName().c_str());
}
player->save(true);
}
//*********************************************************************
// canDropAllObj
//*********************************************************************
bool canDropAllObj(Object* object, Object* container) {
if(!container->flagIsSet(O_BULKLESS_CONTAINER)) {
if(!container->getMaxbulk()) {
if(object->getActualBulk() > container->getActualBulk())
return(false);
} else {
if(object->getActualBulk() > container->getMaxbulk())
return(false);
}
}
if(object->getType() == CONTAINER)
return(false);
if(object->getSize() && container->getSize() && object->getSize() > container->getSize())
return(false);
if(container->getShotsCur() >= container->getShotsMax())
return(false);
// cannot put NODROP items into normal bags
if(!container->flagIsSet(O_DEVOURS_ITEMS) && object->flagIsSet(O_NO_DROP))
return(false);
return(true);
}
//*********************************************************************
// dropAllObj
//*********************************************************************
// This function drops all the items in a player's inventory into a
// container object, if possible. The player is pointed to by the first
// parameter, and the container by the second.
void dropAllObj(Creature* creature, Object *container, Property *p) {
Player *player = creature->getPlayerMaster();
Object *object=0, *last=0;
BaseRoom* room = creature->getRoomParent();
int n=1, found=0, full=0;
bstring txt = "";
bool removeUnique = !container->inCreature() && !p;
// we're being sent either a player or a pet
// - creature will be the one getting the object
// - player will be the one getting the messages
if(!player) {
creature->print("Unable to drop all!\n");
return;
}
if(!player->ableToDoCommand())
return;
ObjectSet::iterator it;
for( it = creature->objects.begin() ; it != creature->objects.end() ; ) {
object = (*it++);
if(creature->canSee(object) && object != container) {
found++;
if(!canDropAllObj(object, container)) {
full++;
continue;
}
// container->incShotsCur();
creature->delObj(object, false, false, true, false);
// broadcast for devouring items
if(container->flagIsSet(O_DEVOURS_ITEMS))
Limited::remove(player, object, false);
else if(removeUnique)
Limited::deleteOwner(player, object, false, true);
container->addObj(object);
if(last && last->showAsSame(player, object))
n++;
else if(last) {
txt += last->getObjStr(player, 0, n);
txt += ", ";
n = 1;
}
last = object;
}
}
player->checkDarkness();
if(found && last) {
txt += last->getObjStr(player, 0, n);
} else {
if(player == creature)
player->print("You don't have anything to put into it.\n");
else
player->print("%M doesn't have anything to put into it.\n", creature);
return;
}
if(full)
player->printColor("%O couldn't hold everything.\n", container);
if(full == found)
return;
if(container->flagIsSet(O_DEVOURS_ITEMS)) {
for( it = container->objects.begin() ; it != container->objects.end() ; ) {
object = (*it++);
delete object;
}
container->objects.clear();
}
container->clearFlag(O_BEING_PREPARED);
broadcast(player->getSock(), room, "%M put %s into %1P.", creature, txt.c_str(), container);
player->bug("%s%s dropped %s into %s.\n",
player->getCName(), player != creature ? "'s pet" : "", txt.c_str(), container->getCName());
if(player == creature)
player->printColor("You put %s into %1P.\n", txt.c_str(), container);
else
player->printColor("%M put %s into %1P.\n", creature, txt.c_str(), container);
if(p)
p->appendLog(player->getName(), "%s stores %s.", player->getCName(), txt.c_str());
if(container->flagIsSet(O_DEVOURS_ITEMS))
broadcast(NULL, room, "%O devours everything!", container);
player->save(true);
}
//*********************************************************************
// finishDropObject
//*********************************************************************
void finishDropObject(Object* object, BaseRoom* room, Creature* player, bool cash, bool printPlayer, bool printRoom) {
Socket* sock = 0;
if(player)
sock = player->getSock();
if(room->isDropDestroy()) {
const AreaRoom* aRoom = room->getAsConstAreaRoom();
if(room->flagIsSet(R_EARTH_BONUS)) {
if(printPlayer) {
if(!cash)
player->printColor("%O was swallowed by the earth!!\n", object);
else
player->print("Your gold was swallowed by the earth!!\n", object);
}
if(printRoom)
broadcast(0, room, "The earth swallowed it!");
} else if(room->flagIsSet(R_AIR_BONUS)) {
if(printPlayer) {
if(!cash)
player->printColor("%O was frozen solid and destroyed!!\n", object);
else
player->print("Your gold frozen solid and destroyed!!\n", object);
}
if(printRoom)
broadcast(0, room, "It froze completely and was destroyed!");
} else if(room->flagIsSet(R_FIRE_BONUS)) {
if(printPlayer) {
if(!cash)
player->printColor("%O was engulfed in flames and incinerated!!\n", object);
else
player->print("Your gold was engulfed in flames and melted away!!\n", object);
}
if(printRoom)
broadcast(0, room, "It was incinerated by flames!");
} else if(room->flagIsSet(R_WATER_BONUS) || (aRoom && aRoom->isWater())) {
if(printPlayer) {
if(!cash)
player->printColor("%O was swept away in the strong current!!\n", object);
else
player->print("Your gold is swept away by the strong current!!\n", object);
}
if(printRoom)
broadcast(0, room, "The current swept it away!");
} else if(room->flagIsSet(R_ELEC_BONUS)) {
if(printPlayer) {
if(!cash)
player->printColor("%O was destroyed by electricity!!\n", object);
else
player->print("Your gold is melted by electricity!!\n", object);
}
if(printRoom)
broadcast(0, room, "It was destroyed by electricity!");
} else if(room->flagIsSet(R_COLD_BONUS) || room->isWinter()) {
if(printPlayer) {
if(!cash)
player->printColor("%O freezes solid and shatters!!\n", object);
else
player->print("Your gold freezes solid and shatters!!\n", object);
}
if(printRoom)
broadcast(0, room, "It froze solid and shattered!");
} else {
if(printPlayer) {
if(!cash)
player->printColor("%O shatters and turns to dust!\n", object);
else
player->print("Your gold shatters and turns to dust!\n", object);
}
if(printRoom)
broadcast(0, room, "It shattered and turned to dust!");
}
if(player)
Limited::remove(player->getAsPlayer(), object);
delete object;
} else if(object->flagIsSet(O_BREAK_ON_DROP) && (!player || !player->isStaff())) {
if(printPlayer)
player->printColor("%O shatters and turns to dust!\n", object);
if(printRoom)
broadcast(sock, room, "It shattered and turned to dust!");
if(player)
Limited::remove(player->getAsPlayer(), object);
delete object;
} else {
if(player) {
if(!player->isPet())
Limited::deleteOwner(player->getAsPlayer(), object);
else
Lore::remove(player->getAsPlayer(), object, true);
}
object->addToRoom(room);
}
}
//*********************************************************************
// containerOutput
//*********************************************************************
void containerOutput(const Player* player, const Object* container, const Object* object) {
if(!container->use_output[0])
return;
bstring output = container->use_output;
output.Replace("*OBJECT-UPPER*", object->getObjStr(NULL, CAP, 0).c_str());
output.Replace("*OBJECT*", object->getObjStr(NULL, 0, 0).c_str());
player->printColor("%s\n", output.c_str());
}
//*********************************************************************
// cmdDrop
//*********************************************************************
// This function allows the player pointed to by the first parameter
// to drop an object in the room at which they are located.
int cmdDrop(Creature* creature, cmd* cmnd) {
Player *player = creature->getPlayerMaster();
BaseRoom* room = creature->getRoomParent();
Object *object=0, *container=0;
int n=0, match=0, in_room=0;
unsigned long cash=0;
bool dmAlias=false, is_pet=false, factionCanRecycle=true, created=false;
Property *p=0;
// TODO: check to see if this extra aliasing check is even needed - won't print handle it?
// we're being sent either a player or a pet
// - creature will be the one getting the object
// - player will be the one getting the messages
if(!player) {
creature->print("Unable to drop!\n");
return(0);
}
if(!player->ableToDoCommand())
return(0);
player->clearFlag(P_AFK);
if(cmnd->num < 2) {
player->print("Drop what?\n");
return(0);
}
if(player->getClass() == BUILDER) {
if(!player->canBuildObjects()) {
player->print("You are not allowed drop items.\n");
return(0);
}
if(!player->checkBuilder(player->getUniqueRoomParent())) {
player->print("Error: Room number not inside any of your alotted ranges.\n");
return(0);
}
}
// a dm possessing a monster - only if they arent using a pet
if(player != creature && player->flagIsSet(P_ALIASING)) {
dmAlias = true;
creature = player->getAlias();
}
// with an extra rule, let's simplify the check to see if a pet is doing it
is_pet = !dmAlias && player != creature;
player->unhide();
factionCanRecycle = !player->inUniqueRoom() || Faction::willDoBusinessWith(player, player->getUniqueRoomParent()->getFaction());
if(cmnd->num == 2) {
if(!player->isStaff() && room->flagIsSet(R_SHOP_STORAGE)) {
player->print("You cannot drop anything here.\n");
return(0);
}
if(!strcmp(cmnd->str[1], "all")) {
dropAllRoom(creature, player, factionCanRecycle);
return(0);
}
// drop gold
if(cmnd->str[1][0] == '$') {
// pets don't carry gold, so they can't drop any
if(is_pet) {
player->print("%M isn't carrying any gold!\n", creature);
return(0);
}
cash = strtoul(cmnd->str[1]+1, 0, 0);
if(cash > 0 && cash <= player->coins[GOLD]) {
loadObject(MONEY_OBJ, &object);
object->nameCoin("gold", cash);
object->value.set(cash, GOLD);
player->coins.sub(cash, GOLD);
gServer->logGold(GOLD_OUT, player, Money(cash, GOLD), NULL, "DropGold");
object->setDroppedBy(player, "DropGold");
created = true;
} else {
player->print("You don't have that much!\n");
return(0);
}
} else {
if(is_pet)
object = creature->findObject(player, cmnd, 1);
else
object = player->findObject(player, cmnd, 1);
}
if(!object) {
player->print("You don't have that.\n");
return(0);
}
if(object->flagIsSet(O_KEEP)) {
player->printColor("%O is currently in safe keeping.\nYou must unkeep it to drop it.\n", object);
if(created)
delete object;
return(0);
}
if(object->getType() == CONTAINER && room->flagIsSet(R_DUMP_ROOM) && !cantDropInBag(object)) {
if(!object->objects.empty()) {
player->print("You don't want to drop that here!\nThere's something inside it!\n");
if(created)
delete object;
return(0);
}
}
if(!storageProperty(player, object, &p)) {
if(created)
delete object;
return(0);
}
if(!room->flagIsSet(R_DUMP_ROOM)) {
// no dropping uniques on the ground or it will reset
// the decay timer
if( object->flagIsSet(O_NO_DROP) &&
!player->checkStaff("You cannot drop that.\n")
) {
if(created)
delete object;
return(0);
}
for(Object* obj : object->objects) {
if( obj->flagIsSet(O_NO_DROP) &&
!player->checkStaff("You cannot drop that. It contains %P.\n", obj)
) {
if(created)
delete object;
return(0);
}
}
}
if(room->flagIsSet(R_DUMP_ROOM) && !factionCanRecycle) {
player->print("The shopkeeper refuses to recycle that for you.\n");
if(created)
delete object;
return(0);
}
if(!cash) {
if(!is_pet) {
player->delObj(object);
} else {
creature->delObj(object);
}
}
if(!is_pet)
player->printColor("You drop %1P.\n", object);
else
player->printColor("%M drops %1P.\n", creature, object);
broadcast(player->getSock(), room, "%M dropped %1P.", creature, object);
player->bug("%s%s dropped %s.\n", player, is_pet ? "'s pet" : "", object);
if(!player->isDm())
log_immort(false,player, "%s%s dropped %s in room %s\n", player->getCName(),
is_pet ? "'s pet" : "", object->getCName(), room->fullName().c_str());
if(!room->flagIsSet(R_DUMP_ROOM)) {
finishDropObject(object, room, player, cash, true, true);
} else {
object->refund.zero();
// can't pawn starting objects for money
if(!object->flagIsSet(O_STARTING)) {
if(created || object->flagIsSet(O_NO_PAWN) || (object->flagIsSet(O_BREAK_ON_DROP) && object->getType() != BANDAGE && object->getType() != LOTTERYTICKET)) {
player->coins.add(object->value);
gServer->logGold(GOLD_IN, player, object->value, object, "Recycle");
object->refund = object->value;
} else {
player->coins.add(5, GOLD);
gServer->logGold(GOLD_IN, player, Money(5, GOLD), object, "Recycle");
object->refund.add(5, GOLD);
}
}
player->print("Thanks for recycling.\n");
if(!object->flagIsSet(O_STARTING))
player->print("You have %s.\n", player->coins.str().c_str());
Limited::remove(player, object);
player->setLastPawn(object);
}
} else {
if(is_pet)
container = creature->findObject(player, cmnd, 2);
else
container = player->findObject(player, cmnd, 2);
if(!container) {
container = room->findObject(player, cmnd, 2);
if(container) {
if(!player->isStaff() && room->flagIsSet(R_SHOP_STORAGE)) {
player->print("You cannot drop anything here.\n");
return(0);
}
// are they allowed to put objects from this storage room?
if(!storageProperty(player, object, &p))
return(0);
in_room = true;
}
}
if(!is_pet && (!container || !cmnd->val[2])) {
for(n=0; n<MAXWEAR; n++) {
if(!player->ready[n])
continue;
if(keyTxtEqual(player->ready[n], cmnd->str[2]))
match++;
else
continue;
if(match == cmnd->val[2] || !cmnd->val[2]) {
container = player->ready[n];
break;
}
}
}
if(!container) {
player->print("You don't see that here.\n");
return(0);
}
if(container->getType() != CONTAINER) {
player->print("That isn't a container.\n");
return(0);
}
if(!strcmp(cmnd->str[1], "all")) {
dropAllObj(player, container, p);
return(0);
}
if(is_pet)
object = creature->findObject(player, cmnd, 1);
else
object = player->findObject(player, cmnd, 1);
if(!object) {
player->print("You don't have that.\n");
return(0);
}
if(object == container) {
player->print("You can't put something in itself!\n");
return(0);
}
if(container->getShotsCur() >= container->getShotsMax()) {
player->printColor("%O can't hold anymore.\n", container);
return(0);
}
if(object->getSize() && container->getSize() && object->getSize() > container->getSize()) {
player->print("That won't fit in there!\n");
return(0);
}
if(object->getType() == CONTAINER) {
player->print("You can't put containers into containers.\n");
return(0);
}
// no putting 2 items with the same quest in a bag
if(object->getQuestnum()) {
for(Object *obj : container->objects) {
if( obj->getQuestnum() == object->getQuestnum() &&
!player->checkStaff("You cannot put that in there.\nIt already contains %P.\n", obj)
)
return(0);
}
}
if(container->getSubType() == "mortar") {
if(object->getType() != HERB && !player->checkStaff("You can only put herbs in there!\n"))
return(0);
for(Object *obj : container->objects) {
if(object->getName() == obj->getName() &&
!player->checkStaff("You can only put one %s in there.\n", object->getCName()))
return(0);
}
}
if( object->flagIsSet(O_NO_DROP) &&
in_room &&
!player->checkStaff("You cannot put %P in there.\n", object)
)
return(0);
if(container->flagIsSet(O_DEVOURS_ITEMS)) {
if(container->use_output[0])
containerOutput(player, container, object);
else
player->printColor("%1O is devoured by %1P!\n", object, container);
broadcast(player->getSock(), room, "%M put %1P in %1P.", creature, object, container);
if(container->info.id == 2636 && container->info.isArea("misc"))
broadcast(NULL, room, "Flush!");
if( object->flagIsSet(O_NO_DROP) &&
in_room &&
!player->checkStaff("You cannot drop that.\n")
)
return(0);
if(is_pet) {
creature->delObj(object);
} else {
player->delObj(object, true);
}
delete object;
return(0);
}
if(!container->flagIsSet(O_BULKLESS_CONTAINER)) {
if(!container->getMaxbulk()) {
if(object->getActualBulk() > container->getActualBulk()) {
player->printColor("%O is too bulky to fit inside %P.\n", object, container);
return(0);
}
} else {
if(object->getActualBulk() > container->getMaxbulk()) {
player->printColor("%O is too bulky to fit inside %P.\n", object, container);
return(0);
}
}
}
if(is_pet)
creature->delObj(object, false, false, true, true, !in_room);
else
// if in storage room, keep ownership
player->delObj(object, false, in_room && !p, true, true, !in_room);
container->addObj(object);
container->clearFlag(O_BEING_PREPARED);
if(!is_pet)
player->printColor("You put %1P in %1P.\n", object, container);
else
player->printColor("%M put %1P in %1P.\n", creature, object, container);
if(container->use_output[0])
containerOutput(player, container, object);
broadcast(player->getSock(), room, "%M put %1P in %1P.",
creature, object, container);
player->bug("%s%s put %s in %s.\n", player->getCName(), !is_pet ? "'s pet" : "",
object->getCName(), container->getCName());
if(p)
p->appendLog(player->getName(), "%s stores %s.", player->getCName(), object->getObjStr(player, player->displayFlags(), 1).c_str());
}
player->save(true);
return(0);
}
//*********************************************************************
// canGiveTransport
//*********************************************************************
// does some simple checks to see if we can give item away
int canGiveTransport(Creature* creature, Creature* target, Object* object, bool give) {
Player *player=0, *pTarget=0, *pMaster=0;
// we're being sent either a player or a pet
// - creature will be the one getting the object
// - player will be the one getting the messages
player = creature->getPlayerMaster();
pMaster = target->getPlayerMaster();
pTarget = target->getAsPlayer();
if(!player) {
creature->print("Unable to give!\n");
return(0);
}
// for transport, target will always be a player
// but for give, target might be a monster
if(pMaster && pMaster != player) {
if(!Lore::canHave(pMaster, object, false)) {
player->print("%M cannot have that item.\n%s cannot currently have any more.\n", target, target->upHeShe());
return(0);
}
if(!Lore::canHave(pMaster, object, true)) {
player->print("%M cannot have that item.\nIt contains a limited item that %s cannot carry.\n", target, target->heShe());
return(0);
}
}
if(pTarget) {
if(pTarget->flagIsSet(P_LINKDEAD)) {
player->print("%s doesn't want that right now.\n", target->getCName());
return(0);
}
if(pTarget->isEffected("petrification")) {
player->print("%s is petrified right now! You can't do that!\n", target->getCName());
return(0);
}
if(pTarget->isRefusing(player->getCName())) {
player->print("%M is refusing items from you right now.\n", target);
return(0);
}
if(!pTarget->isStaff()) {
if(pTarget->getWeight() + object->getActualWeight() > pTarget->maxWeight()) {
player->print("%s can't hold anymore.\n", pTarget->getCName());
return(0);
}
if(target->tooBulky(object->getActualBulk())) {
player->print("%M cannot carry that much.\n", pTarget);
return(0);
}
}
if(!Unique::canGet(pTarget, object, true)){
player->print("%M cannot carry that limited object.\n", pTarget);
return(0);
}
} else {
if( Unique::is(object) &&
!player->checkStaff("%M cannot have that item.\n", target)
)
return(false);
}
if(object->flagIsSet(O_KEEP)) {
player->printColor("%O is currently in safe keeping.\nYou must unkeep it to %s.\n", object, give ? "give it away" : "transport it");
return(0);
}
if( object->getQuestnum() &&
!player->checkStaff("You can't %s a quest object.\n", give ? "give away" : "transport")
) return(0);
if( object->flagIsSet(O_NO_DROP) &&
!player->checkStaff("You cannot %s that object.\n", give ? "give away" : "transport")
) return(0);
if(object->getType() == CONTAINER) {
for(Object* obj : object->objects) {
if( obj->flagIsSet(O_NO_DROP) && !player->checkStaff("You must remove %P first.\n", obj) )
return(0);
if( obj->getQuestnum() && !player->checkStaff("You can't %s a quest object.\nYou must remove %P first.\n", give ? "give away" : "transport", obj))
return(0);
}
}
return(1);
}
//*********************************************************************
// cmdGive
//*********************************************************************
// This function allows a player to give an item in their inventory to
// another player or monster.
int cmdGive(Creature* creature, cmd* cmnd) {
Player *player = creature->getPlayerMaster();
Object *object=0;
Creature* target=0;
BaseRoom* room = creature->getRoomParent();
// we're being sent either a player or a pet
// - creature will be the one giving the object
// - player will be the one getting the messages
if(!player) {
creature->print("Unable to give!\n");
return(0);
}
player->clearFlag(P_AFK);
if(!player->ableToDoCommand())
return(0);
if(cmnd->num < 3) {
player->print("Give what to whom?\n");
return(0);
}
if(player == creature && cmnd->str[1][0] == '$') {
give_money(player, cmnd);
return(0);
}
object = creature->findObject(player, cmnd, 1);
if(!object) {
if(player == creature)
player->print("You don't have that.\n");
else
player->print("%M doesn't have that.\n", creature);
return(0);
}
player->unhide();
cmnd->str[2][0] = up(cmnd->str[2][0]);
target = room->findCreature(player, cmnd->str[2], cmnd->val[2], false);
if(!target || target == creature) {
if(player == creature)
player->print("You don't see that person here.\n");
else
player->print("%M doesn't see that person here.\n", creature);
return(0);
}
if(player->getClass() == BUILDER) {
// can they give their item away?
if(!player->canBuildObjects() && !target->isCt()) {
player->print("You are not allowed to give items to anyone.\n");
return(0);
}
if(!target->isStaff()) {
player->print("You are not allowed to give items to players.\n");
return(0);
}
if(!target->getAsPlayer()->canBuildObjects()) {
player->print("%s are not allowed to receive items.\n", target->upHeShe());
return(0);
}
// they can give it, but can the builder *st/modify it?
if( target->getClass()==BUILDER &&
target->getAsPlayer()->checkRangeRestrict(object->info)
) {
player->printColor("That item is outside their range. Please save to the ^ytest^x range.\n");
return(0);
}
}
if(target->isPlayer()) {
if( target->isEffected("mist") &&
!player->checkStaff("How can you give something to a misted creature?\n")
)
return(0);
} else {
if(target->flagIsSet(M_WILL_WIELD) && object->getType() <= 5) {
player->print("%M doesn't want that.\n", target);
return(0);
}
if(!Faction::willDoBusinessWith(player, target->getAsMonster()->getPrimeFaction())) {
player->print("%M refuses to accept that from you.\n", target);
return(0);
}
// only worry about trade/give mixup if giver is a player
if(player == creature && target->flagIsSet(M_TRADES))
return(cmdTrade(player, cmnd));
}
// most basic checks to see if they can give item away or not
if(!canGiveTransport(creature, target, object, true))
return(0);
/*
if(target->isPlayer() && !player->isCt()) { // checks idle to keep jackasses from loading
t=time(0); // up someone's inventory with crap. -TC
idle = t - Ply[target->getSock()].io->ltime;
if(idle > 10 || target->flagIsSet(P_AFK)) {
player->print("You can't give that to %N right now.\n", target);
return(0);
}
}
*/
if(target->pFlagIsSet(P_AFK) && !player->isCt()) {
player->print("You can't give that to %N when %s is afk.\n", target, target->heShe());
return(0);
}
if(player == creature)
player->printColor("You give %1P to %N.\n", object, target);
else if(player != target)
player->printColor("%M gives %1P to %N.\n", creature, object, target);
target->printColor("%M gave %1P to you.\n", creature, object);
broadcast(player->getSock(), target->getSock(), room, "%M gave %1P to %N.", creature, object, target);
creature->delObj(object);
Limited::transferOwner(player, target->getPlayerMaster(), object);
target->addObj(object);
if(!player->isDm())
log_immort(false, player, "%s%s gave %s to %s.\n", player->getCName(), player != creature ? "'s pet" : "", object->getCName(), target->getCName());
if(object->flagIsSet(O_SILVER_OBJECT) && target->isEffected("lycanthropy")) {
target->printColor("%O burns you and you drop it!\n", object);
broadcast(player->getSock(), room, "%M is burned by %P and %s drops it.",
target, object, target->heShe());
target->delObj(object, false, true);
object->addToRoom(room);
return(0);
}
player->save(true);
return(0);
}
//*********************************************************************
// give_money
//*********************************************************************
// This function allows a player to give gold to another player. Gold
// is interpreted as gold if it is preceded by a dollar sign.
void give_money(Player* player, cmd* cmnd) {
Creature* target=0, *master=0;
Monster* mTarget=0;
BaseRoom* room = player->getRoomParent();
unsigned long amt = strtoul(&cmnd->str[1][1], 0, 0);
if(!player->ableToDoCommand()) return;
if(amt < 1 || amt > player->coins[GOLD]) {
player->print("You don't have that much gold.\n");
return;
}
cmnd->str[2][0] = up(cmnd->str[2][0]);
target = room->findCreature(player, cmnd->str[2], cmnd->val[2], false);
if(!target || target == player) {
player->print("Who do you want to give it to?\n");
return;
}
if(target->isEffected("mist")) {
player->print("How can you give money to a mist?\n");
return;
}
if(!target) {
player->print("That person is not here.\n");
return;
}
master = target;
if(target->isPet())
master = target->getMaster();
if(master->flagIsSet(P_LINKDEAD)) {
player->print("%s doesn't want that right now!\n", target->getCName());
return;
}
if(master->isEffected("petrification")) {
player->print("%s is petrified right now! You can't do that!\n", master->getCName());
return;
}
master->coins.add(amt, GOLD);
player->coins.sub(amt, GOLD);
player->print("Ok.\n");
master->print("%M gave you %ld gold pieces.\n", player, amt);
broadcast(player->getSock(), target->getSock(), room, "%M gave %N %ld gold pieces.", player, target, amt);
if(!player->isDm())
log_immort(true, player, "%s gave %d gold to %s.\n", player->getCName(), amt, master->getCName());
player->save(true);
mTarget = target->getAsMonster();
if(mTarget && !mTarget->isPet()) {
bstring pay = "$pay " + (bstring)amt;
bool match = false;
bool hasPay = false;
unsigned long cost=0;
for(TalkResponse * talkResponse : mTarget->responses) {
for(const bstring& keyword : talkResponse->keywords) {
if(keyword.left(4) == "$pay")
hasPay = true;
// match if this is a flat-rate
match = keyword == pay;
// investigate level-based cost
if(!match && keyword.left(10) == "$pay level") {
cost = atoi(keyword.right(keyword.getLength()-11).c_str());
match = cost * player->getLevel() == amt;
}
if(match) {
if(talkResponse->response != "")
mTarget->sayTo(player, talkResponse->response);
if(talkResponse->action != "") {
if(!mTarget->doTalkAction(player, talkResponse->action)) {
mTarget->coins.sub(amt, GOLD);
player->coins.add(amt, GOLD);
player->print("%M returns your money.\n", mTarget);
broadcast(player->getSock(), mTarget->getSock(), room, "%M returns the money.", mTarget);
player->save(true);
return;
}
}
gServer->logGold(GOLD_OUT, player, Money(amt, GOLD), mTarget, "GiveGold(TalkResponse)");
return;
}
}
}
// if we get this far, the monster has a $pay string, but the player didn't give
// them the right amount
if(hasPay) {
mTarget->sayTo(player, "That's not the right amount!");
mTarget->coins.sub(amt, GOLD);
player->coins.add(amt, GOLD);
player->print("%M returns your money.\n", mTarget);
broadcast(player->getSock(), mTarget->getSock(), room, "%M returns the money.", mTarget);
player->save(true);
return;
}
gServer->logGold(GOLD_OUT, player, Money(amt, GOLD), mTarget, "GiveGold");
}
}
//*********************************************************************
// getRepairCost
//*********************************************************************
unsigned long getRepairCost(Player* player, Monster* smithy, Object* object) {
unsigned long cost=0;
float mult=0.0, rcost=0.0;
int alignDiff=0, skill=0;
alignDiff = getAlignDiff(player, smithy);
cost = object->value[GOLD] / 2;
cost += (cost/10)*alignDiff;
skill = smithy->getSkillLevel();
if(skill < 10) /* 0-9 */
{
mult = 0.1296;
} else if(skill < 20) /* 10-19 */
{
mult = 0.216;
} else if(skill < 30) /* 20-29 */
{
mult = 0.36;
} else if(skill < 40) /* 30-39 */
{
mult = 0.6;
} else if(skill < 50) /* 40-49 */
{
mult = 1.0;
} else if(skill < 60) /* 50-59 */
{
mult = 1.5;
} else if(skill < 70) /* 60-69 */
{
mult = 2.25;
} else if(skill < 80) /* 70-79 */
{
mult = 3.375;
} else if(skill < 90) /* 80-89 */
{
mult = 5.0625;
} else if(skill < 100) /* 90-99 */
{
mult = 7.59375;
} else if(skill >= 100) /* 100+ */
{
mult = 11.390625;
}
// 1.5 moves it down a category in cost
rcost = (float)cost * (mult / 1.5);
cost = (long)rcost;
cost = (MAX(1,cost));
Money money;
money.set(cost, GOLD);
money = Faction::adjustPrice(player, smithy->getPrimeFaction(), money, true);
cost = money[GOLD];
return(cost);
}
//*********************************************************************
// cmdCost
//*********************************************************************
int cmdCost(Player* player, cmd* cmnd) {
int alignDiff=0;
unsigned long cost=0;
Monster *smithy=0;
Object *object=0;
if(!player->ableToDoCommand())
return(0);
if(cmnd->num < 3) {
player->print("Syntax: cost (object) (smithy)\n");
return(0);
}
object = player->findObject(player, cmnd, 1);
if(!object) {
player->print("You don't have that item.\n");
return(0);
}
smithy = player->getParent()->findMonster(player, cmnd, 2);
if(!smithy) {
player->print("That smithy is not here.\n");
return(0);
}
if(!Faction::willDoBusinessWith(player, smithy->getPrimeFaction())) {
player->print("%M refuses to do business with you.\n", smithy);
return(0);
}
if(smithy->getMobTrade() != SMITHY) {
player->print("%M is not a smithy.\n", smithy);
return(0);
}
if(object->flagIsSet(O_NO_FIX)) {
player->print("%M says, \"Unfortunately, that cannot be repaired.\"\n", smithy);
return(0);
}
alignDiff = getAlignDiff(player, smithy);
if(Faction::getAttitude(player->getFactionStanding(smithy->getPrimeFaction())) < Faction::INDIFFERENT) {
switch(alignDiff) {
case 2:
player->print("%M sighs in irritation.\n", smithy);
break;
case 3:
player->print("%M eyes you suspiciously.\n", smithy);
break;
case 4:
player->print("%M mutters obscenities about you.\n", smithy);
break;
case 5:
player->print("%M sneers at you in disgust.\n", smithy);
break;
case 6:
player->print("%M spits on you.\n", smithy);
break;
default:
break;
}
}
cost = getRepairCost(player, smithy, object);
player->print("%M says, \"It'll cost you %ld gold for me to fix that.\"\n", smithy, cost);
return(0);
}
//*********************************************************************
// cmdRepair
//*********************************************************************
// This function allows a player to repair a weapon or armor if they are
// in a repair shop. There is a chance of breakage.
int cmdRepair(Player* player, cmd* cmnd) {
Object *object=0;
Monster *smithy=0;
unsigned long cost=0;
int skill=0, alignDiff=0, repairChance=0, repairMod=0, roll=0, plusRoll=0, keepPlus=0;
player->clearFlag(P_AFK);
if(!player->ableToDoCommand())
return(0);
/*if((player->getClass() == CLERIC && player->getDeity() == JAKAR))
{
return(jakarRepair(player, cmnd));
}*/
if(cmnd->num < 3) {
player->print("Syntax: repair (object) (smithy)\n");
return(0);
}
object = player->findObject(player, cmnd, 1);
if(!object) {
player->print("You don't have that.\n");
return(0);
}
smithy = player->getParent()->findMonster(player, cmnd, 2);
if(!smithy) {
player->print("That smithy is not here!\n");
return(0);
}
if(!Faction::willDoBusinessWith(player, smithy->getPrimeFaction())) {
player->print("%M refuses to do business with you.\n", smithy);
return(0);
}
if(smithy->getMobTrade() != SMITHY) {
player->print("%M is not a smithy.\n", smithy);
return(0);
}
player->unhide();
if(object->flagIsSet(O_NO_FIX) || object->flagIsSet(O_CUSTOM_OBJ)) {
player->print("%M says, \"Sorry, I just can't fix that!\"\n", smithy);
return(0);
}
if(object->getType() != WEAPON && object->getType() != ARMOR) {
player->print("%M says, \"Sorry, I just can't fix that!\"\n", smithy);
return(0);
}
if(object->getShotsCur() > MAX(3, object->getShotsMax() / 10)) {
player->print("%M says, \"I've always said if it ain't broke, don't fix it!\"\n", smithy);
return(0);
}
cost = getRepairCost(player, smithy, object);
if(player->coins[GOLD] < cost) {
player->print("%M eyes you suspiciously.\n%M says, \"That'll be $%ld gold and not a coin less!\n", smithy, smithy, cost);
return(0);
}
player->print("%M says, \"That'll be $%ld.\"\n%M takes the gold from you.\n", smithy, cost, smithy);
player->coins.sub(cost, GOLD);
gServer->logGold(GOLD_OUT, player, Money(cost, GOLD), object, "Repair");
broadcast(player->getSock(), player->getParent(), "%M has %N repair %1P.", player, smithy, object);
alignDiff = getAlignDiff(player, smithy);
switch(alignDiff) {
case 2:
player->print("%M gives you sidelong glances and is working slow on purpose.", smithy);
broadcast(player->getSock(), player->getParent(),
"%M gives %N sidelong glances as %s works and is working slow on purpose.", smithy, player, smithy->heShe());
break;
case 3:
player->print("%M openly glares at you as %s works.\n", smithy, smithy->heShe());
broadcast(player->getSock(), player->getParent(),
"%M openly glares at %N as %s works.\n", smithy, player, smithy->heShe());
break;
case 4:
player->print("%M scowls and curses about you as %s works.\n", smithy, smithy->heShe());
broadcast(player->getSock(), player->getParent(),
"%M scowls and curses about %N as %s works.\n", smithy, player, smithy->heShe());
break;
case 5:
player->print("%M sneers at you in disgust as %s works.\n", smithy, smithy->heShe());
broadcast(player->getSock(), player->getParent(),
"%M sneers at %N in disgust as %s works.\n", smithy, player, smithy->heShe());
break;
case 6:
player->print("As %N works, %s makes no bones about openly despising you.\n", smithy, smithy->heShe());
broadcast(player->getSock(), player->getParent(),
"As %N works, %s makes no bones about openly despising %N.\n", smithy, smithy->heShe(), player);
break;
}
skill = smithy->getSkillLevel();
repairMod = -1 * (50-skill);
repairChance = 50 + repairMod + bonus((int) player->piety.getCur());
if(object->getAdjustment()) {
if(skill < 30) /* skill levels 0-29 cannot repair magical or high quality weapons */
repairChance -= 100;
else if(skill < 80) {
switch(object->getAdjustment()) {
case 1:
repairChance -= 5;
break;
case 2:
repairChance -= 10;
break;
case 3:
repairChance -= 15;
break;
case 4:
repairChance -= 20;
break;
default:
repairChance -= 25;
break;
}
}
}
repairChance -= alignDiff*10;
if(skill < 30) /* 00-29 */
{
keepPlus = 0;
} else if(skill < 40) /* 30-39 */
{
keepPlus = 5;
} else if(skill < 50) /* 40-49 */
{
keepPlus = 10;
} else if(skill < 60) /* 50-59 */
{
keepPlus = 15;
} else if(skill < 70) /* 60-69 */
{
keepPlus = 20;
} else if(skill < 80) /* 70-79 */
{
keepPlus = 50;
} else if(skill < 90) /* 80-89 */
{
keepPlus = 75;
} else if(skill < 100) /* 90-99 */
{
keepPlus = 85;
} else if(skill >= 100) /* 100+ */
{
keepPlus = 100;
}
roll = mrand(1,100);
/*if(player->isDm()) {
player->print("Chance: %d\n", repairChance);
player->print("AlignDiff: %d\n", alignDiff);
player->print("Roll: %d\n", roll);
}*/
if(roll < repairChance) {
if(object->getAdjustment()) {
plusRoll = mrand(1,100);
if(plusRoll > keepPlus && object->getAdjustment() > 1) {
if(plusRoll - keepPlus <= 5) {
object->setAdjustment(object->getAdjustment() - 1);
player->print("%M says, \"Sorry, but it seems to have lost some of its %s.\"\n",
smithy, object->getAdjustment() > 0 ? "fine glow" : "fine quality");
} else {
player->print("%M says, \"Sorry, but it seems to have lost its %s.\"\n",
smithy, object->getAdjustment() > 0 ? "fine glow" : "fine quality");
object->setAdjustment(0);
}
}
}
object->setShotsMax(object->getShotsMax() * 9 / 10);
object->setShotsCur(object->getShotsMax());
player->printColor("%M hands %P back to you, almost good as new.\n", smithy, object);
} else {
player->print("\"Bah!\", %N shouts, \"Broke it. Sorry.\"\n", smithy);
broadcast(player->getSock(), player->getParent(), "Oops! %s broke it.", smithy->heShe());
if(object->getShotsCur() > 0 && !alignDiff) {
player->print("%M says, \"Well, here's your cash back.\"\n", smithy);
player->coins.add(cost, GOLD);
gServer->logGold(GOLD_IN, player, Money(cost, GOLD), object, "RepairRefund");
}
player->delObj(object, true);
delete object;
}
return(0);
}
//*********************************************************************
// checkDarkness
//*********************************************************************
// checks the creature for a darkness item. if they have one, flag them
void Creature::checkDarkness() {
clearFlag(isPlayer() ? P_DARKNESS : M_DARKNESS);
for(int i=0; i<MAXWEAR; i++) {
if(ready[i] && ready[i]->flagIsSet(O_DARKNESS)) {
setFlag(isPlayer() ? P_DARKNESS : M_DARKNESS);
return;
}
}
for(Object *obj : objects) {
if(obj->flagIsSet(O_DARKNESS)) {
setFlag(isPlayer() ? P_DARKNESS : M_DARKNESS);
return;
}
}
}
//*********************************************************************
// count_inv
//*********************************************************************
// Returns the number of objects a creature has in their inventory.
// If perm_only != false then only those objects which are permanent
// will be counted.
int Creature::countInv(bool permOnly) {
int total=0;
for(Object *obj : objects ) {
if(!permOnly || (permOnly && (obj->flagIsSet(O_PERM_ITEM))))
total++;
}
return(MIN(100,total));
}
//*********************************************************************
// countBagInv
//*********************************************************************
int Creature::countBagInv() {
int total=0;
for(Object *obj : objects ) {
total++;
if(obj && obj->getType() == CONTAINER) {
total += obj->countObj();
}
}
return(total);
}