void BTPc::updateSkills() { BTJobList &jobList = BTGame::getGame()->getJobList(); for (int i = 0; i < jobList[job]->skill.size(); ++i) { int value = jobList[job]->skill[i]->value; if ((jobList[job]->skill[i]->modifier >= 0) && (stat[jobList[job]->skill[i]->modifier] > 14)) value += stat[jobList[job]->skill[i]->modifier] - 14; if (getSkill(jobList[job]->skill[i]->skill) == 0) { setSkill(jobList[job]->skill[i]->skill, value, value); if (jobList[job]->skill[i]->improve > 0) { for (int sk = 0; sk < skill.size(); ++sk) { if (skill[sk]->skill == jobList[job]->skill[i]->skill) { for (int k = 2; k <= level; ++k) { if ((k % jobList[job]->skill[i]->improveLevel) == 0) { unsigned int increase = BTDice(1, jobList[job]->skill[i]->improve).roll(); if ((jobList[job]->skill[i]->modifier >= 0) && (stat[jobList[job]->skill[i]->modifier] > 14)) increase += stat[jobList[job]->skill[i]->modifier] - 14; skill[sk]->value += increase; skill[sk]->history.push_back(increase); } } break; } } } } } }
int BTPc::incrementStat() { int s = 0; int i = 0; for (; i < BT_STATS; ++i) { if (stat[i] < BTSTAT_MAX) ++s; } if (s == 0) return -1; if (s != 1) s = BTDice(1, s, 0).roll(); for (i = 0; i < BT_STATS; ++i) { if (stat[i] < BTSTAT_MAX) { --s; if (0 == s) { ++stat[i]; if (statMax[i] < BTSTAT_MAX) ++statMax[i]; if ((i == BTSTAT_LK) && (stat[i] > 14)) ++save; if ((i == BTSTAT_DX) && (stat[i] > 14)) ++ac; return i; } } } return -1; // Can't get here }
bool BTPc::savingThrow(int difficulty /*= BTSAVE_DIFFICULTY*/) const { int roll = BTDice(1, 20, save).roll(); if (roll == 20 + save) return true; else if (roll == 1 + save) return false; else return (roll >= difficulty); }
bool BTPc::drainItem(BTDisplay &d, int amount) { BTFactory<BTItem> &itemList = BTGame::getGame()->getItemList(); int numItems = 0; for (numItems = 0; numItems < BT_ITEMS; ++numItems) { if (BTITEM_NONE == item[numItems].id) break; } if (numItems == 0) return false; int i = BTDice(1, numItems, -1).roll(); if ((item[i].equipped == BTITEM_EQUIPPED) && (BTITEM_ARROW != itemList[item[i].id].getType()) && (BTITEM_BOW != itemList[item[i].id].getType()) && (BTITEM_THROWNWEAPON != itemList[item[i].id].getType()) && (BTITEMCAST_NONE != itemList[item[i].id].getSpellCast()) && (0 < item[i].charges)) { takeItemCharge(d, i, amount); return true; } return false; }
void BTPc::changeJob(int newJob) { XMLVector<BTJob*> &jobList = BTGame::getGame()->getJobList(); toHit += jobList[newJob]->toHit - jobList[job]->toHit - ((level - 1) / jobList[job]->improveToHit); save += jobList[newJob]->save - jobList[job]->save - ((level - 1) / jobList[job]->improveSave); ac += jobList[newJob]->ac - jobList[job]->ac; if (jobList[job]->improveAc != 0) ac -= ((level - 1) / jobList[job]->improveAc); job = newJob; if (gender == BTGENDER_FEMALE) picture = jobList[newJob]->femalePicture; else picture = jobList[newJob]->malePicture; int moreHp = BTDice(1, jobList[job]->hp).roll() + ((stat[BTSTAT_CN] > 14) ? stat[BTSTAT_CN] - 14 : 0); hp += moreHp; maxHp += moreHp; { for (int i = 0; i < skill.size(); ++i) { skill[i]->history.clear(); } } for (int k = 0; k < jobList[newJob]->skill.size(); ++k) { bool found(false); for (int i = 0; i < skill.size(); ++i) { if (skill[i]->skill == jobList[newJob]->skill[k]->skill) { if ((jobList[newJob]->skill[k]->value == 0) && (jobList[newJob]->skill[k]->improve == 0)) { skill.erase(skill.begin() + i); } else { skill[i]->value = jobList[newJob]->skill[k]->value; if ((jobList[newJob]->skill[k]->modifier >= 0) && (stat[jobList[newJob]->skill[k]->modifier] > 14)) skill[i]->value += stat[jobList[newJob]->skill[k]->modifier] - 14; } found = true; break; } } if ((!found) && ((jobList[newJob]->skill[k]->value != 0) || (jobList[newJob]->skill[k]->improve != 0))) { BTSkillValue *value = new BTSkillValue; value->skill = jobList[newJob]->skill[k]->skill; value->value = jobList[newJob]->skill[k]->value; if ((jobList[newJob]->skill[k]->modifier >= 0) && (stat[jobList[newJob]->skill[k]->modifier] > 14)) value->value += stat[jobList[newJob]->skill[k]->modifier] - 14; skill.push_back(value); } } if (jobList[newJob]->spells) { int moreSp = BTDice(1, 4).roll() + ((stat[BTSTAT_IQ] > 14) ? stat[BTSTAT_IQ] - 14 : 0); if (maxSp == 0) moreSp = BTDice(1, 8, 9).roll() + ((stat[BTSTAT_IQ] > 14) ? stat[BTSTAT_IQ] - 14 : 0); sp += moreSp; maxSp += moreSp; } maxLevel = level = 1; xp = 0; }
bool BTPc::advanceLevel() { BTJobList &jobList = BTGame::getGame()->getJobList(); BTXpChartList &xpChartList = BTGame::getGame()->getXpChartList(); if (jobList[job]->xpChart != -1) { if (xp >= xpChartList[jobList[job]->xpChart]->getXpNeeded(level)) { ++level; if (((level - 1) % jobList[job]->improveToHit) == 0) ++toHit; if ((jobList[job]->improveRateAttacks) && (level - 1 < ((jobList[job]->maxRateAttacks - 1) * jobList[job]->improveRateAttacks) + 1) && (((level - 1) % jobList[job]->improveRateAttacks) == 0)) { ++rateAttacks; } if (((level - 1) % jobList[job]->improveSave) == 0) ++save; if ((jobList[job]->improveAc) && (((level - 1) % jobList[job]->improveAc) == 0)) ++ac; if (level > maxLevel) { int moreHp = BTDice(1, jobList[job]->hp).roll() + ((stat[BTSTAT_CN] > 14) ? stat[BTSTAT_CN] - 14 : 0); hp += moreHp; maxHp += moreHp; for (int i = 0; i < jobList[job]->skill.size(); ++i) { if ((jobList[job]->skill[i]->improve > 0) && ((level % jobList[job]->skill[i]->improveLevel) == 0)) { for (int k = 0; k < skill.size(); ++k) { if (skill[k]->skill == jobList[job]->skill[i]->skill) { unsigned int increase = BTDice(1, jobList[job]->skill[i]->improve).roll(); if ((jobList[job]->skill[i]->modifier >= 0) && (stat[jobList[job]->skill[i]->modifier] > 14)) increase += stat[jobList[job]->skill[i]->modifier] - 14; skill[k]->value += increase; skill[k]->history.push_back(increase); break; } } } } if (jobList[job]->spells) { int moreSp = BTDice(1, 4).roll() + ((stat[BTSTAT_IQ] > 14) ? stat[BTSTAT_IQ] - 14 : 0); sp += moreSp; maxSp += moreSp; } maxLevel = level; } else { for (int k = 0; k < skill.size(); ++k) { if (skill[k]->history.size() >= level - 1) { skill[k]->value += skill[k]->history[level - 2]; } } } return true; } } 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; }
void BTCombatant::rollInitiative() { initiative = BTDice(1, 20).roll() + (level / 2); }