Fill in a lot of missed cases (mostly just messages)
- Increase strength of slayer weapons that weren't in the original BoE by making sure that each race applies some multiplier to the ability strength - Messages for every occasional status effect, both negative and positive. If charm/forcecage, ignore. - Fix weapon poison not being applied - Forcecage supported for damaging terrain (in town only, of course) and "affect status" items - Weapon poison supported for "affect status" items; it differs from "poison weapon" items in that it honours the magic use type and doesn't risk messing up (like the Envenom spell) - Show error messages when encountering an unimplemented spell or special node - Fix missing handling of NPCs appearing after town dies when loading a saved town
This commit is contained in:
@@ -848,24 +848,47 @@ short calc_spec_dam(eItemAbil abil,short abil_str,short abil_dat,iLiving& monst,
|
||||
return 0;
|
||||
store += abil_str;
|
||||
switch(eRace(abil_dat)) {
|
||||
case eRace::UNKNOWN:
|
||||
// This one shouldn't happen; it's a negative value, which the editor won't allow.
|
||||
// But just in case it does happen, we'll neutralize it.
|
||||
store = 0;
|
||||
break;
|
||||
case eRace::DEMON:
|
||||
case eRace::GIANT:
|
||||
case eRace::STONE:
|
||||
case eRace::DRAGON:
|
||||
store *= 8;
|
||||
break;
|
||||
case eRace::UNDEAD:
|
||||
store *= 6;
|
||||
break;
|
||||
case eRace::REPTILE:
|
||||
case eRace::BEAST:
|
||||
case eRace::BIRD:
|
||||
store *= 5;
|
||||
break;
|
||||
case eRace::MAGE:
|
||||
case eRace::PRIEST:
|
||||
case eRace::MAGICAL:
|
||||
store *= 4;
|
||||
break;
|
||||
case eRace::BUG:
|
||||
case eRace::PLANT:
|
||||
case eRace::SLIME:
|
||||
store *= 7;
|
||||
break;
|
||||
case eRace::HUMAN:
|
||||
case eRace::NEPHIL:
|
||||
case eRace::SLITH:
|
||||
case eRace::VAHNATAI:
|
||||
case eRace::HUMANOID:
|
||||
store *= 3;
|
||||
break;
|
||||
case eRace::IMPORTANT:
|
||||
// Part of the point of this "race" is to make them immune to slayer abilities.
|
||||
// However, a slayer ability made specifically for VIPs shouldn't be useless, either.
|
||||
store /= 2;
|
||||
break;
|
||||
}
|
||||
} else if(abil == eItemAbil::CAUSES_FEAR) {
|
||||
monst.scare(abil_str * 10);
|
||||
@@ -1227,6 +1250,9 @@ void do_combat_cast(location target) {
|
||||
if(!summon_monster(122,target,r2,2))
|
||||
add_string_to_buf(" Summon failed.");
|
||||
break;
|
||||
default:
|
||||
add_string_to_buf(" Error: Summoning spell " + (*spell_being_cast).name() + " not implemented for combat mode.", 4);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1409,6 +1435,9 @@ void do_combat_cast(location target) {
|
||||
}
|
||||
store_sound = 24;
|
||||
break;
|
||||
default:
|
||||
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,
|
||||
@@ -1906,7 +1935,8 @@ void combat_run_monst() {
|
||||
if(isStatusNegative(status))
|
||||
how_much *= -1;
|
||||
switch(status) {
|
||||
case eStatus::MAIN: break;
|
||||
case eStatus::MAIN: case eStatus::FORCECAGE: case eStatus::CHARM:
|
||||
continue; // Not valid in this context.
|
||||
case eStatus::HASTE_SLOW:
|
||||
if(how_much > 0) add_string_to_buf("An item hastes you!");
|
||||
else add_string_to_buf("An item slows you!");
|
||||
@@ -1925,7 +1955,7 @@ void combat_run_monst() {
|
||||
case eStatus::INVISIBLE:
|
||||
case eStatus::MARTYRS_SHIELD:
|
||||
if(how_much > 0) add_string_to_buf("An item protects you!");
|
||||
// TODO: Message for negative amounts:
|
||||
else add_string_to_buf("An item makes you vulnerable!");
|
||||
break;
|
||||
case eStatus::DISEASE:
|
||||
if(how_much > 0) add_string_to_buf("An item diseases you!");
|
||||
@@ -1936,9 +1966,50 @@ void combat_run_monst() {
|
||||
if(how_much > 0) add_string_to_buf("An item clouds your mind!");
|
||||
else if(univ.party[i].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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
add_string_to_buf("An item neutralizes the acid!");
|
||||
break;
|
||||
case eStatus::POISONED_WEAPON:
|
||||
if(how_much > 0) {
|
||||
if(univ.party[i].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;
|
||||
else continue;
|
||||
add_string_to_buf("An item poisons your weapon!");
|
||||
} else add_string_to_buf("An item augments your weapon poison!");
|
||||
} else add_string_to_buf("An item clears the poison from your weapon!");
|
||||
break;
|
||||
// TODO: Messages for other statuses?
|
||||
}
|
||||
// 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);
|
||||
update_stat = true;
|
||||
}
|
||||
@@ -2246,6 +2317,11 @@ void do_monster_turn() {
|
||||
break;
|
||||
pick_abil = abil;
|
||||
break;
|
||||
// Non-missile abilities
|
||||
case eMonstAbil::ABSORB_SPELLS: case eMonstAbil::DEATH_TRIGGER: case eMonstAbil::HIT_TRIGGER:
|
||||
case eMonstAbil::MARTYRS_SHIELD: case eMonstAbil::NO_ABIL: case eMonstAbil::RADIATE:
|
||||
case eMonstAbil::SPECIAL: case eMonstAbil::SPLITS: case eMonstAbil::SUMMON:
|
||||
continue;
|
||||
}
|
||||
if(pick_abil.second.active) break;
|
||||
}
|
||||
@@ -2641,6 +2717,7 @@ void monster_attack(short who_att,iLiving* target) {
|
||||
case eMonstAbil::FIELD: break; // TODO: Invent messages?
|
||||
case eMonstAbil::DAMAGE: case eMonstAbil::DAMAGE2:
|
||||
switch(abil.second.gen.dmg) {
|
||||
case eDamageType::MARKED: break; // Invalid
|
||||
case eDamageType::FIRE: add_string_to_buf(" Burning touch!"); break;
|
||||
case eDamageType::COLD: add_string_to_buf(" Freezing touch!"); break;
|
||||
case eDamageType::MAGIC: add_string_to_buf(" Shocking touch!"); break;
|
||||
@@ -2649,6 +2726,7 @@ void monster_attack(short who_att,iLiving* target) {
|
||||
case eDamageType::WEAPON: add_string_to_buf(" Drains stamina!"); break;
|
||||
case eDamageType::UNDEAD: add_string_to_buf(" Chilling touch!"); break;
|
||||
case eDamageType::DEMON: add_string_to_buf(" Unholy touch!"); break;
|
||||
case eDamageType::SPECIAL: add_string_to_buf(" Assassinates!"); break;
|
||||
}
|
||||
break;
|
||||
case eMonstAbil::STATUS2:
|
||||
@@ -2656,6 +2734,7 @@ void monster_attack(short who_att,iLiving* target) {
|
||||
if(i > 0) continue;
|
||||
case eMonstAbil::STATUS:
|
||||
switch(abil.second.gen.stat) {
|
||||
case eStatus::MAIN: continue; // Invalid
|
||||
case eStatus::POISON: add_string_to_buf(" Poisonous!"); break;
|
||||
case eStatus::DISEASE: add_string_to_buf(" Causes disease!"); break;
|
||||
case eStatus::DUMB: add_string_to_buf(" Dumbfounds!"); break;
|
||||
@@ -2665,8 +2744,21 @@ void monster_attack(short who_att,iLiving* target) {
|
||||
case eStatus::ACID: add_string_to_buf(" Acid touch!"); break;
|
||||
case eStatus::HASTE_SLOW: add_string_to_buf(" Slowing touch!"); break;
|
||||
case eStatus::BLESS_CURSE: add_string_to_buf(" Cursing touch!"); break;
|
||||
case eStatus::CHARM: if(m_target == nullptr) continue; else add_string_to_buf(" Charming touch!"); break;
|
||||
case eStatus::FORCECAGE: add_string_to_buf(" Entrapping touch!"); break;
|
||||
case eStatus::INVISIBLE: add_string_to_buf(" Revealing touch!"); break;
|
||||
case eStatus::INVULNERABLE: add_string_to_buf(" Piercing touch!"); break;
|
||||
case eStatus::MAGIC_RESISTANCE: add_string_to_buf(" Overwhelming touch!"); break;
|
||||
case eStatus::MARTYRS_SHIELD: add_string_to_buf(" Anti-martyr's touch!"); break;
|
||||
case eStatus::POISONED_WEAPON: add_string_to_buf(" Poison-draining touch!"); break;
|
||||
}
|
||||
break;
|
||||
// Non-touch abilities
|
||||
case eMonstAbil::MISSILE: case eMonstAbil::MISSILE_WEB: case eMonstAbil::RAY_HEAT:
|
||||
case eMonstAbil::ABSORB_SPELLS: case eMonstAbil::DEATH_TRIGGER: case eMonstAbil::HIT_TRIGGER:
|
||||
case eMonstAbil::MARTYRS_SHIELD: case eMonstAbil::NO_ABIL: case eMonstAbil::RADIATE:
|
||||
case eMonstAbil::SPECIAL: case eMonstAbil::SPLITS: case eMonstAbil::SUMMON:
|
||||
continue;
|
||||
}
|
||||
if(snd > 0) play_sound(snd);
|
||||
print_buf();
|
||||
@@ -3038,6 +3130,12 @@ void monst_basic_abil(short m_num, std::pair<eMonstAbil,uAbility> abil, iLiving*
|
||||
}
|
||||
place_spell_pattern(pat, targ_space, abil.second.gen.fld, 7);
|
||||
break;
|
||||
// Non-basic abilities
|
||||
case eMonstAbil::MISSILE: case eMonstAbil::MISSILE_WEB: case eMonstAbil::RAY_HEAT:
|
||||
case eMonstAbil::ABSORB_SPELLS: case eMonstAbil::DEATH_TRIGGER: case eMonstAbil::HIT_TRIGGER:
|
||||
case eMonstAbil::MARTYRS_SHIELD: case eMonstAbil::NO_ABIL: case eMonstAbil::RADIATE:
|
||||
case eMonstAbil::SPECIAL: case eMonstAbil::SPLITS: case eMonstAbil::SUMMON:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3394,6 +3492,9 @@ bool monst_cast_mage(cCreature *caster,short targ) {
|
||||
case eSpell::SHOCKWAVE:
|
||||
do_shockwave(caster->cur_loc);
|
||||
break;
|
||||
default:
|
||||
add_string_to_buf(" Error: Mage spell " + (*spell).name() + " not implemented for monsters.", 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else caster->mp++;
|
||||
@@ -3651,6 +3752,9 @@ bool monst_cast_priest(cCreature *caster,short targ) {
|
||||
case eSpell::HEAL: r1 = get_ran(3,1,6); break;
|
||||
case eSpell::HEAL_MAJOR: r1 = get_ran(5,1,6) + 3; break;
|
||||
case eSpell::HEAL_ALL: r1 = 50; break;
|
||||
default:
|
||||
add_string_to_buf(" Error: Healing spell " + (*spell).name() + " not implemented for monsters.", 4);
|
||||
break;
|
||||
}
|
||||
caster->heal(r1);
|
||||
break;
|
||||
@@ -3697,6 +3801,9 @@ bool monst_cast_priest(cCreature *caster,short targ) {
|
||||
place_spell_pattern(radius2,target,eDamageType::MAGIC,r1,7 );
|
||||
ashes_loc = target;
|
||||
break;
|
||||
default:
|
||||
add_string_to_buf(" Error: Priest spell " + (*spell).name() + " not implemented for monsters.", 4);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -3981,6 +4088,9 @@ static void place_spell_pattern(effect_pat_type pat,location center,unsigned sho
|
||||
} else if(effect > 330 && effect <= 360) {
|
||||
type = eDamageType::DEMON;
|
||||
dice = effect - 330;
|
||||
} else if(effect > 370 && effect <= 400) {
|
||||
type = eDamageType::SPECIAL;
|
||||
dice = effect - 370;
|
||||
}
|
||||
if(type == eDamageType::MARKED) break;
|
||||
r1 = get_ran(dice,1,6);
|
||||
@@ -4071,6 +4181,9 @@ static void place_spell_pattern(effect_pat_type pat,location center,unsigned sho
|
||||
} else if(effect > 330 && effect <= 360) {
|
||||
type = eDamageType::DEMON;
|
||||
dice = effect - 330;
|
||||
} else if(effect > 370 && effect <= 400) {
|
||||
type = eDamageType::SPECIAL;
|
||||
dice = effect - 370;
|
||||
}
|
||||
if(type == eDamageType::MARKED) break;
|
||||
r1 = get_ran(dice,1,6);
|
||||
@@ -4105,6 +4218,10 @@ void place_spell_pattern(effect_pat_type pat,location center,eDamageType type,sh
|
||||
case eDamageType::UNBLOCKABLE: code = 250; break;
|
||||
case eDamageType::UNDEAD: code = 290; break;
|
||||
case eDamageType::DEMON: code = 330; break;
|
||||
case eDamageType::SPECIAL: code = 370; break;
|
||||
case eDamageType::MARKED:
|
||||
// Not valid; do nothing.
|
||||
return;
|
||||
}
|
||||
place_spell_pattern(pat, center, code + dice, who_hit);
|
||||
}
|
||||
@@ -4487,7 +4604,7 @@ void combat_immed_mage_cast(short current_pc, eSpell spell_num, bool freebie) {
|
||||
switch(spell_num) {
|
||||
case eSpell::ENVENOM:
|
||||
c_line += " receives venom.";
|
||||
poison_weapon(target,3 + bonus,1);
|
||||
poison_weapon(target,3 + bonus,true);
|
||||
store_m_type = 11;
|
||||
break;
|
||||
|
||||
@@ -4524,7 +4641,7 @@ void combat_immed_mage_cast(short current_pc, eSpell spell_num, bool freebie) {
|
||||
if(univ.party[i].main_status == eMainStatus::ALIVE) {
|
||||
univ.party[i].slow(-(spell_num == eSpell::HASTE_MAJOR ? 1 + univ.party[current_pc].level / 8 + bonus : 3 + bonus));
|
||||
if(spell_num == eSpell::BLESS_MAJOR) {
|
||||
poison_weapon(i,2,1);
|
||||
poison_weapon(i,2,true);
|
||||
univ.party[i].curse(-4);
|
||||
add_missile(univ.party[i].combat_pos,14,0,0,0);
|
||||
}
|
||||
@@ -4551,6 +4668,9 @@ void combat_immed_mage_cast(short current_pc, eSpell spell_num, bool freebie) {
|
||||
case eSpell::RAVAGE_ENEMIES: add_string_to_buf(" Enemy ravaged:"); break;
|
||||
case eSpell::FEAR_GROUP: add_string_to_buf(" Enemy scared:"); break;
|
||||
case eSpell::PARALYSIS_MASS: add_string_to_buf(" Enemy paralyzed:"); break;
|
||||
default:
|
||||
add_string_to_buf(" Error: Mage group spell " + (*spell_num).name() + " not implemented for combat mode.", 4);
|
||||
break;
|
||||
}
|
||||
for(i = 0; i < univ.town.monst.size(); i++) {
|
||||
if((univ.town.monst[i].active != 0) && (univ.town.monst[i].attitude % 2 == 1)
|
||||
@@ -4573,6 +4693,7 @@ void combat_immed_mage_cast(short current_pc, eSpell spell_num, bool freebie) {
|
||||
which_m->sleep(eStatus::PARALYZED,1000,15);
|
||||
store_m_type = 15;
|
||||
break;
|
||||
default: break; // Silence compiler warning
|
||||
}
|
||||
num_opp++;
|
||||
add_missile(univ.town.monst[i].cur_loc,store_m_type,0,
|
||||
@@ -4585,6 +4706,9 @@ void combat_immed_mage_cast(short current_pc, eSpell spell_num, bool freebie) {
|
||||
case eSpell::BLADE_AURA: // Pyhrrus effect
|
||||
place_spell_pattern(radius2,univ.party[current_pc].combat_pos,WALL_BLADES,6);
|
||||
break;
|
||||
default:
|
||||
add_string_to_buf(" Error: Mage spell " + (*spell_num).name() + " not implemented for combat mode.", 4);
|
||||
break;
|
||||
}
|
||||
if(num_opp < 10)
|
||||
do_missile_anim((num_opp < 5) ? 50 : 25,univ.party[current_pc].combat_pos,store_sound);
|
||||
@@ -4727,6 +4851,9 @@ void combat_immed_priest_cast(short current_pc, eSpell spell_num, bool freebie)
|
||||
which_m->disease(3 + bonus);
|
||||
store_m_type = 0;
|
||||
break;
|
||||
default:
|
||||
add_string_to_buf(" Error: Priest group spell " + (*spell_num).name() + " not implemented for combat mode.", 4);
|
||||
break;
|
||||
}
|
||||
num_opp++;
|
||||
add_missile(univ.town.monst[i].cur_loc,store_m_type,0,
|
||||
@@ -4743,6 +4870,9 @@ void combat_immed_priest_cast(short current_pc, eSpell spell_num, bool freebie)
|
||||
add_string_to_buf(" Protective field created.");
|
||||
place_spell_pattern(protect_pat,univ.party[current_pc].combat_pos,6);
|
||||
break;
|
||||
default:
|
||||
add_string_to_buf(" Error: Priest spell " + (*spell_num).name() + " not implemented for combat mode.", 4);
|
||||
break;
|
||||
}
|
||||
if(num_opp < 10)
|
||||
do_missile_anim((num_opp < 5) ? 50 : 25,univ.party[current_pc].combat_pos,store_sound);
|
||||
@@ -4801,6 +4931,11 @@ void start_spell_targeting(eSpell num, bool freebie, int spell_range, eSpellPat
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if((*num).refer == REFER_TARGET)
|
||||
std::cout << " Warning: Spell " << (*num).name() << " didn't assign target shape." << std::endl;
|
||||
else add_string_to_buf(" Error: Entered targeting for non-targeted spell " + (*num).name(), 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4869,6 +5004,11 @@ void start_fancy_spell_targeting(eSpell num, bool freebie, int spell_range, eSpe
|
||||
case PAT_WALL: current_pat = single; break; // Fancy targeting doesn't support the rotateable pattern
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if((*num).refer == REFER_FANCY)
|
||||
std::cout << " Warning: Spell " << (*num).name() << " didn't assign target shape and count." << std::endl;
|
||||
else add_string_to_buf(" Error: Entered fancy targeting for non-fancy-targeted spell " + (*num).name(), 4);
|
||||
break;
|
||||
}
|
||||
|
||||
num_targets_left = minmax(1,8,num_targets_left);
|
||||
@@ -4882,11 +5022,12 @@ void spell_cast_hit_return() {
|
||||
}
|
||||
}
|
||||
|
||||
static void process_force_cage(location loc, short i) {
|
||||
void process_force_cage(location loc, short i, short adjust) {
|
||||
if(!univ.town.is_force_cage(loc.x,loc.y)) return;
|
||||
if(i >= 100) {
|
||||
short m = i - 100;
|
||||
cCreature& which_m = univ.town.monst[m];
|
||||
if(which_m.attitude % 2 == 1 && get_ran(1,1,100) < which_m.mu * 10 + which_m.cl * 4 + 5) {
|
||||
if(which_m.attitude % 2 == 1 && get_ran(1,1,100) < which_m.mu * 10 + which_m.cl * 4 + 5 + adjust) {
|
||||
// TODO: This sound is not right
|
||||
play_sound(60);
|
||||
which_m.spell_note(50);
|
||||
@@ -4900,7 +5041,7 @@ static void process_force_cage(location loc, short i) {
|
||||
cPlayer& who = univ.party[i];
|
||||
// We want to make sure everyone has a chance of eventually breaking a cage, because it never ends on its own,
|
||||
// and because being trapped unconditionally prevents you from ending combat mode.
|
||||
short bonus = 5 + who.skill(eSkill::MAGE_LORE);
|
||||
short bonus = 5 + who.skill(eSkill::MAGE_LORE) + adjust;
|
||||
if(get_ran(1,1,100) < who.skill(eSkill::MAGE_SPELLS)*10 + who.skill(eSkill::PRIEST_SPELLS)*4 + bonus) {
|
||||
play_sound(60);
|
||||
add_string_to_buf(" " + who.name + " breaks force cage.");
|
||||
|
@@ -60,6 +60,7 @@ void start_spell_targeting(eSpell num, bool freebie = false, int spell_range = 4
|
||||
void start_fancy_spell_targeting(eSpell num, bool freebie = false, int spell_range = 4, eSpellPat pat = PAT_SINGLE, int targets = 1);
|
||||
void spell_cast_hit_return();
|
||||
void process_fields();
|
||||
void process_force_cage(location loc, short i, short bonus = 0);
|
||||
void scloud_space(short m,short n);
|
||||
void web_space(short m,short n);
|
||||
void sleep_cloud_space(short m,short n);
|
||||
|
@@ -218,6 +218,7 @@ void handle_sale(cShopItem item, int i) {
|
||||
size_t size_before = active_shop.size();
|
||||
|
||||
switch(item.type) {
|
||||
case eShopItemType::EMPTY: break; // Invalid
|
||||
case eShopItemType::ITEM:
|
||||
switch(univ.party[current_pc].ok_to_buy(cost,base_item)) {
|
||||
case eBuyStatus::OK:
|
||||
@@ -260,7 +261,9 @@ void handle_sale(cShopItem item, int i) {
|
||||
univ.party.food += base_item.item_level;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
case eShopItemType::HEAL_WOUNDS: case eShopItemType::REMOVE_CURSE: case eShopItemType::CURE_DUMBFOUNDING:
|
||||
case eShopItemType::CURE_POISON: case eShopItemType::CURE_DISEASE: case eShopItemType::CURE_PARALYSIS:
|
||||
case eShopItemType::DESTONE: case eShopItemType::RAISE_DEAD: case eShopItemType::RESURRECT:
|
||||
if(!take_gold(cost,false))
|
||||
ASB("Not enough gold.");
|
||||
else {
|
||||
@@ -291,6 +294,7 @@ void handle_sale(cShopItem item, int i) {
|
||||
case eShopItemType::CURE_DUMBFOUNDING:
|
||||
univ.party[current_pc].status[eStatus::DUMB] = 0;
|
||||
break;
|
||||
default: break; // Silence compiler warning
|
||||
}
|
||||
// Once you've been healed, of course you're no longer eligible for that form of healing.
|
||||
active_shop.clearItem(i);
|
||||
@@ -370,6 +374,7 @@ void handle_info_request(cShopItem item) {
|
||||
cItem base_item = item.item;
|
||||
|
||||
switch(item.type) {
|
||||
case eShopItemType::EMPTY: break;
|
||||
case eShopItemType::ITEM:
|
||||
case eShopItemType::FOOD:
|
||||
display_pc_item(6,0, base_item,0);
|
||||
@@ -387,6 +392,10 @@ void handle_info_request(cShopItem item) {
|
||||
case eShopItemType::SKILL:
|
||||
display_skills(eSkill(base_item.item_level), nullptr);
|
||||
break;
|
||||
case eShopItemType::HEAL_WOUNDS: case eShopItemType::REMOVE_CURSE: case eShopItemType::CURE_DUMBFOUNDING:
|
||||
case eShopItemType::CURE_POISON: case eShopItemType::CURE_DISEASE: case eShopItemType::CURE_PARALYSIS:
|
||||
case eShopItemType::DESTONE: case eShopItemType::RAISE_DEAD: case eShopItemType::RESURRECT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -663,9 +663,7 @@ short check_party_stat(eSkill which_stat, short mode) {
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
//short safe; // 1 - always succeeds
|
||||
bool poison_weapon( short pc_num, short how_much,short safe) {
|
||||
bool poison_weapon(short pc_num, short how_much,bool safe) {
|
||||
short i,weap = 24,p_level,r1;
|
||||
short p_chance[21] = {
|
||||
40,72,81,85,88,89,90,
|
||||
@@ -688,7 +686,7 @@ bool poison_weapon( short pc_num, short how_much,short safe) {
|
||||
// Nimble?
|
||||
if(univ.party[pc_num].traits[eTrait::NIMBLE])
|
||||
r1 -= 6;
|
||||
if((r1 > p_chance[univ.party[pc_num].skill(eSkill::POISON)]) && (safe == 0)) {
|
||||
if(r1 > p_chance[univ.party[pc_num].skill(eSkill::POISON)] && !safe) {
|
||||
add_string_to_buf(" Poison put on badly.");
|
||||
p_level = p_level / 2;
|
||||
r1 = get_ran(1,1,100);
|
||||
@@ -697,10 +695,10 @@ bool poison_weapon( short pc_num, short how_much,short safe) {
|
||||
univ.party[pc_num].status[eStatus::POISON] += p_level;
|
||||
}
|
||||
}
|
||||
if(safe != 1)
|
||||
if(!safe)
|
||||
play_sound(55);
|
||||
univ.party[pc_num].weap_poisoned = weap;
|
||||
max (univ.party[pc_num].status[eStatus::POISON], p_level);
|
||||
univ.party[pc_num].status[eStatus::POISONED_WEAPON] = max(univ.party[pc_num].status[eStatus::POISONED_WEAPON], p_level);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -997,6 +995,9 @@ void do_mage_spell(short pc_num,eSpell spell_num,bool freebie) {
|
||||
add_string_to_buf(" " + univ.party[target].name + " protected.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
add_string_to_buf(" Error: Mage spell " + (*spell_num).name() + " not implemented for town mode.", 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1218,6 +1219,9 @@ void do_priest_spell(short pc_num,eSpell spell_num,bool freebie) {
|
||||
univ.party[target].status[eStatus::DISEASE] = 0;
|
||||
univ.party[target].status[eStatus::WEBS] = 0;
|
||||
break;
|
||||
default:
|
||||
add_string_to_buf(" Error: Healing spell " + (*spell_num).name() + " not implemented for town mode.", 4);
|
||||
break;
|
||||
}
|
||||
add_string_to_buf(sout.str());
|
||||
}
|
||||
@@ -1369,6 +1373,9 @@ void do_priest_spell(short pc_num,eSpell spell_num,bool freebie) {
|
||||
case eSpell::SANCTUARY_MASS: add_string_to_buf(" Party hidden.");break;
|
||||
case eSpell::CLEANSE_MAJOR: add_string_to_buf(" Party cleansed.");break;
|
||||
case eSpell::HYPERACTIVITY: add_string_to_buf(" Party is now really, REALLY awake.");break;
|
||||
default:
|
||||
add_string_to_buf(" Error: Priest group spell " + (*spell_num).name() + " not implemented for town mode.", 4);
|
||||
break;
|
||||
}
|
||||
|
||||
for(i = 0; i < 6; i++)
|
||||
@@ -1394,7 +1401,7 @@ void do_priest_spell(short pc_num,eSpell spell_num,bool freebie) {
|
||||
break;
|
||||
|
||||
default:
|
||||
add_string_to_buf(" Error: Spell not implemented for town.", 4);
|
||||
add_string_to_buf(" Error: Priest spell " + (*spell_num).name() + " not implemented for town mode.", 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1542,6 +1549,9 @@ void cast_town_spell(location where) {
|
||||
else add_string_to_buf(" No barrier there.");
|
||||
|
||||
break;
|
||||
default:
|
||||
add_string_to_buf(" Error: Spell " + (*town_spell).name() + " not implemented for town mode.", 4);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -13,7 +13,7 @@ void award_party_xp(short amt);
|
||||
void award_xp(short pc_num,short amt);
|
||||
void drain_pc(short which_pc,short how_much);
|
||||
short check_party_stat(eSkill which_stat, short mode);
|
||||
bool poison_weapon( short pc_num, short how_much,short safe);
|
||||
bool poison_weapon( short pc_num, short how_much,bool safe);
|
||||
bool is_poisonable_weap(short pc_num,short item);
|
||||
void cast_spell(eSkill type);
|
||||
bool repeat_cast_ok(eSkill type);
|
||||
|
@@ -279,6 +279,15 @@ bool check_special_terrain(location where_check,eSpecCtx mode,cPlayer& which_pc,
|
||||
}
|
||||
|
||||
switch(ter_special) {
|
||||
// First, put the specials that aren't activated on moving into the space here.
|
||||
// This is to silence compiler warnings while still preserving the warning if a new special is added.
|
||||
case eTerSpec::NONE: case eTerSpec::BRIDGE: case eTerSpec::BED:
|
||||
case eTerSpec::UNUSED1: case eTerSpec::CRUMBLING: case eTerSpec::LOCKABLE:
|
||||
case eTerSpec::UNUSED2: case eTerSpec::IS_A_SIGN: case eTerSpec::UNUSED3:
|
||||
case eTerSpec::IS_A_CONTAINER: case eTerSpec::WATERFALL_CAVE: case eTerSpec::WATERFALL_SURFACE:
|
||||
case eTerSpec::CONVEYOR: case eTerSpec::BLOCKED_TO_MONSTERS: case eTerSpec::TOWN_ENTRANCE:
|
||||
case eTerSpec::CHANGE_WHEN_USED: case eTerSpec::CALL_SPECIAL_WHEN_USED:
|
||||
break;
|
||||
case eTerSpec::CHANGE_WHEN_STEP_ON:
|
||||
alter_space(where_check.x,where_check.y,ter_flag1.u);
|
||||
if(ter_flag2.u < 200) {
|
||||
@@ -403,6 +412,11 @@ bool check_special_terrain(location where_check,eSpecCtx mode,cPlayer& which_pc,
|
||||
case eStatus::ACID: // Should say "Your skin tingles pleasantly." / "Your skin burns!"?
|
||||
univ.party[i].acid(ter_flag1.u);
|
||||
break;
|
||||
case eStatus::FORCECAGE:
|
||||
if(is_out()) break;
|
||||
univ.party[i].sleep(eStatus::FORCECAGE,ter_flag1.u,ter_flag1.u / 2);
|
||||
// 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
|
||||
break;
|
||||
}
|
||||
@@ -636,10 +650,24 @@ void use_item(short pc,short item) {
|
||||
|
||||
switch(abil) {
|
||||
case eItemAbil::POISON_WEAPON: // poison weapon
|
||||
take_charge = poison_weapon(pc,str,0);
|
||||
take_charge = poison_weapon(pc,str,false);
|
||||
break;
|
||||
case eItemAbil::AFFECT_STATUS:
|
||||
switch(status) {
|
||||
case eStatus::MAIN: case eStatus::CHARM:
|
||||
// These don't make any sense in this context.
|
||||
break;
|
||||
case eStatus::POISONED_WEAPON:
|
||||
if(the_item.abil_harms()) {
|
||||
ASB(" Weapon poison lost.");
|
||||
if(the_item.abil_group())
|
||||
univ.party.apply_status(eStatus::POISONED_WEAPON,-str);
|
||||
else univ.party[pc].apply_status(eStatus::POISONED_WEAPON,-str);
|
||||
} else if(the_item.abil_group()) {
|
||||
for(i = 0; i < 6; i++)
|
||||
take_charge = take_charge || poison_weapon(i,str,true);
|
||||
} else take_charge = poison_weapon(pc,str,true);
|
||||
break;
|
||||
case eStatus::BLESS_CURSE:
|
||||
play_sound(4);
|
||||
if(the_item.abil_harms()) {
|
||||
@@ -836,6 +864,23 @@ void use_item(short pc,short item) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case eStatus::FORCECAGE:
|
||||
switch(type) {
|
||||
case eItemUse::HELP_ONE:
|
||||
process_force_cage(univ.party[pc].get_loc(), pc, str);
|
||||
break;
|
||||
case eItemUse::HARM_ONE:
|
||||
univ.party[pc].sleep(eStatus::FORCECAGE, str, str / 2);
|
||||
break;
|
||||
case eItemUse::HELP_ALL:
|
||||
for(i = 0; i < 6; i++)
|
||||
process_force_cage(univ.party[i].get_loc(), i, str);
|
||||
break;
|
||||
case eItemUse::HARM_ALL:
|
||||
univ.party.sleep(eStatus::FORCECAGE, str, str / 2);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case eItemAbil::BLISS_DOOM:
|
||||
switch(type) {
|
||||
@@ -1101,6 +1146,23 @@ void use_item(short pc,short item) {
|
||||
add_string_to_buf("Fire pours out!");
|
||||
univ.town.set_quickfire(user_loc.x,user_loc.y,true);
|
||||
break;
|
||||
// Now for all the non-usable abilities. These are enumerated here so that the compiler can catch if we've missed one.
|
||||
case eItemAbil::ACCURACY: case eItemAbil::ANTIMAGIC_WEAPON: case eItemAbil::ASPTONGUE: case eItemAbil::BOOST_MAGIC:
|
||||
case eItemAbil::BOOST_STAT: case eItemAbil::BOOST_WAR: case eItemAbil::CAUSES_FEAR: case eItemAbil::COMFREY:
|
||||
case eItemAbil::DAMAGE_PROTECTION: case eItemAbil::DAMAGING_WEAPON: case eItemAbil::DISTANCE_MISSILE:
|
||||
case eItemAbil::DRAIN_MISSILES: case eItemAbil::EMBERF: case eItemAbil::ENCUMBERING: case eItemAbil::EVASION:
|
||||
case eItemAbil::EXPLODING_WEAPON: case eItemAbil::FREE_ACTION: case eItemAbil::FULL_PROTECTION: case eItemAbil::WILL:
|
||||
case eItemAbil::GIANT_STRENGTH: case eItemAbil::GRAYMOLD: case eItemAbil::HEALING_WEAPON: case eItemAbil::HEAVIER_OBJECT:
|
||||
case eItemAbil::HIT_CALL_SPECIAL: case eItemAbil::HOLLY: case eItemAbil::LIFE_SAVING: case eItemAbil::LIGHTER_OBJECT:
|
||||
case eItemAbil::LOCKPICKS: case eItemAbil::MANDRAKE: case eItemAbil::MARTYRS_SHIELD: case eItemAbil::MELEE_PROTECTION:
|
||||
case eItemAbil::NETTLE: case eItemAbil::NONE: case eItemAbil::OCCASIONAL_STATUS: case eItemAbil::POISON_AUGMENT:
|
||||
case eItemAbil::PROTECT_FROM_PETRIFY: case eItemAbil::PROTECT_FROM_SPECIES: case eItemAbil::RADIANT:
|
||||
case eItemAbil::REGENERATE: case eItemAbil::RESURRECTION_BALM: case eItemAbil::RETURNING_MISSILE: case eItemAbil::SAPPHIRE:
|
||||
case eItemAbil::SEEKING_MISSILE: case eItemAbil::SKILL: case eItemAbil::SLAYER_WEAPON: case eItemAbil::SLOW_WEARER:
|
||||
case eItemAbil::SMOKY_CRYSTAL: case eItemAbil::SOULSUCKER: case eItemAbil::SPEED: case eItemAbil::STATUS_PROTECTION:
|
||||
case eItemAbil::STATUS_WEAPON: case eItemAbil::THIEVING: case eItemAbil::WEAK_WEAPON: case eItemAbil::WEAPON_CALL_SPECIAL:
|
||||
case eItemAbil::WORMGRASS: case eItemAbil::UNUSED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2349,6 +2411,9 @@ void general_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
|
||||
start_talk_mode(i, spec.ex1a, spec.ex1b, spec.pic);
|
||||
*next_spec = -1;
|
||||
break;
|
||||
default:
|
||||
giveError("Special node type \"" + (*cur_node.type).name() + "\" is either miscategorized or unimplemented!");
|
||||
break;
|
||||
}
|
||||
if(check_mess) {
|
||||
handle_message(which_mode,cur_spec_type,cur_node.m1,cur_node.m2,a,b);
|
||||
@@ -2533,6 +2598,9 @@ void oneshot_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
giveError("Special node type \"" + (*cur_node.type).name() + "\" is either miscategorized or unimplemented!");
|
||||
break;
|
||||
}
|
||||
if(check_mess) {
|
||||
handle_message(which_mode,cur_spec_type,cur_node.m1,cur_node.m2,a,b);
|
||||
@@ -2975,6 +3043,9 @@ void affect_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
|
||||
univ.party[pc_num].skills[eSkill::INTELLIGENCE] = spec.ex2c;
|
||||
current_pc_picked_in_spec_enc = &univ.get_target(pc_num);
|
||||
break;
|
||||
default:
|
||||
giveError("Special node type \"" + (*cur_node.type).name() + "\" is either miscategorized or unimplemented!");
|
||||
break;
|
||||
}
|
||||
if(check_mess) {
|
||||
handle_message(which_mode,cur_spec_type,cur_node.m1,cur_node.m2,a,b);
|
||||
@@ -3531,6 +3602,9 @@ void ifthen_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
|
||||
if((spec.ex1b == -1 && univ.party.in_horse >= 0) || spec.ex1b == univ.party.in_horse)
|
||||
*next_spec = spec.ex1c;
|
||||
break;
|
||||
default:
|
||||
giveError("Special node type \"" + (*cur_node.type).name() + "\" is either miscategorized or unimplemented!");
|
||||
break;
|
||||
}
|
||||
if(check_mess) {
|
||||
handle_message(which_mode,cur_spec_type,cur_node.m1,cur_node.m2,a,b);
|
||||
@@ -4041,6 +4115,9 @@ void townmode_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
|
||||
end_missile_anim();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
giveError("Special node type \"" + (*cur_node.type).name() + "\" is either miscategorized or unimplemented!");
|
||||
break;
|
||||
}
|
||||
if(check_mess) {
|
||||
handle_message(which_mode,cur_spec_type,cur_node.m1,cur_node.m2,a,b);
|
||||
@@ -4181,6 +4258,9 @@ void rect_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
|
||||
make_explored(l.x, l.y);
|
||||
else take_explored(l.x, l.y);
|
||||
break;
|
||||
default:
|
||||
giveError("Special node type \"" + (*cur_node.type).name() + "\" is either miscategorized or unimplemented!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
END:
|
||||
@@ -4223,6 +4303,9 @@ void outdoor_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
|
||||
*redraw = 1;
|
||||
*a = 1;
|
||||
break;
|
||||
default:
|
||||
giveError("Special node type \"" + (*cur_node.type).name() + "\" is either miscategorized or unimplemented!");
|
||||
break;
|
||||
}
|
||||
|
||||
if(check_mess) {
|
||||
|
@@ -399,6 +399,9 @@ void place_buy_button(short position,short pc_num,short item_num) {
|
||||
val_to_place = max(aug_cost[shop_identify_cost] * 100,univ.party[pc_num].items[item_num].value * (5 + aug_cost[shop_identify_cost]));
|
||||
}
|
||||
break;
|
||||
case MODE_INVEN: case MODE_SHOP:
|
||||
// These modes don't have buy buttons, so we shouldn't get here; bail out!
|
||||
return;
|
||||
}
|
||||
if(item_area_button_active[position][5]) {
|
||||
store_selling_values[position] = val_to_place;
|
||||
|
@@ -205,6 +205,7 @@ void start_town_mode(short which_town, short entry_dir) {
|
||||
// These should have protected status (i.e. spec1 >= 200, spec1 <= 204)
|
||||
for(j = 0; j < univ.town.monst.size(); j++) {
|
||||
switch(univ.town.monst[j].time_flag){
|
||||
case eMonstTime::ALWAYS: break; // Nothing to do.
|
||||
case eMonstTime::SOMETIMES_A: case eMonstTime::SOMETIMES_B: case eMonstTime::SOMETIMES_C:
|
||||
if((calc_day() % 3) + 3 != int(univ.town.monst[i].time_flag))
|
||||
univ.town.monst[j].active = 0;
|
||||
@@ -242,6 +243,16 @@ void start_town_mode(short which_town, short entry_dir) {
|
||||
univ.town.monst[j].time_flag = eMonstTime::ALWAYS;
|
||||
}
|
||||
break;
|
||||
case eMonstTime::APPEAR_AFTER_CHOP:
|
||||
// TODO: Should these two cases be separated?
|
||||
if(univ.town->town_chop_time > 0 && day_reached(univ.town->town_chop_time,univ.town->town_chop_key))
|
||||
univ.town.monst[i].active += 10;
|
||||
else if(univ.party.m_killed[univ.town.num] > univ.town->max_num_monst)
|
||||
univ.town.monst[i].active += 10;
|
||||
else univ.town.monst[i].active = 0;
|
||||
if(univ.town.monst[i].active >= 10)
|
||||
univ.town.monst[i].time_flag = eMonstTime::ALWAYS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,6 +403,7 @@ void start_town_mode(short which_town, short entry_dir) {
|
||||
|
||||
// Not use the items data flags, starting with forcing an ability
|
||||
if(univ.town->preset_items[i].ability >= 0) {
|
||||
// TODO: What other ways might there be to use this?
|
||||
switch(univ.town.items[j].variety) {
|
||||
case eItemType::ONE_HANDED:
|
||||
case eItemType::TWO_HANDED: {
|
||||
@@ -404,6 +416,7 @@ void start_town_mode(short which_town, short entry_dir) {
|
||||
univ.town.items[j].enchant_weapon(eEnchant(ench), val);
|
||||
break;
|
||||
}
|
||||
default: break; // Silence compiler warning
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -909,33 +909,28 @@ void cItem::append(legacy::item_record_type& old){
|
||||
enchanted = false;
|
||||
unsellable = old.item_properties & 16;
|
||||
// Set missile, if needed
|
||||
switch(variety) {
|
||||
case eItemType::ARROW:
|
||||
case eItemType::BOLTS:
|
||||
missile = magic ? 4 : 3;
|
||||
break;
|
||||
case eItemType::MISSILE_NO_AMMO:
|
||||
// Just assume it's a sling and use the rock missile.
|
||||
missile = 12;
|
||||
break;
|
||||
case eItemType::THROWN_MISSILE:
|
||||
// This is tricky... basically, all we can really do is guess.
|
||||
// And the only way to guess is by examining the item's name
|
||||
// We'll use the unidentified name since it's more likely to contain the appropriate generic words
|
||||
auto npos = std::string::npos;
|
||||
// Okay, that failed. Try examining the item's name.
|
||||
if(name.find("Knife") != npos) missile = 10;
|
||||
// Unidentified name limit was quite short, so the S might've been cut off
|
||||
else if(name.find("Knive") != npos) missile = 10;
|
||||
else if(name.find("Spear") != npos) missile = 5;
|
||||
else if(name.find("Javelin") != npos) missile = 5;
|
||||
else if(name.find("Razordisk") != npos) missile = 7;
|
||||
else if(name.find("Star") != npos) missile = 7;
|
||||
else if(name.find("Dart") != npos) missile = 1;
|
||||
else if(name.find("Rock") != npos) missile = 12;
|
||||
// Okay, give up. Fall back to darts since we have no idea what's correct.
|
||||
else missile = 1;
|
||||
break;
|
||||
if(variety == eItemType::ARROW || variety == eItemType::BOLTS) {
|
||||
missile = magic ? 4 : 3;
|
||||
} else if(variety == eItemType::MISSILE_NO_AMMO) {
|
||||
// Just assume it's a sling and use the rock missile.
|
||||
missile = 12;
|
||||
} else if(variety == eItemType::THROWN_MISSILE) {
|
||||
// This is tricky... basically, all we can really do is guess.
|
||||
// And the only way to guess is by examining the item's name
|
||||
// We'll use the unidentified name since it's more likely to contain the appropriate generic words
|
||||
auto npos = std::string::npos;
|
||||
// Okay, that failed. Try examining the item's name.
|
||||
if(name.find("Knife") != npos) missile = 10;
|
||||
// Unidentified name limit was quite short, so the S might've been cut off
|
||||
else if(name.find("Knive") != npos) missile = 10;
|
||||
else if(name.find("Spear") != npos) missile = 5;
|
||||
else if(name.find("Javelin") != npos) missile = 5;
|
||||
else if(name.find("Razordisk") != npos) missile = 7;
|
||||
else if(name.find("Star") != npos) missile = 7;
|
||||
else if(name.find("Dart") != npos) missile = 1;
|
||||
else if(name.find("Rock") != npos) missile = 12;
|
||||
// Okay, give up. Fall back to darts since we have no idea what's correct.
|
||||
else missile = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -944,6 +939,7 @@ std::string cItem::getAbilName() const {
|
||||
bool party = abil_group();
|
||||
std::ostringstream sout;
|
||||
switch(ability) {
|
||||
case eItemAbil::UNUSED: break; // Invalid
|
||||
case eItemAbil::NONE: sout << "No ability"; break;
|
||||
case eItemAbil::HEALING_WEAPON: sout << "Heals target"; break;
|
||||
case eItemAbil::RETURNING_MISSILE: sout << "Returning missile"; break;
|
||||
@@ -1003,6 +999,7 @@ std::string cItem::getAbilName() const {
|
||||
case eDamageType::UNDEAD: sout << "Necrotic"; break;
|
||||
case eDamageType::DEMON: sout << "Unholy"; break;
|
||||
case eDamageType::UNBLOCKABLE: sout << "Dark"; break;
|
||||
case eDamageType::SPECIAL: sout << "Assassin's"; break;
|
||||
case eDamageType::MARKED: break; // Invalid
|
||||
}
|
||||
sout << " Weapon";
|
||||
@@ -1044,17 +1041,17 @@ std::string cItem::getAbilName() const {
|
||||
case eDamageType::UNBLOCKABLE: sout << "in darkness"; break;
|
||||
case eDamageType::UNDEAD: sout.str("Implodes"); break;
|
||||
case eDamageType::DEMON: sout << "into corruption"; break;
|
||||
case eDamageType::SPECIAL: sout << "into energy"; break;
|
||||
case eDamageType::MARKED: break; // Invalid
|
||||
}
|
||||
break;
|
||||
case eItemAbil::STATUS_WEAPON:
|
||||
switch(eStatus(abil_data[1])) {
|
||||
case eStatus::MAIN: break; // Invalid
|
||||
case eStatus::POISONED_WEAPON:
|
||||
case eStatus::INVULNERABLE:
|
||||
case eStatus::MAGIC_RESISTANCE:
|
||||
case eStatus::INVISIBLE:
|
||||
break; // TODO: Not implemented?
|
||||
case eStatus::POISONED_WEAPON: sout << "Poison-draining"; break;
|
||||
case eStatus::INVULNERABLE: sout << "Piercing"; break;
|
||||
case eStatus::MAGIC_RESISTANCE: sout << "Overwhelming"; break;
|
||||
case eStatus::INVISIBLE: sout << "Anti-sanctuary"; break;
|
||||
case eStatus::ACID: sout << "Acidic"; break;
|
||||
case eStatus::POISON: sout << "Poisoned"; break;
|
||||
case eStatus::BLESS_CURSE: sout << "Cursing"; break;
|
||||
@@ -1080,6 +1077,7 @@ std::string cItem::getAbilName() const {
|
||||
case eDamageType::UNDEAD: sout << "Undead"; break;
|
||||
case eDamageType::POISON: sout << "Poison"; break;
|
||||
case eDamageType::UNBLOCKABLE: sout << "Darkness"; break;
|
||||
case eDamageType::SPECIAL: sout << "Assassin's"; break;
|
||||
case eDamageType::MARKED: break; // Invalid
|
||||
}
|
||||
sout << " Protection";
|
||||
@@ -1087,14 +1085,14 @@ std::string cItem::getAbilName() const {
|
||||
case eItemAbil::STATUS_PROTECTION:
|
||||
sout << "Protect From ";
|
||||
switch(eStatus(abil_data[1])) {
|
||||
case eStatus::MAIN: break; // Invalid;
|
||||
case eStatus::MAIN: break; // Invalid
|
||||
case eStatus::POISONED_WEAPON:
|
||||
case eStatus::INVULNERABLE:
|
||||
case eStatus::MARTYRS_SHIELD:
|
||||
case eStatus::FORCECAGE:
|
||||
case eStatus::CHARM:
|
||||
case eStatus::INVISIBLE:
|
||||
break; // TODO: Not implemented:
|
||||
break; // These have no negative aspect, so protection from them isn't implemented
|
||||
case eStatus::POISON: sout << "Poison"; break;
|
||||
case eStatus::ACID: sout << "Acid"; break;
|
||||
case eStatus::DISEASE: sout << "Disease"; break;
|
||||
@@ -1113,9 +1111,9 @@ std::string cItem::getAbilName() const {
|
||||
case eItemAbil::OCCASIONAL_STATUS:
|
||||
sout << "Occasional ";
|
||||
switch(eStatus(abil_data[1])) {
|
||||
case eStatus::MAIN: break; // Invalid;
|
||||
case eStatus::MAIN: break; // Invalid
|
||||
case eStatus::FORCECAGE:
|
||||
case eStatus::CHARM:
|
||||
case eStatus::CHARM: // Doesn't affect PCs
|
||||
break; // TODO: Not implemented?
|
||||
case eStatus::DISEASE: sout << (harmful ? "Disease" : "Cure Disease"); break;
|
||||
case eStatus::HASTE_SLOW: sout << (harmful ? "Slow" : "Haste"); break;
|
||||
@@ -1163,8 +1161,8 @@ std::string cItem::getAbilName() const {
|
||||
case eItemAbil::AFFECT_STATUS:
|
||||
switch(eStatus(abil_data[1])) {
|
||||
case eStatus::MAIN: break; // Invalid;
|
||||
case eStatus::FORCECAGE: break;
|
||||
case eStatus::CHARM: break;
|
||||
case eStatus::FORCECAGE: sout << (harmful ? "Entrapping" : "Cage Break"); break;
|
||||
case eStatus::CHARM: break; // TODO: Not implemented
|
||||
case eStatus::POISONED_WEAPON: sout << (harmful ? "Increase" : "Decrease") << " Weapon Poison"; break;
|
||||
case eStatus::BLESS_CURSE: sout << (harmful ? "Curse" : "Bless"); break;
|
||||
case eStatus::POISON: sout << (harmful ? "Cause" : "Cure") << " Poison"; break;
|
||||
|
@@ -691,7 +691,6 @@ std::istream& operator >> (std::istream& in, eMonstSummon& e) {
|
||||
|
||||
std::string uAbility::to_string(eMonstAbil key) const {
|
||||
std::ostringstream sout;
|
||||
short i = 0;
|
||||
switch(getMonstAbilCategory(key)){
|
||||
case eMonstAbilCat::INVALID: break;
|
||||
case eMonstAbilCat::MISSILE:
|
||||
@@ -733,6 +732,9 @@ std::string uAbility::to_string(eMonstAbil key) const {
|
||||
case eMonstAbil::STEAL_GOLD: sout << "Steals gold!"; break;
|
||||
case eMonstAbil::FIELD:
|
||||
switch(gen.fld) {
|
||||
case eFieldType::SPECIAL_EXPLORED:
|
||||
case eFieldType::SPECIAL_SPOT:
|
||||
break; // These are invalid field types
|
||||
case eFieldType::CLOUD_SLEEP: sout << "Sleep"; break;
|
||||
case eFieldType::CLOUD_STINK: sout << "Foul"; break;
|
||||
case eFieldType::WALL_FIRE: sout << "Fiery"; break;
|
||||
@@ -742,6 +744,18 @@ std::string uAbility::to_string(eMonstAbil key) const {
|
||||
case eFieldType::FIELD_ANTIMAGIC: sout << "Null"; break;
|
||||
case eFieldType::FIELD_WEB: sout << "Web"; break;
|
||||
case eFieldType::FIELD_QUICKFIRE: sout << "Incendiary"; break;
|
||||
case eFieldType::BARRIER_CAGE: sout << "Entrapping"; break;
|
||||
case eFieldType::BARRIER_FIRE: case eFieldType::BARRIER_FORCE: sout << "Barrier"; break;
|
||||
case eFieldType::FIELD_DISPEL: sout << "Dispelling"; break;
|
||||
case eFieldType::FIELD_SMASH: sout << "Smashing"; break;
|
||||
case eFieldType::OBJECT_BARREL: sout << "Barrel"; break;
|
||||
case eFieldType::OBJECT_BLOCK: sout << "Stone Block"; break;
|
||||
case eFieldType::OBJECT_CRATE: sout << "Crate"; break;
|
||||
case eFieldType::SFX_ASH: case eFieldType::SFX_BONES: case eFieldType::SFX_RUBBLE:
|
||||
case eFieldType::SFX_SMALL_BLOOD: case eFieldType::SFX_MEDIUM_BLOOD: case eFieldType::SFX_LARGE_BLOOD:
|
||||
case eFieldType::SFX_SMALL_SLIME: case eFieldType::SFX_LARGE_SLIME:
|
||||
sout << "Littering";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case eMonstAbil::DAMAGE: case eMonstAbil::DAMAGE2:
|
||||
@@ -754,10 +768,13 @@ std::string uAbility::to_string(eMonstAbil key) const {
|
||||
case eDamageType::WEAPON: sout << "Stamina drain"; break;
|
||||
case eDamageType::DEMON: sout << "Unholy"; break;
|
||||
case eDamageType::UNDEAD: sout << "Necrotic"; break;
|
||||
case eDamageType::SPECIAL: sout << "Assassinating"; break;
|
||||
case eDamageType::MARKED: break; // Invalid
|
||||
}
|
||||
break;
|
||||
case eMonstAbil::STATUS: case eMonstAbil::STATUS2:
|
||||
switch(gen.stat) {
|
||||
case eStatus::MAIN: break; // Invalid
|
||||
case eStatus::POISON: sout << "Poison"; break;
|
||||
case eStatus::DISEASE: sout << "Infectious"; break;
|
||||
case eStatus::DUMB: sout << "Dumbfounding"; break;
|
||||
@@ -767,6 +784,13 @@ std::string uAbility::to_string(eMonstAbil key) const {
|
||||
case eStatus::ACID: sout << "Acid"; break;
|
||||
case eStatus::HASTE_SLOW: sout << "Slowing"; break;
|
||||
case eStatus::BLESS_CURSE: sout << "Curse"; break;
|
||||
case eStatus::CHARM: sout << "Charming"; break;
|
||||
case eStatus::FORCECAGE: sout << "Entrapping"; break;
|
||||
case eStatus::INVISIBLE: sout << "Revealing"; break;
|
||||
case eStatus::INVULNERABLE: sout << "Piercing"; break;
|
||||
case eStatus::MAGIC_RESISTANCE: sout << "Overwhelming"; break;
|
||||
case eStatus::MARTYRS_SHIELD: sout << "Anti-martyr's"; break;
|
||||
case eStatus::POISONED_WEAPON: sout << "Poison-draining"; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -827,8 +851,15 @@ std::string uAbility::to_string(eMonstAbil key) const {
|
||||
break;
|
||||
case eMonstAbil::SPECIAL:
|
||||
case eMonstAbil::DEATH_TRIGGER:
|
||||
case eMonstAbil::HIT_TRIGGER:
|
||||
sout << "Unusual ability";
|
||||
break;
|
||||
// Non-special abilities
|
||||
case eMonstAbil::STUN: case eMonstAbil::NO_ABIL: case eMonstAbil::RADIATE: case eMonstAbil::SUMMON:
|
||||
case eMonstAbil::DAMAGE: case eMonstAbil::DAMAGE2: case eMonstAbil::DRAIN_SP: case eMonstAbil::DRAIN_XP:
|
||||
case eMonstAbil::FIELD: case eMonstAbil::KILL: case eMonstAbil::MISSILE: case eMonstAbil::PETRIFY:
|
||||
case eMonstAbil::STATUS: case eMonstAbil::STATUS2: case eMonstAbil::STEAL_FOOD: case eMonstAbil::STEAL_GOLD:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case eMonstAbilCat::SUMMON:
|
||||
@@ -838,6 +869,9 @@ std::string uAbility::to_string(eMonstAbil key) const {
|
||||
case eMonstAbilCat::RADIATE:
|
||||
sout << "Radiates ";
|
||||
switch(radiate.type) {
|
||||
case eFieldType::SPECIAL_EXPLORED:
|
||||
case eFieldType::SPECIAL_SPOT:
|
||||
break; // These are invalid field types
|
||||
case eFieldType::WALL_BLADES: sout << "blade fields"; break;
|
||||
case eFieldType::WALL_FIRE: sout << "fire fields"; break;
|
||||
case eFieldType::WALL_FORCE: sout << "shock fields"; break;
|
||||
@@ -846,6 +880,19 @@ std::string uAbility::to_string(eMonstAbil key) const {
|
||||
case eFieldType::CLOUD_SLEEP: sout << "sleep fields"; break;
|
||||
case eFieldType::FIELD_ANTIMAGIC: sout << "antimagic fields"; break;
|
||||
case eFieldType::FIELD_WEB: sout << "webs"; break;
|
||||
case eFieldType::FIELD_QUICKFIRE: sout << "quickfire"; break;
|
||||
case eFieldType::BARRIER_CAGE: sout << "forcecages"; break;
|
||||
case eFieldType::BARRIER_FIRE: case eFieldType::BARRIER_FORCE: sout << "barriers"; break;
|
||||
case eFieldType::FIELD_DISPEL: sout.str("Dispels surrounding fields"); break;
|
||||
case eFieldType::FIELD_SMASH: sout.str("Wall-smashing aura");; break;
|
||||
case eFieldType::OBJECT_BARREL: sout << "barrels"; break;
|
||||
case eFieldType::OBJECT_BLOCK: sout << "stone blocks"; break;
|
||||
case eFieldType::OBJECT_CRATE: sout << "crates"; break;
|
||||
case eFieldType::SFX_ASH: case eFieldType::SFX_BONES: case eFieldType::SFX_RUBBLE:
|
||||
case eFieldType::SFX_SMALL_BLOOD: case eFieldType::SFX_MEDIUM_BLOOD: case eFieldType::SFX_LARGE_BLOOD:
|
||||
case eFieldType::SFX_SMALL_SLIME: case eFieldType::SFX_LARGE_SLIME:
|
||||
sout << "litter";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@@ -404,6 +404,10 @@ void cPlayer::finish_create() {
|
||||
items[0] = cItem('nife');
|
||||
items[1] = cItem('rdsk');
|
||||
break;
|
||||
default: break; // Silence compiler warning
|
||||
// It's impossible to reach this point, anyway.
|
||||
// The only way to get a PC of other races is with the Create PC node,
|
||||
// which doesn't call this.
|
||||
}
|
||||
equip[0] = true;
|
||||
equip[1] = true;
|
||||
|
@@ -125,6 +125,7 @@ enum class eStatus {
|
||||
|
||||
inline bool isStatusNegative(eStatus stat) {
|
||||
switch(stat) {
|
||||
case eStatus::MAIN: return false;
|
||||
case eStatus::POISONED_WEAPON: return false;
|
||||
case eStatus::BLESS_CURSE: return false;
|
||||
case eStatus::POISON: return true;
|
||||
|
@@ -155,6 +155,10 @@ void cCurTown::place_preset_fields() {
|
||||
case SFX_RUBBLE:
|
||||
set_rubble(record()->preset_fields[i].loc.x,record()->preset_fields[i].loc.y,true);
|
||||
break;
|
||||
// The rest can't be preset, but enumerate them in case a new field is added.
|
||||
case FIELD_DISPEL: case FIELD_SMASH: case SPECIAL_EXPLORED: case CLOUD_SLEEP: case CLOUD_STINK:
|
||||
case FIELD_ANTIMAGIC: case WALL_BLADES: case WALL_FIRE: case WALL_FORCE: case WALL_ICE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
|
||||
#include "dialog.hpp"
|
||||
#include "graphtool.hpp"
|
||||
@@ -530,6 +531,11 @@ void cButton::setBtnType(eBtnType newType){
|
||||
frame.width() = 30;
|
||||
frame.height() = 30;
|
||||
break;
|
||||
case BTN_TINY:
|
||||
case BTN_LED:
|
||||
frame.width() = std::min<int>(frame.width(), 14);
|
||||
frame.height() = std::min<int>(frame.height(), 10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1040,6 +1040,7 @@ static bool edit_monst_abil_detail(cDialog& me, std::string hit, cMonster& monst
|
||||
case eMonstAbilTemplate::BREATH_DARKNESS:
|
||||
param = get_monst_abil_num("Breath weapon strength:", 0, 4, me);
|
||||
break;
|
||||
default: break; // None of the other templates take parameters
|
||||
}
|
||||
// Protect from overwriting an existing ability.
|
||||
auto save_abils = monst.abil;
|
||||
|
@@ -164,6 +164,11 @@ static short get_small_icon(ter_num_t ter){
|
||||
case eDamageType::DEMON:
|
||||
icon = 19;
|
||||
break;
|
||||
case eDamageType::SPECIAL:
|
||||
// TODO: Need icon for this and possibly new icons for undead/demon
|
||||
break;
|
||||
case eDamageType::MARKED: // Invalid
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case eTerSpec::BRIDGE:
|
||||
@@ -206,6 +211,8 @@ static short get_small_icon(ter_num_t ter){
|
||||
case eStatus::ACID:
|
||||
icon = 41;
|
||||
break;
|
||||
case eStatus::FORCECAGE:
|
||||
// TODO: Need icon for this
|
||||
case eStatus::MAIN: case eStatus::CHARM:
|
||||
break; // Nothing to do here; these values are "magic" and should not be used
|
||||
}
|
||||
|
@@ -708,6 +708,9 @@ static bool edit_spec_enc_value(cDialog& me, std::string item_hit, node_stack_t&
|
||||
case eShopType::PRIEST: btn = 'P'; break;
|
||||
case eShopType::ALCHEMY: btn = 'a'; break;
|
||||
case eShopType::SKILLS: btn = 'k'; break;
|
||||
case eShopType::FOOD: case eShopType::HEALING: case eShopType::MAGIC_GOOD: case eShopType::MAGIC_GREAT:
|
||||
case eShopType::MAGIC_JUNK: case eShopType::MAGIC_LOUSY: case eShopType::MAGIC_SO_SO:
|
||||
break;
|
||||
}
|
||||
}
|
||||
short val = me[field].getTextAsNum(), mode = (btn == 'S' || btn == '$') ? 0 : edit_stack.top().mode, store;
|
||||
|
@@ -1053,6 +1053,9 @@ static bool save_talk_node(cDialog& me, std::string item_hit, std::stack<short>&
|
||||
case eTalkNode::DEP_ON_TOWN:
|
||||
if(cre(talk_node.extras[0],0,scenario.towns.size(),"Town number must be from 0 to " + std::to_string(scenario.towns.size()) + ".","",&me)) return false;
|
||||
break;
|
||||
case eTalkNode::BUY_TOWN_LOC:
|
||||
if(cre(talk_node.extras[1],0,scenario.towns.size(),"Town number must be from 0 to " + std::to_string(scenario.towns.size()) + ".","",&me)) return false;
|
||||
break;
|
||||
case eTalkNode::BUY_ITEMS: case eTalkNode::BUY_MAGE: case eTalkNode::BUY_PRIEST:
|
||||
case eTalkNode::BUY_ALCHEMY: case eTalkNode::BUY_HEALING:
|
||||
if(cre(talk_node.extras[0],0,6,"Cost adjustment must be from 0 (cheapest) to 6 (most expensive).","",&me)) return false;
|
||||
@@ -1076,6 +1079,11 @@ static bool save_talk_node(cDialog& me, std::string item_hit, std::stack<short>&
|
||||
case eTalkNode::CALL_SCEN_SPEC:
|
||||
if(cre(talk_node.extras[0],-1,255,"The scenario special node called must be in the legal range (0 - 255), or -1 for No Special.","",&me)) return false;
|
||||
break;
|
||||
case eTalkNode::BUY_INFO: case eTalkNode::BUY_JUNK: case eTalkNode::DEP_ON_TIME: case eTalkNode::REGULAR:
|
||||
case eTalkNode::END_ALARM: case eTalkNode::END_DIE: case eTalkNode::END_FIGHT: case eTalkNode::END_FORCE:
|
||||
case eTalkNode::IDENTIFY: case eTalkNode::SELL_ARMOR: case eTalkNode::SELL_ITEMS: case eTalkNode::SELL_WEAPONS:
|
||||
case eTalkNode::TRAINING:
|
||||
break;
|
||||
}
|
||||
|
||||
talk_node.str1 = me["str1"].getText();
|
||||
|
Reference in New Issue
Block a user