Don't hard-code player max inventory size at all use points

This commit is contained in:
2016-08-31 15:55:19 -04:00
parent 077d188cdd
commit 0a5a9c089d
17 changed files with 289 additions and 291 deletions

View File

@@ -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);
}
}

View File

@@ -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<cPlayer*>(&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<cPlayer*>(&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<cPlayer*>(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<cPlayer*>(victim)) && (spec_item = pc->has_abil_equip(eItemAbil::HIT_CALL_SPECIAL)) < 24) {
} else if((pc = dynamic_cast<cPlayer*>(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<eMonstAbil,uAbility> 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<eMonstAbil,uAbility> 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<eMonstAbil,uAbility> 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();
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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<cPict&>(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("");
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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<decltype(items)::const_iterator, decltype(items)::const_iterator> {
using iter_t = decltype(items)::const_iterator;
iter_t beg = items.begin(), end = items.end();
std::pair<iter_t, iter_t> 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);

View File

@@ -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<decltype(items)::const_iterator, decltype(items)::const_iterator>;
void take_item(int which_item);
void remove_charge(int which_item);
short has_space() const;

View File

@@ -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;
}

View File

@@ -329,7 +329,7 @@ void draw_items() {
return; // If PC is dead, it has no items
}
sf::Texture& invenbtn_gworld = *ResMgr::get<ImageRsrc>("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)