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/
/*
 * specials.cpp
 *   Special attacks and such
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * 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 "commands.h"
#include "effects.h"
#include "specials.h"

bool Creature::runSpecialAttacks(Creature* victim) {
	if(specials.empty())
		return(false);

	SpecialAttack* attack;

	std::list<SpecialAttack*>::const_iterator eIt;
	for(eIt = specials.begin() ; eIt != specials.end() ; eIt++) {
		attack = *eIt;
		// Try running untill we get one that procs
		if(useSpecial(attack, victim))
			return(true);
	}

	// If we get here, we couldn't find any specials to run
	return(false);
}

SpecialAttack* Creature::getSpecial(const bstring& special) {
	std::list<SpecialAttack*>::const_iterator eIt;
	for(eIt = specials.begin() ; eIt != specials.end() ; eIt++) {
		if((*eIt) && (*eIt)->name == special)
			return((*eIt));
	}
	return(NULL);

}
bool Creature::useSpecial(const bstring& special, Creature* victim) {
	return(useSpecial(getSpecial(special), victim));
}

bool Creature::useSpecial(SpecialAttack* attack, Creature* victim) {
	if(!attack)
		return(false);

	if(attack->flagIsSet(SA_REQUIRE_HIDE) && !isHidden())
		return(false);

	long i, t;
	i = attack->ltime.ltime;
	t = time(0);
	// See if we can use this attack yet
	if(t - i < attack->delay)
		return(false); 	// Not enough time has passed yet

	// Check random chance that this attack goes off -- Chance of 101 means always go off
	if(attack->chance < mrand(1, 100))
		return(false);

	// Check time here

	if(attack->limit) {
		if(attack->used >= attack->limit)
			return(false);
	}

	if(attack->flagIsSet(SA_REQUIRE_HIDE) && isHidden())
		unhide();

	attack->ltime.ltime = time(0);
	attack->ltime.interval = attack->delay;

	if(!attack->isAreaAttack() && !attack->flagIsSet(SA_SINGLE_TARGET))
		attack->setFlag(SA_SINGLE_TARGET);

	if(attack->flagIsSet(SA_SINGLE_TARGET)) {
		return(doSpecial(attack, victim));
	}


	bool attacked = false;
	if(attack->isAreaAttack() && getRoomParent()) {
		attack->printRoomString(this);

		BaseRoom* room = getRoomParent();
		if(attack->flagIsSet(SA_AE_PLAYER) || attack->flagIsSet(SA_AE_ALL)) {
			// First hit players
		    PlayerSet::iterator pIt = room->players.begin();
		    while(pIt != room->players.end()) {
		        Player* ply = (*pIt++);
				doSpecial(attack, ply);
				attacked = true;
			}
			// Second, hit pets
            MonsterSet::iterator mIt = room->monsters.begin();
            while(mIt != room->monsters.end()) {
                Monster* mons = (*mIt++);
				if(mons->isPet()) {
					doSpecial(attack, mons);
					attacked = true;
				}
			}
		}
		if(attack->flagIsSet(SA_AE_MONSTER) || attack->flagIsSet(SA_AE_ALL)) {
			// Hit all non pets
            MonsterSet::iterator mIt = room->monsters.begin();
            while(mIt != room->monsters.end()) {
                Monster* mons = (*mIt++);
				if(!mons->isPet()) {
					doSpecial(attack, mons);
					attacked = true;
				}
			}
		}
	}
	if(attacked && attack->limit)
		attack->used++;
	return(attacked);
}


// Run the given special on a target, should only be called from useSpecial
bool Creature::doSpecial(SpecialAttack* attack, Creature* victim) {
	Player* pVictim = victim->getAsPlayer();
	Monster* mThis = getAsMonster();

	if(victim->isMonster() && victim->flagIsSet(M_NO_CIRCLE) && attack->getName() == "circle")
		return(false);

	if(attack->flagIsSet(SA_NO_UNDEAD) && victim->isUndead())
		return(false);

	if(attack->flagIsSet(SA_BREATHING_TARGETS) && victim->doesntBreathe())
		return(false);

	if(attack->flagIsSet(SA_UNDEAD_ONLY) && !victim->isUndead())
		return(false);

	if(attack->flagIsSet(SA_NO_UNDEAD_WARD) && isUndead() && victim->isEffected("undead-ward"))
		return(false);

	if(attack->flagIsSet(SA_NO_DRAIN_SHIELD) && victim->isEffected("drain-shield"))
		return(false);

	if(attack->flagIsSet(SA_NO_ATTACK_ON_LOW_HP) && hp.getCur() <= (hp.getMax()/5))
		return(false);

	if(	attack->flagIsSet(SA_NO_UNCONSCIOUS) &&
		pVictim && (
			pVictim->isEffected("blindness") ||
			pVictim->isEffected("petrification") ||
			pVictim->flagIsSet(P_UNCONSCIOUS)
		)
	)
		return(false);

	if(attack->flagIsSet(SA_HOLY_WAR)) {
		if(cClass != PALADIN && cClass != DEATHKNIGHT)
			return(false);

		if((cClass == PALADIN && victim->getClass() != DEATHKNIGHT) ||
		   (cClass == DEATHKNIGHT && victim->getClass() != PALADIN))
			return(false);
	}

	if(attack->flagIsSet(SA_TARGET_NEEDS_MANA) && victim->mp.getCur() <= 0)
		return(false);

	if(attack->flagIsSet(SA_SINGLE_TARGET)) {
		if(attack->limit)
			attack->used++;
	}

	victim->checkTarget(this);
	if(attack->type == SPECIAL_WEAPON) {
		// General attack, so compute an attack result
		int resultFlags = NO_CRITICAL | NO_FUMBLE; // We'll be nice for now...no critical backstabs on mobs :)
		if(attack->flagIsSet(SA_NO_DODGE))
			resultFlags |= NO_DODGE;
		if(attack->flagIsSet(SA_NO_PARRY))
			resultFlags |= NO_PARRY;
		if(attack->flagIsSet(SA_NO_BLOCK))
			resultFlags |= NO_BLOCK;

		AttackResult result = getAttackResult(victim, NULL, resultFlags);
		switch(result) {
			case ATTACK_DODGE:
				attack->printFailStrings(this, victim);
				victim->dodge(this);
				victim->doLagProtect();
				return(true);
			case ATTACK_PARRY:
				attack->printFailStrings(this, victim);
				victim->parry(this);
				victim->doLagProtect();
				return(true);
			case ATTACK_MISS:
				attack->printFailStrings(this, victim);
				victim->doLagProtect();
				return(true);
			case ATTACK_BLOCK:
				printColor("^C%M partially blocked your attack!\n", victim);
				victim->printColor("^CYou manage to partially block %N's attack!\n", this);
				break;
			default:
				// Hits etc, do nothing, fall through to the rest of the code
				break;
		}
	}
	Damage attackDamage;
	attackDamage.set(-1);
	bool saved = false;
	// Some attacks don't do any damage
	if(attack->saveType > SAVE_NONE && attack->saveType <= SAVE_SPELL) {
		int bns = 0;
		switch(attack->saveBonus) {
			case BONUS_LEVEL_INT:
				bns = 10*((int)victim->getLevel() - (int)level)+ 3*bonus(victim->intelligence.getCur());
				break;
			case BONUS_LEVEL_CON:
				bns = 10*((int)victim->getLevel() - (int)level)+ 3*bonus(victim->constitution.getCur());
				break;
			case BONUS_LEVEL_DEX:
				bns = 10*((int)victim->getLevel() - (int)level)+ 3*bonus(victim->dexterity.getCur());

			default:
				break;
		}
		int maxBonus = attack->maxBonus;

		if(maxBonus == -1)
			maxBonus = 0;
		else if(maxBonus == 0)
			maxBonus = 100;

		bns = MAX(0,MIN(bns,maxBonus));
		// Save types are saves + 1 to account for NO_SAVE
		if(victim->chkSave(attack->saveType - 1, this, bns))
			saved = true;
	} else {
		int chance = 50;
		switch(attack->saveType) {
			case SAVE_STRENGTH:
				break;
			case SAVE_DEXTERITY:
				chance = 50 + (level - victim->getLevel()) * 10 +
						(dexterity.getCur() - victim->dexterity.getCur())/5 ;
				break;
			case SAVE_CONSTITUTION:
				break;
			case SAVE_INTELLIGENCE:
				break;
			case SAVE_PIETY:
				break;
			case SAVE_LEVEL:
				chance = 35 + ((level - victim->getLevel()) * 20);
				break;
			default:
				break;
		}
		//chance -= attack->saveBonus;
		chance = MAX(1, MIN(90, chance));
		// Chance is chance for the attacker to succeed...so invert the check to see if the victim saved
		if(mrand(1, 100) > chance)
			saved = true;
	}

	// Can't be confused with insight, and always confused with feelblemind
	if(attack->type == SPECIAL_CONFUSE) {
		if(victim->isEffected("insight"))
			saved = true;
		else if(victim->isEffected("feeblemind"))
			saved = false;
	}

	if(saved) {
		attack->printRoomSaveString(this, victim);
		attack->printTargetSaveString(this, victim);

		// This flag can be used on attacks like circle where nothing happens when they save vs dex
		if(attack->flagIsSet(SA_SAVE_NO_DAMAGE)) {
			victim->doLagProtect();
			return(true); // The attack went off, but got saved
		}
	}

	if(attack->type == SPECIAL_EXP_DRAIN) {
		attackDamage.set(attack->damage.roll());
		attackDamage.set(MIN((unsigned)attackDamage.get(), victim->getExperience()));

		if(saved == true)
			attackDamage.set(attackDamage.get() / 2);
	}
	else if(attack->type == SPECIAL_PETRIFY) {
		if(pVictim) {
			if((pVictim->isEffected("resist-earth") || pVictim->isEffected("resist-magic")) && mrand(1,100) <= 50)
				return(false);

			if(!saved) {
				pVictim->addEffect("petrification", 0, 0, 0, true, this);
				pVictim->clearAsEnemy(); // clears player from all mob's enemy lists in the room.
				pVictim->removeFromGroup(false);
			}
		}
	}
	else if(attack->type == SPECIAL_CONFUSE) {
		if(pVictim->isEffected("resist-magic") && mrand(1,100) <= 75)
			return(false);


	}
	else if(attack->type == SPECIAL_STEAL) {
		if(pVictim && !saved)
			mThis->steal(pVictim);
	}
	else if(attack->type != SPECIAL_NO_DAMAGE) {
		// Compute damage
		if(attack->flagIsSet(SA_HALF_HP_DAMAGE))
			attackDamage.set(victim->hp.getCur() / 2);
		else if(attack->flagIsSet(SA_RESIST_MAGIC_NO_DAMAGE) && victim->isEffected("resist-magic"))
			attackDamage.set(0);
		else {
			int dn = attack->damage.getNumber();
			int ds = attack->damage.getSides();
			int dp = attack->damage.getPlus();
			if(attack->flagIsSet(SA_INTELLIGENCE_REDUCE)) {
				if(victim->intelligence.getCur() < 210)
					; // no reduction
				else if(victim->intelligence.getCur() < 240)
					dn -= 1; // slight reduction
				else
					dn -= 2; // more reduction!

				// Can't reduce it past 1
				dn = MAX(dn, 1);
			}
			attackDamage.set(dice(dn, ds, dp));
		}

		// Now check for a save to adjust damage
		if(saved == true)
			attackDamage.set(attackDamage.get() / 2);

		// Now check for realm resists, item disolving, etc
		if(attack->type != SPECIAL_NO_TYPE) {
			// Is the attack elemental damage?
			if(attack->type >= SPECIAL_EARTH && attack->type <= SPECIAL_COLD) {
				// SPECIAL-realm matches up with the corresponding Realm so we can just
				// pass that, after casting it to a Realm
				attackDamage.set(victim->checkRealmResist(attackDamage.get(), (Realm)attack->type));
			}
			// TODO: Check for warmth/heat-protection on elemental attacks
//			if(	pVictim && (
//					(realm == COLD && (pVictim->isEffected("warmth") || pVictim->isEffected("alwayscold"))) ||
//					(realm == FIRE && pVictim->isEffected("heat-protection") || pVictim->isEffected("alwayswarm"))
//			) )
		}

		if(attack->flagIsSet(SA_EARTH_SHIELD_REDUCE))
			attackDamage.set(attackDamage.get() / 2);

		// More adjustments
		if(attack->type == SPECIAL_WEAPON || attack->flagIsSet(SA_CHECK_PHYSICAL_DAMAGE))
			victim->modifyDamage(this, PHYSICAL, attackDamage);
		else if(attack->flagIsSet(SA_CHECK_NEGATIVE_ENERGY))
			victim->modifyDamage(this, NEGATIVE_ENERGY, attackDamage);

		if(attack->flagIsSet(SA_BERSERK_REDUCE))
			attackDamage.set(mrand(1, 10));

		// Put here to avoid other damage reducers
		if(!saved && attack->flagIsSet(SA_CAN_DISINTEGRATE) && mrand(1,100) < 2) {
			victim->printColor("^Y%M seriously damages you!\n", this);
			attackDamage.set(victim->hp.getCur() - 5);
			attackDamage.set(MAX(attackDamage.get(), 1));
		}
	}


	if(pVictim && !isPet()) {
		if(attack->flagIsSet(SA_ACID)) {
			// Check for disolve
			if(attack->saveType == SAVE_NONE || !pVictim->chkSave(attack->saveType-1, this, attack->saveBonus))
				pVictim->loseAcid();
		}
		if(attack->flagIsSet(SA_DISSOLVE)) {
			if(attack->saveType == SAVE_NONE || !pVictim->chkSave(attack->saveType-1, this,attack->saveBonus))
				pVictim->dissolveItem(this);
		}
	}
	if(mThis) {
		if(attack->flagIsSet(SA_POISON)) {
			// Check for poison
			mThis->tryToPoison(victim, attack);
		}
		if(attack->flagIsSet(SA_DISEASE)) {
			// Check for disease
			mThis->tryToDisease(victim, attack);
		}
		if(attack->flagIsSet(SA_BLIND)) {
			// Check for blind
			mThis->tryToBlind(victim, attack);
		}
		if(attack->flagIsSet(SA_ZAP_MANA)) {
			mThis->zapMp(victim, attack);
		}
	}
	if(attack->flagIsSet(SA_SINGLE_TARGET))
		attack->printRoomString(this, victim);

	if(attackDamage.get() != -1) {
		attack->printTargetString(this, victim, attackDamage.get());

		if(attack->flagIsSet(SA_DRAINS_DAMAGE)) {
			victim->printColor("^r%M feeds on your energy.\n", this);
			hp.increase(attackDamage.get() / 2);
		}
		if(attack->type == SPECIAL_EXP_DRAIN) {
			// Damage is experience, not hp
			victim->addExperience(attackDamage.get() * -1);
		} else {
			if(isPet() && getMaster())
				getMaster()->printColor("%M %s %N for %s%d^x damage.\n", this, attack->verb.c_str(), victim, getMaster()->customColorize("*CC:DAMAGE*").c_str(), attackDamage.get());

			broadcastGroup(false, victim, "^M%M^x %s ^M%N^x for *CC:DAMAGE*%d^x damage, %s%s\n", this, attack->verb.c_str(),
				victim, attackDamage.get(), victim->heShe(), victim->getStatusStr(attackDamage.get()));

			if(attack->flagIsSet(SA_CHECK_DIE_ROB)) {
				if(doDamage(victim, attackDamage.get(), CHECK_DIE_ROB))
					return(true);
			} else {
				if(doDamage(victim, attackDamage.get(), CHECK_DIE))
					return(true);
			}
		}

		// TODO: Dom: make a flag for this?
		// 5% chance to get porphyria when bitten by a vampire
		if(attack->getName() == "Vampiric Bite")
			victim->addPorphyria(this, 5);

	} else {
		attack->printTargetString(this, victim);
	}

	// Stun the target if they didn't save
	if(attack->stunLength && !saved) {
		int stunLength = 0;
		if(attack->flagIsSet(SA_RANDOMIZE_STUN)) {
			stunLength = mrand(attack->stunLength - 3, attack->stunLength + 3);
			stunLength = MAX(1, stunLength);
		} else
			stunLength = attack->stunLength;
		victim->print("You have been stunned for %d seconds!\n", stunLength);
		victim->stun(stunLength);
	}
	victim->doLagProtect();
	return(true);
}

bool SpecialAttack::isAreaAttack() const {
	return(flagIsSet(SA_AE_ENEMY) || flagIsSet(SA_AE_ALL) || flagIsSet(SA_AE_PLAYER) || flagIsSet(SA_AE_MONSTER));
}
bool SpecialAttack::flagIsSet(int flag) const {
	return(flags[flag/8] & 1<<(flag%8));
}
void SpecialAttack::setFlag(int flag) {
	flags[flag/8] |= 1<<(flag%8);
}
void SpecialAttack::clearFlag(int flag) {
	flags[flag/8] &= ~(1<<(flag%8));
}

bstring SpecialAttack::modifyAttackString(const bstring& input, Creature* viewer, Creature* attacker, Creature* target, int dmg) {
	bstring toReturn = input;
	/*			Web Editor
	 * 			 _   _  ____ _______ ______
	 *			| \ | |/ __ \__   __|  ____|
	 *			|  \| | |  | | | |  | |__
	 *			| . ` | |  | | | |  |  __|
	 *			| |\  | |__| | | |  | |____
	 *			|_| \_|\____/  |_|  |______|
	 *
	 * 		If you change anything here, make sure the changes are reflected in the web
	 * 		editor! Either edit the PHP yourself or tell Dominus to make the changes.
	 */
	toReturn.Replace("*ATTACKER*", attacker->getCrtStr(viewer, CAP).c_str());
	toReturn.Replace("*LOW-ATTACKER*", attacker->getCrtStr(viewer).c_str());
	toReturn.Replace("*A-DEITY*", gConfig->getDeity(attacker->getDeity())->getName().c_str());
	toReturn.Replace("*A-HESHE*", attacker->heShe());
	toReturn.Replace("*A-HISHER*", attacker->hisHer());
	toReturn.Replace("*A-UPHESHE*", attacker->upHeShe());
	toReturn.Replace("*A-UPHISHER*", attacker->upHisHer());

	if(target) {
		toReturn.Replace("*T-HESHE*", target->heShe());
		toReturn.Replace("*T-HISHER*", target->hisHer());
		toReturn.Replace("*T-UPHESHE*", target->upHeShe());
		toReturn.Replace("*T-UPHISHER*", target->upHisHer());

		toReturn.Replace("*TARGET*", target->getCrtStr(viewer, CAP).c_str());
		toReturn.Replace("*VICTIM*", target->getCrtStr(viewer, CAP).c_str());
		toReturn.Replace("*LOW-TARGET*", target->getCrtStr(viewer).c_str());
		toReturn.Replace("*LOW-VICTIM*", target->getCrtStr(viewer).c_str());
	}
	toReturn.Replace("*CR*", "\n");
	if(dmg != -1)
		toReturn.Replace("*DAMAGE*", xml::numToStr(dmg).c_str());
	toReturn = viewer->customColorize(toReturn);
	return(toReturn);
}

void SpecialAttack::printToRoom(BaseRoom* room, const bstring& str, Creature* attacker, Creature* target, int dmg ) {
	if(str.empty())
		return;

	bstring toPrint = "";
	for(Player* ply : room->players) {
		if(!ply || ply == target)
			continue;

		toPrint = modifyAttackString(str, ply, attacker, target, dmg);
		ply->printColor("%s\n", toPrint.c_str());
	}

}
void SpecialAttack::printFailStrings(Creature* attacker, Creature* target) {
	printToRoom(target->getRoomParent(), roomFailStr, attacker, target);
	bstring toPrint = modifyAttackString(targetFailStr, target, attacker, target);
	target->printColor("%s\n", toPrint.c_str());
	return;
}
void SpecialAttack::printRoomString(Creature* attacker, Creature* target) {
	return(printToRoom(attacker->getRoomParent(), roomStr, attacker, target));
}

void SpecialAttack::printTargetString(Creature* attacker, Creature* target, int dmg) {
	bstring toPrint = modifyAttackString(targetStr, target, attacker, target, dmg);
	target->printColor("%s\n", toPrint.c_str());
	return;
}

void SpecialAttack::printRoomSaveString(Creature* attacker, Creature* target) {
	return(printToRoom(attacker->getRoomParent(), roomSaveStr, attacker, target));
}
void SpecialAttack::printTargetSaveString(Creature* attacker, Creature* target, int dmg) {
	bstring toPrint = modifyAttackString(targetSaveStr, target, attacker, target, dmg);
	target->printColor("%s\n", toPrint.c_str());
	return;
}

void SpecialAttack::reset() {
	delay = chance = stunLength = limit  = used = maxBonus = 0;
	type = SPECIAL_NO_TYPE;
	saveType = SAVE_NONE;
	saveBonus = BONUS_NONE;
	ltime.interval = ltime.ltime = ltime.misc = 0;
	int i;
	for(i = 0 ; i < 8 ; i++)
		flags[i] = 0;

	return;
}
bstring Creature::getSpecialsFullList() const {
	std::ostringstream specialsStr;

	specialsStr << "Special Attacks for " << getName() << ":\n";

	int num = 0;
	SpecialAttack* attack;
	std::list<SpecialAttack*>::const_iterator sIt;
	for(sIt = specials.begin() ; sIt != specials.end() ; sIt++) {
		attack = (*sIt);
		specialsStr << *attack;
		num++;
	}

	specialsStr << "\n" << num << " effect(s) found.\n";
	bstring toPrint = specialsStr.str();

	return(toPrint);
}
int dmSpecials(Player* player, cmd* cmnd) {
	Creature* target=0;
	Monster* mTarget=0;

	if(player->getClass() == BUILDER && !player->canBuildMonsters())
		return(cmdNoAuth(player));

	if(cmnd->num > 1) {
		target = player->getParent()->findCreature(player, cmnd);

		if(target && player->getClass() == BUILDER) {
			mTarget = target->getAsMonster();
			if(mTarget) {
				if(mTarget->info.id && !player->checkBuilder(mTarget->info)) {
					player->print("Error: monster index not in any of your alotted ranges.\n");
					return(0);
				}
			}
		}

		if(!target) {
			if(player->isCt()) {
				cmnd->str[1][0] = up(cmnd->str[1][0]);
				target = gServer->findPlayer(cmnd->str[1]);
			}

			if(!target || !player->canSee(target)) {
				player->print("Target not found.\n");
				return(0);
			}
		}
	} else {
		player->print("Target not found.\n");
		return(0);
	}
	if(cmnd->num > 2) {
		if(!strncmp(cmnd->str[2], "-d", 2)) {
			target->delSpecials();
			player->print("Deleted all specials for %N\n", target);
			return(0);
		}
		SpecialAttack* attack;

		/*			Web Editor
		 * 			 _   _  ____ _______ ______
		 *			| \ | |/ __ \__   __|  ____|
		 *			|  \| | |  | | | |  | |__
		 *			| . ` | |  | | | |  |  __|
		 *			| |\  | |__| | | |  | |____
		 *			|_| \_|\____/  |_|  |______|
		 *
		 * 		If you change anything here, make sure the changes are reflected in the web
		 * 		editor! Either edit the PHP yourself or tell Dominus to make the changes.
		 */
		if(!(attack = target->addSpecial(cmnd->str[2]))) {
			player->printColor("The special ^W%s^x does not exist!\n", cmnd->str[2]);
			player->print("Pick from this list:\n");
            player->print("     backstab          bash\n");
            player->print("     kick              bite\n");
            player->print("     circle            smother\n");
            player->print("     fire-breath       lightning-breath\n");
            player->print("     acid-breath       frost-cone\n");
            player->print("     gas-breath        wind-blast\n");
            player->print("     psychic-blast     energy-drain\n");
            player->print("     touch-of-death    turn\n");
            player->print("     renounce          tail-slap\n");
            player->print("     trample           poisonous-sting\n");
            player->print("     petrifying-gaze   petrifying-breath\n");
            player->print("     confusing-gaze    zap-mana\n");
            player->print("     death-gaze\n");
			return(0);
		} else {
			player->printColor("Added special ^W%s^x to ^W%M^x.\n", attack->getName().c_str(), target);
			return(0);
		}
	} else {
		bstring toPrint = target->getSpecialsFullList();
		player->printColor("%s\n", toPrint.c_str());
	}

	return(0);
}
bool Creature::delSpecials() {
	for(SpecialAttack* special : specials) {
		delete special;
	}
	specials.clear();
	return(true);
}
std::ostream& operator<<(std::ostream& out, const SpecialAttack& attack) {
	//out.setf(std::ios::right, std::ios::adjustfield);

	out << "Special Attack:\n";
	out << "Name: " << attack.name << "\tType: " << attack.type << "\n";

	if(!attack.targetStr.empty())
		out << "TargetStr:     " << attack.targetStr << "\n";
	if(!attack.targetFailStr.empty())
		out << "TargetFailStr: " << attack.targetFailStr << "\n";
	if(!attack.selfStr.empty())
		out << "SelfStr:       " << attack.selfStr << "\n";
	if(!attack.roomStr.empty())
		out << "RoomStr:       " << attack.roomStr << "\n";
	if(!attack.roomFailStr.empty())
		out << "RoomFailStr:   " << attack.roomFailStr << "\n";

	out << "SaveType: ";
	switch(attack.saveType) {
	case SAVE_NONE:
		out << "None";
		break;
	case SAVE_LUCK:
		out << "Luck";
		break;
	case SAVE_POISON:
		out << "Poison";
		break;
	case SAVE_DEATH:
		out << "Death";
		break;
	case SAVE_BREATH:
		out << "Breath";
		break;
	case SAVE_MENTAL:
		out << "Mental";
		break;
	case SAVE_SPELL:
		out << "Spell";
		break;
	default:
		break;
	}
	out << "\tSaveBonus: " << attack.saveBonus << "\n";
	if(!attack.targetSaveStr.empty())
		out << "TargetSaveStr: " << attack.targetSaveStr << "\n";
	if(!attack.selfSaveStr.empty())
		out << "SelfSaveStr:   " << attack.selfSaveStr << "\n";
	if(!attack.roomSaveStr.empty())
		out << "RoomSaveStr:   " << attack.roomSaveStr << "\n";

	out << "Chance: " << attack.chance << "%\t Delay: " << attack.delay << "\n"
		<< "StunLength: " << attack.stunLength << "\t Used/Limit: " << attack.used << "/" << attack.limit << "\n";

	out << "Damage: " << attack.damage.str()
		<< " (Low: " << attack.damage.low() << " High: " << attack.damage.high()
		<< " Avg: " << attack.damage.average() << ")\n"

		<< "Flags: ";
	int i, num = 0;
	for(i = SA_NO_FLAG + 1; i < SA_MAX_FLAG ; i++) {
		if(attack.flagIsSet(i)) {
			if(num != 0)
				out << ", ";
			out << gConfig->getSpecialFlag(i) << "(" << i << ")";
			num++;
		}

	}
	if(num == 0)
		out << "None";
	out << ".\n";
	out << "\n";
	return out;
}

bstring Creature::getSpecialsList() const {
	std::ostringstream specialStr;

	specialStr << "Special Attacks: ";
	int num = 0;
	std::list<SpecialAttack*>::const_iterator aIt;
	SpecialAttack* attack;
	for(aIt = specials.begin() ; aIt != specials.end() ; aIt++) {
		attack = (*aIt);
		if(num != 0)
			specialStr << ", ";
		specialStr << attack->name;
		num++;
	}
	if(num == 0)
		specialStr << "None";
	specialStr << ".\n";

	bstring toPrint = specialStr.str();
	return(toPrint);
}

SpecialAttack::SpecialAttack() {
	reset();
}
SpecialAttack::SpecialAttack(xmlNodePtr rootNode) {
	xmlNodePtr curNode = rootNode->children;
	reset();

	while(curNode) {
			if(NODE_NAME(curNode, "Name")) xml::copyToBString(name, curNode);
		else if(NODE_NAME(curNode, "Verb")) xml::copyToBString(verb, curNode);
		else if(NODE_NAME(curNode, "TargetStr")) xml::copyToBString(targetStr, curNode);
		else if(NODE_NAME(curNode, "TargetFailStr")) xml::copyToBString(targetFailStr, curNode);
		else if(NODE_NAME(curNode, "RoomFailStr")) xml::copyToBString(roomFailStr, curNode);
		else if(NODE_NAME(curNode, "SelfStr")) xml::copyToBString(selfStr, curNode);
		else if(NODE_NAME(curNode, "RoomStr")) xml::copyToBString(roomStr, curNode);

		else if(NODE_NAME(curNode, "TargetSaveStr")) xml::copyToBString(targetSaveStr, curNode);
		else if(NODE_NAME(curNode, "SelfSaveStr")) xml::copyToBString(selfSaveStr, curNode);
		else if(NODE_NAME(curNode, "RoomSaveStr")) xml::copyToBString(roomSaveStr, curNode);

		else if(NODE_NAME(curNode, "Delay")) xml::copyToNum(delay, curNode);
		else if(NODE_NAME(curNode, "Chance")) xml::copyToNum(chance, curNode);
		else if(NODE_NAME(curNode, "StunLength")) xml::copyToNum(stunLength, curNode);
		else if(NODE_NAME(curNode, "Limit")) xml::copyToNum(limit, curNode);
		else if(NODE_NAME(curNode, "MaxBonus")) xml::copyToNum(maxBonus, curNode);
		else if(NODE_NAME(curNode, "SaveType")) saveType = (SpecialSaveType)xml::toNum<int>(xml::getCString(curNode));
		else if(NODE_NAME(curNode, "SaveBonus")) saveBonus = (SaveBonus)xml::toNum<int>(xml::getCString(curNode));
		else if(NODE_NAME(curNode, "Type")) type = (SpecialType)xml::toNum<int>(xml::getCString(curNode));
		else if(NODE_NAME(curNode, "Flags")) loadBits(curNode, flags);
		else if(NODE_NAME(curNode, "LastTime")) loadLastTime(curNode, &ltime);
		else if(NODE_NAME(curNode, "Dice")) damage.load(curNode);

		curNode = curNode->next;
	}
}

bool SpecialAttack::save(xmlNodePtr rootNode) const {
	xmlNodePtr attackNode = xml::newStringChild(rootNode, "SpecialAttack");
	xml::newStringChild(attackNode, "Name", name);
	xml::newStringChild(attackNode, "Verb", verb);

	xml::newStringChild(attackNode, "TargetStr", targetStr);
	xml::newStringChild(attackNode, "TargetFailStr", targetFailStr);
	xml::newStringChild(attackNode, "RoomFailStr", roomFailStr);
	xml::newStringChild(attackNode, "SelfStr", selfStr);
	xml::newStringChild(attackNode, "RoomStr", roomStr);

	xml::newStringChild(attackNode, "TargetSaveStr", targetSaveStr);
	xml::newStringChild(attackNode, "SelfSaveStr", selfSaveStr);
	xml::newStringChild(attackNode, "RoomSaveStr", roomSaveStr);

	xml::newNumChild(attackNode, "Limit", limit);
	xml::newNumChild(attackNode, "Delay", delay);
	xml::newNumChild(attackNode, "Chance", chance);
	xml::newNumChild(attackNode, "StunLength", stunLength);
	xml::newNumChild(attackNode, "Type", type);
	xml::newNumChild(attackNode, "SaveType", saveType);
	xml::newNumChild(attackNode, "SaveBonus", saveBonus);
	xml::newNumChild(attackNode, "MaxBonus", maxBonus);

	saveBits(attackNode, "Flags", SA_MAX_FLAG, flags);
	saveLastTime(attackNode, 0, ltime);
	damage.save(attackNode, "Dice");

	return(true);
}

SpecialAttack* Creature::addSpecial(const bstring specialName) {
	SpecialAttack* attack=0;

	/*			Web Editor
	 * 			 _   _  ____ _______ ______
	 *			| \ | |/ __ \__   __|  ____|
	 *			|  \| | |  | | | |  | |__
	 *			| . ` | |  | | | |  |  __|
	 *			| |\  | |__| | | |  | |____
	 *			|_| \_|\____/  |_|  |______|
	 *
	 * 		If you change anything here, make sure the changes are reflected in the web
	 * 		editor! Either edit the PHP yourself or tell Dominus to make the changes.
	 */
	if(specialName == "backstab") {
		attack = new SpecialAttack();
		attack->name = "Backstab";
		attack->verb = "backstabbed";


		attack->type = SPECIAL_WEAPON;
		attack->targetStr = "^r*ATTACKER* attempts to backstab you!*CR**ATTACKER* backstabs you for ^R*DAMAGE*^r damage!^x";
		attack->targetFailStr = "^c*ATTACKER* attempts to backstab you.*CR**A-UPHISHER* backstab failed!^x";
		attack->roomStr = "^r*ATTACKER* backstabs *LOW-VICTIM*!^x";
		attack->roomFailStr = "^c*ATTACKER*'s backstab missed!^x";
		attack->chance = 101; // Always goes off
		attack->setFlag(SA_SINGLE_TARGET);
		attack->setFlag(SA_REQUIRE_HIDE);
		attack->setFlag(SA_NO_PARRY);	// Being stabbed from behind...can't parry that
		attack->setFlag(SA_NO_BLOCK);
		attack->setFlag(SA_CHECK_DIE_ROB);
		attack->damage.setNumber(damage.getNumber() * 3);
		attack->damage.setSides(damage.getSides());
		attack->damage.setPlus(damage.getPlus() * 3);
		// No need for a delay here because the attack requires hide

		specials.push_back(attack);
	} else if(specialName == "bash") {
		attack = new SpecialAttack();
		attack->name = "Bash";
		attack->verb = "bashed";

		attack->type = SPECIAL_WEAPON;
		attack->targetStr = "^r*ATTACKER* BASHES you for ^R*DAMAGE*^r damage.^x";
		attack->roomStr = "^r*ATTACKER* BASHES *LOW-TARGET*.^x";
		attack->targetSaveStr = attack->targetFailStr = "^c*ATTACKER* tried to bash you.^x";
		attack->roomSaveStr = attack->roomFailStr = "^c*ATTACKER* tried to bash *LOW-TARGET*!^x";
		attack->chance = 101; // Always goes off
		attack->stunLength = 5;
		attack->saveType = SAVE_DEXTERITY;
		attack->setFlag(SA_SAVE_NO_DAMAGE);
		attack->setFlag(SA_RANDOMIZE_STUN);
		attack->setFlag(SA_SINGLE_TARGET);
		attack->setFlag(SA_CHECK_DIE_ROB);
		attack->damage.setNumber(damage.getNumber()/2);
		attack->damage.setSides(damage.getSides());
		attack->damage.setPlus(damage.getPlus()/2);
		attack->limit = 1; // Can only perform this attack once

		specials.push_back(attack);

	} else if(specialName == "kick") {
		attack = new SpecialAttack();
		attack->name = "Kick";
		attack->verb = "kicked";

		attack->type = SPECIAL_WEAPON;
		attack->targetStr = "^r*ATTACKER* kicks you for ^R*DAMAGE*^r damage.^x";
		attack->roomStr = "^r*ATTACKER* kicks *LOW-TARGET*.^x";
		attack->targetSaveStr = attack->targetFailStr = "^c*ATTACKER* tried to kick you.^x";
		attack->roomSaveStr = attack->roomFailStr = "^c*ATTACKER* tried to kick *LOW-TARGET*!^x";
		attack->saveType = SAVE_DEXTERITY;
		attack->chance = 101; // Always goes off
		attack->delay = 12;

		attack->setFlag(SA_SINGLE_TARGET);
		attack->setFlag(SA_CHECK_DIE_ROB);
		attack->setFlag(SA_UNDEAD_WARD_REDUCE);
		attack->setFlag(SA_SAVE_NO_DAMAGE);
		attack->damage.setNumber(2);
		attack->damage.setSides(3);
		attack->damage.setPlus(bonus(strength.getCur()) + cClass == FIGHTER ? level / 4 : 0);

//		if(flagIsSet(OLD_M_TRAMPLE)) {
//			attack->dice[0] *= 2;
//			attack->dice[2] *= 2;
//		}

		specials.push_back(attack);

	} else if(specialName == "bite") {
		attack = new SpecialAttack();
		if(isEffected("vampirism")) {
			attack->name = "Vampiric Bite";
			attack->setFlag(SA_NIGHT_ONLY);
			attack->setFlag(SA_NO_UNDEAD);
			attack->saveType = SAVE_DEATH;
			// Vampires bite for more!
			attack->damage.setNumber(level);
			attack->damage.setSides(3);
			attack->damage.setPlus(level);
			attack->targetSaveStr = "^rYou manage to shove *LOW-ATTACKER* off of you.^x";
			attack->roomSaveStr = "*TARGET* shoves *LOW-ATTACKER* away, interrupting *A-HISHER* bloody feast!";
		} else {
			attack->name = "Bite";
			attack->saveType = SAVE_LEVEL;
			attack->damage.setNumber(level);
			attack->damage.setSides(2);
			attack->damage.setPlus(level);
			// Using level save as old chance for sucess, so no damage on sucessful save
			attack->setFlag(SA_SAVE_NO_DAMAGE);
		}

		attack->verb = "bit";
		attack->chance = 101; // Always goes off

		// Kinda a weapon attack
		attack->type = SPECIAL_WEAPON;
		attack->delay = 30;

		attack->stunLength = 5;
		attack->setFlag(SA_RANDOMIZE_STUN);
		attack->setFlag(SA_SINGLE_TARGET);
		attack->targetStr = "^r*ATTACKER* bites you for ^R*DAMAGE*^r damage.^x";
		attack->roomStr = "^r*ATTACKER* bites *LOW-TARGET*!^x";
		attack->targetFailStr = "^r*ATTACKER* tried to bite you.^x";
		attack->roomFailStr = "^r*ATTACKER* tried to bite *LOW-TARGET*.^x";

		// Can be dodged, or parried, but not blocked
		attack->setFlag(SA_NO_BLOCK);

		specials.push_back(attack);
	} else if(specialName == "circle") {
		attack = new SpecialAttack();
		attack->name = "Circle";
		attack->verb = "circled";
		attack->type = SPECIAL_NO_DAMAGE;
		attack->stunLength = 7;
		attack->delay = 10;
		attack->chance = 25;
		attack->saveType = SAVE_DEXTERITY;
		attack->saveBonus = BONUS_LEVEL_DEX;

		attack->setFlag(SA_SAVE_NO_DAMAGE);
		attack->setFlag(SA_RANDOMIZE_STUN);
		attack->setFlag(SA_SINGLE_TARGET);

		attack->targetStr = "^r*ATTACKER* circles you!^x";
		attack->roomStr = "^r*ATTACKER* circles *LOW-TARGET*!^x";
		attack->targetSaveStr = "^c*ATTACKER* tried to circle you.^x";
		attack->roomSaveStr = "^c*ATTACKER* tried to circle *LOW-TARGET*!^x";

		specials.push_back(attack);

	} else if(specialName == "smother") {
		attack = new SpecialAttack();
		attack->name = "Earth Smother";
		attack->verb = "smothered";
		attack->type = SPECIAL_EARTH;
		attack->saveType = SAVE_BREATH;
		attack->saveBonus = BONUS_LEVEL_CON;
		attack->setFlag(SA_SINGLE_TARGET);
		attack->chance = 25;
		attack->delay = 60;

		attack->targetStr = "^Y*ATTACKER* smothers you for *DAMAGE* damage.^x";
		attack->roomStr = "^Y*ATTACKER* smothers *LOW-TARGET*.^x";
		attack->targetSaveStr = "^cYou almost avoid the pressing earth.^x";
		attack->roomSaveStr = "*TARGET* almost avoids the pressing earth.";
		attack->damage.setNumber(level);
		attack->damage.setSides(4);
		attack->damage.setPlus(0);

		specials.push_back(attack);

	} else if(specialName == "fire-breath") {
		attack = new SpecialAttack();
		attack->name = "Fire Breath";
		attack->verb = "breathes fire on";
		attack->type = SPECIAL_FIRE;
		attack->saveType = SAVE_BREATH;
		attack->targetStr = "^r*ATTACKER* breathes fire on you!*CR*You take ^R*DAMAGE*^r damage!^x";
		attack->roomStr = "^r*ATTACKER* breathes fire on *LOW-TARGET*!^x";
		attack->targetSaveStr = "^cYou almost manage to dive out of the way.^x";
		attack->roomSaveStr = "*TARGET* almost dives out of the way.";
		attack->damage.setNumber(level);
		attack->damage.setSides(4);
		attack->damage.setPlus(0);
		attack->setFlag(SA_SINGLE_TARGET);
		attack->delay = 60;
		attack->chance = 20; // 20 percent chance to go off every time

		specials.push_back(attack);
	} else if(specialName == "lightning-breath") {
		attack = new SpecialAttack();
		attack->name = "Lightning Breath";
		attack->verb = "breathes lightning on";
		attack->type = SPECIAL_ELECTRIC;
		attack->saveType = SAVE_BREATH;
		attack->targetStr = "^W*ATTACKER* breathes lightning on you!*CR*You take ^R*DAMAGE*^W damage!^x";
		attack->roomStr = "^W*ATTACKER* breathes lightning on *LOW-TARGET*!^x";
		attack->targetSaveStr = "^cYou almost manage to dive out of the way.^x";
		attack->roomSaveStr = "*TARGET* almost dives out of the way.";
		attack->damage.setNumber(level);
		attack->damage.setSides(4);
		attack->damage.setPlus(0);
		attack->setFlag(SA_SINGLE_TARGET);
		attack->delay = 60;
		attack->chance = 20; // 20 percent chance to go off every time

		specials.push_back(attack);

	} else if(specialName == "acid-breath") {
		attack = new SpecialAttack();
		attack->name = "Acid Breath";
		attack->verb = "breathed acid on";

		attack->type = SPECIAL_BREATH;
		attack->saveType = SAVE_BREATH;
		attack->targetStr = "^g*ATTACKER* spits acid on you!*CR*You take ^G*DAMAGE*^g damage!^x";
		attack->roomStr = "^g*ATTACKER* spits acid on *LOW-TARGET*!^x";
		attack->targetSaveStr = "You dove to the side, only being partially hit!";
		attack->roomSaveStr = "*TARGET* dove to the ground, only being partially immersed.";
		attack->damage.setNumber(level);
		attack->damage.setSides(3);
		attack->damage.setPlus(0);
		attack->setFlag(SA_SINGLE_TARGET);
		attack->setFlag(SA_ACID);
		attack->delay = 60;
		attack->chance = 20; // 20 percent chance to go off every time

		specials.push_back(attack);

	} else if(specialName == "frost-cone") {
		attack = new SpecialAttack();
		attack->name = "Frost Cone";
		attack->verb = "breathed frost on";
		attack->type = SPECIAL_COLD;
		attack->saveType = SAVE_BREATH;
		attack->targetStr = "^b*ATTACKER* breathes frost on you!*CR*You take ^B*DAMAGE*^b damage!^x";
		attack->roomStr = "^b*ATTACKER* breathes frost on *LOW-TARGET*!^x";
		attack->targetSaveStr = "^cYou almost manage to dive out of the way.^x";
		attack->roomSaveStr = "*TARGET* almost dives out of the way.";
		attack->damage.setNumber(level);
		attack->damage.setSides(4);
		attack->damage.setPlus(0);
		attack->setFlag(SA_SINGLE_TARGET);
		attack->delay = 60;
		attack->chance = 20; // 20 percent chance to go off every time

		specials.push_back(attack);

	} else if(specialName == "gas-breath") {
		attack = new SpecialAttack();
		attack->name = "Gas Breath";
		attack->verb = "breathed gas on";
		attack->type = SPECIAL_BREATH;
		attack->saveType = SAVE_POISON;
		attack->targetStr = "^G*ATTACKER* breathes poisonous gas on you!*CR*You take ^g*DAMAGE*^G damage!^x";
		attack->roomStr = "^G*ATTACKER*'s poisonous breath fills the room!^x";
		attack->targetSaveStr = "^cYou manage to hold your breath, coughing erratically.^x";
		attack->damage.setNumber(level);
		attack->damage.setSides(2);
		attack->damage.setPlus(1);
		attack->delay = 60;
		attack->setFlag(SA_AE_PLAYER);
		attack->setFlag(SA_POISON);
		attack->setFlag(SA_BREATHING_TARGETS);
		attack->chance = 20; // 20 percent chance to go off every time

		specials.push_back(attack);

	} else if(specialName == "wind-blast") {
		attack = new SpecialAttack();
		attack->name = "Wind Blast";
		attack->verb = "breathes a blast of turbulent wind at";
		attack->type = SPECIAL_WIND;
		attack->saveType = SAVE_BREATH;
		attack->targetStr = "^y*ATTACKER* breathes a blast of turbulent wind at you!*CR*You take ^Y*DAMAGE*^y damage!^x";
		attack->roomStr = "^y*ATTACKER* breathes a blast of turbulent wind at *LOW-TARGET*!^x";
		attack->targetSaveStr = "^cYou almost manage to dive out of the way.^x";
		attack->roomSaveStr = "*TARGET* almost dives out of the way.";
		attack->damage.setNumber(level);
		attack->damage.setSides(4);
		attack->damage.setPlus(0);
		attack->setFlag(SA_SINGLE_TARGET);
		attack->delay = 60;
		attack->chance = 20; // 20 percent chance to go off every time

	} else if(specialName == "psychic-blast") {
		attack = new SpecialAttack();
		attack->name = "Psychic Blast";
		attack->verb = "blasts psychic energy at";
		attack->type = SPECIAL_GENERAL;
		attack->saveType = SAVE_MENTAL;
		attack->saveBonus = BONUS_LEVEL_INT;
		attack->targetStr = "^C*ATTACKER* blasts you with psychic energy!*CR*You take ^c*DAMAGE*^C damage!^x";
		attack->roomStr = "^C*ATTACKER* blasts *LOW-TARGET* with psychic energy^x";
		attack->targetSaveStr = "^cYou fight to lock your mind, avoiding the brunt of the attack.^x";
		attack->damage.setNumber(level);
		attack->damage.setSides(4);
		attack->damage.setPlus(0);
		attack->delay = 60;
		attack->chance = 20; // 20 percent chance to go off every time

		attack->setFlag(SA_SINGLE_TARGET);
		attack->setFlag(SA_INTELLIGENCE_REDUCE);
		attack->setFlag(SA_BERSERK_REDUCE);
		attack->setFlag(SA_UNDEAD_WARD_REDUCE);
		specials.push_back(attack);

	} else if(specialName == "energy-drain") {
		attack = new SpecialAttack();
		attack->name = "Energy Drain";
		attack->verb = "drains";
		attack->type = SPECIAL_EXP_DRAIN;
		attack->saveType = SAVE_DEATH;
		attack->targetStr = "^M*ATTACKER* drains your life energy!*CR*You lose *CC:DAMAGE**DAMAGE*^M experience!^x";
		attack->roomStr = "^M*ATTACKER* drains *LOW-TARGET*'s life energy!^x";
		attack->targetSaveStr = "^c*ATTACKER* only partially drains your life energy.^x";
		attack->damage.setNumber(level);
		attack->damage.setSides(10);
		attack->damage.setPlus(level*10);
		attack->delay = 60;
		attack->chance = 10; // 10 percent chance to go off every time

		attack->setFlag(SA_SINGLE_TARGET);
		attack->setFlag(SA_NO_UNDEAD_WARD);
		attack->setFlag(SA_NO_DRAIN_SHIELD);
		specials.push_back(attack);

	} else if(specialName == "touch-of-death") {
		attack = new SpecialAttack();
		attack->name = "Touch of Death";
		attack->verb = "used the touch of death on";
		// Weapon like attack
		attack->type = SPECIAL_WEAPON;
		attack->saveType = SAVE_DEATH;
		attack->saveBonus = BONUS_LEVEL_CON;
		attack->limit = 1;
		attack->chance = 25;

		attack->targetStr = "^r*ATTACKER* used the touch of death on you!^x";
		attack->roomStr = "*ATTACKER* used the touch of death on *LOW-TARGET*.";
		attack->targetFailStr = "^c*ATTACKER* failed the touch of death on you.^x";
		attack->roomFailStr = "*ATTACKER* failed the touch of death on *LOW-TARGET*.";
		attack->targetSaveStr = "^R*ATTACKER*'s touch of death was only a glancing blow!^x";

		attack->setFlag(SA_HALF_HP_DAMAGE);
		attack->setFlag(SA_SINGLE_TARGET);
		attack->setFlag(SA_NO_UNDEAD_WARD);
		attack->setFlag(SA_NO_UNDEAD);

		specials.push_back(attack);
	} else if(specialName == "turn") {
		attack = new SpecialAttack();
		attack->name = "Turn";
		attack->verb = "turns";
		attack->type = SPECIAL_GENERAL;
		attack->saveType = SAVE_LEVEL;
		attack->delay = 30;
		attack->chance = 101;
		attack->targetStr = "^r*ATTACKER* turns you!^x";
		attack->roomStr = "*ATTACKER* turns *LOW-TARGET*.";
		attack->targetSaveStr = "^c*ATTACKER* failed to turn you.^x";
		attack->roomSaveStr = "*ATTACKER* failed to turn *LOW-TARGET*.";

		attack->setFlag(SA_HALF_HP_DAMAGE);
		attack->setFlag(SA_CAN_DISINTEGRATE);
		attack->setFlag(SA_SINGLE_TARGET);
		attack->setFlag(SA_NO_UNDEAD_WARD);
		attack->setFlag(SA_UNDEAD_ONLY);
		attack->setFlag(SA_SAVE_NO_DAMAGE);

		specials.push_back(attack);
	} else if(specialName == "renounce") {
		attack = new SpecialAttack();
		attack->name = "Renounce";
		attack->verb = "renounces";
		attack->type = SPECIAL_GENERAL;
		attack->saveType = SAVE_DEATH;
		attack->saveBonus = BONUS_LEVEL_CON;
		attack->delay = 60;
		attack->chance = 101;


		attack->targetStr = "^r*ATTACKER* renounced you for *CC:DAMAGE**DAMAGE*^r damage!^x";
		attack->roomStr = "*ATTACKER* renounced *LOW-TARGET* with the power of *A-DEITY*!";
		attack->targetSaveStr = "^c*ATTACKER* failed to renounce you with the power of *A-DEITY*.^x";
		attack->roomSaveStr = "*ATTACKER* tried to renounced *LOW-TARGET* with the power of *A-DEITY*.";

		attack->setFlag(SA_HALF_HP_DAMAGE);
		attack->setFlag(SA_CAN_DISINTEGRATE);
		attack->setFlag(SA_SINGLE_TARGET);
		attack->setFlag(SA_HOLY_WAR);
		attack->setFlag(SA_SAVE_NO_DAMAGE);

		specials.push_back(attack);
	} else if(specialName == "tail-slap") {
		attack = new SpecialAttack();
		attack->name = "Tail Slap";
		attack->verb = "tail-slapped";

		// Weapon like attack
		attack->type = SPECIAL_WEAPON;
		attack->saveType = SAVE_LUCK; // Chance to reduce damage
		attack->setFlag(SA_NO_ATTACK_ON_LOW_HP);
		attack->setFlag(SA_SINGLE_TARGET);

		attack->chance = 101;
		attack->delay = 20;

		attack->damage.setNumber(1);
		attack->damage.setSides(level/2);
		attack->damage.setPlus(level);

		attack->targetStr = "^r*ATTACKER* tail-slapped you for ^R*DAMAGE*^r damage.^x";
		attack->roomStr = "^R*ATTACKER* tail-slaps *LOW-TARGET*.^x";
		attack->targetFailStr = "^c*ATTACKER* tried to slap you with *A-HISHER* tail!";
		attack->roomFailStr = "*ATTACKER* tried to slap *LOW-TARGET* with *A-HISHER* tail.";

		attack->setFlag(SA_NO_UNDEAD_WARD);
		attack->setFlag(SA_CHECK_DIE_ROB);
		attack->setFlag(SA_RANDOMIZE_STUN);
		attack->stunLength = 6;

		specials.push_back(attack);

	} else if(specialName == "trample") {
		attack = new SpecialAttack();
		attack->name = "Trample";
		attack->verb = "trampled";

		// Use weapon logic, dodge & ripsote included
		attack->type = SPECIAL_WEAPON;
		attack->setFlag(SA_NO_BLOCK);
		attack->setFlag(SA_SINGLE_TARGET);

		attack->saveType = SAVE_LUCK; // Chance to reduce damage

		attack->setFlag(SA_NO_UNDEAD_WARD);
		attack->setFlag(SA_CHECK_DIE_ROB);
		attack->setFlag(SA_RANDOMIZE_STUN);
		attack->stunLength = 5;

		attack->delay = 90;
		attack->chance = 25;

		attack->damage.setNumber(damage.getNumber() * 2);
		attack->damage.setSides(damage.getSides());
		attack->damage.setPlus(damage.getPlus() * 2);

		attack->targetStr = "^r*ATTACKER* tramples you for ^R*DAMAGE*^r damage!^x";
		attack->roomStr = "^R*ATTACKER* trampled *LOW-VICTIM*!^x";
		attack->targetFailStr = "^c*ATTACKER* almost trampled you.^x";
		attack->roomFailStr = "*ATTACKER* almost trampled *LOW-VICTIM*.";

		specials.push_back(attack);

	} else if(specialName == "poisonous-sting") {
		attack = new SpecialAttack();
		attack->name = "Poisonous Sting";
		attack->verb = "stung";

		// Use weapon logic, dodge & ripsote included
		attack->type = SPECIAL_WEAPON;
		attack->saveType = SAVE_LUCK; // Chance to reduce damage

		attack->setFlag(SA_NO_BLOCK);
		attack->setFlag(SA_SINGLE_TARGET);
		attack->setFlag(SA_NO_UNDEAD_WARD);
		attack->setFlag(SA_CHECK_DIE_ROB);
		attack->setFlag(SA_RANDOMIZE_STUN);
		attack->setFlag(SA_POISON);
		attack->stunLength = 4;

		attack->damage.setNumber(damage.getNumber() * 3 / 2);
		attack->damage.setSides(damage.getSides());
		attack->damage.setPlus(damage.getPlus() * 3 / 2);

		attack->chance = 33;

		attack->targetStr = "^r*ATTACKER* stings you for ^R*DAMAGE*^r damage!^x";
		attack->roomStr = "^R*ATTACKER* stung *LOW-VICTIM*!^x";
		attack->targetFailStr = "^c*ATTACKER* almost stung you.^x";
		attack->roomFailStr = "*ATTACKER* almost stung *LOW-VICTIM*.";

		specials.push_back(attack);

	} else if(specialName == "petrifying-gaze") {
		attack = new SpecialAttack();
		attack->name = "Petrifying Gaze";
		attack->type = SPECIAL_PETRIFY;
		attack->saveType = SAVE_DEATH;
		attack->saveBonus = BONUS_LEVEL_CON;
		attack->maxBonus = 60;

		attack->delay = 30;
		attack->chance = intelligence.getCur()/5;

		attack->targetStr = "^D*ATTACKER* locks *A-HISHER* gaze on you.*CR**A-UPHISHER* gaze turned you to stone!^x";
		attack->roomStr = "*ATTACKER* petrified *LOW-TARGET* with *A-HISHER* gaze!";
		attack->targetSaveStr = "^D*ATTACKER* locks *A-HISHER* gaze on you.*CR*^cYou avoided *ATTACKER*'s petrifying gaze.^x";
		attack->roomSaveStr = "^c*ATTACKER* tried to petrify *LOW-TARGET* with *A-HISHER* gaze.^x";
		attack->setFlag(SA_SINGLE_TARGET);
		attack->setFlag(SA_NO_UNDEAD_WARD);

		specials.push_back(attack);
	} else if(specialName == "petrifying-breath") {
		attack = new SpecialAttack();
		attack->name = "Petrifying Breath";
		attack->type = SPECIAL_PETRIFY;
		attack->saveType = SAVE_BREATH;
		attack->saveBonus = BONUS_LEVEL_DEX;
		attack->maxBonus = 75;

		attack->chance = 20; // 20 percent chance to go off every time
		attack->delay = 60;

		attack->targetStr = "^Y*ATTACKER* breathes a cloud of choking smoke at you!^x";
		attack->roomStr = "^Y*ATTACKER*'s cloud of choking smoke fills the room!^x";
		attack->targetSaveStr = "^cYou managed to avoid *LOW-ATTACKER*'s smoking breath.^x";
		attack->roomSaveStr = "*TARGET* managed to avoid *LOW-ATTACKER*'s smoking breath.";

		attack->setFlag(SA_AE_PLAYER);
		specials.push_back(attack);
	} else if(specialName == "confusing-gaze") {
		attack = new SpecialAttack();
		attack->name = "Confusing Gaze";
		attack->type = SPECIAL_CONFUSE;
		attack->saveType = SAVE_MENTAL;
		attack->saveBonus = BONUS_LEVEL_CON;

		attack->targetStr = "^g%*ATTACKER*'s enigmatic gaze clouds your mind.^x";
		attack->roomStr = "*ATTACKER* fixes *LOW-TARGET* with *A-HISHER* enigmatic gaze.";
		attack->targetSaveStr = "^cYou avoided *LOW-ATTACKER*'s enigmatic gaze.^x";
		attack->roomSaveStr = "*ATTACKER* tried to confuse *LOW-TARGET* with *A-HISHER* gaze.";

		attack->delay = 30;
		attack->chance = intelligence.getCur()/5;

		attack->setFlag(SA_SINGLE_TARGET);
		attack->setFlag(SA_NO_UNCONSCIOUS);
		specials.push_back(attack);
	} else if(specialName == "zap-mana") {
		attack = new SpecialAttack();
		attack->name = "Zap Mana";
		attack->type = SPECIAL_NO_DAMAGE;
		attack->setFlag(SA_SINGLE_TARGET);
		attack->chance = intelligence.getCur()/10;


		specials.push_back(attack);
	} else if(specialName == "death-gaze") {
		attack = new SpecialAttack();
		attack->name = "Death Gaze";
		attack->saveType = SAVE_DEATH;
		attack->saveBonus = BONUS_LEVEL_CON;

		attack->targetStr = "^m*ATTACKER* locks *A-HISHER* gaze on you.*CR**A-HISHER*'s deadly gaze drains your life.^x";
		attack->roomStr = "*ATTACKER* drains *LOW-TARGET*'s life with *A-HISHER* gaze!";
		attack->targetSaveStr = "You avoided *LOW-ATTACKER*'s deadly gaze.";
		attack->roomSaveStr = "*ATTACKER* tried to kill *LOW-TARGET* with *A-HISHER* gaze.";


		attack->setFlag(SA_NO_UNCONSCIOUS);
		attack->setFlag(SA_SINGLE_TARGET);
		attack->setFlag(SA_HALF_HP_DAMAGE);

		attack->delay = 30;
		attack->chance = intelligence.getCur()/5;
		specials.push_back(attack);
	} else {
		std::cout << "Unknown special name - " << specialName << "." << std::endl;
	}

	return(attack);
}

bstring SpecialAttack::getName() {
	return(name);
}