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; }
void BTSerializedEditor::edit(BTDisplay &d, ObjectSerializer &serial) { BTDisplayConfig *oldConfig = d.getConfig(); BTDisplayConfig config; XMLSerializer parser; config.serialize(&parser); parser.parse(BTDisplay::applyDisplayDir("data/specialedit.xml").c_str(), true); d.setConfig(&config); int start(0); int current(0); BitField active; std::vector<BTDisplay::selectItem> list(entries); initActive(serial, active); int len = setup(serial, active, list); d.addSelection(list.data(), len, start, current); int key; char extra[2] = {BTKEY_DEL, 0}; while (27 != (key = d.process(extra))) { d.clearText(); XMLAction *curField = NULL; if (list[current].value < entries) curField = serial.find(field[list[current].value], NULL); if (key == BTKEY_DEL) { if (curField) { int where = 0; if (curField->getType() == XMLTYPE_CREATE) { XMLArray *obj = reinterpret_cast<XMLArray*>(curField->object); int where = 0; for (int i = current - 1; (i >= 0) && (list[i].value == list[current].value); --i) { ++where; } if (where < obj->size()) { obj->erase(where); for (int i = current; i < len - 1; ++i) { list[i].name = list[i + 1].name; list[i].value = list[i + 1].value; } --len; } } else if (curField->getType() == XMLTYPE_VECTORSTRING) { std::vector<std::string> *obj = reinterpret_cast<std::vector<std::string>*>(curField->object); int where = 0; for (int i = current - 1; (i >= 0) && (list[i].value == list[current].value); --i) { ++where; } if (where < obj->size()) { obj->erase(obj->begin() + where); for (int i = current; i < len - 1; ++i) { list[i].name = list[i + 1].name; list[i].value = list[i + 1].value; } --len; } } } else { delSpecialField(d, serial, list[current].value); } } else { if (curField) { int where = 0; if (curField->getType() == XMLTYPE_CREATE) { XMLArray *obj = reinterpret_cast<XMLArray*>(curField->object); for (int i = current - 1; (i >= 0) && (list[i].value == list[current].value); --i) { ++where; } if (where >= obj->size()) { obj->push_back((*reinterpret_cast<XMLObject::create>(curField->data))(field[list[current].value], NULL)); list.push_back(BTDisplay::selectItem()); for (int i = list.size() - 1; i > current; --i) { list[i].name = list[i - 1].name; list[i].value = list[i - 1].value; } len++; } } else if (curField->getType() == XMLTYPE_VECTORSTRING) { std::vector<std::string> *obj = reinterpret_cast<std::vector<std::string>*>(curField->object); for (int i = current - 1; (i >= 0) && (list[i].value == list[current].value); --i) { ++where; } if (where >= obj->size()) { obj->push_back(std::string()); list.push_back(BTDisplay::selectItem()); for (int i = list.size() - 1; i > current; --i) { list[i].name = list[i - 1].name; list[i].value = list[i - 1].value; } len++; } } editField(d, serial, description[list[current].value], curField, list[current].value, where); if (curField->getType() == XMLTYPE_OBJECT) { XMLObject *obj = reinterpret_cast<XMLObject*>(curField->object); BTDice *dice = dynamic_cast<BTDice*>(obj); if (dice) list[current].name = std::string(description[list[current].value]) + ": " + dice->createString(); } else if (curField->getType() == XMLTYPE_VECTORSTRING) { std::vector<std::string> *obj = reinterpret_cast<std::vector<std::string>*>(curField->object); list[current].name = std::string(description[list[current].value]) + ": " + (*obj)[where]; } else if (curField->getType() != XMLTYPE_CREATE) { list[current].name = std::string(description[list[current].value]) + ": " + curField->createString(); } else { XMLArray *obj = reinterpret_cast<XMLArray*>(curField->object); list[current].name = std::string(description[list[current].value]) + ": " + obj->get(where)->createString(); } } else { handleSpecialField(d, serial, list[current].value); } } if (updateActive(serial, active, list[current].value)) len = setup(serial, active, list); d.addSelection(list.data(), len, start, current); } complete(serial); d.clearText(); d.setConfig(oldConfig); }
void BTSerializedEditor::editField(BTDisplay &d, ObjectSerializer &serial, const char *text, XMLAction *curField, int modField, int where) { int key; switch (curField->getType()) { case XMLTYPE_STDSTRING: { std::string val = curField->createString(); d.addReadString(std::string(text) + ": ", 100, val); key = d.process(); if ('\r' == key) *(reinterpret_cast<std::string*>(curField->object)) = val; break; } case XMLTYPE_STRING: { std::string val = curField->createString(); d.addReadString(std::string(text) + ": ", 100, val); key = d.process(); if ('\r' == key) { char *str = *(reinterpret_cast<char**>(curField->object)); if (str) { delete [] str; } int len = val.length(); str = new char[len + 1]; strncpy(str, val.c_str(), len); str[len] = 0; *(reinterpret_cast<char**>(curField->object)) = str; } break; } case XMLTYPE_BOOL: { BTDisplay::selectItem vals[2]; vals[0].name = "false"; vals[1].name = "true"; int lookupStart(0); int lookupCurrent((*(reinterpret_cast<bool*>(curField->object)) ? 1 : 0)); d.addSelection(vals, 2, lookupStart, lookupCurrent); if (27 != d.process()) { *(reinterpret_cast<bool*>(curField->object)) = lookupCurrent; } break; } case XMLTYPE_BITFIELD: { ValueLookup *lookup = reinterpret_cast<ValueLookup*>(curField->data); BitField *bits = reinterpret_cast<BitField*>(curField->object); BTDisplay::selectItem lookupItem[lookup->size()]; for (int i = 0; i < lookup->size(); ++i) { lookupItem[i].name = lookup->getName(i); if (bits->isSet(i)) lookupItem[i].first = '*'; } int lookupStart(0); int lookupCurrent(0); d.addSelection(lookupItem, lookup->size(), lookupStart, lookupCurrent); int key; while (27 != (key = d.process())) { if (bits->toggle(lookupCurrent)) lookupItem[lookupCurrent].first = '*'; else lookupItem[lookupCurrent].first = 0; } break; } case XMLTYPE_INT: { if (curField->data) { ValueLookup *lookup = reinterpret_cast<ValueLookup*>(curField->data); bool extra = ((curField->extra == EXTRA_NONE) ? false : true); BTDisplay::selectItem lookupItem[lookup->size() + (extra ? 1 : 0)]; int i = 0; if (extra) { lookupItem[0].name = curField->extraText; lookupItem[0].value = -1; ++i; } int endIndex = lookup->getEndIndex(); int lookupCurrent(0); int valIndex((*(reinterpret_cast<int*>(curField->object))) + (extra ? 1 : 0)); for (int curIndex = lookup->getFirstIndex(); curIndex != endIndex; curIndex = lookup->getNextIndex(curIndex)) { lookupItem[i].name = lookup->getName(curIndex); lookupItem[i].value = curIndex; if (curIndex == valIndex) lookupCurrent = i; ++i; } int lookupStart(0); d.addSelection(lookupItem, lookup->size() + (extra ? 1 : 0), lookupStart, lookupCurrent); if (27 != d.process()) { *(reinterpret_cast<int*>(curField->object)) = lookupItem[lookupCurrent].value; } } else { std::string val = curField->createString(); d.addReadString(std::string(text) + ": ", 100, val); key = d.process(); if ('\r' == key) *(reinterpret_cast<int*>(curField->object)) = atol(val.c_str()); } break; } case XMLTYPE_UINT: { std::string val = curField->createString(); d.addReadString(std::string(text) + ": ", 100, val); key = d.process(); if ('\r' == key) *(reinterpret_cast<unsigned int*>(curField->object)) = atol(val.c_str()); break; } case XMLTYPE_INT16: { std::string val = curField->createString(); d.addReadString(std::string(text) + ": ", 100, val); key = d.process(); if ('\r' == key) *(reinterpret_cast<int16_t*>(curField->object)) = atol(val.c_str()); break; } case XMLTYPE_VECTORUINT: { std::vector<unsigned int> *vec = reinterpret_cast<std::vector<unsigned int> *>(curField->object); std::string val; for (size_t i = 0; i < vec->size(); ++i) { if (i != 0) val += ","; char convert[30]; sprintf(convert, "%u", (*vec)[i]); val += convert; } d.addReadString(std::string(text) + ": ", 100, val); key = d.process(); if ('\r' == key) { size_t i = 0; const char *start = val.c_str(); for (const char *comma = strchr(val.c_str(), ','); (start) && (*start); ++i) { if (i < vec->size()) (*vec)[i] = atol(start); else vec->push_back(atol(start)); start = comma; if (start) { if ((*start) == ',') ++start; comma = strchr(start, ','); } } if (i < vec->size()) vec->resize(i); } break; } case XMLTYPE_OBJECT: { XMLObject *obj = reinterpret_cast<XMLObject*>(curField->object); BTDice *dice = dynamic_cast<BTDice*>(obj); if (dice) { std::ostringstream stream; stream << dice->getNumber(); std::string val = stream.str(); d.addReadString(std::string(text) + "- Number of Dice: ", 100, val); key = d.process(); if ('\r' == key) dice->setNumber(atol(val.c_str())); d.clearText(); stream.str(""); stream << dice->getType(); val = stream.str(); d.addReadString(std::string(text) + "- Type of Dice: ", 100, val); key = d.process(); if ('\r' == key) dice->setType(atol(val.c_str())); d.clearText(); stream.str(""); stream << dice->getModifier(); val = stream.str(); d.addReadString(std::string(text) + "- Modifier to Roll: ", 100, val); key = d.process(); if ('\r' == key) dice->setModifier(atol(val.c_str())); } else printf("Unsuppported type: %d\n", curField->getType()); break; } case XMLTYPE_CREATE: { XMLArray *obj = reinterpret_cast<XMLArray*>(curField->object); handleObject(d, obj->get(where), modField); break; } case XMLTYPE_PICTURE: { BTDisplayConfig *oldConfig = d.getConfig(); BTDisplayConfig config; XMLSerializer parser; config.serialize(&parser); parser.parse(BTDisplay::applyDisplayDir("data/pictureselect.xml").c_str(), true); d.setConfig(&config); d.clearText(); d.addText(text); int val(reinterpret_cast<PictureIndex*>(curField->object)->value); d.addSelectImage(val); key = d.process(); if ('\r' == key) reinterpret_cast<PictureIndex*>(curField->object)->value = val; d.clearImage(); d.setConfig(oldConfig); break; } case XMLTYPE_VECTORSTRING: { std::vector<std::string> *obj = reinterpret_cast<std::vector<std::string>*>(curField->object); std::string val = (*obj)[where]; d.addReadString(std::string(text) + ": ", 100, val); key = d.process(); if ('\r' == key) (*obj)[where] = val; break; } default: printf("Unsuppported type: %d\n", curField->getType()); break; } d.clearText(); }
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; }