Several new item abilities and one new monster ability
- Range augment ability for missiles - Seeking ability for missiles (can strike an adjacent space if targeted space lacks a target, including chance of hitting invisible monsters) - Weapon that calls node when attacking with it (works both in range and melee; the cases can be distinguished by the node with IF_CONTEXT) - Armour that calls node when attacked while wearing (works both in range and melee; the cases can be distinguished by the node with IF_CONTEXT) - Monster ability that calls node when monster attacked (works both in range and melee; the cases can be distinguished by the node with IF_CONTEXT) - The above three only apply to non-magical attacks - some things don't trigger it, like spells, monster rays and breath weapons, possible a few others - Armour that protects from all melee damage (including demon/undead, though less) - Armour that decreases chance to be hit (both in range and melee, against non-magical attacks only) - Armour that behaves like to the martyr's shield effect but also has a chance of adding some extra bonus damage - Armour that's more encumbering than advertised (best for cursed items with concealed ability) - Multiple items with the accuracy ability now stack - Fix nephilim not getting their racial bonus to missile weapons - In specials called as part of an attack, the reserved pointer -20 contains the target in a form ready to pass to a SELECT_TARGET node, while -21 and -22 contain the location of the target. This includes the new cases added in this commit plus the monster ability to call a special node on its turn. It does not include specials called in the spell targeting context (to do so would break legacy scenarios), nor specials called after a targeting node. - If a PC is carrying more than their max weight, they gain encumbrance equal to one-tenth of the excess. - Add some missing context cases to IF_CONTEXT node
This commit is contained in:
@@ -788,10 +788,18 @@ void pc_attack_weapon(short who_att,short target,short hit_adj,short dam_adj,cIt
|
||||
}
|
||||
if((weap.ability == eItemAbil::STATUS_WEAPON) && (get_ran(1,0,1) == 1)) {
|
||||
apply_weapon_status(eStatus(weap.abil_data[1]), weap.abil_data[0], r2 + spec_dam, target + 100, "Blade");
|
||||
}
|
||||
if((weap.ability == eItemAbil::SOULSUCKER) && (get_ran(1,0,1) == 1)) {
|
||||
} else if(weap.ability == eItemAbil::SOULSUCKER && get_ran(1,0,1) == 1) {
|
||||
add_string_to_buf(" Blade drains life.");
|
||||
heal_pc(who_att,weap.abil_data[0] / 2);
|
||||
} else if(weap.ability == eItemAbil::WEAPON_CALL_SPECIAL) {
|
||||
short s1,s2,s3;
|
||||
univ.party.force_ptr(21, 301, 5);
|
||||
univ.party.force_ptr(22, 301, 6);
|
||||
univ.party.force_ptr(20, 301, 7);
|
||||
PSD[SDF_SPEC_TARGLOC_X] = which_m->cur_loc.x;
|
||||
PSD[SDF_SPEC_TARGLOC_Y] = which_m->cur_loc.y;
|
||||
PSD[SDF_SPEC_TARGET] = 100 + target; // ready to be passed to SELECT_TARGET node
|
||||
run_special(eSpecCtx::ATTACKING_MELEE, 0, weap.abil_data[0],univ.party[who_att].combat_pos, &s1, &s2, &s3);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1464,6 +1472,8 @@ void load_missile() {
|
||||
add_string_to_buf(" (Hit 's' to cancel.)");
|
||||
overall_mode = MODE_THROWING;
|
||||
current_spell_range = 8;
|
||||
if(univ.party[current_pc].items[thrown].ability == eItemAbil::DISTANCE_MISSILE)
|
||||
current_spell_range += univ.party[current_pc].items[thrown].abil_data[0];
|
||||
current_pat = single;
|
||||
}
|
||||
else if(((bolts < 24) && (bow < 24)) || ((arrow < 24) && (crossbow < 24))) {
|
||||
@@ -1482,6 +1492,8 @@ void load_missile() {
|
||||
add_string_to_buf("Fire: Select a target. ");
|
||||
add_string_to_buf(" (Hit 's' to cancel.)");
|
||||
current_spell_range = 12;
|
||||
if(univ.party[current_pc].items[arrow].ability == eItemAbil::DISTANCE_MISSILE)
|
||||
current_spell_range += univ.party[current_pc].items[arrow].abil_data[0];
|
||||
if(univ.party[current_pc].items[arrow].ability == eItemAbil::EXPLODING_WEAPON)
|
||||
current_pat = radius2;
|
||||
else
|
||||
@@ -1494,6 +1506,8 @@ void load_missile() {
|
||||
add_string_to_buf("Fire: Select a target. ");
|
||||
add_string_to_buf(" (Hit 's' to cancel.)");
|
||||
current_spell_range = 12;
|
||||
if(univ.party[current_pc].items[bolts].ability == eItemAbil::DISTANCE_MISSILE)
|
||||
current_spell_range += univ.party[current_pc].items[bolts].abil_data[0];
|
||||
current_pat = single;
|
||||
}
|
||||
else if(no_ammo < 24) {
|
||||
@@ -1503,6 +1517,8 @@ void load_missile() {
|
||||
add_string_to_buf("Fire: Select a target. ");
|
||||
add_string_to_buf(" (Hit 's' to cancel.)");
|
||||
current_spell_range = 12;
|
||||
if(univ.party[current_pc].items[no_ammo].ability == eItemAbil::DISTANCE_MISSILE)
|
||||
current_spell_range += univ.party[current_pc].items[no_ammo].abil_data[0];
|
||||
current_pat = single;
|
||||
}
|
||||
else add_string_to_buf("Fire: Equip a missile. ");
|
||||
@@ -1523,14 +1539,42 @@ void fire_missile(location target) {
|
||||
hit_bonus = univ.party[missile_firer].items[missile_inv_slot].bonus;
|
||||
hit_bonus += stat_adj(missile_firer,eSkill::DEXTERITY) - can_see_light(univ.party[missile_firer].combat_pos,target,sight_obscurity)
|
||||
+ minmax(-8,8,univ.party[missile_firer].status[eStatus::BLESS_CURSE]);
|
||||
if((skill_item = univ.party[missile_firer].has_abil_equip(eItemAbil::ACCURACY)) < 24) {
|
||||
hit_bonus += univ.party[missile_firer].items[skill_item].abil_data[0] / 2;
|
||||
dam_bonus += univ.party[missile_firer].items[skill_item].abil_data[0] / 2;
|
||||
skill_item = univ.party[missile_firer].get_prot_level(eItemAbil::ACCURACY) / 2;
|
||||
hit_bonus += skill_item;
|
||||
dam_bonus += skill_item;
|
||||
if(univ.party[missile_firer].items[ammo_inv_slot].ability == eItemAbil::SEEKING_MISSILE) {
|
||||
targ_monst = monst_there(target);
|
||||
std::set<int> targets;
|
||||
if(targ_monst >= univ.town->max_monst() || univ.town.monst[targ_monst].attitude % 2 == 0) {
|
||||
for(int i = -1; i <= 1; i++) {
|
||||
for(int j = -1; j <= 1; j++) {
|
||||
if(i == 0 && j == 0) continue;
|
||||
targ_monst = monst_there(loc(target.x + i, target.y + j));
|
||||
if(targ_monst < univ.town->max_monst()) {
|
||||
bool invisible = univ.town.monst[targ_monst].invisible;
|
||||
bool friendly = univ.town.monst[targ_monst].attitude % 2 == 0;
|
||||
int seek_chance = 10;
|
||||
if(invisible && friendly)
|
||||
seek_chance -= 8;
|
||||
else if(invisible)
|
||||
seek_chance -= 5;
|
||||
else if(friendly)
|
||||
seek_chance -= 9;
|
||||
if(get_ran(1,1,10) <= seek_chance)
|
||||
targets.insert(targ_monst);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!targets.empty()) {
|
||||
auto iter = targets.begin();
|
||||
std::advance(iter, get_ran(1,1,targets.size()) - 1);
|
||||
target = univ.town.monst[*iter].cur_loc;
|
||||
}
|
||||
} else hit_bonus += 10;
|
||||
}
|
||||
|
||||
// race adj.
|
||||
// TODO: Should this apply to sliths as well? The bladbase suggests otherwise, but it has been changed from the original; maybe the sliths were originally considered to be reptiles.
|
||||
if(univ.party[missile_firer].race == eRace::REPTILE)
|
||||
if(univ.party[missile_firer].race == eRace::NEPHIL)
|
||||
hit_bonus += 2;
|
||||
|
||||
if(univ.party[missile_firer].items[ammo_inv_slot].ability == eItemAbil::EXPLODING_WEAPON)
|
||||
@@ -1600,11 +1644,20 @@ void fire_missile(location target) {
|
||||
}
|
||||
if((missile.ability == eItemAbil::STATUS_WEAPON) && (get_ran(1,0,1) == 1)) {
|
||||
apply_weapon_status(eStatus(missile.abil_data[1]), missile.abil_data[0], r2 + spec_dam, targ_monst + 100, "Missile");
|
||||
}
|
||||
if((missile.ability == eItemAbil::SOULSUCKER) && (get_ran(1,0,1) == 1)) {
|
||||
} else if(missile.ability == eItemAbil::SOULSUCKER && get_ran(1,0,1) == 1) {
|
||||
add_string_to_buf(" Missile drains life.");
|
||||
heal_pc(missile_firer,missile.abil_data[0] / 2);
|
||||
}
|
||||
if(cur_monst->abil[eMonstAbil::HIT_TRIGGER].active) {
|
||||
short s1,s2,s3;
|
||||
univ.party.force_ptr(21, 301, 5);
|
||||
univ.party.force_ptr(22, 301, 6);
|
||||
univ.party.force_ptr(20, 301, 7);
|
||||
PSD[SDF_SPEC_TARGLOC_X] = cur_monst->cur_loc.x;
|
||||
PSD[SDF_SPEC_TARGLOC_Y] = cur_monst->cur_loc.y;
|
||||
PSD[SDF_SPEC_TARGET] = 100 + targ_monst; // ready to be passed to SELECT_TARGET node
|
||||
run_special(eSpecCtx::ATTACKED_RANGE, 0, cur_monst->abil[eMonstAbil::HIT_TRIGGER].special.extra1, univ.party[missile_firer].combat_pos, &s1, &s2, &s3);
|
||||
}
|
||||
} else if((targ_monst = pc_there(target)) < 6) {
|
||||
eDamageType dmg_tp = eDamageType::UNBLOCKABLE;
|
||||
cItem& missile = univ.party[missile_firer].items[ammo_inv_slot];
|
||||
@@ -1625,10 +1678,29 @@ void fire_missile(location target) {
|
||||
}
|
||||
if((missile.ability == eItemAbil::STATUS_WEAPON) && (get_ran(1,0,1) == 1)) {
|
||||
apply_weapon_status(eStatus(missile.abil_data[1]), missile.abil_data[0], r2 + spec_dam, targ_monst, "Missile");
|
||||
}
|
||||
if((missile.ability == eItemAbil::SOULSUCKER) && (get_ran(1,0,1) == 1)) {
|
||||
} else if(missile.ability == eItemAbil::SOULSUCKER && get_ran(1,0,1) == 1) {
|
||||
add_string_to_buf(" Missile drains life.");
|
||||
heal_pc(missile_firer,missile.abil_data[0] / 2);
|
||||
} else if(missile.ability == eItemAbil::WEAPON_CALL_SPECIAL) {
|
||||
short s1,s2,s3;
|
||||
univ.party.force_ptr(21, 301, 5);
|
||||
univ.party.force_ptr(22, 301, 6);
|
||||
univ.party.force_ptr(20, 301, 7);
|
||||
PSD[SDF_SPEC_TARGLOC_X] = univ.party[targ_monst].combat_pos.x;
|
||||
PSD[SDF_SPEC_TARGLOC_Y] = univ.party[targ_monst].combat_pos.y;
|
||||
PSD[SDF_SPEC_TARGET] = 11 + targ_monst; // ready to be passed to SELECT_TARGET node
|
||||
run_special(eSpecCtx::ATTACKING_RANGE, 0, missile.abil_data[0], univ.party[missile_firer].combat_pos, &s1, &s2, &s3);
|
||||
}
|
||||
int spec_item = univ.party[targ_monst].has_abil_equip(eItemAbil::HIT_CALL_SPECIAL);
|
||||
if(spec_item < 24) {
|
||||
short s1,s2,s3;
|
||||
univ.party.force_ptr(21, 301, 5);
|
||||
univ.party.force_ptr(22, 301, 6);
|
||||
univ.party.force_ptr(20, 301, 7);
|
||||
PSD[SDF_SPEC_TARGLOC_X] = univ.party[targ_monst].combat_pos.x;
|
||||
PSD[SDF_SPEC_TARGLOC_Y] = univ.party[targ_monst].combat_pos.y;
|
||||
PSD[SDF_SPEC_TARGET] = 11 + targ_monst; // ready to be passed to SELECT_TARGET node
|
||||
run_special(eSpecCtx::ATTACKED_RANGE, 0, univ.party[targ_monst].items[spec_item].abil_data[0], univ.party[missile_firer].combat_pos, &s1, &s2, &s3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2171,7 +2243,14 @@ void do_monster_turn() {
|
||||
uAbility abil = cur_monst->abil[eMonstAbil::SPECIAL];
|
||||
short s1, s2, s3;
|
||||
special_called = true;
|
||||
// TODO: Is it good to allow only one monster to use a special ability per combat round?
|
||||
univ.party.force_ptr(21, 301, 5);
|
||||
univ.party.force_ptr(22, 301, 6);
|
||||
univ.party.force_ptr(20, 301, 7);
|
||||
PSD[SDF_SPEC_TARGLOC_X] = targ_space.x;
|
||||
PSD[SDF_SPEC_TARGLOC_Y] = targ_space.y;
|
||||
if(target < 6)
|
||||
PSD[SDF_SPEC_TARGET] = 11 + target; // ready to be passed to SELECT_TARGET node
|
||||
else PSD[SDF_SPEC_TARGET] = target; // ready to be passed to SELECT_TARGET node
|
||||
run_special(eSpecCtx::MONST_SPEC_ABIL,0,abil.special.extra1,cur_monst->cur_loc,&s1,&s2,&s3);
|
||||
take_m_ap(abil.special.extra2,cur_monst);
|
||||
}
|
||||
@@ -2433,6 +2512,7 @@ void monster_attack_pc(short who_att,short target) {
|
||||
r1 = get_ran(1,1,100) - 5 * min(8,attacker->status[eStatus::BLESS_CURSE]) + 5 * univ.party[target].status[eStatus::BLESS_CURSE]
|
||||
+ 5 * stat_adj(target,eSkill::DEXTERITY) - 15;
|
||||
r1 += 5 * (attacker->status[eStatus::WEBS] / 3);
|
||||
r1 += univ.party[target].get_prot_level(eItemAbil::EVASION);
|
||||
if(univ.party[target].parry < 100)
|
||||
r1 += 5 * univ.party[target].parry;
|
||||
|
||||
@@ -2465,9 +2545,13 @@ void monster_attack_pc(short who_att,short target) {
|
||||
damaged_message(store_hp - univ.party[target].cur_health,
|
||||
attacker->a[i].type);
|
||||
|
||||
if(univ.party[target].status[eStatus::MARTYRS_SHIELD] > 0) {
|
||||
int martyr1 = univ.party[target].status[eStatus::MARTYRS_SHIELD];
|
||||
int martyr2 = univ.party[target].get_prot_level(eItemAbil::MARTYRS_SHIELD);
|
||||
if(martyr1 + martyr2 > 0) {
|
||||
int dmg = store_hp - univ.party[target].cur_health;
|
||||
if(get_ran(1,1,20) < martyr2) dmg += max(1, martyr2 / 5);
|
||||
add_string_to_buf(" Shares damage! ");
|
||||
damage_monst(who_att, 6, store_hp - univ.party[target].cur_health, 0, eDamageType::MAGIC,0);
|
||||
damage_monst(who_att, 6, dmg, 0, eDamageType::MAGIC,0);
|
||||
}
|
||||
|
||||
for(auto& abil : attacker->abil) {
|
||||
@@ -2521,6 +2605,18 @@ void monster_attack_pc(short who_att,short target) {
|
||||
if(snd > 0) play_sound(snd);
|
||||
monst_basic_abil(who_att, abil, target);
|
||||
}
|
||||
|
||||
int spec_item = univ.party[target].has_abil_equip(eItemAbil::HIT_CALL_SPECIAL);
|
||||
if(spec_item < 24) {
|
||||
short s1,s2,s3;
|
||||
univ.party.force_ptr(21, 301, 5);
|
||||
univ.party.force_ptr(22, 301, 6);
|
||||
univ.party.force_ptr(20, 301, 7);
|
||||
PSD[SDF_SPEC_TARGLOC_X] = univ.party[target].combat_pos.x;
|
||||
PSD[SDF_SPEC_TARGLOC_Y] = univ.party[target].combat_pos.y;
|
||||
PSD[SDF_SPEC_TARGET] = 11 + who_att; // ready to be passed to SELECT_TARGET node
|
||||
run_special(eSpecCtx::ATTACKED_MELEE, 0, univ.party[target].items[spec_item].abil_data[0], attacker->cur_loc, &s1, &s2, &s3);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -2644,6 +2740,17 @@ void monster_attack_monster(short who_att,short attackee) {
|
||||
monst_basic_abil(who_att, abil, attackee + 100);
|
||||
put_pc_screen();
|
||||
}
|
||||
|
||||
if(target->abil[eMonstAbil::HIT_TRIGGER].active) {
|
||||
short s1,s2,s3;
|
||||
univ.party.force_ptr(21, 301, 5);
|
||||
univ.party.force_ptr(22, 301, 6);
|
||||
univ.party.force_ptr(20, 301, 7);
|
||||
PSD[SDF_SPEC_TARGLOC_X] = target->cur_loc.x;
|
||||
PSD[SDF_SPEC_TARGLOC_Y] = target->cur_loc.y;
|
||||
PSD[SDF_SPEC_TARGET] = 100 + attackee; // ready to be passed to SELECT_TARGET node
|
||||
run_special(eSpecCtx::ATTACKED_MELEE, 0, target->abil[eMonstAbil::HIT_TRIGGER].special.extra1, attacker->cur_loc, &s1, &s2, &s3);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -2739,6 +2846,7 @@ void monst_fire_missile(short m_num,short bless,std::pair<eMonstAbil,uAbility> a
|
||||
int target_bless = target < 100 ? univ.party[target].status[eStatus::BLESS_CURSE] : m_target->status[eStatus::BLESS_CURSE];
|
||||
location target_pos = target < 100 ? univ.party[target].combat_pos : m_target->cur_loc;
|
||||
int r1 = get_ran(1,1,100) - 5 * min(10,bless) + 5 * target_bless - 5 * can_see_light(source, target_pos, sight_obscurity);
|
||||
r1 += univ.party[target].get_prot_level(eItemAbil::EVASION);
|
||||
if(univ.party[target].parry < 100)
|
||||
r1 += 5 * univ.party[target].parry;
|
||||
|
||||
@@ -2756,6 +2864,29 @@ void monst_fire_missile(short m_num,short bless,std::pair<eMonstAbil,uAbility> a
|
||||
if(target < 100) add_string_to_buf(" Misses " + univ.party[target].name + '.');
|
||||
else monst_spell_note(m_target->number,18);
|
||||
}
|
||||
if(target < 100) {
|
||||
int spec_item = univ.party[target].has_abil_equip(eItemAbil::HIT_CALL_SPECIAL);
|
||||
if(spec_item < 24) {
|
||||
short s1,s2,s3;
|
||||
// TODO: This force_ptr...run_special code is almost duplicated in several places; maybe make a call_attack_spec subroutine?
|
||||
univ.party.force_ptr(21, 301, 5);
|
||||
univ.party.force_ptr(22, 301, 6);
|
||||
univ.party.force_ptr(20, 301, 7);
|
||||
PSD[SDF_SPEC_TARGLOC_X] = univ.party[target].combat_pos.x;
|
||||
PSD[SDF_SPEC_TARGLOC_Y] = univ.party[target].combat_pos.y;
|
||||
PSD[SDF_SPEC_TARGET] = 11 + target; // ready to be passed to SELECT_TARGET node
|
||||
run_special(eSpecCtx::ATTACKED_RANGE, 0, univ.party[target].items[spec_item].abil_data[0], univ.town.monst[m_num].cur_loc, &s1, &s2, &s3);
|
||||
}
|
||||
} else if(m_target->abil[eMonstAbil::HIT_TRIGGER].active) {
|
||||
short s1,s2,s3;
|
||||
univ.party.force_ptr(21, 301, 5);
|
||||
univ.party.force_ptr(22, 301, 6);
|
||||
univ.party.force_ptr(20, 301, 7);
|
||||
PSD[SDF_SPEC_TARGLOC_X] = m_target->cur_loc.x;
|
||||
PSD[SDF_SPEC_TARGLOC_Y] = m_target->cur_loc.y;
|
||||
PSD[SDF_SPEC_TARGET] = target; // ready to be passed to SELECT_TARGET node
|
||||
run_special(eSpecCtx::ATTACKED_RANGE, 0, m_target->abil[eMonstAbil::HIT_TRIGGER].special.extra1, univ.town.monst[m_num].cur_loc, &s1, &s2, &s3);
|
||||
}
|
||||
} else if(abil.first == eMonstAbil::MISSILE_WEB) {
|
||||
if(target < 100) add_string_to_buf(" Throws web at " + univ.party[target].name + '.');
|
||||
else monst_spell_note(m_target->number, 58);
|
||||
|
@@ -28,6 +28,9 @@
|
||||
#define SDF_SPEC_TER 301][2
|
||||
#define SDF_SPEC_STRBUF 301][3
|
||||
#define SDF_SPEC_TRAPLVL 301][4
|
||||
#define SDF_SPEC_TARGLOC_X 301][5
|
||||
#define SDF_SPEC_TARGLOC_Y 301][6
|
||||
#define SDF_SPEC_TARGET 301][7
|
||||
#define SDF_SKIP_STARTUP 305][4 // preferably deprecated
|
||||
#define SDF_LESS_SOUND 305][5
|
||||
#define SDF_NO_TARGET_LINE 305][6
|
||||
|
@@ -1375,9 +1375,14 @@ void activate_monsters(short code,short /*attitude*/) {
|
||||
short get_encumberance(short pc_num) {
|
||||
short store = 0,i,what_val;
|
||||
|
||||
what_val = univ.party[pc_num].free_weight();
|
||||
if(what_val < 0) store += what_val / -10;
|
||||
|
||||
for(i = 0; i < 24; i++)
|
||||
if(univ.party[pc_num].equip[i]) {
|
||||
what_val = univ.party[pc_num].items[i].awkward;
|
||||
if(univ.party[pc_num].items[i].ability == eItemAbil::ENCUMBERING)
|
||||
what_val += univ.party[pc_num].items[i].abil_data[0];
|
||||
if(what_val == 1 && get_ran(1,0,130) < hit_chance[univ.party[pc_num].skill(eSkill::DEFENSE)])
|
||||
what_val--;
|
||||
if(what_val > 1 && get_ran(1,0,70) < hit_chance[univ.party[pc_num].skill(eSkill::DEFENSE)])
|
||||
|
@@ -2610,7 +2610,7 @@ bool damage_pc(short which_pc,short how_much,eDamageType damage_type,eRace type_
|
||||
// armor
|
||||
if(damage_type == eDamageType::WEAPON || damage_type == eDamageType::UNDEAD || damage_type == eDamageType::DEMON) {
|
||||
how_much -= minmax(-5,5,univ.party[which_pc].status[eStatus::BLESS_CURSE]);
|
||||
for(i = 0; i < 24; i++)
|
||||
for(i = 0; i < 24; i++) {
|
||||
if((univ.party[which_pc].items[i].variety != eItemType::NO_ITEM) && (univ.party[which_pc].equip[i])) {
|
||||
if(isArmourType(univ.party[which_pc].items[i].variety)) {
|
||||
r1 = get_ran(1,1,univ.party[which_pc].items[i].item_level);
|
||||
@@ -2638,6 +2638,15 @@ bool damage_pc(short which_pc,short how_much,eDamageType damage_type,eRace type_
|
||||
how_much += r1;
|
||||
}
|
||||
}
|
||||
if(univ.party[which_pc].items[i].ability == eItemAbil::MELEE_PROTECTION) {
|
||||
r1 = get_ran(1,1,univ.party[which_pc].items[i].abil_data[0]);
|
||||
if(damage_type == eDamageType::DEMON)
|
||||
how_much -= max(1,r1 / 5);
|
||||
else if(damage_type == eDamageType::UNDEAD)
|
||||
how_much -= max(1,r1 / 4);
|
||||
else how_much -= max(1,r1 / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parry
|
||||
|
@@ -1594,7 +1594,6 @@ void kill_monst(cCreature *which_m,short who_killed,eMainStatus type) {
|
||||
play_sound(29 + i);
|
||||
} else switch(which_m->m_type) {
|
||||
case eRace::GIANT: play_sound(29); break;
|
||||
// TODO: Should sliths be considered reptiles too? Check original bladbase.
|
||||
// TODO: Should birds be considered beasts? If there are any birds in the bladbase, probably; otherwise, better to have new sound
|
||||
case eRace::REPTILE: case eRace::BEAST: case eRace::DEMON: case eRace::UNDEAD: case eRace::STONE:
|
||||
i = get_ran(1,0,1); play_sound(31 + i); break;
|
||||
@@ -1932,8 +1931,14 @@ void run_special(eSpecCtx which_mode,short which_type,short start_spec,location
|
||||
}
|
||||
break;
|
||||
case eSpecCtx::KILL_MONST: case eSpecCtx::SEE_MONST: case eSpecCtx::MONST_SPEC_ABIL:
|
||||
// The monster is the target
|
||||
case eSpecCtx::ATTACKED_MELEE: case eSpecCtx::ATTACKING_MELEE:
|
||||
case eSpecCtx::ATTACKED_RANGE: case eSpecCtx::ATTACKING_RANGE:
|
||||
// The monster/PC on the trigger space is the target
|
||||
current_pc_picked_in_spec_enc = 100 + monst_there(spec_loc);
|
||||
if(current_pc_picked_in_spec_enc > univ.town->max_monst())
|
||||
current_pc_picked_in_spec_enc = pc_there(spec_loc);
|
||||
if(current_pc_picked_in_spec_enc == 6)
|
||||
current_pc_picked_in_spec_enc = -1;
|
||||
break;
|
||||
case eSpecCtx::TARGET: case eSpecCtx::USE_SPACE:
|
||||
// If there's a monster on the space, select that as the target
|
||||
@@ -3613,6 +3618,30 @@ void ifthen_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
|
||||
if(which_mode == eSpecCtx::SEE_MONST)
|
||||
*next_spec = spec.ex1c;
|
||||
break;
|
||||
case 19: // Monster using special ability
|
||||
if(which_mode == eSpecCtx::MONST_SPEC_ABIL)
|
||||
*next_spec = spec.ex1c;
|
||||
break;
|
||||
case 20: // Town goes hostile
|
||||
if(which_mode == eSpecCtx::TOWN_HOSTILE)
|
||||
*next_spec = spec.ex1c;
|
||||
break;
|
||||
case 21: // Item ability activated on attacking
|
||||
if(which_mode == eSpecCtx::ATTACKING_MELEE)
|
||||
*next_spec = spec.ex1c;
|
||||
break;
|
||||
case 22: // Item ability activated on attacking
|
||||
if(which_mode == eSpecCtx::ATTACKING_RANGE)
|
||||
*next_spec = spec.ex1c;
|
||||
break;
|
||||
case 23: // Item or monster ability activated on being hit
|
||||
if(which_mode == eSpecCtx::ATTACKED_MELEE)
|
||||
*next_spec = spec.ex1c;
|
||||
break;
|
||||
case 24: // Item or monster ability activated on being hit
|
||||
if(which_mode == eSpecCtx::ATTACKED_RANGE)
|
||||
*next_spec = spec.ex1c;
|
||||
break;
|
||||
// Past here are special values that don't have an equivalent in eSpecCtx.
|
||||
case 100: // Look (town or out)
|
||||
if(which_mode == eSpecCtx::OUT_LOOK || which_mode == eSpecCtx::TOWN_LOOK)
|
||||
|
@@ -295,9 +295,12 @@ std::map<eMonstAbil,uAbility>::iterator cMonster::addAbil(eMonstAbilTemplate wha
|
||||
case eMonstAbilTemplate::SPECIAL:
|
||||
abil[eMonstAbil::SPECIAL].special = {true, param, 1};
|
||||
return abil.find(eMonstAbil::SPECIAL);
|
||||
case eMonstAbilTemplate::HIT_TRIGGERS:
|
||||
abil[eMonstAbil::HIT_TRIGGER].special = {true, param, 0};
|
||||
return abil.find(eMonstAbil::HIT_TRIGGER);
|
||||
case eMonstAbilTemplate::DEATH_TRIGGERS:
|
||||
abil[eMonstAbil::DEATH_TRIGGER].special = {true, param, 0};
|
||||
return abil.find(eMonstAbil::SPECIAL);
|
||||
return abil.find(eMonstAbil::DEATH_TRIGGER);
|
||||
// Radiate abilities
|
||||
case eMonstAbilTemplate::RADIATE_FIRE:
|
||||
abil[eMonstAbil::RADIATE].radiate = {true, eFieldType::WALL_FIRE, param};
|
||||
|
@@ -38,7 +38,7 @@ enum class eMonstAbilTemplate {
|
||||
TOUCH_POISON, TOUCH_ACID, TOUCH_DISEASE, TOUCH_WEB, TOUCH_SLEEP, TOUCH_DUMB, TOUCH_PARALYSIS,
|
||||
TOUCH_PETRIFY, TOUCH_DEATH, TOUCH_XP_DRAIN, TOUCH_ICY, TOUCH_ICY_DRAINING, TOUCH_STUN, TOUCH_STEAL_FOOD, TOUCH_STEAL_GOLD,
|
||||
// Misc abilities
|
||||
SPLITS, MARTYRS_SHIELD, ABSORB_SPELLS, SUMMON_5, SUMMON_20, SUMMON_50, SPECIAL, DEATH_TRIGGERS,
|
||||
SPLITS, MARTYRS_SHIELD, ABSORB_SPELLS, SUMMON_5, SUMMON_20, SUMMON_50, SPECIAL, HIT_TRIGGERS, DEATH_TRIGGERS,
|
||||
// Radiate abilities
|
||||
RADIATE_FIRE, RADIATE_ICE, RADIATE_SHOCK, RADIATE_ANTIMAGIC, RADIATE_SLEEP, RADIATE_STINK, RADIATE_BLADE, RADIATE_WEB,
|
||||
// Advanced abilities
|
||||
|
@@ -162,6 +162,7 @@ enum class eMonstAbil {
|
||||
MISSILE_WEB,
|
||||
RAY_HEAT,
|
||||
SPECIAL,
|
||||
HIT_TRIGGER,
|
||||
DEATH_TRIGGER,
|
||||
|
||||
RADIATE,
|
||||
@@ -323,14 +324,21 @@ enum class eItemAbil {
|
||||
HEALING_WEAPON = 3,
|
||||
EXPLODING_WEAPON = 4,
|
||||
RETURNING_MISSILE = 5,
|
||||
DISTANCE_MISSILE = 6,
|
||||
SEEKING_MISSILE = 7,
|
||||
STATUS_WEAPON = 9,
|
||||
SOULSUCKER = 10,
|
||||
DRAIN_MISSILES = 11,
|
||||
WEAK_WEAPON = 12,
|
||||
CAUSES_FEAR = 13,
|
||||
WEAPON_CALL_SPECIAL = 14,
|
||||
// General abilities
|
||||
DAMAGE_PROTECTION = 30,
|
||||
FULL_PROTECTION = 31,
|
||||
MELEE_PROTECTION = 32,
|
||||
EVASION = 33,
|
||||
MARTYRS_SHIELD = 34,
|
||||
ENCUMBERING = 35,
|
||||
STATUS_PROTECTION = 36,
|
||||
SKILL = 37,
|
||||
BOOST_STAT = 38,
|
||||
@@ -340,6 +348,7 @@ enum class eItemAbil {
|
||||
LIGHTER_OBJECT = 44,
|
||||
HEAVIER_OBJECT = 45,
|
||||
OCCASIONAL_STATUS = 46,
|
||||
HIT_CALL_SPECIAL = 47,
|
||||
LIFE_SAVING = 48,
|
||||
PROTECT_FROM_PETRIFY = 49,
|
||||
REGENERATE = 50,
|
||||
@@ -487,6 +496,10 @@ enum class eSpecCtx {
|
||||
SEE_MONST = 18,
|
||||
MONST_SPEC_ABIL = 19,
|
||||
TOWN_HOSTILE = 20,
|
||||
ATTACKING_MELEE = 21,
|
||||
ATTACKING_RANGE = 22,
|
||||
ATTACKED_MELEE = 23,
|
||||
ATTACKED_RANGE = 24,
|
||||
};
|
||||
|
||||
enum class eSpecType {
|
||||
|
@@ -898,6 +898,7 @@ static bool edit_monst_abil_detail(cDialog& me, std::string hit, cMonster& monst
|
||||
param = choose_text(STRT_MONST, 0, &me, "Summon which monster?");
|
||||
break;
|
||||
case eMonstAbilTemplate::SPECIAL:
|
||||
case eMonstAbilTemplate::HIT_TRIGGERS:
|
||||
case eMonstAbilTemplate::DEATH_TRIGGERS:
|
||||
param = get_fresh_spec(0);
|
||||
if(param < 0) {
|
||||
@@ -1052,7 +1053,7 @@ static bool edit_monst_abil_detail(cDialog& me, std::string hit, cMonster& monst
|
||||
return true;
|
||||
});
|
||||
} else if(cat == eMonstAbilCat::SPECIAL) {
|
||||
if(abil == eMonstAbil::SPECIAL || abil == eMonstAbil::DEATH_TRIGGER)
|
||||
if(abil == eMonstAbil::SPECIAL || abil == eMonstAbil::HIT_TRIGGER || abil == eMonstAbil::DEATH_TRIGGER)
|
||||
abil_dlg["pick-extra1"].attachClickHandler([&](cDialog& me,std::string,eKeyMod) -> bool {
|
||||
short spec = me["extra1"].getTextAsNum();
|
||||
if(spec < 0 || spec > 255) {
|
||||
|
Reference in New Issue
Block a user