bool BTPc::useSkill(int index, int difficulty /*= BTSKILL_DEFAULTDIFFICULTY*/) { BTSkillList &skillList = BTGame::getGame()->getSkillList(); if (difficulty == BTSKILL_DEFAULTDIFFICULTY) difficulty = skillList[index]->defaultDifficulty; for (int i = 0; i < skill.size(); ++i) { if (skill[i]->skill == index) { if (0 < skill[i]->value) { if (skillList[index]->limited) { if (skill[i]->uses > 0) --(skill[i]->uses); else return false; } BTDice *dice = skillList[index]->getRoll(skill[i]->value); if (dice) { int roll = dice->roll(); if ((roll != dice->getMin()) && (roll + skill[i]->value >= difficulty)) { return true; } } } return false; } } return false; }
std::string BTCombatant::attack(BTCombatant *defender, bool melee, const std::string &cause, const std::string &effect, const BTDice &damageDice, IShort chanceXSpecial, IShort xSpecial, int &numAttacksLeft, int &activeNum, int toHitBonus /*= 0*/) { int hits = 0; int totalDamage = 0; bool dead = false; bool totalDrain = false; BitField finalSpecial; while ((defender->isAlive()) && (numAttacksLeft > 0)) { int roll = BTDice(1, 20).roll(); if ((1 != roll) && ((20 == roll) || (roll + toHit + toHitBonus >= defender->ac))) { ++hits; int damage = 0; BitField special; damage = damageDice.roll(); for (int i = 0; i < dmgBonus.size(); i++) damage += dmgBonus[i]->apply(melee); if ((BTEXTRADAMAGE_NONE != xSpecial) && (BTDice(1, 100).roll() <= chanceXSpecial)) special.set(xSpecial); if (damage < 0) damage = 0; totalDamage += damage; if (defender->takeHP(damage)) { dead = true; defender->deactivate(activeNum); } else { useAutoCombatSkill(melee, special); int maxSpecial = special.getMaxSet(); if (maxSpecial > -1) { std::string specialText; for (int i = 0; i <= maxSpecial; ++i) { if (!special.isSet(i)) continue; if (defender->savingThrow(BTSAVE_DIFFICULTY)) { special.clear(i); continue; } switch(i) { case BTEXTRADAMAGE_POISON: defender->status.set(BTSTATUS_POISONED); break; case BTEXTRADAMAGE_LEVELDRAIN: if (defender->drainLevel()) { totalDrain = true; defender->deactivate(activeNum); } break; case BTEXTRADAMAGE_INSANITY: defender->status.set(BTSTATUS_INSANE); break; case BTEXTRADAMAGE_AGED: if (defender->age()) { defender->deactivate(activeNum); } break; case BTEXTRADAMAGE_POSSESSION: defender->status.set(BTSTATUS_POSSESSED); break; case BTEXTRADAMAGE_PARALYSIS: defender->status.set(BTSTATUS_PARALYZED); break; case BTEXTRADAMAGE_STONED: defender->status.set(BTSTATUS_STONED); defender->deactivate(activeNum); break; case BTEXTRADAMAGE_CRITICALHIT: defender->status.set(BTSTATUS_DEAD); defender->deactivate(activeNum); break; case BTEXTRADAMAGE_ITEMZOT: if (!defender->drainItem(5)) { special.clear(BTEXTRADAMAGE_ITEMZOT); } break; case BTEXTRADAMAGE_POINTPHAZE: if (!defender->takeSP(5)) { special.clear(BTEXTRADAMAGE_POINTPHAZE); } break; default: break; } } finalSpecial |= special; } } } --numAttacksLeft; } std::string text = getName(); text += " "; text += cause; text += " "; std::string defenderName; text += defenderName = defender->getName(); if (0 < hits) { text += " "; text += effect; text += " "; char tmp[20]; if (hits > 1) { sprintf(tmp, "%d", hits); text += tmp; text += " times "; } text += "for "; sprintf(tmp, "%d", totalDamage); text += tmp; text += " points of damage"; if (dead) { text += ", killing "; text += genderPronouns[defender->getGender()]; } else { int maxSpecial = finalSpecial.getMaxSet(); if (maxSpecial > -1) { std::string specialText; for (int i = 0; i <= maxSpecial; ++i) { if (!finalSpecial.isSet(i)) continue; if ((specialText == "") || (maxSpecial == i)) specialText += " and"; else specialText += ","; switch(i) { case BTEXTRADAMAGE_POISON: specialText += " poisons"; break; case BTEXTRADAMAGE_LEVELDRAIN: specialText += " drains a level from "; specialText += defenderName; if (totalDrain) { specialText += " totally draining "; specialText += genderPronouns[defender->getGender()]; } break; case BTEXTRADAMAGE_INSANITY: specialText += " inflicts insanity"; break; case BTEXTRADAMAGE_AGED: specialText += " withers "; specialText += genderPronouns[defender->getGender()]; break; case BTEXTRADAMAGE_POSSESSION: specialText += " possesses"; break; case BTEXTRADAMAGE_PARALYSIS: specialText += " paralyzes"; break; case BTEXTRADAMAGE_STONED: specialText += " stones"; break; case BTEXTRADAMAGE_CRITICALHIT: specialText += " critically hits"; break; case BTEXTRADAMAGE_ITEMZOT: specialText += " drains an item"; break; case BTEXTRADAMAGE_POINTPHAZE: specialText += " absorbs spell points"; break; default: break; } } text += specialText; } } if (defender->isAlive()) text += "."; else text += "!"; } else text += ", but misses!"; return text; }
std::string BTCombatant::specialAttack(BTCombatant *defender, const BTDice &damageDice, IShort xSpecial, bool farRange, int &activeNum, bool *saved /*= NULL*/) { int totalDamage = 0; bool dead = false; bool totalDrain = false; BitField special; totalDamage = damageDice.roll(); if (farRange) totalDamage = totalDamage / 2; bool saveResult = false; if (saved) saveResult = *saved; else saveResult = defender->savingThrow(BTSAVE_DIFFICULTY); if (saveResult) { totalDamage = totalDamage / 2; } else if (BTEXTRADAMAGE_NONE != xSpecial) { special.set(xSpecial); } if (defender->takeHP(totalDamage)) { dead = true; defender->deactivate(activeNum); } else { int maxSpecial = special.getMaxSet(); if (maxSpecial > -1) { for (int i = 0; i <= maxSpecial; ++i) { if (!special.isSet(i)) continue; switch(i) { case BTEXTRADAMAGE_POISON: defender->status.set(BTSTATUS_POISONED); break; case BTEXTRADAMAGE_LEVELDRAIN: if (defender->drainLevel()) { totalDrain = true; defender->deactivate(activeNum); } break; case BTEXTRADAMAGE_INSANITY: defender->status.set(BTSTATUS_INSANE); break; case BTEXTRADAMAGE_AGED: if (defender->age()) { defender->deactivate(activeNum); } break; case BTEXTRADAMAGE_POSSESSION: defender->status.set(BTSTATUS_POSSESSED); break; case BTEXTRADAMAGE_PARALYSIS: defender->status.set(BTSTATUS_PARALYZED); break; case BTEXTRADAMAGE_STONED: defender->status.set(BTSTATUS_STONED); defender->deactivate(activeNum); break; case BTEXTRADAMAGE_CRITICALHIT: defender->status.set(BTSTATUS_DEAD); defender->deactivate(activeNum); break; case BTEXTRADAMAGE_ITEMZOT: if (!defender->drainItem(5)) { special.clear(BTEXTRADAMAGE_ITEMZOT); } break; case BTEXTRADAMAGE_POINTPHAZE: if (!defender->takeSP(5)) { special.clear(BTEXTRADAMAGE_POINTPHAZE); } break; default: break; } } } } std::string text; std::string defenderName; text = defenderName = defender->getName(); if (saveResult == false) { if (totalDamage > 0) { text += " takes "; char tmp[20]; sprintf(tmp, "%d", totalDamage); text += tmp; text += " points of damage"; } if (dead) { text += ", killing "; text += genderPronouns[defender->getGender()]; } else { int maxSpecial = special.getMaxSet(); if (maxSpecial > -1) { std::string specialText; for (int i = 0; i <= maxSpecial; ++i) { if (!special.isSet(i)) continue; if ((totalDamage > 0) || (specialText != "")) { if ((specialText == "") || (maxSpecial == i)) specialText += " and"; else specialText += ","; } switch(i) { case BTEXTRADAMAGE_POISON: specialText += " is poisoned"; break; case BTEXTRADAMAGE_LEVELDRAIN: specialText += " is drained of a level"; if (totalDrain) { specialText += " totally draining "; specialText += genderPronouns[defender->getGender()]; } break; case BTEXTRADAMAGE_INSANITY: specialText += " has gone insane"; break; case BTEXTRADAMAGE_AGED: specialText += " withers"; break; case BTEXTRADAMAGE_POSSESSION: specialText += " is possessed"; break; case BTEXTRADAMAGE_PARALYSIS: specialText += " is paralyzed"; break; case BTEXTRADAMAGE_STONED: specialText += " is stoned"; break; case BTEXTRADAMAGE_CRITICALHIT: specialText += " is killed"; break; case BTEXTRADAMAGE_ITEMZOT: specialText += " has an item drained"; break; case BTEXTRADAMAGE_POINTPHAZE: specialText += " is drained of spell points"; break; default: break; } } text += specialText; } } if (defender->isAlive()) text += "."; else text += "!"; } else { if (totalDamage > 0) { text += " saves and takes "; char tmp[20]; sprintf(tmp, "%d", totalDamage); text += tmp; text += " points of damage"; if (dead) { text += ", killing "; text += genderPronouns[defender->getGender()]; } text += "!"; } else text += " saves!"; } return text; }