Allow items that boost skills other than the three basic stats (STR/DEX/INT)

Where stat-boosting items were already accounted for, the effects remain unchanged by this; however, some additional effects have been added.

Strength-boosting items have the following new effects:
- Increases hit points gained on level-up
- Increases amount PCs can carry
Dexterity-boosting items have the following new effects:
- Increases hit chance in unarmed combat
Intelligence-boosting items have the following new effects:
- Increases effectiveness in a mindduel
This commit is contained in:
2015-01-20 12:56:49 -05:00
parent 54a8ae8213
commit 4c271140c6
9 changed files with 49 additions and 38 deletions

View File

@@ -503,7 +503,7 @@ bool pc_combat_move(location destination) {
void char_parry() {
univ.party[current_pc].parry = (univ.party[current_pc].ap / 4) *
(2 + stat_adj(current_pc,eSkill::DEXTERITY) + univ.party[current_pc].skills[eSkill::DEFENSE]);
(2 + stat_adj(current_pc,eSkill::DEXTERITY) + univ.party[current_pc].skill(eSkill::DEFENSE));
univ.party[current_pc].ap = 0;
}
@@ -514,9 +514,8 @@ void char_stand_ready() {
void pc_attack(short who_att,short target) {
short r1,r2,weap1 = 24, weap2 = 24,i,store_hp,skill_item;
eSkill what_skill1 = eSkill::DEXTERITY, what_skill2 = eSkill::DEXTERITY;
cCreature *which_m;
short hit_adj, dam_adj, spec_dam = 0,poison_amt;
short hit_adj, dam_adj;
// slice out bad attacks
if(univ.party[who_att].main_status != eMainStatus::ALIVE)
@@ -570,7 +569,7 @@ void pc_attack(short who_att,short target) {
r1 += 5 * (univ.party[current_pc].status[eStatus::WEBS] / 3);
r2 = get_ran(1,1,4) + dam_adj;
if(r1 <= hit_chance[univ.party[who_att].skills[what_skill1]]) {
if(r1 <= hit_chance[univ.party[who_att].skill(eSkill::DEXTERITY)]) {
damage_monst(target, who_att, r2, 0,eDamageType::WEAPON,4);
}
else {
@@ -636,7 +635,7 @@ void pc_attack_weapon(short who_att,short target,short hit_adj,short dam_adj,cIt
if(weap.ability == eItemAbil::WEAK_WEAPON)
r2 = (r2 * (10 - weap.abil_data[0])) / 10;
if(r1 <= hit_chance[univ.party[who_att].skills[what_skill]]) {
if(r1 <= hit_chance[univ.party[who_att].skill(what_skill)]) {
eDamageType dmg_tp = eDamageType::UNBLOCKABLE;
short spec_dam = calc_spec_dam(weap.ability,weap.abil_data[0],weap.abil_data[1],which_m,dmg_tp);
short bonus_dam = 0;
@@ -645,10 +644,10 @@ void pc_attack_weapon(short who_att,short target,short hit_adj,short dam_adj,cIt
if(primary) {
// assassinate
r1 = get_ran(1,1,100);
if((univ.party[who_att].level >= which_m->level - 1)
&& univ.party[who_att].skills[eSkill::ASSASSINATION] >= which_m->level / 2
int assassin = univ.party[who_att].skill(eSkill::ASSASSINATION);
if((univ.party[who_att].level >= which_m->level - 1) && assassin >= which_m->level / 2
&& (!which_m->abil[eMonstAbil::SPLITS].active)) // Can't assassinate splitters
if(r1 < hit_chance[max(univ.party[who_att].skills[eSkill::ASSASSINATION] - which_m->level,0)]) {
if(r1 < hit_chance[max(assassin - which_m->level,0)]) {
add_string_to_buf(" You assassinate.");
spec_dam += r2;
}
@@ -1481,7 +1480,7 @@ void fire_missile(location target) {
bool exploding = false;
missile_firer = current_pc;
skill = univ.party[missile_firer].skills[univ.party[missile_firer].items[missile_inv_slot].weap_type];
skill = univ.party[missile_firer].skill(univ.party[missile_firer].items[missile_inv_slot].weap_type);
range = (overall_mode == MODE_FIRING) ? 12 : 8;
dam = univ.party[missile_firer].items[ammo_inv_slot].item_level;
dam_bonus = univ.party[missile_firer].items[ammo_inv_slot].bonus + minmax(-8,8,univ.party[missile_firer].status[eStatus::BLESS_CURSE]);
@@ -4297,7 +4296,7 @@ bool combat_cast_mage_spell() {
store_sp = univ.party[current_pc].cur_sp;
if(univ.party[current_pc].cur_sp == 0)
add_string_to_buf("Cast: No spell points. ");
else if(univ.party[current_pc].skills[eSkill::MAGE_SPELLS] == 0)
else if(univ.party[current_pc].skill(eSkill::MAGE_SPELLS) == 0)
add_string_to_buf("Cast: No mage skill. ");
else if(get_encumberance(current_pc) > 1) {
add_string_to_buf("Cast: Too encumbered. ");
@@ -4508,7 +4507,7 @@ bool combat_cast_priest_spell() {
if(univ.party[current_pc].cur_sp == 0) {
add_string_to_buf("Cast: No spell points. ");
return false;
} else if(univ.party[current_pc].skills[eSkill::PRIEST_SPELLS] == 0) {
} else if(univ.party[current_pc].skill(eSkill::PRIEST_SPELLS) == 0) {
add_string_to_buf("Cast: No priest skill. ");
return false;
}
@@ -4798,8 +4797,8 @@ static void process_force_cage(location loc, short i) {
cPlayer& who = univ.party[i];
// We want to make sure everyone has a chance of eventually breaking a cage, because it never ends on its own,
// and because being trapped unconditionally prevents you from ending combat mode.
short bonus = 5 + who.skills[eSkill::MAGE_LORE];
if(get_ran(1,1,100) < who.skills[eSkill::MAGE_SPELLS]*10 + who.skills[eSkill::PRIEST_SPELLS]*4 + bonus) {
short bonus = 5 + who.skill(eSkill::MAGE_LORE);
if(get_ran(1,1,100) < who.skill(eSkill::MAGE_SPELLS)*10 + who.skill(eSkill::PRIEST_SPELLS)*4 + bonus) {
play_sound(60);
add_string_to_buf(" " + who.name + " breaks force cage.");
univ.town.set_force_cage(loc.x,loc.y,false);

View File

@@ -541,7 +541,11 @@ static void display_pc_info(cDialog& me, const short pc) {
for(i = 0; i < 19; i++) {
eSkill skill = eSkill(i);
me[skill_ids[i]].setTextToNum(univ.party[pc].skills[skill]);
int bonus = univ.party[pc].get_prot_level(eItemAbil::BOOST_STAT, i);
to_draw << univ.party[pc].skills[skill];
if(bonus > 0) to_draw << '+' << bonus;
me[skill_ids[i]].setText(to_draw.str());
to_draw.str("");
}
store = total_encumberance(pc);
me["encumb"].setTextToNum(store);

View File

@@ -996,7 +996,7 @@ void place_treasure(location where,short level,short loot,short mode) {
if(new_item.variety != eItemType::NO_ITEM) {
for(i = 0; i < 6; i++)
if((univ.party[i].main_status == eMainStatus::ALIVE)
&& get_ran(1,1,100) < id_odds[univ.party[i].skills[eSkill::ITEM_LORE]])
&& get_ran(1,1,100) < id_odds[univ.party[i].skill(eSkill::ITEM_LORE)])
new_item.ident = true;
place_item(new_item,where,false);
}

View File

@@ -1378,9 +1378,9 @@ short get_encumberance(short pc_num) {
for(i = 0; i < 24; i++)
if(univ.party[pc_num].equip[i]) {
what_val = univ.party[pc_num].items[i].awkward;
if(what_val == 1 && get_ran(1,0,130) < hit_chance[univ.party[pc_num].skills[eSkill::DEFENSE]])
if(what_val == 1 && get_ran(1,0,130) < hit_chance[univ.party[pc_num].skill(eSkill::DEFENSE)])
what_val--;
if(what_val > 1 && get_ran(1,0,70) < hit_chance[univ.party[pc_num].skills[eSkill::DEFENSE]])
if(what_val > 1 && get_ran(1,0,70) < hit_chance[univ.party[pc_num].skill(eSkill::DEFENSE)])
what_val--;
store += what_val;
}

View File

@@ -648,8 +648,8 @@ void award_xp(short pc_num,short amt) {
std::string level = std::to_string(univ.party[pc_num].level);
add_string_to_buf(" " + univ.party[pc_num].name + " is level " + level + "!");
univ.party[pc_num].skill_pts += (univ.party[pc_num].level < 20) ? 5 : 4;
add_hp = (univ.party[pc_num].level < 26) ? get_ran(1,2,6) + skill_bonus[univ.party[pc_num].skills[eSkill::STRENGTH]]
: max (skill_bonus[univ.party[pc_num].skills[eSkill::STRENGTH]],0);
add_hp = (univ.party[pc_num].level < 26) ? get_ran(1,2,6) + skill_bonus[univ.party[pc_num].skill(eSkill::STRENGTH)]
: max (skill_bonus[univ.party[pc_num].skill(eSkill::STRENGTH)],0);
if(add_hp < 0)
add_hp = 0;
univ.party[pc_num].max_health += add_hp;
@@ -687,7 +687,7 @@ static short check_party_stat_get(short pc, eSkill which_stat) {
case eSkill::CUR_LEVEL:
return univ.party[pc].level;
default:
return univ.party[pc].skills[which_stat];
return univ.party[pc].skill(which_stat);
}
return 0;
}
@@ -739,11 +739,11 @@ bool poison_weapon( short pc_num, short how_much,short safe) {
// Nimble?
if(univ.party[pc_num].traits[eTrait::NIMBLE])
r1 -= 6;
if((r1 > p_chance[univ.party[pc_num].skills[eSkill::POISON]]) && (safe == 0)) {
if((r1 > p_chance[univ.party[pc_num].skill(eSkill::POISON)]) && (safe == 0)) {
add_string_to_buf(" Poison put on badly. ");
p_level = p_level / 2;
r1 = get_ran(1,1,100);
if(r1 > p_chance[univ.party[pc_num].skills[eSkill::POISON]] + 10) {
if(r1 > p_chance[univ.party[pc_num].skill(eSkill::POISON)] + 10) {
add_string_to_buf(" You nick yourself. ");
univ.party[pc_num].status[eStatus::POISON] += p_level;
}
@@ -1629,7 +1629,7 @@ void crumble_wall(location where) { // TODO: Add something like this to the spre
void do_mindduel(short pc_num,cCreature *monst) {
short i = 0,adjust,r1,r2,balance = 0;
adjust = (univ.party[pc_num].level + univ.party[pc_num].skills[eSkill::INTELLIGENCE]) / 2 - monst->level * 2;
adjust = (univ.party[pc_num].level + univ.party[pc_num].skill(eSkill::INTELLIGENCE)) / 2 - monst->level * 2;
adjust += univ.party[pc_num].get_prot_level(eItemAbil::WILL) * 5;
if(monst->attitude % 2 != 1)
make_town_hostile();
@@ -1757,7 +1757,7 @@ bool pc_can_cast_spell(short pc_num,eSpell spell_num) {
return false; // From Windows version. It does kinda make sense, though this function shouldn't even be called in these modes.
if(!isMage(spell_num) && !isPriest(spell_num))
return false;
if(univ.party[pc_num].skills[type] < level)
if(univ.party[pc_num].skill(type) < level)
return false;
if(univ.party[pc_num].main_status != eMainStatus::ALIVE)
return false;
@@ -2180,7 +2180,7 @@ eSpell pick_spell(short pc_num,eSkill type) { // 70 - no spell OW spell num
}
if(!can_choose_caster) {
if(univ.party[pc_num].skills[type] == 0) {
if(univ.party[pc_num].skill(type) == 0) {
if(type == eSkill::MAGE_SPELLS) add_string_to_buf("Cast: No mage skill.");
else add_string_to_buf("Cast: No priest skill.");
return eSpell::NONE;
@@ -2277,6 +2277,8 @@ void print_spell_cast(eSpell spell,eSkill which) {
short stat_adj(short pc_num,eSkill which) {
short tr;
// This is one place where we use the base skill level instead of the adjusted skill level
// Using the adjusted skill level here would alter the original mechanics of stat-boosting items
tr = skill_bonus[univ.party[pc_num].skills[which]];
if(which == eSkill::INTELLIGENCE) {
if(univ.party[pc_num].traits[eTrait::MAGICALLY_APT])
@@ -2366,16 +2368,16 @@ void do_alchemy() {
play_sound(8);
r1 = get_ran(1,1,100);
if(r1 < fail_chance[univ.party[pc_num].skills[eSkill::ALCHEMY] - alch_difficulty[which_p]]) {
if(r1 < fail_chance[univ.party[pc_num].skill(eSkill::ALCHEMY) - alch_difficulty[which_p]]) {
add_string_to_buf("Alchemy: Failed. ");
r1 = get_ran(1,0,1);
play_sound(41 );
}
else {
cItem store_i(potion);
if(univ.party[pc_num].skills[eSkill::ALCHEMY] - alch_difficulty[which_p] >= 5)
if(univ.party[pc_num].skill(eSkill::ALCHEMY) - alch_difficulty[which_p] >= 5)
store_i.charges++;
if(univ.party[pc_num].skills[eSkill::ALCHEMY] - alch_difficulty[which_p] >= 11)
if(univ.party[pc_num].skill(eSkill::ALCHEMY) - alch_difficulty[which_p] >= 11)
store_i.charges++;
store_i.graphic_num += get_ran(1,0,2);
if(!univ.party[pc_num].give_item(store_i,false)) {
@@ -2420,12 +2422,12 @@ eAlchemy alch_choice(short pc_num) {
std::string n = boost::lexical_cast<std::string>(i + 1);
chooseAlchemy["label" + n].setText(get_str("magic-names", i + 200));
chooseAlchemy["potion" + n].attachClickHandler(alch_choice_event_filter);
if(univ.party[pc_num].skills[eSkill::ALCHEMY] < difficulty[i] || univ.party.alchemy[i] == 0)
if(univ.party[pc_num].skill(eSkill::ALCHEMY) < difficulty[i] || univ.party.alchemy[i] == 0)
chooseAlchemy["potion" + n].hide();
}
std::ostringstream sout;
sout << univ.party[pc_num].name;
sout << " (skill " << univ.party[pc_num].skills[eSkill::ALCHEMY] << ")";
sout << " (skill " << univ.party[pc_num].skill(eSkill::ALCHEMY) << ")";
chooseAlchemy["mixer"].setText(sout.str());
if(univ.party.help_received[20] == 0) {
// TODO: I'm not sure if the initial draw is needed
@@ -2624,7 +2626,7 @@ bool damage_pc(short which_pc,short how_much,eDamageType damage_type,eRace type_
how_much = how_much - univ.party[which_pc].items[i].bonus;
}
r1 = get_ran(1,1,100);
if(r1 < hit_chance[univ.party[which_pc].skills[eSkill::DEFENSE]] - 20)
if(r1 < hit_chance[univ.party[which_pc].skill(eSkill::DEFENSE)] - 20)
how_much -= 1;
}
if(univ.party[which_pc].items[i].protection > 0) {
@@ -2651,7 +2653,7 @@ bool damage_pc(short which_pc,short how_much,eDamageType damage_type,eRace type_
if(univ.party[which_pc].traits[eTrait::TOUGHNESS])
how_much--;
// luck
if(get_ran(1,1,100) < 2 * (hit_chance[univ.party[which_pc].skills[eSkill::LUCK]] - 20))
if(get_ran(1,1,100) < 2 * (hit_chance[univ.party[which_pc].skill(eSkill::LUCK)] - 20))
how_much -= 1;
}
@@ -2772,8 +2774,9 @@ void kill_pc(short which_pc,eMainStatus type) {
if(type != eMainStatus::STONE)
i = univ.party[which_pc].has_abil_equip(eItemAbil::LIFE_SAVING);
if(!no_save && type != eMainStatus::ABSENT && univ.party[which_pc].skills[eSkill::LUCK] > 0 &&
get_ran(1,1,100) < hit_chance[univ.party[which_pc].skills[eSkill::LUCK]]) {
int luck = univ.party[which_pc].skill(eSkill::LUCK);
if(!no_save && type != eMainStatus::ABSENT && luck > 0 &&
get_ran(1,1,100) < hit_chance[luck]) {
add_string_to_buf(" But you luck out! ");
univ.party[which_pc].cur_health = 0;
}

View File

@@ -1073,7 +1073,7 @@ void pick_lock(location where,short pc_num) {
will_break = true;
r1 = get_ran(1,1,100) - 5 * stat_adj(pc_num,eSkill::DEXTERITY) + univ.town.difficulty * 7
- 5 * univ.party[pc_num].skills[eSkill::LOCKPICKING] - univ.party[pc_num].items[which_item].abil_data[0] * 7;
- 5 * univ.party[pc_num].skill(eSkill::LOCKPICKING) - univ.party[pc_num].items[which_item].abil_data[0] * 7;
// Nimble?
if(univ.party[pc_num].traits[eTrait::NIMBLE])

View File

@@ -66,8 +66,8 @@ bool run_trap(short pc_num,eTrapType trap_type,short trap_level,short diff) {
if(pc_num < 6) {
i = stat_adj(pc_num,eSkill::DEXTERITY);
i += univ.party[pc_num].get_prot_level(eItemAbil::THIEVING) / 2;
skill = minmax(0,20,univ.party[pc_num].skills[eSkill::DISARM_TRAPS] +
+ univ.party[pc_num].skills[eSkill::LUCK] / 2 + 1 - univ.town.difficulty + 2 * i);
skill = minmax(0,20,univ.party[pc_num].skill(eSkill::DISARM_TRAPS) +
+ univ.party[pc_num].skill(eSkill::LUCK) / 2 + 1 - univ.town.difficulty + 2 * i);
r1 = get_ran(1,1,100) + diff;
// Nimble?

View File

@@ -186,7 +186,7 @@ bool cPlayer::give_item(cItem item, bool do_print, bool allow_overload) {
}
short cPlayer::max_weight() {
return 100 + (15 * min(skills[eSkill::STRENGTH],20)) + (traits[eTrait::STRENGTH] * 30)
return 100 + (15 * min(skill(eSkill::STRENGTH),20)) + (traits[eTrait::STRENGTH] * 30)
+ (traits[eTrait::BAD_BACK] * -50);
}
@@ -281,6 +281,10 @@ short cPlayer::has_abil(eItemAbil abil,short dat) {
return 24;
}
short cPlayer::skill(eSkill skill) {
return min(20, skills[skill] + get_prot_level(eItemAbil::BOOST_STAT, int(skill)));
}
eBuyStatus cPlayer::ok_to_buy(short cost,cItem item) {
if(item.variety != eItemType::GOLD && item.variety != eItemType::FOOD) {
for(int i = 0; i < 24; i++)

View File

@@ -69,6 +69,7 @@ public:
short get_prot_level(eItemAbil abil, short dat = -1);
short has_abil_equip(eItemAbil abil, short dat = -1);
short has_abil(eItemAbil abil, short dat = -1);
short skill(eSkill skill);
eBuyStatus ok_to_buy(short cost,cItem item);
void append(legacy::pc_record_type old);