From 07054eb46522fa72cfc6056809f8092fcc267ab1 Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Sun, 1 Feb 2015 15:43:31 -0500 Subject: [PATCH] Move most of the methods affecting specific status effects into the appropriate files Other changes: - PC-on-PC attacks now account for the target's dexterity, evasion items, and parry status - Harmful spells that inflict a status effect now work if targeted on a PC - Turn Undead, Dispel Undead, Ravage Spirit spells, when cast by a PC, now consider the possibility of undead/demon party members, and work if targeted on them - Forcecage is now allowed for monster touch/ray abilities - Items that inflict curses, slowing, or webs now account for items that grant resistance --- src/BoE.xcodeproj/project.pbxproj | 2 + src/boe.combat.cpp | 154 +++++++++++++++----- src/boe.main.cpp | 1 + src/boe.monster.cpp | 135 ------------------ src/boe.party.cpp | 215 ---------------------------- src/boe.specials.cpp | 46 ++++-- src/boe.townspec.cpp | 2 + src/classes/creature.cpp | 134 +++++++++++++++++ src/classes/living.cpp | 5 + src/classes/pc.cpp | 230 ++++++++++++++++++++++++++++++ src/classes/pc.h | 2 + 11 files changed, 529 insertions(+), 397 deletions(-) diff --git a/src/BoE.xcodeproj/project.pbxproj b/src/BoE.xcodeproj/project.pbxproj index 895a6034a..9bf28f6a2 100644 --- a/src/BoE.xcodeproj/project.pbxproj +++ b/src/BoE.xcodeproj/project.pbxproj @@ -61,6 +61,7 @@ 9107074C18F1D18400F7BD7F /* scrollbar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9191460018E63D8E005CF3A4 /* scrollbar.cpp */; }; 9107074D18F1D18400F7BD7F /* scrollbar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9191460018E63D8E005CF3A4 /* scrollbar.cpp */; }; 9107074E18F1D18500F7BD7F /* scrollbar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9191460018E63D8E005CF3A4 /* scrollbar.cpp */; }; + 9117A4111A7EC06700CD6EB4 /* living.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 914698FB1A7362D900F20F5E /* living.cpp */; }; 91222FC11A72366D008413A5 /* spell.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91597A6E1A3BEDC700BE7BF9 /* spell.cpp */; }; 912283C90FD0E16C00B21642 /* undo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 912283C80FD0E16C00B21642 /* undo.cpp */; }; 912286F80FD330E500B21642 /* dlogutil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 910BBADA0FB91D2A001E34EA /* dlogutil.cpp */; }; @@ -1568,6 +1569,7 @@ 91E30F2C1A74819D0057C54A /* fileio_party.cpp in Sources */, 91E30F2F1A7481C50057C54A /* fileio.cpp in Sources */, 91E30F311A748ABA0057C54A /* fileio_scen.cpp in Sources */, + 9117A4111A7EC06700CD6EB4 /* living.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/src/boe.combat.cpp b/src/boe.combat.cpp index d10b7d684..0c61b868e 100644 --- a/src/boe.combat.cpp +++ b/src/boe.combat.cpp @@ -567,6 +567,15 @@ void pc_attack(short who_att,iLiving* target) { r1 += 5 * (univ.party[current_pc].status[eStatus::WEBS] / 3); r2 = get_ran(1,1,4) + dam_adj; + if(cPlayer* pc_target = dynamic_cast(target)) { + // PCs get some additional defensive perks + // These calculations were taken straight from the monster-on-PC attack code + r1 += 5 * pc_target->stat_adj(eSkill::DEXTERITY); + r1 += pc_target->get_prot_level(eItemAbil::EVASION); + if(pc_target->parry < 100) + r1 += 5 * pc_target->parry; + } + if(r1 <= hit_chance[attacker.skill(eSkill::DEXTERITY)]) { size_t i_monst = univ.get_target_i(*target); // TODO: Change to damage_target() @@ -663,12 +672,19 @@ static void apply_weapon_status(eStatus status, int how_much, int dmg, iLiving& case eStatus::FORCECAGE: add_string_to_buf(" " + weap_type + " emits a green flash."); which_m.sleep(eStatus::FORCECAGE, 0, dmg - how_much / 2); + if(which_m.status[eStatus::FORCECAGE] > 0) + univ.town.set_force_cage(which_m.get_loc().x, which_m.get_loc().y, true); break; case eStatus::MARTYRS_SHIELD: add_string_to_buf(" " + weap_type + " leaks an odd-coloured aura."); which_m.apply_status(eStatus::MARTYRS_SHIELD, how_much / -2); break; } + if(dynamic_cast(&which_m)) { + put_pc_screen(); + if(status == eStatus::DUMB) + adjust_spell_menus(); + } } // primary: 0 - secondary weapon, 1 - primary (and only) weapon, 2 - primary of two weapons @@ -702,6 +718,15 @@ void pc_attack_weapon(short who_att,iLiving& target,short hit_adj,short dam_adj, if(weap.ability == eItemAbil::WEAK_WEAPON) r2 = (r2 * (10 - weap.abil_data[0])) / 10; + if(cPlayer* pc_target = dynamic_cast(&target)) { + // PCs get some additional defensive perks + // These calculations were taken straight from the monster-on-PC attack code + r1 += 5 * pc_target->stat_adj(eSkill::DEXTERITY); + r1 += pc_target->get_prot_level(eItemAbil::EVASION); + if(pc_target->parry < 100) + r1 += 5 * pc_target->parry; + } + if(weap.ability == eItemAbil::EXPLODING_WEAPON) { add_string_to_buf(" The weapon produces an explosion!"); if(PSD[SDF_GAME_SPEED] == 0) @@ -787,6 +812,8 @@ void pc_attack_weapon(short who_att,iLiving& target,short hit_adj,short dam_adj, if(univ.party[who_att].has_abil_equip(eItemAbil::POISON_AUGMENT) < 24) 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]); } } @@ -1273,7 +1300,7 @@ void do_combat_cast(location target) { default: - if(!(victim = univ.target_there(target, TARG_MONST))) + if(!(victim = univ.target_there(target))) add_string_to_buf(" Nobody there."); else { cCreature* cur_monst = dynamic_cast(victim); @@ -1282,12 +1309,12 @@ void do_combat_cast(location target) { switch(spell_being_cast) { case eSpell::ACID_SPRAY: store_m_type = 0; - cur_monst->acid(level); + victim->acid(level); store_sound = 24; break; case eSpell::PARALYZE_BEAM: store_m_type = 9; - cur_monst->sleep(eStatus::PARALYZED,500,0); + victim->sleep(eStatus::PARALYZED,500,0); store_sound = 24; break; case eSpell::UNHOLY_RAVAGING: @@ -1296,11 +1323,15 @@ void do_combat_cast(location target) { r1 = get_ran(4,1,8); r2 = get_ran(1,0,2); damage_monst(targ_num, 7, r1, eDamageType::MAGIC,0); - cur_monst->slow(4 + r2); - cur_monst->poison(5 + r2); + victim->slow(4 + r2); + victim->poison(5 + r2); break; case eSpell::SCRY_MONSTER: + if(cur_monst == nullptr) { + add_string_to_buf(" Nobody there."); + break; + } store_m_type = -1; play_sound(52); univ.party.m_noted[cur_monst->number] = true; @@ -1309,12 +1340,21 @@ void do_combat_cast(location target) { store_sound = 25; break; case eSpell::CAPTURE_SOUL: + if(cur_monst == nullptr) { + add_string_to_buf(" Nobody there."); + break; + } store_m_type = 15; record_monst(cur_monst); store_sound = 25; break; case eSpell::MINDDUEL: + if(cur_monst == nullptr) { + // TODO: Support PC-on-PC mindduels? Might be no point though... + add_string_to_buf(" Nobody there."); + break; + } store_m_type = -1; if((cur_monst->mu == 0) && (cur_monst->cl == 0)) add_string_to_buf(" Can't duel: no magic."); @@ -1334,118 +1374,135 @@ void do_combat_cast(location target) { case eSpell::CHARM_FOE: store_m_type = 14; - cur_monst->sleep(eStatus::CHARM,0,-1 * (bonus + caster.level / 8)); + victim->sleep(eStatus::CHARM,0,-1 * (bonus + caster.level / 8)); store_sound = 24; break; case eSpell::DISEASE: store_m_type = 0; r1 = get_ran(1,0,1); - cur_monst->disease(2 + r1 + bonus); + victim->disease(2 + r1 + bonus); store_sound = 24; break; case eSpell::STRENGTHEN_TARGET: store_m_type = 14; - cur_monst->health += 20; + victim->heal(20); store_sound = 55; break; case eSpell::DUMBFOUND: store_m_type = 14; - cur_monst->dumbfound(1 + bonus / 3); + victim->dumbfound(1 + bonus / 3); store_sound = 53; break; case eSpell::SCARE: store_m_type = 11; - cur_monst->scare(get_ran(2 + bonus,1,6)); + victim->scare(get_ran(2 + bonus,1,6)); store_sound = 54; break; case eSpell::FEAR: store_m_type = 11; - cur_monst->scare(get_ran(min(20,caster.level / 2 + bonus),1,8)); + victim->scare(get_ran(min(20,caster.level / 2 + bonus),1,8)); store_sound = 54; break; case eSpell::SLOW: store_m_type = 11; r1 = get_ran(1,0,1); - cur_monst->slow(2 + r1 + bonus); + victim->slow(2 + r1 + bonus); store_sound = 25; break; case eSpell::POISON_MINOR: case eSpell::ARROWS_VENOM: store_m_type = (spell_being_cast == eSpell::ARROWS_VENOM) ? 4 : 11; - cur_monst->poison(2 + bonus / 2); + victim->poison(2 + bonus / 2); store_sound = 55; break; case eSpell::PARALYZE: store_m_type = 9; - cur_monst->sleep(eStatus::PARALYZED,1000,-10); + victim->sleep(eStatus::PARALYZED,1000,-10); store_sound = 25; break; case eSpell::POISON: store_m_type = 11; - cur_monst->poison(4 + bonus / 2); + victim->poison(4 + bonus / 2); store_sound = 55; break; case eSpell::POISON_MAJOR: store_m_type = 11; - cur_monst->poison(8 + bonus / 2); + victim->poison(8 + bonus / 2); store_sound = 55; break; case eSpell::STUMBLE: store_m_type = 8; - cur_monst->curse(4 + bonus); + victim->curse(4 + bonus); store_sound = 24; break; case eSpell::CURSE: store_m_type = 8; - cur_monst->curse(2 + bonus); + victim->curse(2 + bonus); store_sound = 24; break; case eSpell::HOLY_SCOURGE: store_m_type = 8; - cur_monst->curse(2 + caster.level / 2); + victim->curse(2 + caster.level / 2); store_sound = 24; break; case eSpell::TURN_UNDEAD: case eSpell::DISPEL_UNDEAD: - if(cur_monst->m_type != eRace::UNDEAD && cur_monst->m_type != eRace::SKELETAL) { + if(cur_monst != nullptr && cur_monst->m_type != eRace::UNDEAD && cur_monst->m_type != eRace::SKELETAL) { add_string_to_buf(" Not undead."); store_m_type = -1; break; + } else if(cPlayer* who = dynamic_cast(victim)) { + if(who->race != eRace::UNDEAD && who->race != eRace::SKELETAL) { + add_string_to_buf(" Not undead."); + store_m_type = -1; + break; + } } store_m_type = 8; r1 = get_ran(1,0,90); - if(r1 > hit_chance[minmax(0,19,bonus * 2 + level * 4 - (cur_monst->level / 2) + 3)]) + if(r1 > hit_chance[minmax(0,19,bonus * 2 + level * 4 - (victim->get_level() / 2) + 3)]) add_string_to_buf(" Monster resisted."); else { r1 = get_ran((spell_being_cast == eSpell::TURN_UNDEAD) ? 2 : 6, 1, 14); - - hit_space(cur_monst->cur_loc,r1,eDamageType::UNBLOCKABLE,0,current_pc); + size_t i_targ = univ.get_target_i(*victim); + if(i_targ < 100) + damage_pc(i_targ, r1, eDamageType::UNBLOCKABLE, eRace::UNKNOWN, 0); + else damage_monst(i_targ, current_pc, r1, eDamageType::UNBLOCKABLE, 0); } store_sound = 24; break; case eSpell::RAVAGE_SPIRIT: - if(cur_monst->m_type != eRace::DEMON) { + if(cur_monst != nullptr && cur_monst->m_type != eRace::DEMON) { add_string_to_buf(" Not a demon."); store_m_type = -1; break; + } else if(cPlayer* who = dynamic_cast(victim)) { + if(who->race != eRace::DEMON) { + add_string_to_buf(" Not a demon."); + store_m_type = -1; + break; + } } r1 = get_ran(1,1,100); - if(r1 > hit_chance[minmax(0,19,level * 4 - cur_monst->level + 10)]) + if(r1 > hit_chance[minmax(0,19,level * 4 - victim->get_level() + 10)]) add_string_to_buf(" Demon resisted."); else { r1 = get_ran(8 + bonus * 2, 1, 11); if(univ.party[spell_caster].status[eStatus::DUMB] < 0) r1 += -25 * univ.party[spell_caster].status[eStatus::DUMB] / 3; - hit_space(cur_monst->cur_loc,r1,eDamageType::UNBLOCKABLE,0,current_pc); + size_t i_targ = univ.get_target_i(*victim); + if(i_targ < 100) + damage_pc(i_targ, r1, eDamageType::UNBLOCKABLE, eRace::UNKNOWN, 0); + else damage_monst(i_targ, current_pc, r1, eDamageType::UNBLOCKABLE, 0); } store_sound = 24; break; @@ -1453,9 +1510,11 @@ void do_combat_cast(location target) { add_string_to_buf(" Error: Spell " + (*spell_being_cast).name() + " not implemented for combat mode.", 4); break; } - if(store_m_type >= 0) - add_missile(target,store_m_type,1, - 14 * (cur_monst->x_width - 1),18 * (cur_monst->y_width - 1)); + if(store_m_type >= 0) { + int w = cur_monst ? cur_monst->x_width : 1; + int h = cur_monst ? cur_monst->y_width : 1; + add_missile(target,store_m_type,1, 14 * (w - 1),18 * (h - 1)); + } } break; @@ -1481,6 +1540,9 @@ void do_combat_cast(location target) { handle_marked_damage(); combat_posing_monster = current_working_monster = -1; + if(dynamic_cast(victim)) + put_pc_screen(); + print_buf(); } @@ -1717,6 +1779,8 @@ void fire_missile(location target) { if(missile_firer.has_abil_equip(eItemAbil::POISON_AUGMENT) < 24) poison_amt++; victim->poison(poison_amt); + if(dynamic_cast(victim)) + put_pc_screen(); } if((ammo.ability == eItemAbil::STATUS_WEAPON) && (get_ran(1,0,1) == 1)) { apply_weapon_status(eStatus(ammo.abil_data[1]), ammo.abil_data[0], r2 + spec_dam, *victim, "Missile"); @@ -2650,7 +2714,6 @@ void monster_attack(short who_att,iLiving* target) { r1 += 5 * target->status[eStatus::BLESS_CURSE] - 15; r1 += 5 * (attacker->status[eStatus::WEBS] / 3); if(pc_target != nullptr) { - // TODO: Consider this stuff in PC-on-PC attacks r1 += 5 * pc_target->stat_adj(eSkill::DEXTERITY); r1 += pc_target->get_prot_level(eItemAbil::EVASION); if(pc_target->parry < 100) @@ -2706,6 +2769,8 @@ void monster_attack(short who_att,iLiving* target) { if(i == 0 && attacker->status[eStatus::POISONED_WEAPON] > 0) { short poison_amt = attacker->status[eStatus::POISONED_WEAPON]; target->poison(poison_amt); + if(dynamic_cast(target)) + put_pc_screen(); move_to_zero(attacker->status[eStatus::POISONED_WEAPON]); } @@ -3087,14 +3152,18 @@ void monst_basic_abil(short m_num, std::pair abil, iLiving* case eStatus::MARTYRS_SHIELD: target->apply_status(abil.second.gen.stat, -abil.second.gen.strength); break; + case eStatus::FORCECAGE: + target->sleep(abil.second.gen.stat, 8, abil.second.gen.strength); + if(target->status[eStatus::FORCECAGE] > 0) + univ.town.set_force_cage(target->get_loc().x, target->get_loc().y, true); + break; // This only works on monsters case eStatus::CHARM: target->sleep(abil.second.gen.stat, univ.town.monst[m_num].attitude, abil.second.gen.strength); break; - // These three don't make sense in this context + // These two don't make sense in this context case eStatus::MAIN: case eStatus::POISONED_WEAPON: - case eStatus::FORCECAGE: return; } break; @@ -3157,6 +3226,13 @@ void monst_basic_abil(short m_num, std::pair abil, iLiving* case eMonstAbil::SPECIAL: case eMonstAbil::SPLITS: case eMonstAbil::SUMMON: break; } + if(pc_target != nullptr) { + put_pc_screen(); + if(abil.first == eMonstAbil::STUN || abil.first == eMonstAbil::STATUS || abil.first == eMonstAbil::STATUS2) { + if(abil.second.gen.stat == eStatus::DUMB) + adjust_spell_menus(); + } + } } bool monst_breathe(cCreature *caster,location targ_space,uAbility abil) { @@ -3522,6 +3598,12 @@ bool monst_cast_mage(cCreature *caster,short targ) { end_missile_anim(); handle_marked_damage(); + if(dynamic_cast(&victim)) { + put_pc_screen(); + if(spell == eSpell::DUMBFOUND) + adjust_spell_menus(); + } + return acted; } @@ -3828,6 +3910,9 @@ bool monst_cast_priest(cCreature *caster,short targ) { end_missile_anim(); handle_marked_damage(); + if(dynamic_cast(&victim)) + put_pc_screen(); + return acted; } @@ -4112,6 +4197,7 @@ static void place_spell_pattern(effect_pat_type pat,location center,unsigned sho } } } + put_pc_screen(); fast_bang = 0; @@ -4416,9 +4502,10 @@ void handle_disease() { break; case 8: univ.party[i].dumbfound(3); + adjust_spell_menus(); break; case 9: case 10: - add_string_to_buf(" " + univ.party[i].name + "unaffected."); + add_string_to_buf(" " + univ.party[i].name + " unaffected."); break; } r1 = get_ran(1,0,7); @@ -4904,6 +4991,7 @@ void combat_immed_priest_cast(short current_pc, eSpell spell_num, bool freebie) i = get_ran(3,1,6); univ.party[target].apply_status(eStatus::DUMB, i / -3); univ.party[target].cur_sp += i * 2; + adjust_spell_menus(); } break; default: diff --git a/src/boe.main.cpp b/src/boe.main.cpp index 0305c38d5..30ce6704d 100644 --- a/src/boe.main.cpp +++ b/src/boe.main.cpp @@ -114,6 +114,7 @@ int main(int /*argc*/, char* argv[]) { init_menubar(); // Do this first of all because otherwise a default File and Window menu will be seen sync_prefs(); cUniverse::print_result = iLiving::print_result = add_string_to_buf; + cPlayer::give_help = give_help; init_graph_tool(); Initialize(); init_fileio(); diff --git a/src/boe.monster.cpp b/src/boe.monster.cpp index 17b04c4c8..9196cd1f1 100644 --- a/src/boe.monster.cpp +++ b/src/boe.monster.cpp @@ -1066,141 +1066,6 @@ bool monst_check_special_terrain(location where_check,short mode,short which_mon return can_enter; } -void cCreature::poison(int how_much) { - if(how_much > 0) { - how_much *= poison_res; - how_much /= 100; - } - apply_status(eStatus::POISON, how_much); - if(how_much >= 0) - spell_note((how_much == 0) ? 10 : 4); - else - spell_note(34); - -} - -void cCreature::acid(int how_much) { - how_much = magic_adjust(how_much); - apply_status(eStatus::ACID, how_much); - if(how_much >= 0) - spell_note(31); - else - spell_note(48); -} - -void cCreature::slow(int how_much) { - how_much = magic_adjust(how_much); - apply_status(eStatus::HASTE_SLOW, -how_much); - if(how_much >= 0) - spell_note((how_much == 0) ? 10 : 2); - else - spell_note(35); - -} - -void cCreature::curse(int how_much) { - how_much = magic_adjust(how_much); - apply_status(eStatus::BLESS_CURSE, -how_much); - if(how_much >= 0) - spell_note((how_much == 0) ? 10 : 5); - else - spell_note(36); - -} - -void cCreature::web(int how_much) { - how_much = magic_adjust(how_much); - apply_status(eStatus::WEBS, how_much); - if(how_much >= 0) - spell_note((how_much == 0) ? 10 : 19); - else - spell_note(37); - -} - -void cCreature::scare(int how_much) { - how_much = magic_adjust(how_much); - morale -= how_much; - // TODO: I don't think there's currently any way to increase monster morale at the moment - add one! - if(how_much >= 0) - spell_note((how_much == 0) ? 10 : 1); - else - spell_note(47); - -} - -void cCreature::disease(int how_much) { - how_much = magic_adjust(how_much); - apply_status(eStatus::DISEASE, how_much); - if(how_much >= 0) - spell_note((how_much == 0) ? 10 : 25); - else - spell_note(38); - -} - -void cCreature::dumbfound(int how_much) { - how_much = magic_adjust(how_much); - apply_status(eStatus::DUMB, how_much); - if(how_much >= 0) - spell_note((how_much == 0) ? 10 : 22); - else - spell_note(39); - -} - -// For charm, amount is the resulting attitude of the charmed monster; if 0, attitude is 2. -void cCreature::sleep(eStatus which_status,int amount,int penalty) { - if(which_status != eStatus::CHARM && which_status != eStatus::FORCECAGE && amount < 0) { - status[which_status] -= amount; - if(which_status == eStatus::PARALYZED) - status[which_status] = max(0, status[which_status]); - return; - } - - if((which_status == eStatus::ASLEEP) && - (m_type == eRace::UNDEAD || m_type == eRace::SKELETAL || m_type == eRace::SLIME || - m_type == eRace::STONE || m_type == eRace::PLANT)) - return; - short r1 = get_ran(1,1,100); - if(magic_res > 0) { - r1 *= 100; - r1 /= magic_res; - } else r1 = 200; - r1 += penalty; - if(which_status == eStatus::ASLEEP) - r1 -= 25; - if(which_status == eStatus::PARALYZED) - r1 -= 15; - if(which_status == eStatus::ASLEEP && abil[eMonstAbil::FIELD].active && abil[eMonstAbil::FIELD].gen.fld == eFieldType::CLOUD_SLEEP) - return; - - if(r1 > charm_odds[level / 2]) { - //one_sound(68); - spell_note(10); - } - else { - if(which_status == eStatus::CHARM) { - if(amount == 0 || amount > 3) amount = 2; - attitude = amount; - spell_note(23); - } else if(which_status == eStatus::FORCECAGE) { - status[eStatus::FORCECAGE] = 8; - univ.town.set_force_cage(cur_loc.x, cur_loc.y, true); - spell_note(52); - } else { - status[which_status] = amount; - if(which_status == eStatus::ASLEEP && (amount >= 0)) - spell_note(28); - if(which_status == eStatus::PARALYZED && (amount >= 0)) - spell_note(30); - if(amount < 0) - spell_note(40); - } - //one_sound(53); - } -} - void record_monst(cCreature *which_m) { short r1; diff --git a/src/boe.party.cpp b/src/boe.party.cpp index 88edbc4f0..c8ed0a0a6 100644 --- a/src/boe.party.cpp +++ b/src/boe.party.cpp @@ -349,166 +349,6 @@ bool take_sp(short pc_num,short amt) { return true; } -void cPlayer::heal(int amt) { - if(!is_alive()) return; - if(cur_health >= max_health) return; - cur_health += amt; - if(cur_health > max_health) - cur_health = max_health; - if(cur_health < 0) - cur_health = 0; -} - -void cPlayer::cure(int amt) { - if(!is_alive()) return; - if(status[eStatus::POISON] <= amt) - status[eStatus::POISON] = 0; - else status[eStatus::POISON] -= amt; - one_sound(51); -} - -// if how_much < 0, bless -void cPlayer::curse(int how_much) { - if(!is_alive()) return; - if(how_much > 0) - how_much -= get_prot_level(eItemAbil::STATUS_PROTECTION,int(eStatus::BLESS_CURSE)) / 2; - apply_status(eStatus::BLESS_CURSE, -how_much); - if(how_much < 0) - add_string_to_buf(" " + name + " blessed."); - else if(how_much > 0) - add_string_to_buf(" " + name + " cursed."); - put_pc_screen(); - if(how_much > 0) - give_help(59,0); - else if(how_much > 0) - give_help(34,0); -} - -void cPlayer::dumbfound(int how_much) { - if(!is_alive()) return; - short r1 = get_ran(1,0,90); - if(has_abil_equip(eItemAbil::WILL) < 24) { - add_string_to_buf(" Ring of Will glows."); - r1 -= 10; - } - how_much -= get_prot_level(eItemAbil::STATUS_PROTECTION,int(eStatus::DUMB)) / 4; - if(r1 < level) - how_much -= 2; - if(how_much <= 0) { - add_string_to_buf(" " + name + " saved."); - return; - } - apply_status(eStatus::DUMB, how_much); - add_string_to_buf(" " + name + " dumbfounded."); - one_sound(67); - put_pc_screen(); - adjust_spell_menus(); - give_help(28,0); -} - -void cPlayer::disease(int how_much) { - if(is_alive()) return; - short r1 = get_ran(1,1,100); - if(r1 < level * 2) - how_much -= 2; - if(how_much <= 0) { - add_string_to_buf(" " + name + " saved."); - return; - } - how_much -= get_prot_level(eItemAbil::STATUS_PROTECTION,int(eStatus::DISEASE)) / 2; - if(traits[eTrait::FRAIL] && how_much > 1) - how_much++; - if(traits[eTrait::FRAIL] && how_much == 1 && get_ran(1,0,1) == 0) - how_much++; - apply_status(eStatus::DISEASE, how_much); - add_string_to_buf(" " + name + " diseased."); - one_sound(66); - put_pc_screen(); - give_help(29,0); -} - -void cPlayer::sleep(eStatus what_type,int how_much,int adjust) { - if(what_type == eStatus::CHARM) return; - short level = 0; - if(!is_alive()) return; - if(how_much == 0) return; - - if((what_type == eStatus::ASLEEP) && - (race == eRace::UNDEAD || race == eRace::SKELETAL || race == eRace::SLIME || - race == eRace::STONE || race == eRace::PLANT)) - return; - if(what_type == eStatus::ASLEEP || what_type == eStatus::PARALYZED) { - how_much -= get_prot_level(eItemAbil::WILL) / 2; - level = get_prot_level(eItemAbil::FREE_ACTION); - how_much -= (what_type == eStatus::ASLEEP) ? level : level * 300; - how_much -= get_prot_level(eItemAbil::STATUS_PROTECTION,int(what_type)) / 4; - } - - short r1 = get_ran(1,1,100) + adjust; - if(r1 < 30 + level * 2) - how_much = -1; - if(what_type == eStatus::ASLEEP && (traits[eTrait::HIGHLY_ALERT] || status[eStatus::ASLEEP] < 0)) - how_much = -1; - if(how_much <= 0) { - add_string_to_buf(" " + name + " resisted."); - return; - } - status[what_type] = how_much; - if(what_type == eStatus::FORCECAGE) - univ.town.set_force_cage(get_loc().x, get_loc().y, true); - if(what_type == eStatus::ASLEEP) - add_string_to_buf(" " + name + " falls asleep."); - else if(what_type == eStatus::FORCECAGE) - add_string_to_buf(" " + name + " is trapped!"); - else add_string_to_buf(" " + name + " paralyzed."); - if(what_type == eStatus::ASLEEP) - play_sound(96); - else play_sound(90); - if(what_type != eStatus::FORCECAGE) - ap = 0; - put_pc_screen(); - if(what_type == eStatus::ASLEEP) - give_help(30,0); - else if(what_type == eStatus::PARALYZED) - give_help(32,0); -} - -// if how_much < 0, haste -void cPlayer::slow(int how_much) { - if(!is_alive()) return; - if(how_much > 0) - how_much -= get_prot_level(eItemAbil::STATUS_PROTECTION,int(eStatus::HASTE_SLOW)) / 2; - apply_status(eStatus::HASTE_SLOW, -how_much); - if(how_much < 0) - add_string_to_buf(" " + name + " hasted."); - else if(how_much > 0) - add_string_to_buf(" " + name + " slowed."); - put_pc_screen(); - give_help(35,0); -} - -void cPlayer::web(int how_much) { - if(!is_alive()) return; - how_much -= get_prot_level(eItemAbil::STATUS_PROTECTION,int(eStatus::WEBS)) / 2; - apply_status(eStatus::WEBS, how_much); - add_string_to_buf(" " + name + " webbed."); - one_sound(17); - put_pc_screen(); - give_help(31,0); -} - -void cPlayer::acid(int how_much) { - if(!is_alive()) return; - if(has_abil_equip(eItemAbil::STATUS_PROTECTION,int(eStatus::ACID)) < 24) { - add_string_to_buf(" " + name + " resists acid."); - return; - } - status[eStatus::ACID] += how_much; - add_string_to_buf(" " + name + " covered with acid!"); - one_sound(42); - put_pc_screen(); -} - void increase_light(short amt) { short i; location where; @@ -529,16 +369,6 @@ void increase_light(short amt) { put_pc_screen(); } -void cPlayer::restore_sp(int amt) { - if(!is_alive()) return; - if(cur_sp >= max_sp) return; - cur_sp += amt; - if(cur_sp > max_sp) - cur_sp = max_sp; - if(cur_sp < 0) - cur_sp = 0; -} - void award_party_xp(short amt) { short i; @@ -2260,24 +2090,6 @@ void print_spell_cast(eSpell spell,eSkill which) { add_string_to_buf("Spell: " + name); } -short cPlayer::stat_adj(eSkill which) const { - // This is one place where we use the base skill level instead of the adjusted skill level - // Using the adjusted skill level here would alter the original mechanics of stat-boosting items - short tr = skill_bonus[skills[which]]; - if(which == eSkill::INTELLIGENCE) { - if(traits[eTrait::MAGICALLY_APT]) - tr++; - } - if(which == eSkill::STRENGTH) { - if(traits[eTrait::STRENGTH]) - tr++; - } - // TODO: Use ability strength? - if(has_abil_equip(eItemAbil::BOOST_STAT,int(which)) < 24) - tr++; - return tr; -} - void start_town_targeting(eSpell s_num,short who_c,bool freebie,eSpellPat pat) { add_string_to_buf(" Target spell."); overall_mode = MODE_TOWN_TARGET; @@ -2504,33 +2316,6 @@ bool flying() { else return true; } -void cPlayer::poison(int how_much) { - if(!is_alive()) return; - how_much -= get_prot_level(eItemAbil::STATUS_PROTECTION,int(eStatus::POISON)) / 2; - how_much -= get_prot_level(eItemAbil::FULL_PROTECTION) / 3; - - if(traits[eTrait::FRAIL] && how_much > 1) - how_much++; - if(traits[eTrait::FRAIL] && how_much == 1 && get_ran(1,0,1) == 0) - how_much++; - - if(how_much > 0) { - apply_status(eStatus::POISON, how_much); - add_string_to_buf(" " + name + " poisoned."); - one_sound(17); - give_help(33,0); - } - put_pc_screen(); -} - -void iLiving::void_sanctuary() { - if(status[eStatus::INVISIBLE] > 0) { - if(dynamic_cast(this)) - add_string_to_buf("You become visible!"); - status[eStatus::INVISIBLE] = 0; - } -} - void hit_party(short how_much,eDamageType damage_type,short snd_type) { short i; bool dummy; diff --git a/src/boe.specials.cpp b/src/boe.specials.cpp index 9ecef99ee..3440f1c28 100644 --- a/src/boe.specials.cpp +++ b/src/boe.specials.cpp @@ -30,6 +30,7 @@ #include "fileio.hpp" #include #include "spell.hpp" +#include "boe.menus.h" extern sf::RenderWindow mainPtr; extern eGameMode overall_mode; @@ -235,9 +236,9 @@ bool check_special_terrain(location where_check,eSpecCtx mode,cPlayer& which_pc, r1 = get_ran(1,2,3); univ.party[i].web(r1); } - put_pc_screen(); } else univ.party[current_pc].web(get_ran(1,2,3)); + put_pc_screen(); univ.town.set_web(where_check.x,where_check.y,false); } if(univ.town.is_force_barr(where_check.x,where_check.y)) { @@ -416,6 +417,8 @@ bool check_special_terrain(location where_check,eSpecCtx mode,cPlayer& which_pc, case eStatus::FORCECAGE: if(is_out()) break; univ.party[i].sleep(eStatus::FORCECAGE,ter_flag1,ter_flag1 / 2); + if(univ.party[i].status[eStatus::FORCECAGE] > 0) + univ.town.set_force_cage(univ.party[i].get_loc().x, univ.party[i].get_loc().y, true); // TODO: Do we need to process fields here? Or is it done after returning from this function? break; case eStatus::MAIN: case eStatus::CHARM: // These magic values are illegal in this context @@ -424,6 +427,9 @@ bool check_special_terrain(location where_check,eSpecCtx mode,cPlayer& which_pc, if(mode == eSpecCtx::COMBAT_MOVE) break; // only damage once in combat! } } + put_pc_screen(); + if(ter_flag3 == int(eStatus::DUMB)) + adjust_spell_menus(); //print_nums(1,which_pc,current_pc); break; case eTerSpec::CALL_SPECIAL: { @@ -525,7 +531,6 @@ void check_fields(location where_check,eSpecCtx mode,cPlayer& which_pc) { if(univ.town.is_sleep_cloud(where_check.x,where_check.y)) { add_string_to_buf(" Sleep cloud!"); univ.party[current_pc].sleep(eStatus::ASLEEP,3,0); - put_pc_screen(); } if(univ.town.is_fire_barr(where_check.x,where_check.y)) { add_string_to_buf(" Magic barrier!"); @@ -541,6 +546,7 @@ void check_fields(location where_check,eSpecCtx mode,cPlayer& which_pc) { add_string_to_buf(" Trapped in force cage!"); which_pc.status[eStatus::FORCECAGE] = 8; } else which_pc.status[eStatus::FORCECAGE] = 0; + put_pc_screen(); } void use_spec_item(short item) { @@ -668,24 +674,24 @@ void use_item(short pc,short item) { break; case eStatus::BLESS_CURSE: play_sound(4); - if(the_item.abil_harms()) { - ASB(" You feel awkward."); + if(!the_item.abil_harms()) { + ASB(" You feel blessed."); str = str * -1; - }else ASB(" You feel blessed."); + }else ASB(" You feel awkward."); if(the_item.abil_group()) - univ.party.apply_status(status,str); - else univ.party[pc].apply_status(status,str); + univ.party.curse(str); + else univ.party[pc].curse(str); break; case eStatus::HASTE_SLOW: // TODO: Is this the right sound? play_sound(75); - if(the_item.abil_harms()) { - ASB(" You feel sluggish."); + if(!the_item.abil_harms()) { + ASB(" You feel speedy."); str = str * -1; - }else ASB(" You feel speedy."); + }else ASB(" You feel sluggish."); if(the_item.abil_group()) - univ.party.apply_status(status,str); - else univ.party[pc].apply_status(status,str); + univ.party.slow(str); + else univ.party[pc].slow(str); break; case eStatus::INVULNERABLE: // TODO: Is this the right sound? @@ -700,6 +706,7 @@ void use_item(short pc,short item) { break; case eStatus::MAGIC_RESISTANCE: // TODO: Is this the right sound? + // TODO: This ignores resistances if it's negative play_sound(51); if(the_item.abil_harms()) { ASB(" You feel odd."); @@ -717,8 +724,8 @@ void use_item(short pc,short item) { str = str * -1; } if(the_item.abil_group()) - univ.party.apply_status(status,str); - else univ.party[pc].apply_status(status,str); + univ.party.web(str); + else univ.party[pc].web(str); break; case eStatus::INVISIBLE: // TODO: Is this the right sound? @@ -801,6 +808,7 @@ void use_item(short pc,short item) { univ.party.dumbfound(str); break; } + adjust_spell_menus(); break; case eStatus::ASLEEP: switch(type) { @@ -869,6 +877,8 @@ void use_item(short pc,short item) { break; case eItemUse::HARM_ONE: univ.party[pc].sleep(eStatus::FORCECAGE, str, str / 2); + if(univ.party[pc].status[eStatus::FORCECAGE] > 0) + univ.town.set_force_cage(univ.party[pc].get_loc().x, univ.party[pc].get_loc().y, true); break; case eItemUse::HELP_ALL: for(i = 0; i < 6; i++) @@ -876,6 +886,9 @@ void use_item(short pc,short item) { break; case eItemUse::HARM_ALL: univ.party.sleep(eStatus::FORCECAGE, str, str / 2); + for(i = 0; i < 6; i++) + if(univ.party[i].status[eStatus::FORCECAGE] > 0) + univ.town.set_force_cage(univ.party[i].get_loc().x, univ.party[i].get_loc().y, true); break; } break; @@ -909,6 +922,8 @@ void use_item(short pc,short item) { } break; } + if(the_item.abil_harms()) + adjust_spell_menus(); break; case eItemAbil::AFFECT_EXPERIENCE: switch(type) { @@ -2978,6 +2993,9 @@ void affect_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type, case eStatus::FORCECAGE: break; } + put_pc_screen(); + if(spec.ex2a == int(eStatus::DUMB)) + adjust_spell_menus(); break; case eSpecType::AFFECT_STAT: if(pc_num >= 100) break; diff --git a/src/boe.townspec.cpp b/src/boe.townspec.cpp index bb888fd20..4b6112ec4 100644 --- a/src/boe.townspec.cpp +++ b/src/boe.townspec.cpp @@ -16,6 +16,7 @@ #include "mathutil.hpp" #include "dlogutil.hpp" #include "winutil.hpp" +#include "boe.menus.h" extern eGameMode overall_mode; extern short current_pc,stat_window; @@ -128,6 +129,7 @@ bool run_trap(short pc_num,eTrapType trap_type,short trap_level,short diff) { case TRAP_DUMBFOUND: add_string_to_buf(" You feel disoriented."); univ.party.dumbfound(2 + trap_level * 2); + adjust_spell_menus(); break; case TRAP_DISEASE: diff --git a/src/classes/creature.cpp b/src/classes/creature.cpp index 35a3169a7..e33bd2f3e 100644 --- a/src/classes/creature.cpp +++ b/src/classes/creature.cpp @@ -127,6 +127,140 @@ void cCreature::drain_sp(int drain) { } } +void cCreature::poison(int how_much) { + if(how_much > 0) { + how_much *= poison_res; + how_much /= 100; + } + apply_status(eStatus::POISON, how_much); + if(how_much >= 0) + spell_note((how_much == 0) ? 10 : 4); + else + spell_note(34); + +} + +void cCreature::acid(int how_much) { + how_much = magic_adjust(how_much); + apply_status(eStatus::ACID, how_much); + if(how_much >= 0) + spell_note(31); + else + spell_note(48); +} + +void cCreature::slow(int how_much) { + how_much = magic_adjust(how_much); + apply_status(eStatus::HASTE_SLOW, -how_much); + if(how_much >= 0) + spell_note((how_much == 0) ? 10 : 2); + else + spell_note(35); + +} + +void cCreature::curse(int how_much) { + how_much = magic_adjust(how_much); + apply_status(eStatus::BLESS_CURSE, -how_much); + if(how_much >= 0) + spell_note((how_much == 0) ? 10 : 5); + else + spell_note(36); + +} + +void cCreature::web(int how_much) { + how_much = magic_adjust(how_much); + apply_status(eStatus::WEBS, how_much); + if(how_much >= 0) + spell_note((how_much == 0) ? 10 : 19); + else + spell_note(37); + +} + +void cCreature::scare(int how_much) { + how_much = magic_adjust(how_much); + morale -= how_much; + // TODO: I don't think there's currently any way to increase monster morale at the moment - add one! + if(how_much >= 0) + spell_note((how_much == 0) ? 10 : 1); + else + spell_note(47); + +} + +void cCreature::disease(int how_much) { + how_much = magic_adjust(how_much); + apply_status(eStatus::DISEASE, how_much); + if(how_much >= 0) + spell_note((how_much == 0) ? 10 : 25); + else + spell_note(38); + +} + +void cCreature::dumbfound(int how_much) { + how_much = magic_adjust(how_much); + apply_status(eStatus::DUMB, how_much); + if(how_much >= 0) + spell_note((how_much == 0) ? 10 : 22); + else + spell_note(39); + +} + +// For charm, amount is the resulting attitude of the charmed monster; if 0, attitude is 2. +void cCreature::sleep(eStatus which_status,int amount,int penalty) { + if(which_status != eStatus::CHARM && which_status != eStatus::FORCECAGE && amount < 0) { + status[which_status] -= amount; + if(which_status == eStatus::PARALYZED) + status[which_status] = max(0, status[which_status]); + return; + } + + if((which_status == eStatus::ASLEEP) && + (m_type == eRace::UNDEAD || m_type == eRace::SKELETAL || m_type == eRace::SLIME || + m_type == eRace::STONE || m_type == eRace::PLANT)) + return; + short r1 = get_ran(1,1,100); + if(magic_res > 0) { + r1 *= 100; + r1 /= magic_res; + } else r1 = 200; + r1 += penalty; + if(which_status == eStatus::ASLEEP) + r1 -= 25; + if(which_status == eStatus::PARALYZED) + r1 -= 15; + if(which_status == eStatus::ASLEEP && abil[eMonstAbil::FIELD].active && abil[eMonstAbil::FIELD].gen.fld == eFieldType::CLOUD_SLEEP) + return; + + if(r1 > charm_odds[level / 2]) { + //one_sound(68); + spell_note(10); + } + else { + if(which_status == eStatus::CHARM) { + if(amount == 0 || amount > 3) amount = 2; + attitude = amount; + spell_note(23); + } else if(which_status == eStatus::FORCECAGE) { + status[eStatus::FORCECAGE] = 8; + spell_note(52); + } else { + status[which_status] = amount; + if(which_status == eStatus::ASLEEP && (amount >= 0)) + spell_note(28); + if(which_status == eStatus::PARALYZED && (amount >= 0)) + spell_note(30); + if(amount < 0) + spell_note(40); + } + //one_sound(53); + } +} + bool cCreature::is_alive() const { return active > 0; } diff --git a/src/classes/living.cpp b/src/classes/living.cpp index a2e79eac2..7c6cdb100 100644 --- a/src/classes/living.cpp +++ b/src/classes/living.cpp @@ -55,4 +55,9 @@ void iLiving::clear_bad_status() { status[eStatus::MAGIC_RESISTANCE] = 0; } +void iLiving::void_sanctuary() { + if(status[eStatus::INVISIBLE] > 0) + status[eStatus::INVISIBLE] = 0; +} + void(* iLiving::print_result)(std::string) = nullptr; diff --git a/src/classes/pc.cpp b/src/classes/pc.cpp index b7d49ed8e..4ae5df7fa 100644 --- a/src/classes/pc.cpp +++ b/src/classes/pc.cpp @@ -17,6 +17,8 @@ #include "oldstructs.h" #include "mathutil.hpp" +extern short skill_bonus[21]; + void cPlayer::append(legacy::pc_record_type old){ int i; main_status = (eMainStatus) old.main_status; @@ -107,6 +109,232 @@ void cPlayer::scare(int) { // TODO: Not implemented } +void cPlayer::void_sanctuary() { + if(status[eStatus::INVISIBLE] > 0 && print_result) + print_result("You become visible!"); + iLiving::void_sanctuary(); +} + +void cPlayer::heal(int amt) { + if(!is_alive()) return; + if(cur_health >= max_health) return; + cur_health += amt; + if(cur_health > max_health) + cur_health = max_health; + if(cur_health < 0) + cur_health = 0; +} + +void cPlayer::cure(int amt) { + if(!is_alive()) return; + if(status[eStatus::POISON] <= amt) + status[eStatus::POISON] = 0; + else status[eStatus::POISON] -= amt; + one_sound(51); +} + +// if how_much < 0, bless +void cPlayer::curse(int how_much) { + if(!is_alive()) return; + if(how_much > 0) + how_much -= get_prot_level(eItemAbil::STATUS_PROTECTION,int(eStatus::BLESS_CURSE)) / 2; + apply_status(eStatus::BLESS_CURSE, -how_much); + if(print_result) { + if(how_much < 0) + print_result(" " + name + " blessed."); + else if(how_much > 0) + print_result(" " + name + " cursed."); + } + if(give_help) { + if(how_much > 0) + give_help(59,0); + else if(how_much > 0) + give_help(34,0); + } +} + +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(print_result) + print_result(" Ring of Will glows."); + r1 -= 10; + } + how_much -= get_prot_level(eItemAbil::STATUS_PROTECTION,int(eStatus::DUMB)) / 4; + if(r1 < level) + how_much -= 2; + if(how_much <= 0) { + if(print_result) + print_result(" " + name + " saved."); + return; + } + apply_status(eStatus::DUMB, how_much); + if(print_result) + print_result(" " + name + " dumbfounded."); + one_sound(67); + if(give_help) + give_help(28,0); +} + +void cPlayer::disease(int how_much) { + if(is_alive()) return; + short r1 = get_ran(1,1,100); + if(r1 < level * 2) + how_much -= 2; + if(how_much <= 0) { + if(print_result) + print_result(" " + name + " saved."); + return; + } + how_much -= get_prot_level(eItemAbil::STATUS_PROTECTION,int(eStatus::DISEASE)) / 2; + if(traits[eTrait::FRAIL] && how_much > 1) + how_much++; + if(traits[eTrait::FRAIL] && how_much == 1 && get_ran(1,0,1) == 0) + how_much++; + apply_status(eStatus::DISEASE, how_much); + if(print_result) + print_result(" " + name + " diseased."); + one_sound(66); + if(give_help) + give_help(29,0); +} + +void cPlayer::sleep(eStatus what_type,int how_much,int adjust) { + if(what_type == eStatus::CHARM) return; + short level = 0; + if(!is_alive()) return; + if(how_much == 0) return; + + if((what_type == eStatus::ASLEEP) && + (race == eRace::UNDEAD || race == eRace::SKELETAL || race == eRace::SLIME || + race == eRace::STONE || race == eRace::PLANT)) + return; + if(what_type == eStatus::ASLEEP || what_type == eStatus::PARALYZED) { + how_much -= get_prot_level(eItemAbil::WILL) / 2; + level = get_prot_level(eItemAbil::FREE_ACTION); + how_much -= (what_type == eStatus::ASLEEP) ? level : level * 300; + how_much -= get_prot_level(eItemAbil::STATUS_PROTECTION,int(what_type)) / 4; + } + + short r1 = get_ran(1,1,100) + adjust; + if(r1 < 30 + level * 2) + how_much = -1; + if(what_type == eStatus::ASLEEP && (traits[eTrait::HIGHLY_ALERT] || status[eStatus::ASLEEP] < 0)) + how_much = -1; + if(how_much <= 0) { + if(print_result) + print_result(" " + name + " resisted."); + return; + } + status[what_type] = how_much; + if(print_result) { + if(what_type == eStatus::ASLEEP) + print_result(" " + name + " falls asleep."); + else if(what_type == eStatus::FORCECAGE) + print_result(" " + name + " is trapped!"); + else print_result(" " + name + " paralyzed."); + } + if(what_type == eStatus::ASLEEP) + play_sound(96); + else play_sound(90); + if(what_type != eStatus::FORCECAGE) + ap = 0; + if(give_help) { + if(what_type == eStatus::ASLEEP) + give_help(30,0); + else if(what_type == eStatus::PARALYZED) + give_help(32,0); + } +} + +// if how_much < 0, haste +void cPlayer::slow(int how_much) { + if(!is_alive()) return; + if(how_much > 0) + how_much -= get_prot_level(eItemAbil::STATUS_PROTECTION,int(eStatus::HASTE_SLOW)) / 2; + apply_status(eStatus::HASTE_SLOW, -how_much); + if(print_result) { + if(how_much < 0) + print_result(" " + name + " hasted."); + else if(how_much > 0) + print_result(" " + name + " slowed."); + } + if(give_help) + give_help(35,0); +} + +void cPlayer::web(int how_much) { + if(!is_alive()) return; + if(how_much > 0) + how_much -= get_prot_level(eItemAbil::STATUS_PROTECTION,int(eStatus::WEBS)) / 2; + apply_status(eStatus::WEBS, how_much); + if(print_result) + print_result(" " + name + " webbed."); + one_sound(17); + give_help(31,0); +} + +void cPlayer::acid(int how_much) { + if(!is_alive()) return; + if(has_abil_equip(eItemAbil::STATUS_PROTECTION,int(eStatus::ACID)) < 24) { + if(print_result) + print_result(" " + name + " resists acid."); + return; + } + status[eStatus::ACID] += how_much; + if(print_result) + print_result(" " + name + " covered with acid!"); + one_sound(42); +} + +void cPlayer::restore_sp(int amt) { + if(!is_alive()) return; + if(cur_sp >= max_sp) return; + cur_sp += amt; + if(cur_sp > max_sp) + cur_sp = max_sp; + if(cur_sp < 0) + cur_sp = 0; +} + +void cPlayer::poison(int how_much) { + if(!is_alive()) return; + how_much -= get_prot_level(eItemAbil::STATUS_PROTECTION,int(eStatus::POISON)) / 2; + how_much -= get_prot_level(eItemAbil::FULL_PROTECTION) / 3; + + if(traits[eTrait::FRAIL] && how_much > 1) + how_much++; + if(traits[eTrait::FRAIL] && how_much == 1 && get_ran(1,0,1) == 0) + how_much++; + + if(how_much > 0) { + apply_status(eStatus::POISON, how_much); + if(print_result) + print_result(" " + name + " poisoned."); + one_sound(17); + give_help(33,0); + } +} + +short cPlayer::stat_adj(eSkill which) const { + // This is one place where we use the base skill level instead of the adjusted skill level + // Using the adjusted skill level here would alter the original mechanics of stat-boosting items + short tr = skill_bonus[skills[which]]; + if(which == eSkill::INTELLIGENCE) { + if(traits[eTrait::MAGICALLY_APT]) + tr++; + } + if(which == eSkill::STRENGTH) { + if(traits[eTrait::STRENGTH]) + tr++; + } + // TODO: Use ability strength? + if(has_abil_equip(eItemAbil::BOOST_STAT,int(which)) < 24) + tr++; + return tr; +} + bool cPlayer::is_alive() const { return main_status == eMainStatus::ALIVE; } @@ -779,3 +1007,5 @@ std::istream& operator >> (std::istream& in, eMainStatus& e){ else e = eMainStatus::ABSENT; return in; } + +void(* cPlayer::give_help)(short,short) = nullptr; diff --git a/src/classes/pc.h b/src/classes/pc.h index fd10c26b1..d10d9fc7c 100644 --- a/src/classes/pc.h +++ b/src/classes/pc.h @@ -28,6 +28,7 @@ class cParty; class cPlayer : public iLiving { cParty& party; public: + static void(* give_help)(short,short); eMainStatus main_status; std::string name; // HACK: This is only really marked mutable so that I can use operator[] from const methods @@ -65,6 +66,7 @@ public: location get_loc() const; void finish_create(); + void void_sanctuary(); void heal(int how_much); void poison(int how_much); void cure(int how_much);