From 0a5a9c089d2e2be54fa92c0bbb4a383eae5cf56a Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Wed, 31 Aug 2016 15:55:19 -0400 Subject: [PATCH] Don't hard-code player max inventory size at all use points --- src/boe.actions.cpp | 70 +++++++-------- src/boe.combat.cpp | 178 +++++++++++++++++-------------------- src/boe.combat.hpp | 2 +- src/boe.dlgutil.cpp | 4 +- src/boe.infodlg.cpp | 41 ++++----- src/boe.items.cpp | 8 +- src/boe.monster.cpp | 2 +- src/boe.party.cpp | 83 +++++++++-------- src/boe.party.hpp | 4 +- src/boe.specials.cpp | 30 +++---- src/boe.text.cpp | 2 +- src/boe.town.cpp | 22 ++--- src/classes/party.cpp | 19 ++-- src/classes/pc.cpp | 108 +++++++++++++--------- src/classes/pc.hpp | 1 + src/pcedit/pc.action.cpp | 4 +- src/pcedit/pc.graphics.cpp | 2 +- 17 files changed, 289 insertions(+), 291 deletions(-) diff --git a/src/boe.actions.cpp b/src/boe.actions.cpp index a1af39c3..d9a8c07e 100644 --- a/src/boe.actions.cpp +++ b/src/boe.actions.cpp @@ -1571,14 +1571,13 @@ void initiate_outdoor_combat(short i) { univ.party.out_c[i].exists = false; - for(short m = 0; m < 6; m++) - if(univ.party[m].main_status == eMainStatus::ALIVE) - to_place = univ.party[m].combat_pos; - for(short m = 0; m < 6; m++) - for(short n = 0; n < 24; n++) - if(univ.party[m].main_status != eMainStatus::ALIVE && univ.party[m].items[n].variety != eItemType::NO_ITEM) { - place_item(univ.party[m].items[n],to_place); - univ.party[m].items[n].variety = eItemType::NO_ITEM; + for(cPlayer& pc : univ.party) + if(pc.main_status == eMainStatus::ALIVE) + to_place = pc.combat_pos; + else for(cItem& item : pc.items) + if(item.variety != eItemType::NO_ITEM) { + place_item(item,to_place); + item.variety = eItemType::NO_ITEM; } overall_mode = MODE_COMBAT; @@ -2258,9 +2257,8 @@ void do_rest(long length, int hp_restore, int mp_restore) { // Specials countdowns if((length > 500 || age_before / 500 < univ.party.age / 500) && univ.party.has_abil(eItemAbil::OCCASIONAL_STATUS)) { // TODO: There used to be a "display strings" here; should we hook in a special node call? - for(int i = 0; i < 6; i++) - for(int j = 0; j < 24; j++) { - cItem& item = univ.party[i].items[j]; + for(cPlayer& pc : univ.party) + for(const cItem& item : pc.items) { if(item.ability != eItemAbil::OCCASIONAL_STATUS) continue; if(item.abil_data[1] > 15) continue; if(!item.abil_group()) continue; @@ -2279,27 +2277,27 @@ void do_rest(long length, int hp_restore, int mp_restore) { univ.party.heal(hp_restore); univ.party.restore_sp(mp_restore); // Recuperation and chronic disease disads - for(int i = 0; i < 6; i++) - if(univ.party[i].main_status == eMainStatus::ALIVE) { - if(univ.party[i].traits[eTrait::RECUPERATION] && univ.party[i].cur_health < univ.party[i].max_health) { - univ.party[i].heal(hp_restore / 5); + for(cPlayer& pc : univ.party) + if(pc.main_status == eMainStatus::ALIVE) { + if(pc.traits[eTrait::RECUPERATION] && pc.cur_health < pc.max_health) { + pc.heal(hp_restore / 5); } - if(univ.party[i].traits[eTrait::CHRONIC_DISEASE] && get_ran(1,0,110) == 1) { - univ.party[i].disease(6); + if(pc.traits[eTrait::CHRONIC_DISEASE] && get_ran(1,0,110) == 1) { + pc.disease(6); } - short item = univ.party[i].has_abil_equip(eItemAbil::REGENERATE); - if(item < 24 && univ.party[i].cur_health < univ.party[i].max_health && (overall_mode > MODE_OUTDOORS || get_ran(1,0,10) == 5)){ - int j = get_ran(1,0,univ.party[i].items[item].abil_data[0] / 3); - if(univ.party[i].items[item].abil_data[0] / 3 == 0) + short item = pc.has_abil_equip(eItemAbil::REGENERATE); + if(item < pc.items.size() && pc.cur_health < pc.max_health && (overall_mode > MODE_OUTDOORS || get_ran(1,0,10) == 5)){ + int j = get_ran(1,0,pc.items[item].abil_data[0] / 3); + if(pc.items[item].abil_data[0] / 3 == 0) j = get_ran(1,0,1); if(is_out()) j = j * 4; - univ.party[i].heal(j); + pc.heal(j); } // Bonus SP and HP wear off - if(univ.party[i].cur_sp > univ.party[i].max_sp) - univ.party[i].cur_sp = univ.party[i].max_sp; - if(univ.party[i].cur_health > univ.party[i].max_health) - univ.party[i].cur_health = univ.party[i].max_health; + if(pc.cur_sp > pc.max_sp) + pc.cur_sp = pc.max_sp; + if(pc.cur_health > pc.max_health) + pc.cur_health = pc.max_health; } special_increase_age(length, true); put_pc_screen(); @@ -2377,9 +2375,8 @@ void increase_age() { // Specials countdowns if(univ.party.age % 500 == 0 && univ.party.has_abil(eItemAbil::OCCASIONAL_STATUS)) { // TODO: There used to be a "display strings" here; should we hook in a special node call? - for(int i = 0; i < 6; i++) - for(int j = 0; j < 24; j++) { - cItem& item = univ.party[i].items[j]; + for(cPlayer& pc : univ.party) + for(const cItem& item : pc.items) { if(item.ability != eItemAbil::OCCASIONAL_STATUS) continue; if(item.abil_data[1] > 15) continue; if(!item.abil_group()) continue; @@ -2507,17 +2504,16 @@ void increase_age() { // Blessing, slowed,etc. if(univ.party.age % 4 == 0) - for(short i = 0; i < 6; i++) { - move_to_zero(univ.party[i].status[eStatus::BLESS_CURSE]); - move_to_zero(univ.party[i].status[eStatus::HASTE_SLOW]); - if((item = univ.party[i].has_abil_equip(eItemAbil::REGENERATE)) < 24 - && (univ.party[i].cur_health < univ.party[i].max_health) + for(cPlayer& pc : univ.party) { + move_to_zero(pc.status[eStatus::BLESS_CURSE]); + move_to_zero(pc.status[eStatus::HASTE_SLOW]); + if((item = pc.has_abil_equip(eItemAbil::REGENERATE)) < pc.items.size() && (pc.cur_health < pc.max_health) && ((overall_mode > MODE_OUTDOORS) || (get_ran(1,0,10) == 5))){ - int j = get_ran(1,0,univ.party[i].items[item].abil_data[0] / 3); - if(univ.party[i].items[item].abil_data[0] / 3 == 0) + int j = get_ran(1,0,pc.items[item].abil_data[0] / 3); + if(pc.items[item].abil_data[0] / 3 == 0) j = get_ran(1,0,1); if(is_out()) j = j * 4; - univ.party[i].heal(j); + pc.heal(j); } } diff --git a/src/boe.combat.cpp b/src/boe.combat.cpp index c71c04fe..ad957174 100644 --- a/src/boe.combat.cpp +++ b/src/boe.combat.cpp @@ -512,7 +512,7 @@ void char_stand_ready() { } void pc_attack(short who_att,iLiving* target) { - short r1,r2,weap1 = 24, weap2 = 24,skill_item; + short r1,r2,skill_item; short hit_adj, dam_adj; cPlayer& attacker = univ.party[who_att]; @@ -529,12 +529,8 @@ void pc_attack(short who_att,iLiving* target) { attacker.last_attacked = target; - for(short i = 0; i < 24; i++) - if((attacker.items[i].variety == eItemType::ONE_HANDED || attacker.items[i].variety == eItemType::TWO_HANDED) && attacker.equip[i]) { - if(weap1 == 24) - weap1 = i; - else weap2 = i; - } + auto weapons = attacker.get_weapons(); + auto weap1 = weapons.first, weap2 = weapons.second, no_weap = attacker.items.cend(); hit_adj = (-5 * minmax(-8,8,attacker.status[eStatus::BLESS_CURSE])) + 5 * minmax(-8,8,target->status[eStatus::BLESS_CURSE]) - attacker.stat_adj(eSkill::DEXTERITY) * 5 + (get_encumbrance(who_att)) * 5; @@ -548,11 +544,11 @@ void pc_attack(short who_att,iLiving* target) { } // TODO: These don't stack? - if((skill_item = attacker.has_abil_equip(eItemAbil::SKILL)) < 24) { + if((skill_item = attacker.has_abil_equip(eItemAbil::SKILL)) < attacker.items.size()) { hit_adj += 5 * (attacker.items[skill_item].abil_data[0] / 2 + 1); dam_adj += attacker.items[skill_item].abil_data[0] / 2; } - if((skill_item = attacker.has_abil_equip(eItemAbil::GIANT_STRENGTH)) < 24) { + if((skill_item = attacker.has_abil_equip(eItemAbil::GIANT_STRENGTH)) < attacker.items.size()) { dam_adj += attacker.items[skill_item].abil_data[0]; hit_adj += attacker.items[skill_item].abil_data[0] * 2; } @@ -563,7 +559,7 @@ void pc_attack(short who_att,iLiving* target) { combat_posing_monster = current_working_monster = who_att; - if(weap1 == 24) { + if(weap1 == no_weap) { std::string create_line = univ.party[who_att].name + " punches."; add_string_to_buf(create_line); @@ -605,11 +601,11 @@ void pc_attack(short who_att,iLiving* target) { } } - short weap_poisoned = attacker.weap_poisoned; - if(weap1 < 24) - pc_attack_weapon(who_att, *target, hit_adj, dam_adj, attacker.items[weap1], weap2 < 24 ? 2 : 1, weap_poisoned == weap1); - if(weap2 < 24 && target->is_alive()) - pc_attack_weapon(who_att, *target, hit_adj, dam_adj, attacker.items[weap2], 0, weap_poisoned == weap2); + auto weap_poisoned = attacker.items.begin() + attacker.weap_poisoned; + if(weap1 != no_weap) + pc_attack_weapon(who_att, *target, hit_adj, dam_adj, *weap1, 1 + (weap2 != no_weap), weap_poisoned == weap1); + if(weap2 != no_weap && target->is_alive()) + pc_attack_weapon(who_att, *target, hit_adj, dam_adj, *weap2, 0, weap_poisoned == weap2); move_to_zero(attacker.status[eStatus::POISONED_WEAPON]); take_ap(4); @@ -699,19 +695,19 @@ static void apply_weapon_status(eStatus status, int how_much, int dmg, iLiving& } // primary: 0 - secondary weapon, 1 - primary (and only) weapon, 2 - primary of two weapons -void pc_attack_weapon(short who_att,iLiving& target,short hit_adj,short dam_adj,cItem& weap,short primary,bool do_poison) { +void pc_attack_weapon(short who_att,iLiving& target,short hit_adj,short dam_adj,const cItem& weap,short primary,bool do_poison) { short r1, r2; cPlayer& attacker = univ.party[who_att]; // safety valve int skill; if(weap.weap_type == eSkill::INVALID) - skill = univ.party[who_att].skill(eSkill::EDGED_WEAPONS); + skill = attacker.skill(eSkill::EDGED_WEAPONS); else if(weap.weap_type == eSkill::MAX_HP) - skill = 20 * univ.party[who_att].cur_health / univ.party[who_att].max_health; + skill = 20 * attacker.cur_health / attacker.max_health; else if(weap.weap_type == eSkill::MAX_SP) - skill = 20 * univ.party[who_att].cur_sp / univ.party[who_att].max_sp; - else skill = univ.party[who_att].skill(weap.weap_type); + skill = 20 * attacker.cur_sp / attacker.max_sp; + else skill = attacker.skill(weap.weap_type); std::string create_line = attacker.name + " swings."; add_string_to_buf(create_line); @@ -780,8 +776,8 @@ void pc_attack_weapon(short who_att,iLiving& target,short hit_adj,short dam_adj, splits = who->amorphous; // assassinate r1 = get_ran(1,1,100); - int assassin = univ.party[who_att].skill(eSkill::ASSASSINATION); - if((univ.party[who_att].level >= target.get_level() - 1) && assassin >= target.get_level() / 2 + int assassin = attacker.skill(eSkill::ASSASSINATION); + if((attacker.level >= target.get_level() - 1) && assassin >= target.get_level() / 2 && !splits) // Can't assassinate splitters if(r1 < hit_chance[max(assassin - target.get_level(),0)]) { add_string_to_buf(" You assassinate."); @@ -821,7 +817,7 @@ void pc_attack_weapon(short who_att,iLiving& target,short hit_adj,short dam_adj, if(damaged) monst->damaged_msg(r2, spec_dam + bonus_dam); } else if(cPlayer* who = dynamic_cast(&target)) { - eRace race = univ.party[who_att].race; + eRace race = attacker.race; if(dmg_snd != no_dmg) damaged = damaged || damage_pc(*who, r2, eDamageType::WEAPON, race, dmg_snd, false); if(spec_dam) @@ -837,21 +833,21 @@ void pc_attack_weapon(short who_att,iLiving& target,short hit_adj,short dam_adj, } if(do_poison) { // poison - if(univ.party[who_att].status[eStatus::POISONED_WEAPON] > 0) { - short poison_amt = univ.party[who_att].status[eStatus::POISONED_WEAPON]; - if(univ.party[who_att].has_abil_equip(eItemAbil::POISON_AUGMENT) < 24) + if(attacker.status[eStatus::POISONED_WEAPON] > 0) { + short poison_amt = attacker.status[eStatus::POISONED_WEAPON]; + if(attacker.has_abil_equip(eItemAbil::POISON_AUGMENT) < attacker.items.size()) poison_amt += 2; target.poison(poison_amt); if(dynamic_cast(&target)) put_pc_screen(); - move_to_zero(univ.party[who_att].status[eStatus::POISONED_WEAPON]); + move_to_zero(attacker.status[eStatus::POISONED_WEAPON]); } } if((weap.ability == eItemAbil::STATUS_WEAPON) && (get_ran(1,0,1) == 1)) { apply_weapon_status(eStatus(weap.abil_data[1]), weap.abil_data[0], r2 + spec_dam, target, "Blade"); } else if(weap.ability == eItemAbil::SOULSUCKER && get_ran(1,0,1) == 1) { add_string_to_buf(" Blade drains life."); - univ.party[who_att].heal(weap.abil_data[0] / 2); + attacker.heal(weap.abil_data[0] / 2); } else if(weap.ability == eItemAbil::ANTIMAGIC_WEAPON) { short before = target.get_magic(); int mage = 0, cleric = 0; @@ -863,16 +859,16 @@ void pc_attack_weapon(short who_att,iLiving& target,short hit_adj,short dam_adj, target.drain_sp(weap.abil_data[0]); if(before > target.get_magic()) { add_string_to_buf(" Blade drains energy."); - univ.party[who_att].restore_sp(before / 3); + attacker.restore_sp(before / 3); } } else if(weap.ability == eItemAbil::WEAPON_CALL_SPECIAL) { short s1,s2,s3; univ.party.force_ptr(21, target.get_loc().x); univ.party.force_ptr(22, target.get_loc().y); univ.party.force_ptr(20, i_monst); - run_special(eSpecCtx::ATTACKING_MELEE, 0, weap.abil_data[0],univ.party[who_att].combat_pos, &s1, &s2, &s3); + run_special(eSpecCtx::ATTACKING_MELEE, 0, weap.abil_data[0],attacker.combat_pos, &s1, &s2, &s3); if(s1 > 0) - univ.party[who_att].ap += 4; + attacker.ap += 4; } } else { @@ -1416,7 +1412,7 @@ void do_combat_cast(location target) { add_string_to_buf(" Can't duel: no magic."); else { item = caster.has_abil(eItemAbil::SMOKY_CRYSTAL); - if(item >= 24) + if(item >= caster.items.size()) add_string_to_buf(" You need a smoky crystal. "); else { caster.remove_charge(item); @@ -1854,7 +1850,7 @@ void fire_missile(location target) { // poison if(missile_firer.status[eStatus::POISONED_WEAPON] > 0 && missile_firer.weap_poisoned == ammo_inv_slot) { poison_amt = missile_firer.status[eStatus::POISONED_WEAPON]; - if(missile_firer.has_abil_equip(eItemAbil::POISON_AUGMENT) < 24) + if(missile_firer.has_abil_equip(eItemAbil::POISON_AUGMENT) < missile_firer.items.size()) poison_amt++; victim->poison(poison_amt); if(dynamic_cast(victim)) @@ -1897,7 +1893,7 @@ void fire_missile(location target) { run_special(eSpecCtx::ATTACKED_RANGE, 0, monst->abil[eMonstAbil::HIT_TRIGGER].special.extra1, missile_firer.combat_pos, &s1, &s2, &s3); if(s1 > 0) missile_firer.ap += (overall_mode == MODE_FIRING) ? 3 : 2; - } else if((pc = dynamic_cast(victim)) && (spec_item = pc->has_abil_equip(eItemAbil::HIT_CALL_SPECIAL)) < 24) { + } else if((pc = dynamic_cast(victim)) && (spec_item = pc->has_abil_equip(eItemAbil::HIT_CALL_SPECIAL)) < pc->items.size()) { short s1,s2,s3; univ.party.force_ptr(21, pc->combat_pos.x); univ.party.force_ptr(22, pc->combat_pos.y); @@ -1913,7 +1909,7 @@ void fire_missile(location target) { if(ammo.ability != eItemAbil::RETURNING_MISSILE) ammo.charges--; else ammo.charges = 1; - if(missile_firer.has_abil_equip(eItemAbil::DRAIN_MISSILES) < 24 + if(missile_firer.has_abil_equip(eItemAbil::DRAIN_MISSILES) < missile_firer.items.size() && ammo.ability != eItemAbil::RETURNING_MISSILE) ammo.charges--; if(ammo.charges <= 0) @@ -2083,34 +2079,33 @@ void combat_run_monst() { univ.party.age++; if(univ.party.age % 4 == 0) - for(short i = 0; i < 6; i++) { - if(univ.party[i].status[eStatus::BLESS_CURSE] != 0 || univ.party[i].status[eStatus::HASTE_SLOW] != 0) + for(cPlayer& pc : univ.party) { + if(pc.status[eStatus::BLESS_CURSE] != 0 || pc.status[eStatus::HASTE_SLOW] != 0) update_stat = true; - move_to_zero(univ.party[i].status[eStatus::BLESS_CURSE]); - move_to_zero(univ.party[i].status[eStatus::HASTE_SLOW]); + move_to_zero(pc.status[eStatus::BLESS_CURSE]); + move_to_zero(pc.status[eStatus::HASTE_SLOW]); move_to_zero(univ.party.status[ePartyStatus::STEALTH]); - if((item = univ.party[i].has_abil_equip(eItemAbil::REGENERATE)) < 24) { + if((item = pc.has_abil_equip(eItemAbil::REGENERATE)) < pc.items.size()) { update_stat = true; - univ.party[i].heal(get_ran(1,0,univ.party[i].items[item].item_level + 1)); + pc.heal(get_ran(1,0,pc.items[item].item_level + 1)); } } - for(short i = 0; i < 6; i++) - if(univ.party[i].main_status == eMainStatus::ALIVE) { - if(univ.party[i].status[eStatus::INVULNERABLE] != 0 || univ.party[i].status[eStatus::MAGIC_RESISTANCE] != 0 - || univ.party[i].status[eStatus::INVISIBLE] != 0 || univ.party[i].status[eStatus::MARTYRS_SHIELD] != 0 - || univ.party[i].status[eStatus::ASLEEP] != 0 || univ.party[i].status[eStatus::PARALYZED] != 0) + for(cPlayer& pc : univ.party) + if(pc.main_status == eMainStatus::ALIVE) { + if(pc.status[eStatus::INVULNERABLE] != 0 || pc.status[eStatus::MAGIC_RESISTANCE] != 0 + || pc.status[eStatus::INVISIBLE] != 0 || pc.status[eStatus::MARTYRS_SHIELD] != 0 + || pc.status[eStatus::ASLEEP] != 0 || pc.status[eStatus::PARALYZED] != 0) update_stat = true; - move_to_zero(univ.party[i].status[eStatus::INVULNERABLE]); - move_to_zero(univ.party[i].status[eStatus::MAGIC_RESISTANCE]); - move_to_zero(univ.party[i].status[eStatus::INVISIBLE]); - move_to_zero(univ.party[i].status[eStatus::MARTYRS_SHIELD]); - move_to_zero(univ.party[i].status[eStatus::ASLEEP]); - move_to_zero(univ.party[i].status[eStatus::PARALYZED]); + move_to_zero(pc.status[eStatus::INVULNERABLE]); + move_to_zero(pc.status[eStatus::MAGIC_RESISTANCE]); + move_to_zero(pc.status[eStatus::INVISIBLE]); + move_to_zero(pc.status[eStatus::MARTYRS_SHIELD]); + move_to_zero(pc.status[eStatus::ASLEEP]); + move_to_zero(pc.status[eStatus::PARALYZED]); // Do special items - for(int j = 0; j < 24; j++) { - cItem& item = univ.party[i].items[j]; + for(const cItem& item : pc.items) { if(item.ability != eItemAbil::OCCASIONAL_STATUS) continue; if(item.abil_group()) continue; // Affects whole party, which is handled elsewhere if(get_ran(1,0,10) != 5) continue; @@ -2132,7 +2127,7 @@ void combat_run_monst() { break; case eStatus::POISON: if(how_much > 0) add_string_to_buf("An item poisons you!"); - else if(univ.party[i].status[eStatus::POISON] > 0) + else if(pc.status[eStatus::POISON] > 0) add_string_to_buf("An item cures you!"); break; case eStatus::INVULNERABLE: @@ -2144,55 +2139,49 @@ void combat_run_monst() { break; case eStatus::DISEASE: if(how_much > 0) add_string_to_buf("An item diseases you!"); - else if(univ.party[i].status[eStatus::DISEASE] > 0) + else if(pc.status[eStatus::DISEASE] > 0) add_string_to_buf("An item cures you!"); break; case eStatus::DUMB: if(how_much > 0) add_string_to_buf("An item clouds your mind!"); - else if(univ.party[i].status[eStatus::DUMB] > 0) + else if(pc.status[eStatus::DUMB] > 0) add_string_to_buf("An item clears your mind!"); else add_string_to_buf("An item enlightens you!"); break; case eStatus::WEBS: if(how_much > 0) add_string_to_buf("An item constricts you!"); - else if(univ.party[i].status[eStatus::WEBS] > 0) + else if(pc.status[eStatus::WEBS] > 0) add_string_to_buf("An item cleanses you!"); break; case eStatus::ASLEEP: if(how_much > 0) add_string_to_buf("An item knocks you out!"); - else if(univ.party[i].status[eStatus::ASLEEP] > 0) + else if(pc.status[eStatus::ASLEEP] > 0) add_string_to_buf("An item wakes you!"); else add_string_to_buf("An item makes you restless!"); break; case eStatus::PARALYZED: if(how_much > 0) add_string_to_buf("An item paralyzes you!"); - else if(univ.party[i].status[eStatus::PARALYZED] > 0) + else if(pc.status[eStatus::PARALYZED] > 0) add_string_to_buf("An item restores your movement!"); break; case eStatus::ACID: if(how_much > 0) add_string_to_buf("An item covers you in acid!"); - else if(univ.party[i].status[eStatus::ACID] > 0) + else if(pc.status[eStatus::ACID] > 0) add_string_to_buf("An item neutralizes the acid!"); break; case eStatus::FORCECAGE: if(how_much > 0) add_string_to_buf("An item entraps you!"); - else if(-how_much > univ.party[i].status[eStatus::FORCECAGE]) + else if(-how_much > pc.status[eStatus::FORCECAGE]) add_string_to_buf("An item frees you!"); else add_string_to_buf("An item weakens the barrier!"); break; case eStatus::POISONED_WEAPON: if(how_much > 0) { - if(univ.party[i].status[eStatus::POISONED_WEAPON] <= 0) { + if(pc.status[eStatus::POISONED_WEAPON] <= 0) { // Need to figure out which weapon to apply to. - int weap = 24; - for(int k = 0; k < 24; k++) { - if(is_poisonable_weap(i, k)) { - weap = k; - break; - } - } - if(weap < 24) - univ.party[i].weap_poisoned = weap; + auto weap = std::find_if(pc.items.begin(), pc.items.end(), is_poisonable_weap); + if(weap != pc.items.end()) + pc.weap_poisoned = weap - pc.items.begin(); else continue; add_string_to_buf("An item poisons your weapon!"); } else add_string_to_buf("An item augments your weapon poison!"); @@ -2201,7 +2190,7 @@ void combat_run_monst() { } // Note: Since this is an item you're wearing, it bypasses any resistance you might have to the status effect. // Thus we just call apply_status instead of all the various status-specific calls. - univ.party[i].apply_status(status, how_much); + pc.apply_status(status, how_much); update_stat = true; } } @@ -2977,7 +2966,7 @@ void monster_attack(short who_att,iLiving* target) { } int spec_item; - if(pc_target != nullptr && (spec_item = pc_target->has_abil_equip(eItemAbil::HIT_CALL_SPECIAL)) < 24) { + if(pc_target != nullptr && (spec_item = pc_target->has_abil_equip(eItemAbil::HIT_CALL_SPECIAL)) < pc_target->items.size()) { short s1,s2,s3; univ.party.force_ptr(21, target->get_loc().x); univ.party.force_ptr(22, target->get_loc().y); @@ -3118,7 +3107,7 @@ void monst_fire_missile(short m_num,short bless,std::pair a } if(pc_target != nullptr) { int spec_item = pc_target->has_abil_equip(eItemAbil::HIT_CALL_SPECIAL); - if(spec_item < 24) { + if(spec_item < pc_target->items.size()) { short s1,s2,s3; // TODO: This force_ptr...run_special code is almost duplicated in several places; maybe make a call_attack_spec subroutine! univ.party.force_ptr(21, target->get_loc().x); @@ -3238,7 +3227,7 @@ void monst_basic_abil(short m_num, std::pair abil, iLiving* handle_marked_damage(); break; case eMonstAbil::STUN: - if(pc_target != nullptr && pc_target->has_abil_equip(eItemAbil::LIFE_SAVING) < 24) + if(pc_target != nullptr && pc_target->has_abil_equip(eItemAbil::LIFE_SAVING) < pc_target->items.size()) break; case eMonstAbil::STATUS: case eMonstAbil::STATUS2: switch(abil.second.gen.stat) { @@ -3311,8 +3300,8 @@ void monst_basic_abil(short m_num, std::pair abil, iLiving* case eMonstAbil::DRAIN_XP: if(pc_target != nullptr) { i = univ.get_target_i(*target); - if(pc_target->has_abil_equip(eItemAbil::LIFE_SAVING) < 24) break; - drain_pc(i, univ.town.monst[m_num].level * abil.second.gen.strength / 100); + if(pc_target->has_abil_equip(eItemAbil::LIFE_SAVING) < pc_target->items.size()) break; + drain_pc(*pc_target, univ.town.monst[m_num].level * abil.second.gen.strength / 100); } break; case eMonstAbil::KILL: @@ -4582,45 +4571,42 @@ void do_poison() { void handle_disease() { short r1 = 0; - bool disease = false; - - for(short i = 0; i < 6; i++) - if(univ.party[i].main_status == eMainStatus::ALIVE) - if(univ.party[i].status[eStatus::DISEASE] > 0) - disease = true; + bool disease = std::any_of(univ.party.begin(), univ.party.end(), [](const cPlayer& pc) { + return pc.main_status == eMainStatus::ALIVE && pc.status[eStatus::DISEASE] > 0; + }); if(disease) { add_string_to_buf("Disease:"); - for(short i = 0; i < 6; i++) - if(univ.party[i].main_status == eMainStatus::ALIVE) - if(univ.party[i].status[eStatus::DISEASE] > 0) { + for(cPlayer& pc : univ.party) + if(pc.main_status == eMainStatus::ALIVE) + if(pc.status[eStatus::DISEASE] > 0) { r1 = get_ran(1,1,10); switch(r1) { case 1: case 2: - univ.party[i].poison(2); + pc.poison(2); break; case 3: case 4: - univ.party[i].slow(2); + pc.slow(2); break; case 5: - drain_pc(i,5); + drain_pc(pc,5); break; case 6: case 7: - univ.party[i].curse(3); + pc.curse(3); break; case 8: - univ.party[i].dumbfound(3); + pc.dumbfound(3); adjust_spell_menus(); break; case 9: case 10: - add_string_to_buf(" " + univ.party[i].name + " unaffected."); + add_string_to_buf(" " + pc.name + " unaffected."); break; } r1 = get_ran(1,0,7); - if(univ.party[i].traits[eTrait::GOOD_CONST]) + if(pc.traits[eTrait::GOOD_CONST]) r1 -= 2; - if(r1 <= 0 || univ.party[i].has_abil_equip(eItemAbil::STATUS_PROTECTION,int(eStatus::DISEASE)) < 24) - move_to_zero(univ.party[i].status[eStatus::DISEASE]); + if(r1 <= 0 || pc.has_abil_equip(eItemAbil::STATUS_PROTECTION,int(eStatus::DISEASE)) < pc.items.size()) + move_to_zero(pc.status[eStatus::DISEASE]); } put_pc_screen(); } diff --git a/src/boe.combat.hpp b/src/boe.combat.hpp index b8e0d4b5..a489d7e9 100644 --- a/src/boe.combat.hpp +++ b/src/boe.combat.hpp @@ -13,7 +13,7 @@ bool pc_combat_move(location destination); void char_parry(); void char_stand_ready(); void pc_attack(short who_att,iLiving* target); -void pc_attack_weapon(short who_att,iLiving& target,short hit_adj,short dam_adj,cItem& weap,short primary,bool do_poison); +void pc_attack_weapon(short who_att,iLiving& target,short hit_adj,short dam_adj,const cItem& weap,short primary,bool do_poison); short calc_spec_dam(eItemAbil abil,short abil_str,short abil_dat,iLiving& monst,eDamageType& dmg_type); void place_target(location target); void do_combat_cast(location target); diff --git a/src/boe.dlgutil.cpp b/src/boe.dlgutil.cpp index e3973544..c6f45c20 100644 --- a/src/boe.dlgutil.cpp +++ b/src/boe.dlgutil.cpp @@ -312,7 +312,7 @@ void handle_sale(cShopItem item, int i) { univ.party[current_pc].status[eStatus::PARALYZED] = 0; break; case eShopItemType::REMOVE_CURSE: - for(int i = 0; i < 24; i++) + for(int i = 0; i < univ.party[current_pc].items.size(); i++) if((univ.party[current_pc].equip[i]) && (univ.party[current_pc].items[i].cursed)) univ.party[current_pc].items[i].cursed = univ.party[current_pc].items[i].unsellable = false; @@ -522,7 +522,7 @@ void set_up_shop_array() { shop_array[i++] = j; break; case eShopItemType::REMOVE_CURSE: - for(int i = 0; i < 24; i++) { + for(int i = 0; i < univ.party[current_pc].items.size(); i++) { if((univ.party[current_pc].equip[i]) && (univ.party[current_pc].items[i].cursed)) { shop_array[i++] = j; break; diff --git a/src/boe.infodlg.cpp b/src/boe.infodlg.cpp index b8463235..34c881e7 100644 --- a/src/boe.infodlg.cpp +++ b/src/boe.infodlg.cpp @@ -498,7 +498,7 @@ void display_alchemy() { static void display_pc_info(cDialog& me, const short pc) { std::ostringstream to_draw; - short weap1 = 24,weap2 = 24,hit_adj = 0, dam_adj = 0,skill_item; + short hit_adj = 0, dam_adj = 0,skill_item; to_draw << univ.party[pc].name << " is carrying " << univ.party[pc].cur_weight() << " stones out of " << univ.party[pc].max_weight() << '.'; me["weight"].setText(to_draw.str()); @@ -531,26 +531,21 @@ static void display_pc_info(cDialog& me, const short pc) { else dynamic_cast(me["pic"]).setPict(pic,PIC_PC); // Fight bonuses - for(short i = 0; i < 24; i++) - if((univ.party[pc].items[i].variety == eItemType::ONE_HANDED || univ.party[pc].items[i].variety == eItemType::TWO_HANDED) && - (univ.party[pc].equip[i])) { - if(weap1 == 24) - weap1 = i; - else weap2 = i; - } + decltype(univ.party[pc].items)::const_iterator weap1, weap2, no_weap = univ.party[pc].items.end(); + std::tie(weap1, weap2) = univ.party[pc].get_weapons(); hit_adj = univ.party[pc].stat_adj(eSkill::DEXTERITY) * 5 - (total_encumbrance(pc)) * 5 + 5 * minmax(-8,8,univ.party[pc].status[eStatus::BLESS_CURSE]); - if(!univ.party[pc].traits[eTrait::AMBIDEXTROUS] && weap2 < 24) + if(!univ.party[pc].traits[eTrait::AMBIDEXTROUS] && weap2 != no_weap) hit_adj -= 25; // TODO: Perhaps dam_adj and hit_adj calculation should be moved into a function somewhere? dam_adj = univ.party[pc].stat_adj(eSkill::STRENGTH) + minmax(-8,8,univ.party[pc].status[eStatus::BLESS_CURSE]); - if((skill_item = univ.party[pc].has_abil_equip(eItemAbil::SKILL)) < 24) { + if((skill_item = univ.party[pc].has_abil_equip(eItemAbil::SKILL)) < univ.party[pc].items.size()) { hit_adj += 5 * (univ.party[pc].items[skill_item].abil_data[0] / 2 + 1); dam_adj += univ.party[pc].items[skill_item].abil_data[0] / 2; } - if((skill_item = univ.party[pc].has_abil_equip(eItemAbil::GIANT_STRENGTH)) < 24) { + if((skill_item = univ.party[pc].has_abil_equip(eItemAbil::GIANT_STRENGTH)) < univ.party[pc].items.size()) { dam_adj += univ.party[pc].items[skill_item].abil_data[0]; hit_adj += univ.party[pc].items[skill_item].abil_data[0] * 2; } @@ -559,31 +554,31 @@ static void display_pc_info(cDialog& me, const short pc) { me["weap1b"].setText(""); me["weap2a"].setText("No weapon."); me["weap2b"].setText(""); - if(weap1 < 24) { - if(!univ.party[pc].items[weap1].ident) + if(weap1 != no_weap) { + if(!weap1->ident) me["weap1a"].setText("Not identified."); else { // TODO: What's with always putting the percent sign in front? - if(hit_adj + 5 * univ.party[pc].items[weap1].bonus < 0) - to_draw << "Penalty to hit: %" << hit_adj + 5 * univ.party[pc].items[weap1].bonus; - else to_draw << "Bonus to hit: +%" << hit_adj + 5 * univ.party[pc].items[weap1].bonus; + if(hit_adj + 5 * weap1->bonus < 0) + to_draw << "Penalty to hit: %" << hit_adj + 5 * weap1->bonus; + else to_draw << "Bonus to hit: +%" << hit_adj + 5 * weap1->bonus; me["weap1a"].setText(to_draw.str()); to_draw.str(""); - to_draw << "Damage: (1-" << univ.party[pc].items[weap1].item_level << ") + " << dam_adj + univ.party[pc].items[weap1].bonus; + to_draw << "Damage: (1-" << weap1->item_level << ") + " << dam_adj + weap1->bonus; me["weap1b"].setText(to_draw.str()); to_draw.str(""); } } - if(weap2 < 24) { - if(!univ.party[pc].items[weap2].ident) + if(weap2 != no_weap) { + if(!weap2->ident) me["weap2a"].setText("Not identified."); else { - if(hit_adj + 5 * univ.party[pc].items[weap2].bonus < 0) - to_draw << "Penalty to hit: %" << hit_adj + 5 * univ.party[pc].items[weap2].bonus; - else to_draw << "Bonus to hit: +%" << hit_adj + 5 * univ.party[pc].items[weap2].bonus; + if(hit_adj + 5 * weap2->bonus < 0) + to_draw << "Penalty to hit: %" << hit_adj + 5 * weap2->bonus; + else to_draw << "Bonus to hit: +%" << hit_adj + 5 * weap2->bonus; me["weap2a"].setText(to_draw.str()); to_draw.str(""); - to_draw << "Damage: (1-" << univ.party[pc].items[weap2].item_level << ") + " << dam_adj + univ.party[pc].items[weap2].bonus; + to_draw << "Damage: (1-" << weap2->item_level << ") + " << dam_adj + weap2->bonus; me["weap2b"].setText(to_draw.str()); to_draw.str(""); } diff --git a/src/boe.items.cpp b/src/boe.items.cpp index 5b3e1066..9071e208 100644 --- a/src/boe.items.cpp +++ b/src/boe.items.cpp @@ -221,7 +221,7 @@ void give_thing(short pc_num, short item_num) { univ.party[pc_num].take_item(item_num); } else { - if(univ.party[who_to].has_space() == 24) + if(univ.party[who_to].has_space() == univ.party[who_to].items.size()) ASB("Can't give: PC has max. # of items."); else ASB("Can't give: PC carrying too much."); if(how_many > 0) @@ -364,7 +364,7 @@ static void put_item_graphics(cDialog& me, size_t& first_item_shown, short& curr // First make sure all arrays for who can get stuff are in order. if(current_getting_pc < 6 && (univ.party[current_getting_pc].main_status != eMainStatus::ALIVE - || univ.party[current_getting_pc].has_space() == 24)) { + || univ.party[current_getting_pc].has_space() == univ.party[current_getting_pc].items.size())) { current_getting_pc = 6; } @@ -373,7 +373,7 @@ static void put_item_graphics(cDialog& me, size_t& first_item_shown, short& curr std::ostringstream sout; sout << "pc" << i + 1; std::string id = sout.str(); - if(univ.party[i].main_status == eMainStatus::ALIVE && univ.party[i].has_space() < 24 + if(univ.party[i].main_status == eMainStatus::ALIVE && univ.party[i].has_space() < univ.party[i].items.size() && ((!is_combat()) || (current_pc == i))) { if(current_getting_pc == 6) current_getting_pc = i; @@ -912,7 +912,7 @@ short char_select_pc(short mode,const char *title) { can_pick = false; else switch(mode) { case 3: - if(univ.party[i].has_space() == 24) + if(univ.party[i].has_space() == univ.party[i].items.size()) can_pick = false; case 0: if(univ.party[i].main_status != eMainStatus::ALIVE) diff --git a/src/boe.monster.cpp b/src/boe.monster.cpp index c745d71c..76c0573a 100644 --- a/src/boe.monster.cpp +++ b/src/boe.monster.cpp @@ -1192,7 +1192,7 @@ short get_encumbrance(short pc_num) { what_val = univ.party[pc_num].free_weight(); if(what_val < 0) store += what_val / -10; - for(short i = 0; i < 24; i++) + for(short i = 0; i < univ.party[pc_num].items.size(); i++) if(univ.party[pc_num].equip[i]) { what_val = univ.party[pc_num].items[i].awkward; if(univ.party[pc_num].items[i].ability == eItemAbil::ENCUMBERING) diff --git a/src/boe.party.cpp b/src/boe.party.cpp index 85eaf612..eb2385c5 100644 --- a/src/boe.party.cpp +++ b/src/boe.party.cpp @@ -348,10 +348,10 @@ void award_xp(short pc_num,short amt,bool force) { } } -void drain_pc(short which_pc,short how_much) { - if(univ.party[which_pc].main_status == eMainStatus::ALIVE) { - univ.party[which_pc].experience = max(univ.party[which_pc].experience - how_much,0); - add_string_to_buf(" " + univ.party[which_pc].name + " drained."); +void drain_pc(cPlayer& which_pc,short how_much) { + if(which_pc.main_status == eMainStatus::ALIVE) { + which_pc.experience = max(which_pc.experience - how_much,0); + add_string_to_buf(" " + which_pc.name + " drained."); } } @@ -401,22 +401,21 @@ short check_party_stat(eSkill which_stat, short mode) { } bool poison_weapon(short pc_num, short how_much,bool safe) { - short weap = 24,p_level,r1; + short p_level,r1; short p_chance[21] = { 40,72,81,85,88,89,90, 91,92,93,94,94,95,95,96,97,98,100,100,100,100}; // TODO: This doesn't allow you to choose between poisoning a melee weapon and poisoning arrows, except by temporarily dequipping one - for(short i = 0; i < 24; i++) - if((univ.party[pc_num].equip[i]) && (is_poisonable_weap(pc_num,i))) { - weap = i; - i = 30; + auto weap = univ.party[pc_num].items.begin(); + do { + weap = std::find_if(weap, univ.party[pc_num].items.end(), is_poisonable_weap); + + if(!univ.party[pc_num].equip[weap - univ.party[pc_num].items.begin()]) { + weap++; + continue; } - if(weap == 24) { - add_string_to_buf(" No weapon equipped."); - return false; - } - else { + p_level = how_much; add_string_to_buf(" You poison your weapon."); r1 = get_ran(1,1,100); @@ -434,18 +433,19 @@ bool poison_weapon(short pc_num, short how_much,bool safe) { } if(!safe) play_sound(55); - univ.party[pc_num].weap_poisoned = weap; + univ.party[pc_num].weap_poisoned = weap - univ.party[pc_num].items.end(); univ.party[pc_num].status[eStatus::POISONED_WEAPON] = max(univ.party[pc_num].status[eStatus::POISONED_WEAPON], p_level); return true; - } + } while(weap != univ.party[pc_num].items.end()); + + add_string_to_buf(" No weapon equipped."); + return false; } -bool is_poisonable_weap(short pc_num,short item) { - if((univ.party[pc_num].items[item].variety == eItemType::ONE_HANDED) || - (univ.party[pc_num].items[item].variety == eItemType::TWO_HANDED) || - (univ.party[pc_num].items[item].variety == eItemType::ARROW) || - (univ.party[pc_num].items[item].variety == eItemType::BOLTS)) +bool is_poisonable_weap(cItem& weap) { + if(weap.variety == eItemType::ONE_HANDED || weap.variety == eItemType::TWO_HANDED || + weap.variety == eItemType::ARROW || weap.variety == eItemType::BOLTS) return true; else return false; @@ -587,9 +587,9 @@ void do_mage_spell(short pc_num,eSpell spell_num,bool freebie) { if(!freebie) univ.party[pc_num].cur_sp -= (*spell_num).cost; ASB("All of your items are identified."); - for(short i = 0; i < 6; i++) - for(short j = 0; j < 24; j++) - univ.party[i].items[j].ident = true; + for(cPlayer& pc : univ.party) + for(cItem& item : pc.items) + item.ident = true; break; case eSpell::TRUE_SIGHT: @@ -683,7 +683,7 @@ void do_mage_spell(short pc_num,eSpell spell_num,bool freebie) { case eSpell::MAGIC_MAP: item = univ.party[pc_num].has_abil(eItemAbil::SAPPHIRE); - if(item == 24 && !freebie) + if(item == univ.party[pc_num].items.size() && !freebie) add_string_to_buf(" You need a sapphire."); else if(univ.town->defy_scrying || univ.town->defy_mapping) add_string_to_buf(" The spell fails."); @@ -1051,11 +1051,11 @@ void do_priest_spell(short pc_num,eSpell spell_num,bool freebie) { } else sout << " wasn't stoned."; } else if(spell_num == eSpell::CURSE_REMOVE) { - for(int i = 0; i < 24; i++) - if(univ.party[target].items[i].cursed){ + for(cItem& item : univ.party[target].items) + if(item.cursed){ r1 = get_ran(1,0,200) - 10 * adj; if(r1 < 60) { - univ.party[target].items[i].cursed = univ.party[target].items[i].unsellable = false; + item.cursed = item.unsellable = false; } } play_sound(52); @@ -1063,7 +1063,7 @@ void do_priest_spell(short pc_num,eSpell spell_num,bool freebie) { } else { if(!univ.scenario.is_legacy) { - if((item = univ.party[pc_num].has_abil(eItemAbil::RESURRECTION_BALM)) == 24) { + if((item = univ.party[pc_num].has_abil(eItemAbil::RESURRECTION_BALM)) == univ.party[pc_num].items.size()) { add_string_to_buf(" Need resurrection balm."); break; } @@ -2054,18 +2054,18 @@ void do_alchemy() { // TODO: Remove need for this cast by changing the above data to either std::maps or an unary operator* int which_p = int(potion); if(potion != eAlchemy::NONE) { - if(univ.party[pc_num].has_space() == 24) { + if(univ.party[pc_num].has_space() == univ.party[pc_num].items.size()) { add_string_to_buf("Alchemy: Can't carry another item."); return; } - if((which_item = univ.party[pc_num].has_abil(alch_ingred1[which_p])) == 24) { + if((which_item = univ.party[pc_num].has_abil(alch_ingred1[which_p])) == univ.party[pc_num].items.size()) { add_string_to_buf("Alchemy: Don't have ingredients."); return; } if(alch_ingred2[which_p] != eItemAbil::NONE) { - if(univ.party[pc_num].has_abil(alch_ingred2[which_p]) == 24) { + if(univ.party[pc_num].has_abil(alch_ingred2[which_p]) == univ.party[pc_num].items.size()) { add_string_to_buf("Alchemy: Don't have ingredients."); return; } @@ -2268,7 +2268,7 @@ bool damage_pc(cPlayer& which_pc,short how_much,eDamageType damage_type,eRace ty // armor if(damage_type == eDamageType::WEAPON || damage_type == eDamageType::UNDEAD || damage_type == eDamageType::DEMON) { how_much -= minmax(-5,5,which_pc.status[eStatus::BLESS_CURSE]); - for(short i = 0; i < 24; i++) { + for(short i = 0; i < which_pc.items.size(); i++) { if((which_pc.items[i].variety != eItemType::NO_ITEM) && (which_pc.equip[i])) { if(isArmourType(which_pc.items[i].variety)) { r1 = get_ran(1,1,which_pc.items[i].item_level); @@ -2427,7 +2427,7 @@ void petrify_pc(cPlayer& which_pc,int strength) { r1 += which_pc.status[eStatus::BLESS_CURSE]; r1 -= strength; - if(which_pc.has_abil_equip(eItemAbil::PROTECT_FROM_PETRIFY) < 24) + if(which_pc.has_abil_equip(eItemAbil::PROTECT_FROM_PETRIFY) < which_pc.items.size()) r1 = 20; if(r1 > 14) { @@ -2440,7 +2440,7 @@ void petrify_pc(cPlayer& which_pc,int strength) { } void kill_pc(cPlayer& which_pc,eMainStatus type) { - short i_weap = 24; + short i_weap = which_pc.items.size(); bool dummy,no_save = false; location item_loc; @@ -2457,12 +2457,11 @@ void kill_pc(cPlayer& which_pc,eMainStatus type) { get_ran(1,1,100) < hit_chance[luck]) { add_string_to_buf(" But you luck out!"); which_pc.cur_health = 0; - } - else if(i_weap == 24 || type == eMainStatus::ABSENT) { + } else if(i_weap == which_pc.items.size() || type == eMainStatus::ABSENT) { if(combat_active_pc < 6 && &which_pc == &univ.party[combat_active_pc]) combat_active_pc = 6; - for(short i = 0; i < 24; i++) + for(short i = 0; i < which_pc.items.size(); i++) which_pc.equip[i] = false; item_loc = (overall_mode >= MODE_COMBAT) ? which_pc.combat_pos : univ.party.town_loc; @@ -2493,10 +2492,10 @@ void kill_pc(cPlayer& which_pc,eMainStatus type) { } if(overall_mode != MODE_OUTDOORS) - for(short i = 0; i < 24; i++) - if(which_pc.items[i].variety != eItemType::NO_ITEM) { - dummy = place_item(which_pc.items[i],item_loc); - which_pc.items[i].variety = eItemType::NO_ITEM; + for(cItem& item : which_pc.items) + if(item.variety != eItemType::NO_ITEM) { + dummy = place_item(item,item_loc); + item.variety = eItemType::NO_ITEM; } if(type == eMainStatus::DEAD || type == eMainStatus::DUST) play_sound(21); diff --git a/src/boe.party.hpp b/src/boe.party.hpp index b84a9b90..e2f528aa 100644 --- a/src/boe.party.hpp +++ b/src/boe.party.hpp @@ -11,10 +11,10 @@ bool take_sp(short pc_num,short amt); void increase_light(short amt); void award_party_xp(short amt); void award_xp(short pc_num,short amt,bool force = false); -void drain_pc(short which_pc,short how_much); +void drain_pc(cPlayer& who,short how_much); // TODO: Move to a member function short check_party_stat(eSkill which_stat, short mode); bool poison_weapon( short pc_num, short how_much,bool safe); -bool is_poisonable_weap(short pc_num,short item); +bool is_poisonable_weap(class cItem& weap); void cast_spell(eSkill type); bool repeat_cast_ok(eSkill type); void give_party_spell(short which); diff --git a/src/boe.specials.cpp b/src/boe.specials.cpp index fe3e1df6..0cca444f 100644 --- a/src/boe.specials.cpp +++ b/src/boe.specials.cpp @@ -890,7 +890,7 @@ void use_item(short pc,short item) { break; case eItemUse::HARM_ONE: ASB(" You feel terrible."); - drain_pc(pc,str * 5); + drain_pc(univ.party[pc],str * 5); damage_pc(univ.party[pc],20 * str,eDamageType::UNBLOCKABLE,eRace::HUMAN,0); univ.party[pc].disease(2 * str); univ.party[pc].dumbfound(2 * str); @@ -903,7 +903,7 @@ void use_item(short pc,short item) { case eItemUse::HARM_ALL: ASB(" You all feel terrible."); for(short i = 0; i < 6; i++) { - drain_pc(i,str * 5); + drain_pc(univ.party[i],str * 5); damage_pc(univ.party[i],20 * str,eDamageType::UNBLOCKABLE,eRace::HUMAN,0); univ.party[i].disease(2 * str); univ.party[i].dumbfound(2 * str); @@ -921,7 +921,7 @@ void use_item(short pc,short item) { break; case eItemUse::HARM_ONE: ASB(" You feel forgetful."); - drain_pc(pc,str * 5); + drain_pc(univ.party[pc],str * 5); break; case eItemUse::HELP_ALL: ASB(" You all feel much smarter."); @@ -930,7 +930,7 @@ void use_item(short pc,short item) { case eItemUse::HARM_ALL: ASB(" You all feel forgetful."); for(short i = 0; i < 6; i++) - drain_pc(i,str * 5); + drain_pc(univ.party[i],str * 5); break; } break; @@ -2754,7 +2754,7 @@ void affect_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type, can_pick = false; else if(spec.ex1a == 3 && univ.party[pc].main_status == eMainStatus::ALIVE) can_pick = false; - else if(spec.ex1a == 4 && univ.party[pc].has_space() == 24) + else if(spec.ex1a == 4 && univ.party[pc].has_space() == univ.party[pc].items.size()) can_pick = false; } else if(pc >= 100 && pc < univ.town.monst.size() + 100) { short monst = pc - 100; @@ -2791,7 +2791,7 @@ void affect_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type, can_pick = false; else if(spec.ex1a == 3 && found->main_status == eMainStatus::ALIVE) can_pick = false; - else if(spec.ex1a == 4 && found->has_space() == 24) + else if(spec.ex1a == 4 && found->has_space() == found->items.size()) can_pick = false; } if(can_pick) @@ -2817,7 +2817,7 @@ void affect_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type, can_pick = false; else if(spec.ex1a == 3 && univ.party[i].main_status == eMainStatus::ALIVE) can_pick = false; - else if(spec.ex1a == 4 && univ.party[i].has_space() == 24) + else if(spec.ex1a == 4 && univ.party[i].has_space() == univ.party[i].items.size()) can_pick = false; tries++; } @@ -2866,7 +2866,7 @@ void affect_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type, if(spec.ex1a < 0) univ.party[i].experience = univ.party[i].level * univ.party[i].get_tnl(); else if(spec.ex1b == 0) award_xp(i,spec.ex1a,true); - else drain_pc(i,spec.ex1a); + else drain_pc(univ.party[i],spec.ex1a); } break; case eSpecType::AFFECT_SKILL_PTS: @@ -3406,16 +3406,16 @@ void ifthen_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type, *next_spec = spec.ex1b; break; case eSpecType::IF_EQUIP_ITEM_CLASS: - for(short i = 0; i < 6; i++) - if(univ.party[i].main_status == eMainStatus::ALIVE) - for(short j = 0; j < 24; j++) - if(univ.party[i].items[j].variety != eItemType::NO_ITEM && univ.party[i].items[j].special_class == (unsigned)spec.ex1a - && univ.party[i].equip[j]) { + for(cPlayer& pc : univ.party) + if(pc.main_status == eMainStatus::ALIVE) + for(short j = 0; j < pc.items.size(); j++) + if(pc.items[j].variety != eItemType::NO_ITEM && pc.items[j].special_class == (unsigned)spec.ex1a + && pc.equip[j]) { *next_spec = spec.ex1b; if(spec.ex2a > 0) { *redraw = 1; - univ.party[i].take_item(j); - if(i == stat_window) + pc.take_item(j); + if(&pc == &univ.party[stat_window]) put_item_screen(stat_window); } } diff --git a/src/boe.text.cpp b/src/boe.text.cpp index de033ebc..6112beaf 100644 --- a/src/boe.text.cpp +++ b/src/boe.text.cpp @@ -628,7 +628,7 @@ void refresh_stat_areas(short mode) { short total_encumbrance(short pc_num) { short store = 0,what_val; - for(short i = 0; i < 24; i++) + for(short i = 0; i < univ.party[pc_num].items.size(); i++) if(univ.party[pc_num].equip[i]) { what_val = univ.party[pc_num].items[i].awkward; store += what_val; diff --git a/src/boe.town.cpp b/src/boe.town.cpp index 630d7336..5e1db0b2 100644 --- a/src/boe.town.cpp +++ b/src/boe.town.cpp @@ -476,13 +476,13 @@ void start_town_mode(short which_town, short entry_dir) { update_explored(univ.party.town_loc); // If a PC dead, drop his items - for(short m = 0; m < 6; m++) { - if(univ.party[m].main_status == eMainStatus::ALIVE || isSplit(univ.party[m].main_status)) + for(cPlayer& pc : univ.party) { + if(pc.main_status == eMainStatus::ALIVE || isSplit(pc.main_status)) continue; - for(short n = 0; n < 24; n++) - if(univ.party[m].items[n].variety != eItemType::NO_ITEM) { - place_item(univ.party[m].items[n],univ.party.town_loc); - univ.party[m].items[n].variety = eItemType::NO_ITEM; + for(cItem& item : pc.items) + if(item.variety != eItemType::NO_ITEM) { + place_item(item,univ.party.town_loc); + item.variety = eItemType::NO_ITEM; } } @@ -659,9 +659,9 @@ void handle_leave_town_specials(short /*town_number*/, short which_spec,location } bool abil_exists(eItemAbil abil) { // use when outdoors - for(short i = 0; i < 6; i++) - for(short j = 0; j < 24; j++) - if(univ.party[i].items[j].variety != eItemType::NO_ITEM && univ.party[i].items[j].ability == abil) + for(const cPlayer& pc : univ.party) + for(const cItem& item : pc.items) + if(item.variety != eItemType::NO_ITEM && item.ability == abil) return true; for(short i = 0; i < 3; i++) for(short j = 0; j < univ.town.items.size(); j++) @@ -1149,7 +1149,7 @@ void pick_lock(location where,short pc_num) { terrain = univ.town->terrain(where.x,where.y); which_item = univ.party[pc_num].has_abil_equip(eItemAbil::LOCKPICKS); - if(which_item == 24) { + if(which_item == univ.party[pc_num].items.size()) { add_string_to_buf(" Need lockpick equipped."); return; } @@ -1166,7 +1166,7 @@ void pick_lock(location where,short pc_num) { if(univ.party[pc_num].traits[eTrait::NIMBLE]) r1 -= 8; - if(univ.party[pc_num].has_abil_equip(eItemAbil::THIEVING) < 24) + if(univ.party[pc_num].has_abil_equip(eItemAbil::THIEVING) < univ.party[pc_num].items.size()) r1 = r1 - 12; if(univ.scenario.ter_types[terrain].special != eTerSpec::UNLOCKABLE) { diff --git a/src/classes/party.cpp b/src/classes/party.cpp index e1b5c37a..89df1dcc 100644 --- a/src/classes/party.cpp +++ b/src/classes/party.cpp @@ -458,22 +458,23 @@ bool cParty::forced_give(cItem item,eItemAbil abil,short dat) { item.abil_data[0] = dat / 1000; item.abil_data[1] = dat % 1000; } - for(int i = 0; i < 6; i++) - for(int j = 0; j < 24; j++) - if(adven[i]->main_status == eMainStatus::ALIVE && adven[i]->items[j].variety == eItemType::NO_ITEM) { - adven[i]->items[j] = item; + // TODO: It's strange to check main_status in the inner loop here rather than the outer loop + for(cPlayer& pc : *this) + for(cItem& slot : pc.items) + if(pc.main_status == eMainStatus::ALIVE && slot.variety == eItemType::NO_ITEM) { + slot = item; if(print_result) { std::ostringstream announce; - announce << " " << adven[i]->name << " gets "; + announce << " " << pc.name << " gets "; if(!item.ident) announce << item.name; else announce << item.full_name; announce << '.'; print_result(announce.str()); } - adven[i]->combine_things(); - adven[i]->sort_items(); + pc.combine_things(); + pc.sort_items(); return true; } return false; @@ -482,7 +483,7 @@ bool cParty::forced_give(cItem item,eItemAbil abil,short dat) { bool cParty::has_abil(eItemAbil abil, short dat) { for(int i = 0; i < 6; i++) if(adven[i]->main_status == eMainStatus::ALIVE) - if(adven[i]->has_abil(abil,dat) < 24) + if(adven[i]->has_abil(abil,dat) < adven[i]->items.size()) return true; return false; } @@ -491,7 +492,7 @@ bool cParty::take_abil(eItemAbil abil, short dat) { short item; for(int i = 0; i < 6; i++) if(adven[i]->main_status == eMainStatus::ALIVE) - if((item = adven[i]->has_abil(abil,dat)) < 24) { + if((item = adven[i]->has_abil(abil,dat)) < adven[i]->items.size()) { if(adven[i]->items[item].charges > 1) adven[i]->items[item].charges--; else adven[i]->take_item(item); diff --git a/src/classes/pc.cpp b/src/classes/pc.cpp index 72d147d6..36a52619 100644 --- a/src/classes/pc.cpp +++ b/src/classes/pc.cpp @@ -159,7 +159,7 @@ void cPlayer::curse(int how_much) { void cPlayer::dumbfound(int how_much) { if(!is_alive()) return; short r1 = get_ran(1,0,90); - if(has_abil_equip(eItemAbil::WILL) < 24) { + if(has_abil_equip(eItemAbil::WILL) < items.size()) { if(print_result) print_result(" Ring of Will glows."); r1 -= 10; @@ -285,7 +285,7 @@ void cPlayer::web(int how_much) { void cPlayer::acid(int how_much) { if(!is_alive()) return; - if(has_abil_equip(eItemAbil::STATUS_PROTECTION,int(eStatus::ACID)) < 24) { + if(has_abil_equip(eItemAbil::STATUS_PROTECTION,int(eStatus::ACID)) < items.size()) { if(print_result) print_result(" " + name + " resists acid."); return; @@ -340,7 +340,7 @@ short cPlayer::stat_adj(eSkill which) const { tr -= 2; } // TODO: Use ability strength? - if(has_abil_equip(eItemAbil::BOOST_STAT,int(which)) < 24) + if(has_abil_equip(eItemAbil::BOOST_STAT,int(which)) < items.size()) tr++; return tr; } @@ -479,7 +479,7 @@ bool cPlayer::give_item(cItem item, int flags) { return false; } free_space = has_space(); - if(free_space == 24 || main_status != eMainStatus::ALIVE) + if(free_space == items.size() || main_status != eMainStatus::ALIVE) return false; else { item.property = false; @@ -503,8 +503,8 @@ bool cPlayer::give_item(cItem item, int flags) { if(num_hands_to_use.count(item.variety)) exclude = 100; else exclude = excluding_types[item.variety]; - int rem1 = 24, rem2 = 24; - for(int i = 0; i < 24; i++) { + int rem1 = items.size(), rem2 = items.size(); + for(int i = 0; i < items.size(); i++) { if(i == free_space) continue; if(!equip[i]) continue; int check_exclude = 0; @@ -515,20 +515,20 @@ bool cPlayer::give_item(cItem item, int flags) { if(exclude == 0 && item.variety != items[i].variety) continue; if(exclude == 100) { - if(rem1 == 24) { - if(item.variety == eItemType::ONE_HANDED || item.variety == eItemType::TWO_HANDED || rem2 < 24) + if(rem1 == items.size()) { + if(item.variety == eItemType::ONE_HANDED || item.variety == eItemType::TWO_HANDED || rem2 < items.size()) rem1 = i; - if(rem1 < 24) continue; + if(rem1 < items.size()) continue; } - if(rem2 == 24) { - if(item.variety == eItemType::SHIELD || item.variety == eItemType::SHIELD_2 || rem1 < 24) + if(rem2 == items.size()) { + if(item.variety == eItemType::SHIELD || item.variety == eItemType::SHIELD_2 || rem1 < items.size()) rem2 = i; } - } else if(rem1 < 24) + } else if(rem1 < items.size()) rem1 = i; } - bool can_rem1 = rem1 < 24 && (!items[rem1].cursed || equip_type == GIVE_EQUIP_FORCE); - bool can_rem2 = rem2 < 24 && (!items[rem2].cursed || equip_type == GIVE_EQUIP_FORCE); + bool can_rem1 = rem1 < items.size() && (!items[rem1].cursed || equip_type == GIVE_EQUIP_FORCE); + bool can_rem2 = rem2 < items.size() && (!items[rem2].cursed || equip_type == GIVE_EQUIP_FORCE); if(exclude == 100) { if(item.variety == eItemType::TWO_HANDED) { if(can_rem1) equip[rem1] = false; @@ -564,7 +564,7 @@ bool cPlayer::equip_item(int which_item, bool do_print) { return false; } unsigned short num_this_type = 0, hands_occupied = 0; - for(int i = 0; i < 24; i++) + for(int i = 0; i < items.size(); i++) if(equip[i]) { if(items[i].variety == items[which_item].variety) num_this_type++; @@ -575,7 +575,7 @@ bool cPlayer::equip_item(int which_item, bool do_print) { short equip_item_type = excluding_types[items[which_item].variety]; // Now if missile is already equipped, no more missiles if(equip_item_type > 0) { - for(int i = 0; i < 24; i++) + for(int i = 0; i < items.size(); i++) if(equip[i] && excluding_types[items[i].variety] == equip_item_type) { if(do_print && print_result) { print_result("Equip: You have something of this type"); @@ -623,6 +623,32 @@ bool cPlayer::unequip_item(int which_item, bool do_print) { return true; } +auto cPlayer::get_weapons() -> std::pair { + using iter_t = decltype(items)::const_iterator; + iter_t beg = items.begin(), end = items.end(); + std::pair result = {beg, beg}; + auto is_weapon = [](const cItem& item) { + return item.variety == eItemType::ONE_HANDED || item.variety == eItemType::TWO_HANDED; + }; + auto is_equipped = [this](iter_t item) { + if(item == items.end()) return true; // Treat a non-existent item as equipped to avoid incrementing an end iterator + return equip[item - items.begin()]; + }; + + do { + result.first = std::find_if(result.first, end, is_weapon); + if(!is_equipped(result.first)) result.first++; + } while(result.first != end); + if(result.first != end && result.first + 1 != end) { + result.second = result.first + 1; + do { + result.second = std::find_if(result.second, end, is_weapon); + if(!is_equipped(result.second)) result.second++; + } while(result.second != end); + } + return result; +} + short cPlayer::max_weight() const { return 100 + (15 * min(skill(eSkill::STRENGTH),20)) + (traits[eTrait::STRENGTH] * 30) + (traits[eTrait::BAD_BACK] * -50) + (race == eRace::VAHNATAI) * -25; @@ -632,7 +658,7 @@ short cPlayer::cur_weight() const { short weight = 0; bool airy = false,heavy = false; - for(int i = 0; i < 24; i++) + for(int i = 0; i < items.size(); i++) if(items[i].variety != eItemType::NO_ITEM) { weight += items[i].item_weight(); if(items[i].ability == eItemAbil::LIGHTER_OBJECT) @@ -654,17 +680,17 @@ short cPlayer::free_weight() const { } short cPlayer::has_space() const { - for(int i = 0; i < 24; i++) { + for(int i = 0; i < items.size(); i++) { if(items[i].variety == eItemType::NO_ITEM) return i; } - return 24; + return items.size(); } void cPlayer::combine_things() { - for(int i = 0; i < 24; i++) { + for(int i = 0; i < items.size(); i++) { if(items[i].variety != eItemType::NO_ITEM && items[i].type_flag > 0 && items[i].ident) { - for(int j = i + 1; j < 24; j++) + for(int j = i + 1; j < items.size(); j++) if(items[j].variety != eItemType::NO_ITEM && items[j].type_flag == items[i].type_flag && items[j].ident) { if(print_result) print_result("(items combined)"); short test = items[i].charges + items[j].charges; @@ -687,7 +713,7 @@ void cPlayer::combine_things() { short cPlayer::get_prot_level(eItemAbil abil, short dat) const { int sum = 0; - for(int i = 0; i < 24; i++) { + for(int i = 0; i < items.size(); i++) { if(items[i].variety == eItemType::NO_ITEM) continue; if(items[i].ability != abil) continue; if(!equip[i]) continue; @@ -699,24 +725,24 @@ short cPlayer::get_prot_level(eItemAbil abil, short dat) const { } short cPlayer::has_abil_equip(eItemAbil abil,short dat) const { - for(short i = 0; i < 24; i++) { + for(short i = 0; i < items.size(); i++) { if(items[i].variety == eItemType::NO_ITEM) continue; if(items[i].ability != abil) continue; if(!equip[i]) continue; if(dat >= 0 && dat != items[i].abil_data[1]) continue; return i; } - return 24; + return items.size(); } short cPlayer::has_abil(eItemAbil abil,short dat) const { - for(short i = 0; i < 24; i++) { + for(short i = 0; i < items.size(); i++) { if(items[i].variety == eItemType::NO_ITEM) continue; if(items[i].ability != abil) continue; if(dat >= 0 && dat != items[i].abil_data[1]) continue; return i; } - return 24; + return items.size(); } short cPlayer::skill(eSkill skill) const { @@ -737,11 +763,11 @@ eBuyStatus cPlayer::ok_to_buy(short cost,cItem item) const { if(party->quest_status[item.item_level] != eQuestStatus::AVAILABLE) return eBuyStatus::HAVE_LOTS; } else if(item.variety != eItemType::GOLD && item.variety != eItemType::FOOD) { - for(int i = 0; i < 24; i++) + for(int i = 0; i < items.size(); i++) if(items[i].variety != eItemType::NO_ITEM && items[i].type_flag == item.type_flag && items[i].charges > 123) return eBuyStatus::HAVE_LOTS; - if(has_space() == 24) + if(has_space() == items.size()) return eBuyStatus::NO_SPACE; if(item.item_weight() > free_weight()) { return eBuyStatus::TOO_HEAVY; @@ -842,17 +868,15 @@ cPlayer::cPlayer(cParty& party) : party(&party) { experience = 0; skill_pts = 65; level = 1; - for(short i = 0; i < 24; i++) - items[i] = cItem(); - for(short i = 0; i < 24; i++) - equip[i] = false; + std::fill(items.begin(), items.end(), cItem()); + std::fill(equip.begin(), equip.end(), false); for(short i = 0; i < 62; i++) { priest_spells[i] = i < 30; mage_spells[i] = i < 30; } which_graphic = 0; - weap_poisoned = 24; + weap_poisoned = items.size(); race = eRace::HUMAN; direction = DIR_N; @@ -900,16 +924,14 @@ cPlayer::cPlayer(cParty& party,long key,short slot) : cPlayer(party) { experience = 0; skill_pts = 60; level = 1; - for(short i = 0; i < 24; i++) - items[i] = cItem(); - for(short i = 0; i < 24; i++) - equip[i] = false; + std::fill(items.begin(), items.end(), cItem()); + std::fill(equip.begin(), equip.end(), false); priest_spells.set(); mage_spells.set(); which_graphic = slot * 3 + 1; // 1, 4, 7, 10, 13, 16 if(slot == 2) which_graphic++; - weap_poisoned = 24; // was 16, as an E2 relic + weap_poisoned = items.size(); for(short i = 0; i < 10; i++) { eTrait trait = eTrait(i); @@ -992,10 +1014,8 @@ cPlayer::cPlayer(cParty& party,long key,short slot) : cPlayer(party) { skill_pts = 0; level = 1; - for(short i = 0; i < 24; i++) - items[i] = cItem(); - for(short i = 0; i < 24; i++) - equip[i] = false; + std::fill(items.begin(), items.end(), cItem()); + std::fill(equip.begin(), equip.end(), false); cur_sp = pc_sp[slot]; max_sp = pc_sp[slot]; for(short i = 0; i < 62; i++) { @@ -1049,7 +1069,7 @@ void cPlayer::writeTo(std::ostream& file) const { if(status[stat] != 0) file << "STATUS " << i << ' ' << status.at(stat) << '\n'; } - for(int i = 0; i < 24; i++) + for(int i = 0; i < equip.size(); i++) if(equip[i]) file << "EQUIP " << i << '\n'; for(int i = 0; i < 62; i++) @@ -1069,7 +1089,7 @@ void cPlayer::writeTo(std::ostream& file) const { file << "DIRECTION " << direction << '\n'; file << "POISON " << weap_poisoned << '\n'; file << '\f'; - for(int i = 0; i < 24; i++) + for(int i = 0; i < items.size(); i++) if(items[i].variety != eItemType::NO_ITEM){ file << "ITEM " << i << '\n'; items[i].writeTo(file); diff --git a/src/classes/pc.hpp b/src/classes/pc.hpp index e37e0346..1fff0a87 100644 --- a/src/classes/pc.hpp +++ b/src/classes/pc.hpp @@ -98,6 +98,7 @@ public: bool give_item(cItem item, int flags); bool equip_item(int which_item, bool do_print); bool unequip_item(int which_item, bool do_print); + auto get_weapons() -> std::pair; void take_item(int which_item); void remove_charge(int which_item); short has_space() const; diff --git a/src/pcedit/pc.action.cpp b/src/pcedit/pc.action.cpp index 0ef0ed96..aa2eac68 100644 --- a/src/pcedit/pc.action.cpp +++ b/src/pcedit/pc.action.cpp @@ -69,18 +69,18 @@ bool handle_action(sf::Event event) { break; } } - for(short i = 0; i < 24; i++) + for(short i = 0; i < univ.party[current_active_pc].items.size(); i++) { if((the_point.in(item_string_rects[i][1])) && // drop item univ.party[current_active_pc].items[i].variety != eItemType::NO_ITEM) { flash_rect(item_string_rects[i][1]); univ.party[current_active_pc].take_item(i); } - for(short i = 0; i < 24; i++) if((the_point.in(item_string_rects[i][2])) && // identify item univ.party[current_active_pc].items[i].variety != eItemType::NO_ITEM) { flash_rect(item_string_rects[i][2]); univ.party[current_active_pc].items[i].ident = true; } + } return to_return; } diff --git a/src/pcedit/pc.graphics.cpp b/src/pcedit/pc.graphics.cpp index 8694b913..ac592f92 100644 --- a/src/pcedit/pc.graphics.cpp +++ b/src/pcedit/pc.graphics.cpp @@ -329,7 +329,7 @@ void draw_items() { return; // If PC is dead, it has no items } sf::Texture& invenbtn_gworld = *ResMgr::get("invenbtns"); - for(short i = 0; i < 24; i++) // Loop through items and draw each + for(short i = 0; i < univ.party[current_active_pc].items.size(); i++) // Loop through items and draw each if(univ.party[current_active_pc].items[i].variety != eItemType::NO_ITEM) { // i.e. does item exist std::string to_draw = std::to_string(i + 1) + ". "; if(!univ.party[current_active_pc].items[i].ident)