roh/conf.old/area/
roh/config/code/python/
roh/config/game/area/
roh/config/game/signs/
roh/help/dmhelp/
roh/help/help/
roh/log/
roh/log/staff/
roh/monsters/ocean/
roh/objects/misc/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.47e/
/*
 * 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);
}