resurrection spells hide invalid targets & hide res spells when all alive

This commit is contained in:
2025-05-14 15:40:54 -05:00
parent 176f0645a4
commit e35086d6b2
7 changed files with 60 additions and 23 deletions

View File

@@ -11,6 +11,7 @@
#include <limits>
#include <boost/optional.hpp>
#include <set>
enum class eDamageType {
WEAPON = 0,
@@ -92,6 +93,8 @@ enum class eMainStatus {
SPLIT_WON = SPLIT + WON,
};
const std::set<eMainStatus> dead_statuses = { eMainStatus::DEAD, eMainStatus::STONE, eMainStatus::DUST };
inline eMainStatus exceptSplit(eMainStatus stat) {
if(int(stat) >= 10)
return (eMainStatus) (-10 + (int)stat);

View File

@@ -1002,6 +1002,12 @@ short select_pc(eSelectPC mode, std::string title, eSkill highlight_highest, boo
extra_info = "";
}
break;
case eSelectPC::ONLY_STONE:
if(univ.party[i].main_status != eMainStatus::STONE){
can_pick = false;
extra_info = "";
}
break;
case eSelectPC::ONLY_DEAD:
if(univ.party[i].main_status == eMainStatus::ALIVE){
can_pick = false;

View File

@@ -55,6 +55,7 @@ enum class eSelectPC {
// Must have skill points
ONLY_CAN_TRAIN,
ONLY_DEAD,
ONLY_STONE,
};
// Prompt the player to choose a party member. Returns 0-5 for a pc, 6 for cancel, 7 for all, or 8 if no PCs fit the mode's filter.
// Pass a string poiner to no_choice_reason to get the reason why no choices were available, if none are.

View File

@@ -1598,6 +1598,20 @@ bool pc_can_cast_spell(const cPlayer& pc,eSpell spell_num) {
eSkill type = (*spell_num).type;
cSpell spell = *spell_num;
if(spell.need_select == eSpellSelect::SELECT_DEAD){
bool any_dead = false;
for(int i = 0; i < 6; ++i){
if(dead_statuses.count(univ.party[i].main_status)) any_dead = true;
}
if(!any_dead) return false;
}else if(spell.need_select == eSpellSelect::SELECT_STONE){
bool any_stone = false;
for(int i = 0; i < 6; ++i){
if(univ.party[i].main_status == eMainStatus::STONE) any_stone = true;
}
if(!any_stone) return false;
}
level = spell.level;
int effective_skill = pc.skill(type);
if(pc.status[eStatus::DUMB] < 0)
@@ -1696,7 +1710,21 @@ static void draw_spell_info(cDialog& me, const eSkill store_situation, const sho
me[id].hide();
}
break;
case SELECT_DEAD:
if(dead_statuses.count(univ.party[i].main_status)) {
me[id].show();
}else{
me[id].hide();
}
break;
case SELECT_STONE:
if(univ.party[i].main_status == eMainStatus::STONE) {
me[id].show();
}
else {
me[id].hide();
}
break;
}
}
}
@@ -1887,22 +1915,12 @@ static bool pick_spell_caster(cDialog& me, std::string id, const eSkill store_si
}
static bool pick_spell_target(cDialog& me, std::string id, const eSkill store_situation, short& last_darkened, const short& store_spell) {
static const char*const no_target = " No target needed.";
static const char*const bad_target = " Can't cast on them.";
static const char*const got_target = " Target selected.";
short item_hit = id[id.length() - 1] - '1';
std::string casting = id;
casting[casting.length() - 1] = pc_casting + '1';
if(!me[casting].isVisible()) {
me["feedback"].setText(no_target);
} else if(!me[id].isVisible()) {
me["feedback"].setText(bad_target);
} else {
me["feedback"].setText(got_target);
store_spell_target = item_hit;
draw_spell_info(me, store_situation, store_spell);
put_pc_target_buttons(me, last_darkened);
}
me["feedback"].setText(got_target);
store_spell_target = item_hit;
draw_spell_info(me, store_situation, store_spell);
put_pc_target_buttons(me, last_darkened);
return true;
}
@@ -1941,14 +1959,21 @@ static bool pick_spell_select_led(cDialog& me, std::string id, eKeyMod mods, con
put_pc_target_buttons(me, last_darkened);
}
}
// Cute trick now... if a target is needed, caster can always be picked
std::string targ = "target" + boost::lexical_cast<std::string>(pc_casting + 1);
if((store_spell_target == 6) && me[targ].isVisible()) {
bool any_targets = false;
for(int i = 0; i < 6; ++i){
std::string targ = "target" + boost::lexical_cast<std::string>(i + 1);
if(me[targ].isVisible()){
any_targets = true;
break;
}
}
if((store_spell_target == 6) && any_targets) {
me["feedback"].setText(choose_target);
draw_spell_info(me, store_situation, store_spell);
play_sound(45); // formerly force_play_sound
}
else if(!me[targ].isVisible()) {
else{
me["feedback"].setText("");
store_spell_target = 6;
put_pc_target_buttons(me, last_darkened);
}

View File

@@ -1133,6 +1133,8 @@ void use_item(short pc,short item) {
case SELECT_NO: break;
case SELECT_ACTIVE: store_spell_target = select_pc(eSelectPC::ONLY_LIVING); break;
case SELECT_ANY: store_spell_target = select_pc(eSelectPC::ANY); break;
case SELECT_DEAD: store_spell_target = select_pc(eSelectPC::ONLY_DEAD); break;
case SELECT_STONE: store_spell_target = select_pc(eSelectPC::ONLY_STONE); break;
}
if(overall_mode == MODE_COMBAT) {
bool priest = (*spell).is_priest();

View File

@@ -328,7 +328,7 @@ cSpell P_BLESS_PARTY = cSpell(eSpell::BLESS_PARTY).asType(eSkill::PRIEST_SPELLS)
cSpell P_HEAL_MAJOR = cSpell(eSpell::HEAL_MAJOR).asType(eSkill::PRIEST_SPELLS).asLevel(5)
.withCost(7).needsSelect().when(WHEN_COMBAT).when(WHEN_TOWN).when(WHEN_OUTDOORS).finish();
cSpell P_RAISE_DEAD = cSpell(eSpell::RAISE_DEAD).asType(eSkill::PRIEST_SPELLS).asLevel(5)
.withCost(25).needsSelect(SELECT_ANY).when(WHEN_TOWN).when(WHEN_OUTDOORS).finish();
.withCost(25).needsSelect(SELECT_DEAD).when(WHEN_TOWN).when(WHEN_OUTDOORS).finish();
cSpell P_FLAMESTRIKE = cSpell(eSpell::FLAMESTRIKE).asType(eSkill::PRIEST_SPELLS).asLevel(5)
.withRange(9).withTargetLock().withCost(8).withRefer(REFER_TARGET).when(WHEN_COMBAT).finish();
cSpell P_SANCTUARY_MASS = cSpell(eSpell::SANCTUARY_MASS).asType(eSkill::PRIEST_SPELLS).asLevel(5)
@@ -348,7 +348,7 @@ cSpell P_REVIVE = cSpell(eSpell::REVIVE).asType(eSkill::PRIEST_SPELLS).asLevel(6
cSpell P_HYPERACTIVITY = cSpell(eSpell::HYPERACTIVITY).asType(eSkill::PRIEST_SPELLS).asLevel(6)
.withCost(8).when(WHEN_COMBAT).when(WHEN_TOWN).when(WHEN_OUTDOORS).asPeaceful().finish();
cSpell P_DESTONE = cSpell(eSpell::DESTONE).asType(eSkill::PRIEST_SPELLS).asLevel(6)
.withCost(8).needsSelect(SELECT_ANY).when(WHEN_TOWN).when(WHEN_OUTDOORS).finish();
.withCost(8).needsSelect(SELECT_STONE).when(WHEN_TOWN).when(WHEN_OUTDOORS).finish();
cSpell P_SUMMON_GUARDIAN = cSpell(eSpell::SUMMON_GUARDIAN).asType(eSkill::PRIEST_SPELLS).asLevel(6)
.withRange(4).withCost(14).withRefer(REFER_TARGET).when(WHEN_COMBAT).when(WHEN_TOWN).finish();
// This is always centered on the caster:
@@ -366,7 +366,7 @@ cSpell P_REVIVE_ALL = cSpell(eSpell::REVIVE_ALL).asType(eSkill::PRIEST_SPELLS).a
cSpell P_RAVAGE_SPIRIT = cSpell(eSpell::RAVAGE_SPIRIT).asType(eSkill::PRIEST_SPELLS).asLevel(7)
.withRange(4).withTargetLock().withCost(10).withRefer(REFER_TARGET).when(WHEN_COMBAT).finish();
cSpell P_RESURRECT = cSpell(eSpell::RESURRECT).asType(eSkill::PRIEST_SPELLS).asLevel(7)
.withCost(35).needsSelect(SELECT_ANY).when(WHEN_TOWN).when(WHEN_OUTDOORS).finish();
.withCost(35).needsSelect(SELECT_DEAD).when(WHEN_TOWN).when(WHEN_OUTDOORS).finish();
cSpell P_DIVINE_THUD = cSpell(eSpell::DIVINE_THUD).asType(eSkill::PRIEST_SPELLS).asLevel(7)
.withRange(12).withTargetLock().withCost(10).withRefer(REFER_TARGET).when(WHEN_COMBAT).finish();
cSpell P_AVATAR = cSpell(eSpell::AVATAR).asType(eSkill::PRIEST_SPELLS).asLevel(7)

View File

@@ -16,7 +16,7 @@
// This controls how a spell is cast in combat; YES means it's the same as in town, IMMED means it has a special implementation in town, and TARGET / FANCY both mean it requires target selection.
enum eSpellRefer {REFER_YES, REFER_IMMED, REFER_TARGET, REFER_FANCY};
// This specifies whether a spell targets a party member and whether dead PCs can be chosen.
enum eSpellSelect {SELECT_NO, SELECT_ACTIVE, SELECT_ANY};
enum eSpellSelect {SELECT_NO, SELECT_ACTIVE, SELECT_ANY, SELECT_DEAD, SELECT_STONE};
// This one is meant for indexing a bit field
enum eSpellWhen {WHEN_COMBAT = 1, WHEN_TOWN = 2, WHEN_OUTDOORS = 4};