roh/conf/area/
roh/game/talk/
roh/help/
roh/monsters/ocean/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.44b/
/*
 * command2.cpp
 *	 Command handling/parsing routines.
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * Permission to use, modify and distribute is granted via the
 *  Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License
 *    http://creativecommons.org/licenses/by-nc-sa/3.0/
 *
 * 	Copyright (C) 2007-2009 Jason Mitchell, Randi Mitchell
 * 	   Contributions by Tim Callahan, Jonathan Hseu
 *  Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
 *
 */
#include "mud.h"
#include "commands.h"
#include "move.h"
#include "unique.h"

#define STONE_SCROLL_INDEX		10

//*********************************************************************
//						stoneScroll
//*********************************************************************

int stoneScroll(Player* player, cmd* cmnd) {
	char	filename[80];
	sprintf(filename, "%sstone_scroll", SIGNSCROLL);

	if(!strncmp(cmnd->str[2], "class", strlen(cmnd->str[2])))
		strcat(filename, "_class");
	else if(!strncmp(cmnd->str[2], "race", strlen(cmnd->str[2])))
		strcat(filename, "_race");
	else if(!strncmp(cmnd->str[2], "deity", strlen(cmnd->str[2])))
		strcat(filename, "_deity");
	else if(!strncmp(cmnd->str[2], "breakdown", strlen(cmnd->str[2])))
		strcat(filename, "_breakdown");
	strcat(filename, ".txt");
	viewLoginFile(player->getSock(), filename);
	return(0);
}


//*********************************************************************
//						cmdLook
//*********************************************************************

int cmdLook(Player* player, cmd* cmnd) {
	void *target=0;
	int targetType = -1;
	int flags = player->displayFlags();
	bool found=false;

	if(!player->ableToDoCommand())
		return(0);
	if(player->isBlind()) {
		player->printColor("^CYou're blind!\n");
		return(0);
	}

	if(!cmnd || cmnd->num < 2) {
		display_rom(player);
		return(0);
	}

	found = findTarget(player, FIND_OBJ_INVENTORY | FIND_OBJ_EQUIPMENT | FIND_OBJ_ROOM |
		FIND_MON_ROOM | FIND_PLY_ROOM, flags, cmnd->str[1], cmnd->val[1], &target, &targetType);

	if(found) {
		switch(targetType) {
			case PLAYER:
			case MONSTER:
				player->displayCreature((Creature *)target);
				break;
			case OBJECT:
				if(cmnd->num == 3 && ((Object*)target)->info.id == STONE_SCROLL_INDEX && ((Object*)target)->info.isArea("misc"))
					stoneScroll(player, cmnd);
				else
					displayObject(player, (Object*)target);
				break;
			default:
				player->print("You get all confused looking at it.\n");
				break;
		}
	} else {
		player->print("You don't see that here.\n");
	}

	return(0);
}

//*********************************************************************
//						getGuardingExit
//*********************************************************************

Monster* BaseRoom::getGuardingExit(const Exit* exit) const {
	ctag* cp=0;
	if(exit->flagIsSet(X_PASSIVE_GUARD)) {
		cp = first_mon;
		while(cp) {
			if(cp->crt->flagIsSet(M_PASSIVE_EXIT_GUARD))
				return(cp->crt->getMonster());
			cp = cp->next_tag;
		}
	}
	return(0);
}

//*********************************************************************
//						cmdThrow
//*********************************************************************

void finishDropObject(Object* object, BaseRoom* room, Creature* player, bool cash, bool printPlayer, bool printRoom);

int cmdThrow(Creature* creature, cmd* cmnd) {
	Object*	object=0;
	Creature* victim=0;
	Monster* guard=0;
	Exit*	exit=0;
	BaseRoom *room=0;
	Room*	uRoom=0;
	AreaRoom* aRoom=0;
	Player* player = creature->getPlayer(), *pVictim=0;

	if(!creature->ableToDoCommand())
		return(0);
	if(!creature->checkAttackTimer())
		return(0);
	if(creature->isBlind()) {
		creature->printColor("^CYou can't do that. You're blind!\n");
		return(0);
	}

	object = findObject(creature, creature->first_obj, cmnd);
	room = creature->getRoom();

	if(!object) {
		creature->print("You don't have that in your inventory.\n");
		return(0);
	}

	if(	object->getActualWeight() > creature->strength.getCur()/3 &&
		!creature->checkStaff("%O is too heavy for you to throw!\n", object)
	)
		return(0);

	exit = findExit(creature, cmnd, 2, room->first_ext);

	if(!exit)
		victim = room->findCreature(creature, cmnd, 2);

	if(exit) {
		if(creature->inCombat() && !creature->checkStaff("Not while you are in combat!\n"))
			return(0);

		creature->printColor("You throw %P to the %s.\n", object, exit->name);
		broadcast(creature->getSock(), room, "%M throws %P to the %s.",
			creature, object, exit->name);
		creature->delObj(object);

		guard = room->getGuardingExit(exit);

		// dont bother getting rooms if exit is closed or guarded
		if(!exit->flagIsSet(X_CLOSED) && !guard)
			Move::getRoom(creature, exit, &uRoom, &aRoom, false, &exit->target.mapmarker);

		room->wake("Loud noises disturb your sleep.", true);

		// closed, or off map, or being guarded
		if(exit->flagIsSet(X_CLOSED) || (!uRoom && !aRoom) || guard) {
			if(guard)
				broadcast(0, room, "%M knocks %P to the ground.", guard, object);
			else
				broadcast(0, room, "%O hits the %s and falls to the ground.",
					object, exit->name);
			finishDropObject(object, room, creature, false, true, true);
		} else {
			if(aRoom)
				room = aRoom;
			else
				room = uRoom;

			broadcast(0, room, "%1O comes flying into the room.", object);
			room->wake("Loud noises disturb your sleep.", true);
			finishDropObject(object, room, creature, false, false, true);

			if(aRoom && aRoom->canDelete())
				aRoom->area->remove(aRoom);
		}

		creature->updateAttackTimer(true, DEFAULT_WEAPON_DELAY);

	} else if(victim) {

		pVictim = victim->getPlayer();
		if(!creature->canAttack(victim))
			return(0);

		if(creature->vampireCharmed(pVictim) || (victim->hasCharm(creature->name) && creature->isPlayer() && creature->flagIsSet(P_CHARMED))) {
			creature->print("You like %N too much to do that.\n", victim);
			return(0);
		}

		creature->updateAttackTimer(true, DEFAULT_WEAPON_DELAY);
		creature->smashInvis();
		creature->unhide();

		if(player)
			player->statistics.swing();
		creature->printColor("You throw %P at %N.\n", object, victim);
		victim->printColor("%M throws %P at you.\n", creature, object);
		broadcast(creature->getSock(), victim->getSock(), room,
			"%M throws %P at %N.", creature, object, victim);
		creature->delObj(object);

		if(!pVictim)
			victim->getMonster()->addEnmCrt(creature);

		if(pVictim && victim->flagIsSet(P_MISTED)) {
			pVictim->statistics.wasMissed();
			if(player)
				player->statistics.miss();
			broadcast(victim->getSock(), room, "%O passes right through %N.", object, victim);
			victim->printColor("%O passes right through you.\n", object);
		} else {
			int skillLevel = (int)creature->getSkillGained("thrown");
			AttackResult result = creature->getAttackResult(victim, 0, NO_FUMBLE, skillLevel);

			if(pVictim && victim->flagIsSet(P_UNCONSCIOUS))
				result = ATTACK_HIT;

			if(result == ATTACK_DODGE) {
				if(pVictim)
					pVictim->statistics.dodge();
				if(player)
					player->statistics.miss();
				victim->printColor("You dodge out of the way.\n");
				broadcast(victim->getSock(), room, "%M dodges out of the way.", victim);
				creature->checkImprove("thrown", false);
			} else if(result == ATTACK_MISS || result == ATTACK_BLOCK || result == ATTACK_PARRY) {
				if(pVictim)
					pVictim->statistics.wasMissed();
				if(player)
					player->statistics.miss();
				victim->printColor("You knock %P to the ground.\n", object);
				broadcast(victim->getSock(), room, "%M knocks %P to the ground.", victim, object);
				creature->checkImprove("thrown", false);
			} else {

				Damage damage;
				damage.set(1);
				if(object->getActualWeight() > 1)
					damage.set(mrand(1,6));

				victim->modifyDamage(creature, PHYSICAL, damage);
				if(pVictim)
					pVictim->statistics.wasHit();
				if(player) {
					player->statistics.hit();
					player->statistics.attackDamage(damage.get(), Statistics::damageWith(player, object));
				}

				creature->printColor("You hit %N for %s%d^x damage.\n", victim, creature->customColorize("*CC:DAMAGE*"), damage.get());
				victim->printColor("%M hit you%s for %s%d^x damage!\n", creature,
					victim->isBrittle() ? "r brittle body" : "", victim->customColorize("*CC:DAMAGE*"), damage.get());
				broadcastGroup(false, victim, "^M%M^x hit ^M%N^x for *CC:DAMAGE*%d^x damage, %s%s\n", creature,
					victim, damage.get(), victim->heShe(), victim->getStatusStr(damage.get()));

				creature->doDamage(victim, damage.get(), CHECK_DIE);
				creature->checkImprove("thrown", true);
			}

		}

		finishDropObject(object, room, creature, false, true, true);
		room->wake("Loud noises disturb your sleep.", true);

	} else {
		creature->printColor("Throw %P at what?\n", object);
	}
	return(0);
}

//*********************************************************************
//						cmdKnock
//*********************************************************************

int cmdKnock(Creature* creature, cmd* cmnd) {
	BaseRoom* targetRoom=0;
	Exit	*exit=0;

	if(cmnd->num < 2) {
		creature->print("Knock on what exit?\n");
		return(0);
	}

	lowercize(cmnd->str[1], 0);
	exit = findExit(creature, cmnd);
	if(!exit) {
		creature->print("Knock on what exit?\n");
		return(0);
	}

	if(!exit->flagIsSet(X_CLOSED)) {
		creature->print("That exit is not closed!\n");
		return(0);
	}

	creature->getRoom()->wake("You awaken suddenly!", true);
	creature->print("You knock on the %s.\n", exit->name);
	broadcast(creature->getSock(), creature->getRoom(), "%M knocks on the %s.", creature, exit->name);

	// change the meaning of exit
	exit = exit->getReturnExit(creature->getRoom(), &targetRoom);
	targetRoom->wake("You awaken suddenly!", true);

	if(exit)
		broadcast(0, targetRoom, "You hear someone knocking on the %s.", exit);
	else
		broadcast(0, targetRoom, "You hear the sound of someone knocking.");
	return(0);
}

//*********************************************************************
//						cmdPrepare
//*********************************************************************

int cmdPrepare(Player* player, cmd* cmnd) {
	if(cmnd->num < 2)
		return(cmdPrepareForTraps(player, cmnd));
	return(cmdPrepareObject(player, cmnd));
}


//*********************************************************************
//						loseAcid
//*********************************************************************
// This function goes through a players possessions worn AND carried
// and determines whether it was fragged due to dissolving acid.

void Player::loseAcid() {
	Object* object=0;
	otag    *op=0;
	int		i=0;

	// Check all equipped items
	for(i=0; i<MAXWEAR; i++) {
		if(ready[i]) {
			if( !ready[i]->flagIsSet(O_RESIST_DISOLVE) &&
				(mrand(1,100) <= 5 - abs(ready[i]->getAdjustment()))
			) {
				if(ready[i]->flagIsSet(O_NO_PREFIX)) {
					printColor("^r%s was dissolved by acid!\n", ready[i]->name);
				} else {
					printColor("^rYour %s was dissolved by acid!\n", ready[i]->name);
				}

				logn("log.dissolve", "%s(L%d) lost %s to acid in room %s.\n",
					name, level, ready[i]->name, getRoom()->fullName().c_str());
				unequip(i+1, UNEQUIP_DELETE);
			}
		}
	}


	computeAC();
	computeAttackPower();

	// Remove and possibly dissolve possessions
	op = first_obj;
	while(op) {
		object = op->obj;
		op = op->next_tag;
		if( !object->flagIsSet(O_RESIST_DISOLVE) &&
			(mrand(1,100) <= 5 - abs(object->getAdjustment()))
		) {
			if(object->flagIsSet(O_NO_PREFIX)) {
				printColor("^r%s is dissolved by acid!\n", object->name);
			} else {
				printColor("^rYour %s is dissolved by acid!\n", object->name);
			}
			logn("log.dissolve", "%s(L%d) lost %s to acid in room %s.\n",
				name, level, object->name, getRoom()->fullName().c_str());
			delObj(object, true, false, true, false);
			delete object;
		}
	}
	checkDarkness();
}

//*********************************************************************
//						resistLose
//*********************************************************************

bool resistLose(Object* object) {
	if(object->flagIsSet(O_RESIST_DISOLVE) || object->getQuestnum())
		return(true);

	int r = 15 + abs(object->getAdjustment()) * 5;

	// containers with lots of items are more resistant,
	// since it would suck to lose a lot of items
	if(object->getType() == CONTAINER)
		r += object->getShotscur() * 5;

	return(mrand(1,100) < r);
}

//*********************************************************************
//						lose_all
//*********************************************************************

void lose_all(Player* player, bool destroyAll) {
	Object* object=0;
	otag	*op=0;
	int		i=0;

	// if we send !destroyAll, there are some scenarios where
	// we dont destroy everything

	// remove all equipted items
	for(i=0; i<MAXWEAR; i++) {
		if(player->ready[i]) {
			if(!destroyAll && resistLose(player->ready[i])) {
				player->printColor("%O resisted destruction.\n", player->ready[i]);
				continue;
			}

			logn("log.dissolve", "%s(L%d) lost %s to acid in room %s.\n",
				player->name, player->getLevel(), player->ready[i]->name, player->getRoom()->fullName().c_str());
			player->ready[i]->popBag(player, true, false, false, false, true);
			player->unequip(i+1, UNEQUIP_DELETE);
		}
	}

	player->computeAC();
	player->computeAttackPower();

	// delete all possessions
	op = player->first_obj;
	while(op) {
		object = op->obj;
		op = op->next_tag;

		if(!destroyAll && resistLose(object)) {
			player->printColor("%O resisted destruction.\n", object);
			continue;
		}

		logn("log.dissolve", "%s(L%d) lost %s to acid in room %s.\n",
			player->name, player->getLevel(), object->name, player->getRoom()->fullName().c_str());
		object->popBag(player, true, false, false, false, true);
		player->delObj(object, true, false, true, false);
		delete object;
	}
	player->checkDarkness();
}

//*********************************************************************
//						dissolveItem
//*********************************************************************
// dissolve_item will randomly select one equipted (including held or
// wield) items on the given player and then delete it. The player
// receives a message that the item was destroyed as well as who is
// responsible for the deed.

void Player::dissolveItem(Creature* creature) {
	char	checklist[MAXWEAR];
	int		numwear=0, i=0, n=0;

	for(i=0; i<MAXWEAR; i++) {
		checklist[i] = 0;
		// if(i==WIELD-1 || i==HELD-1) continue;
		if(ready[i])
			checklist[numwear++] = i+1;
	}

	if(!numwear)
		n = 0;
	else {
		i = mrand(0, numwear-1);
		n = (int) checklist[i];
	}
	if(n) {
		if(ready[n-1]) {
			if(ready[n - 1]->flagIsSet(O_RESIST_DISOLVE)) {
				printColor("%M tried to dissolve your %s.\n", creature, ready[n-1]->name);
				n = 0;
				return;
			}
		}
	}


	if(n) {
		broadcast(getSock(), getRoom(),"%M destroys %N's %s.", creature, this, ready[n-1]->name);
		printColor("%M destroys your %s.\n",creature, ready[n-1]->name);
		logn("log.dissolve", "%s(L%d) lost %s to acid in room %s.\n",
			name, level, ready[n-1]->name, getRoom()->fullName().c_str());
		// Unequip it and don't add it to the inventory, delete it
		unequip(n, UNEQUIP_DELETE);
		computeAC();
	}
}

//*********************************************************************
//						cmdBreak
//*********************************************************************

int cmdBreak(Player* player, cmd* cmnd) {
	int		duration=0;
	CatRef	newloc;
	int  	chance=0, dmg=0, xpgain=0, splvl=0;
	float	mtbf=0, shots=0, shotsmax=0;
	ctag	*cp=0;
	Room *new_rom=0;
	char	item[80];
	Object	*object=0;

	player->clearFlag(P_AFK);

	if(cmnd->num < 2) {
		player->print("Break what?\n");
		return(0);
	}


	if(!player->checkAttackTimer())
		return(0);

	object = findObject(player, player->first_obj, cmnd);

	if(!object) {
		player->print("You don't have that in your inventory.\n");
		return(0);
	}

	if(	object->flagIsSet(O_BROKEN_BY_CMD) ||
		object->flagIsSet(O_NO_BREAK) ||
		object->getType() == KEY ||
		object->getSpecial() ||
		object->getType() == MONEY ||
		(object->getShotscur() < 1 && object->getType() != CONTAINER)
	) {
		player->print("You can't break that.\n");
		return(0);
	}



	if(object->getType() == CONTAINER && object->getShotsmax() < 1) {
		player->print("You can't break that.\n");
		return(0);
	}

	if((object->getType() == WAND || (object->getType() < 5 && object->flagIsSet(O_WEAPON_CASTS) && object->getMagicpower())) &&
			player->getRoom()->flagIsSet(R_SAFE_ROOM) && !player->isCt()) {
		player->print("You really shouldn't do that in here. Someone could get hurt.\n");
		return(0);
	}

	chance = player->strength.getCur()*4;
	if(player->isDm())
		player->print("Chance(str): +%d%\n", player->strength.getCur()*4);

	shots = (float)object->getShotscur();
	shotsmax = (float)object->getShotsmax();

	mtbf = shots/shotsmax;
	mtbf *=100;
	mtbf = (100 - mtbf);
	chance += (int)mtbf;

	if(player->isDm())
		player->print("Chance(shotslost): +%f%\n", mtbf);

	chance -= object->getAdjustment()*10;
	if(player->isDm())
		player->print("Chance(adj): -%d%\n", object->getAdjustment()*10);

	chance -= object->getWeight()/10;
	if(player->isDm())
		player->print("Chance(wgt): -%d%\n",object->getWeight()/10 );

	chance = MAX(1, chance);


	if(object->getQuestnum())
		chance = 0;

	if(player->isDm()) {
		player->print("Chance: %d%\n", chance);
		//	chance = 101;
	}



	if(object->getType() == CONTAINER && object->first_obj) {
		player->print("You have to dump its contents out first!\n");
		return(0);
	}

	if(mrand(1,100) <= chance) {

		object->setFlag(O_BROKEN_BY_CMD);
		if(object->compass) {
			delete object->compass;
			object->compass = 0;
		}

		if(!(object->getType() == POISON && player->getClass() == PALADIN)) {
			player->printColor("You manage to break %P.\n", object);
			broadcast(player->getSock(), player->getRoom(), "%M breaks %P.", player, object);
		} else {
			player->printColor("You dispose of the vile %P.\n", object);
			broadcast(player->getSock(), player->getRoom(), "%M neatly disposes of the vile %P.", player, object);
		}


		if(object->getType() == POISON || object->getType() == POTION)
			strcpy(item, "used up ");
		else
			strcpy(item, "broken ");
		strcat(item, object->name);
		sprintf(object->name, item);
		strncpy(object->key[2],"broken",20);


		if(object->getType() == CONTAINER) {
			object->setShotsmax(0);
			object->setType(MISC);
		}

		object->setShotscur(0);
		object->setFlag(O_NO_FIX);
		player->updateAttackTimer(true, 60);


		if(	(player->getClass() == BERSERKER || player->isCt()) && object->getType() > 5 &&
			(shots > 0.0) && object->value[GOLD] > 100
		) {
			xpgain = (int)mtbf+(object->getAdjustment()*10)+mrand(1,50);
			if(object->getType() == WAND)
				xpgain *= 3;

			if(!player->halftolevel()) {
				player->print("You %s %d experience for your deed.\n", gConfig->isAprilFools() ? "lose" : "gain", xpgain);
				player->addExperience(xpgain);
			}
		}

		if(	(object->getType() == WAND || (object->getType() < 5 && object->flagIsSet(O_WEAPON_CASTS) && object->getMagicpower())) &&
			(shots > 0.0) && (mrand(1,100) <= 50)
		) {
			splvl = get_spell_lvl(object->getMagicpower()-1);
			if(player->isCt())
				player->print("Spell level: %d.\n", splvl);

			if(splvl >= 4) {
				player->printColor("%O explodes in a retributive strike!\n", object);
				broadcast(player->getSock(), player->getRoom(), "%O explodes in a retributive strike!", object);

				player->delObj(object, true);
				delete object;
			} else {
				player->printColor("%O explodes!\n", object);
				broadcast(player->getSock(), player->getRoom(), "%O explodes!", object);
				broadcast(player->getSock(), player->getRoom(), "%M is engulfed by magical energy!", player);

				player->delObj(object, true);
				delete object;
			}

			broadcast(player->getSock(), player->getRoom(), "%M is engulfed by a magical vortex!", player);

			dmg = mrand(1,5);
			dmg += MAX(5,(mrand(splvl*2, splvl*6)))+((int)mtbf/2);

			if(player->chkSave(BRE, player, 0))
				dmg /= 2;

			player->printColor("You take %s%d^x damage from the release of magical energy!\n", player->customColorize("*CC:DAMAGE*"), dmg);

			if(splvl >= 4) {
				cp = player->getRoom()->first_ply;
				while(cp) {
					if(cp->crt != player && !cp->crt->inCombat()) {
						dmg = mrand(splvl*4, splvl*8);

						if(cp->crt->chkSave(BRE, cp->crt, 0))

							dmg /= 2;
						cp->crt->printColor("You take %s%d^x damage from the magical explosion!\n", cp->crt->customColorize("*CC:DAMAGE*"), dmg);
						/*	cp->crt->hp.getCur() = MAX(1, cp->crt->hp.getCur()); */
						/*	if(cp->crt->hp.getCur() < 1) { // HAHAHA...Suicide wand explosion attacks to make people lose xp!
						die(cp->crt, EXPLOSION);// That'd be cool! but no...heh
						cp = cp->next_tag;
						continue;
						}*/
						// Grin...suicide exploding wand pkill attacks!
						// At some risk to one's self though..heh
						if(player->doDamage(cp->crt, dmg, CHECK_DIE)) {
							cp = cp->next_tag;
							continue;
						}
					}
					cp = cp->next_tag;
				}
			}

			player->hp.decrease(dmg);
			if(player->hp.getCur() < 1) {
				player->die(EXPLOSION);
				return(0);
			}

			if(splvl >= 4) {
				if(mrand(1,100) <= 50) {
					newloc = getEtherealTravelRoom();
					if(player->inJail())
						newloc = player->parent_rom->info;
					else if(player->getRoom()->flagIsSet(R_ETHEREAL_PLANE))
						newloc.id = 50;

					if(!loadRoom(newloc, &new_rom))
						return(0);

					if(!player->getRoom()->flagIsSet(R_ETHEREAL_PLANE)) {
						broadcast(player->getSock(), player->getRoom(), "%M was blown from this universe by the explosion!", player);
						player->print("You are blown into an alternate dimension.\n");
					}
					player->deleteFromRoom();
					player->addToRoom(new_rom);
					player->doPetFollow();
				}
			}

			return(0);
		}


		if(object->getType() == POISON && (player->getClass() == PALADIN || player->isCt())) {
			xpgain = object->getEffectStrength()*15;
			// no super fast leveling by breaking poison over and over.
			if(player->getLevel() < 9)
				xpgain =  MIN(xpgain, player->getLevel()*10);

			if(!player->halftolevel()) {
				player->print("You %s %d experience for your deed.\n", gConfig->isAprilFools() ? "lose" : "gain", xpgain);
				player->addExperience(xpgain);
			}
		}

	} else {
		if(!(object->getType() == POISON && player->getClass() == PALADIN)) {
			player->printColor("You were unable to break %P.\n", object);
			broadcast(player->getSock(), player->getRoom(), "%M tried to break %P.", player, object);
		} else {
			player->printColor("You were unable to properly dispose of the %P.\n", object);
			broadcast(player->getSock(), player->getRoom(), "%M tried to dispose of the %P.", player, object);
			chance = 30 - (bonus((int)player->dexterity.getCur()));

			if(player->immuneToPoison())
				chance = 101;

			if(mrand(1,100) <= chance) {
				player->printColor("^r^#You accidentally poisoned yourself!\n");
				broadcast(player->getSock(), player->getRoom(), "%M accidentally poisoned %sself!",
					player, player->himHer());

				duration = standardPoisonDuration(object->getEffectDuration(), player->constitution.getCur());

				if(player->chkSave(POI, player, -1))
					duration = duration * 2 / 3;

				player->poison(player, object->getEffectStrength(), duration);
			}
		}
		player->updateAttackTimer(true, 40);
	}
	return(0);
}