Unification of petrification abilities

- Note: Petrification from higher-level monsters is now harder to resist!
- AFFECT_DEADNESS special node now has an additional option to allow PCs a saving throw (based on things like luck and items with life-saving ability) when killing them, and to specify the difficulty of resisting when petrifying monsters or PCs
- AFFECT_DEADNESS special node now triggers monster death specials when petrifying them (in addition to when killing them), and substitutes ash for the normal sfx when turning them to dust
This commit is contained in:
2014-12-18 21:22:24 -05:00
parent d41616db6a
commit 8e26881331
6 changed files with 78 additions and 73 deletions

View File

@@ -2350,41 +2350,16 @@ void monster_attack_pc(short who_att,short target) {
}
// Petrification touch
if((attacker->spec_skill == 30)
&& (pc_has_abil_equip(target,eItemAbil::PROTECT_FROM_PETRIFY) == 24)
&& (get_ran(1,0,20) + univ.party[target].level / 4 + univ.party[target].status[eStatus::BLESS_CURSE]) <= 14) {
if(attacker->spec_skill == 30) {
add_string_to_buf(" Petrifying touch!");
print_buf();
kill_pc(target,eMainStatus::STONE); // petrified, duh!
petrify_pc(target,attacker->level / 4);
}
#if 0 // TODO: This is *i's version of the petrification touch ability.
// It seems better in some ways, like printing a message when you resist,
// but its calculation is very different, so I'm not sure what to with it.
// Note, his version has also been incorporated into monster_attack_monster.
// Petrify target
if(attacker->spec_skill == 30) {
add_string_to_buf(" Petrification touch! ");
r1 = max(0,(get_ran(1,0,100) - univ.party[target].level + 0.5*attacker->level));
// Equip petrify protection?
if(pc_has_abil_equip(target,eItemAbil:PROTECT_FROM_PETRIFY) < 24)
r1 = 0;
// Check if petrified.
if(r1 > 60) {
kill_pc(target,eMainStatus::STONE);
add_string_to_buf(" Turned to stone! ");
play_sound(43);
}
else {
add_string_to_buf(" Resists! ");
}
}
#endif
// Undead xp drain
if(((attacker->spec_skill == 16) || (attacker->spec_skill == 17))
&& (pc_has_abil_equip(target,eItemAbil::LIFE_SAVING) == 24)) {
// TODO: Uh, wait a second. These two abilities have an identical effect? That doesn't seem right!
// Note: spec_skill 17 (Icy+Draining Touch) also enters another if block further down.
add_string_to_buf(" Drains life! ");
drain_pc(target,(attacker->level * 3) / 2);
put_pc_screen();
@@ -2556,17 +2531,7 @@ void monster_attack_monster(short who_att,short attackee) {
// Petrify target
if(attacker->spec_skill == 30) {
add_string_to_buf(" Petrification touch! ");
r1 = max(0,(get_ran(1,0,100) - target->level + 0.5*attacker->level));
// Check if petrified.
if((r1 < 60) || (target->immunities & 2)) {
add_string_to_buf(" Resists! ");
}
else {
kill_monst(target,7);
add_string_to_buf(" Turned to stone! ");
play_sound(43);
}
petrify_monst(target, attacker->level / 4);
}
// Acid touch
@@ -2692,29 +2657,12 @@ void monst_fire_missile(short m_num,short bless,short level,location source,shor
if(target < 100) { // on PC
sprintf (create_line, " Gazes at %s. ",univ.party[target].name.c_str());
add_string_to_buf(create_line);
r1 = get_ran(1,0,20) + univ.party[target].level / 4 + univ.party[target].status[eStatus::BLESS_CURSE];
if(pc_has_abil_equip(target,eItemAbil::PROTECT_FROM_PETRIFY) < 24)
r1 = 20;
if(r1 > 14) {
sprintf (create_line, " %s resists. ",univ.party[target].name.c_str());
add_string_to_buf(create_line);
}
else {
sprintf (create_line, " %s is turned to stone. ",univ.party[target].name.c_str());
add_string_to_buf(create_line);
kill_pc(target,eMainStatus::STONE);
}
petrify_pc(target, univ.town.monst[i].level / 4);
}
else {
// TODO: This might be relevant to the AFFECT_DEADNESS special when used on monsters
monst_spell_note(m_target->number,9);
r1 = get_ran(1,0,20) + m_target->level / 4 + m_target->status[eStatus::BLESS_CURSE];
if((r1 > 14) || (m_target->immunities & 2))
monst_spell_note(m_target->number,10);
else {
monst_spell_note(m_target->number,8);
kill_monst(m_target,7);
}
petrify_monst(m_target, univ.town.monst[i].level / 4);
}
}
else if(level == 9) { /// Drain sp

View File

@@ -2988,6 +2988,25 @@ bool damage_pc(short which_pc,short how_much,eDamageType damage_type,eRace type_
return true;
}
void petrify_pc(short which_pc, short strength) {
std::ostringstream create_line;
short r1 = get_ran(1,0,20);
r1 += univ.party[which_pc].level / 4;
r1 += univ.party[which_pc].status[eStatus::BLESS_CURSE];
r1 -= strength;
if(pc_has_abil_equip(which_pc,eItemAbil::PROTECT_FROM_PETRIFY) < 24)
r1 = 20;
if(r1 > 14) {
create_line << " " << univ.party[which_pc].name << "resists.";
} else {
create_line << " " << univ.party[which_pc].name << "is turned to stone.";
kill_pc(which_pc,eMainStatus::STONE);
}
add_string_to_buf(create_line.str());
}
void kill_pc(short which_pc,eMainStatus type) {
short i = 24;
bool dummy,no_save = false;

View File

@@ -58,6 +58,7 @@ void hit_party(short how_much,eDamageType damage_type);
void slay_party(eMainStatus mode);
bool damage_pc(short which_pc,short how_much,eDamageType damage_type,eRace type_of_attacker, short sound_type);
void kill_pc(short which_pc,eMainStatus type);
void petrify_pc(short which_pc, short strength);
void set_pc_moves();
void take_ap(short num);
short trait_present(eTrait which_trait);

View File

@@ -1622,7 +1622,22 @@ bool damage_monst(short which_m, short who_hit, short how_much, short how_much_s
return true;
}
void kill_monst(cCreature *which_m,short who_killed) {
void petrify_monst(cCreature* m_target, short strength) {
monst_spell_note(m_target->number,9);
short r1 = get_ran(1,0,20);
r1 += m_target->level / 4;
r1 += m_target->status[eStatus::BLESS_CURSE];
r1 -= strength;
if(r1 > 14 || m_target->immunities & 2)
monst_spell_note(m_target->number,10);
else {
monst_spell_note(m_target->number,8);
kill_monst(m_target,7);
}
}
void kill_monst(cCreature *which_m,short who_killed,eMainStatus type) {
short xp,i,j,s1,s2,s3;
location l;
@@ -1673,7 +1688,10 @@ void kill_monst(cCreature *which_m,short who_killed) {
i = which_m->cur_loc.x;
j = which_m->cur_loc.y;
switch(which_m->m_type) {
if(type == eMainStatus::DUST)
univ.town.set_ash(i,j,true);
else if(type == eMainStatus::ABSENT || type == eMainStatus::STONE);
else switch(which_m->m_type) {
case eRace::DEMON:
univ.town.set_ash(i,j,true);
break;
@@ -2636,27 +2654,43 @@ void affect_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
else switch(spec.ex1a){
// When passed to kill_pc, the SPLIT party status actually means "no saving throw".
case 0:
kill_pc(i,eMainStatus::SPLIT_DEAD);
kill_pc(i,spec.ex1c > 0 ? eMainStatus::DEAD : eMainStatus::SPLIT_DEAD);
break;
case 1:
kill_pc(i,eMainStatus::SPLIT_DUST);
kill_pc(i,spec.ex1c > 0 ? eMainStatus::DUST : eMainStatus::SPLIT_DUST);
break;
case 2:
kill_pc(i,eMainStatus::SPLIT_STONE);
if(spec.ex1c > 0)
petrify_pc(i,spec.ex1c);
else kill_pc(i,eMainStatus::SPLIT_STONE);
break;
}
}
*redraw = 1;
}
else {
} else {
// Kill monster
if((univ.town.monst[spec.ex2a].active > 0) && (spec.ex1b > 0)) {
// If dead/dust actually kill, if stone just erase
if(spec.ex1a < 2) {
kill_monst(&univ.town.monst[spec.ex2a],7);
monst_spell_note(univ.town.monst[spec.ex2a].number,46);
if(univ.town.monst[spec.ex2a].active > 0 && spec.ex1b > 0) {
switch(spec.ex1a) {
case 0:
monst_spell_note(univ.town.monst[spec.ex2a].number,46);
kill_monst(&univ.town.monst[spec.ex2a],7,eMainStatus::DEAD);
break;
case 1:
monst_spell_note(univ.town.monst[spec.ex2a].number,51);
kill_monst(&univ.town.monst[spec.ex2a],7,eMainStatus::DUST);
break;
case 2:
if(spec.ex1c > 0)
petrify_monst(&univ.town.monst[spec.ex2a], spec.ex1c);
else {
monst_spell_note(univ.town.monst[spec.ex2a].number,8);
kill_monst(&univ.town.monst[spec.ex2a],7,eMainStatus::STONE);
}
break;
}
univ.town.monst[spec.ex2a].active = 0;
}
// Bring back to life
if((univ.town.monst[spec.ex2a].active == 0) && (spec.ex1b == 0)) {
else if(univ.town.monst[spec.ex2a].active == 0 && spec.ex1b == 0) {
univ.town.monst[spec.ex2a].active = 1;
monst_spell_note(univ.town.monst[spec.ex2a].number,45);
}

View File

@@ -9,7 +9,8 @@ bool use_space(location where);
bool adj_town_look(location where);
void PSOE(short which_special,unsigned char *stuff_done_val,short where_put);
bool damage_monst(short which_m, short who_hit, short how_much, short how_much_spec, eDamageType dam_type, short sound_type);
void kill_monst(cCreature *which_m,short who_killed);
void kill_monst(cCreature *which_m,short who_killed,eMainStatus type = eMainStatus::DEAD);
void petrify_monst(cCreature* m_target, short strength);
void special_increase_age(long length = 1, bool queue = false);
void do_rest(long length, int hp_restore, int mp_restore);
void out_move_party(char x,char y) ;

View File

@@ -1158,6 +1158,8 @@ void monst_spell_note(m_num_t number,short which_mess) {
case 50:
msg = " " + msg + " breaks force cage.";
break;
case 51:
msg = " " + msg + " is obliterated!";
}
if(which_mess > 0)