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:
2015-01-27 23:52:47 -05:00
parent ea0fbcffc8
commit 92a20b1c67
18 changed files with 396 additions and 57 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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