Tweak monster ability system to reduce mechanical changes relative to original BoE

This commit is contained in:
2015-01-15 16:13:48 -05:00
parent ac77552a0b
commit 0b9593f3d1
5 changed files with 121 additions and 87 deletions

View File

@@ -2048,13 +2048,26 @@ void do_monster_turn() {
break; // We're looking for ranged attacks
if(dist(cur_monst->cur_loc, targ_space) > abil.second.gen.range)
break; // Target not in range
if(abil.second.gen.type != eMonstGen::RAY && abil.second.gen.type != eMonstGen::BREATH
&& monst_adjacent(targ_space, i))
if(abil.second.gen.type == eMonstGen::SPIT && monst_adjacent(targ_space, i))
break; // Target adjacent; prefer melee attacks
if(get_ran(1,1,1000) >= abil.second.gen.odds)
break;
pick_abil = abil;
break;
case eMonstAbil::MISSILE_WEB:
if(dist(cur_monst->cur_loc, targ_space) > abil.second.special.extra1)
break; // Target not in range
if(get_ran(1,1,1000) >= abil.second.special.extra2)
break;
pick_abil = abil;
break;
case eMonstAbil::RAY_HEAT:
if(dist(cur_monst->cur_loc, targ_space) > abil.second.special.extra1)
break; // Target not in range
if(get_ran(1,1,1000) >= abil.second.special.extra2)
break;
pick_abil = abil;
break;
}
if(pick_abil.second.active) break;
}
@@ -2064,16 +2077,13 @@ void do_monster_turn() {
monst_fire_missile(i/*,cur_monst->skill*/,cur_monst->status[eStatus::BLESS_CURSE],
pick_abil,cur_monst->cur_loc,target);
if(pick_abil.first == eMonstAbil::MISSILE) {
if(pick_abil.second.missile.type == eMonstMissile::ARROW || pick_abil.second.missile.type == eMonstMissile::BOLT)
if(pick_abil.second.missile.type == eMonstMissile::ARROW || pick_abil.second.missile.type == eMonstMissile::BOLT
|| pick_abil.second.missile.type == eMonstMissile::SPINE)
take_m_ap(3,cur_monst);
else take_m_ap(2,cur_monst);
} else {
if(pick_abil.second.gen.type == eMonstGen::BREATH)
take_m_ap(4,cur_monst);
else if(pick_abil.second.gen.type == eMonstGen::SPIT)
take_m_ap(3,cur_monst);
else take_m_ap(2,cur_monst);
}
} else if(pick_abil.first == eMonstAbil::RAY_HEAT)
take_m_ap(1,cur_monst);
else take_m_ap(3,cur_monst);
had_monst = true;
acted_yet = true;
}
@@ -2647,9 +2657,23 @@ 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);
}
} 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);
run_a_missile(source, targ_space, 8, 0, 14, 0, 0, 100);
web_space(targ_space.x, targ_space.y);
} else if(abil.first == eMonstAbil::RAY_HEAT) {
if(target < 100) add_string_to_buf(" Hits " + univ.party[target].name + " with heat ray!");
else monst_spell_note(m_target->number, 55);
run_a_missile(source, targ_space, 13, 0, 51, 0, 0, 100);
uAbility proxy = {true};
proxy.gen.strength = abil.second.special.extra3;
proxy.gen.type = eMonstGen::RAY;
proxy.gen.dmg = eDamageType::FIRE;
monst_basic_abil(m_num, {eMonstAbil::DAMAGE, proxy}, target);
} else {
if(abil.first == eMonstAbil::DRAIN_SP && target < 100 && univ.party[target].cur_sp < 4) {
// modify target is target has no sp
// modify target if target has no sp
for(i = 0; i < 8; i++) {
j = get_ran(1,0,5);
if(univ.party[j].main_status == eMainStatus::ALIVE && univ.party[j].cur_sp > 4 &&
@@ -2667,30 +2691,23 @@ void monst_fire_missile(short m_num,short bless,std::pair<eMonstAbil,uAbility> a
case eMonstGen::RAY:
snd = 51;
if(target < 100) add_string_to_buf(" Fires ray at " + univ.party[target].name + '.');
else monst_spell_note(m_target->number, 55); // TODO: Add this note
else monst_spell_note(m_target->number, 55);
break;
case eMonstGen::GAZE:
snd = 43;
if(target < 100) add_string_to_buf(" Gazes at " + univ.party[target].name + '.');
else monst_spell_note(m_target->number, 56); // TODO: Add this note
else monst_spell_note(m_target->number, 56);
break;
case eMonstGen::BREATH:
snd = 44;
if(target < 100) add_string_to_buf(" Breathes on " + univ.party[target].name + '.');
else monst_spell_note(m_target->number, 57); // TODO: Add this note
else monst_spell_note(m_target->number, 57);
break;
case eMonstGen::SPIT:
// Special case for "spit web" -> "throws web"
if(abil.first == eMonstAbil::FIELD && abil.second.gen.fld == eFieldType::FIELD_WEB) {
snd = 14;
if(target < 100) add_string_to_buf(" Throws web at " + univ.party[target].name + '.');
else monst_spell_note(m_target->number, 58); // TODO: Add this note
} else {
path_type = 1;
snd = 64;
if(target < 100) add_string_to_buf(" Spits at " + univ.party[target].name + '.');
else monst_spell_note(m_target->number, 59); // TODO: Add this note
}
path_type = 1;
snd = 64;
if(target < 100) add_string_to_buf(" Spits at " + univ.party[target].name + '.');
else monst_spell_note(m_target->number, 59);
break;
}
if(abil.second.gen.pic < 0) play_sound(snd);

View File

@@ -1124,6 +1124,21 @@ void monst_spell_note(mon_num_t number,short which_mess) {
case 54:
msg = " Throws knife at " + msg + '.';
break;
case 55:
msg = " Fires ray at " + msg + '.';
break;
case 56:
msg = " Gazes at " + msg + '.';
break;
case 57:
msg = " Breathes on " + msg + '.';
break;
case 58:
msg = " Throws web at " + msg + '.';
break;
case 59:
msg = " Spits at " + msg + '.';
break;
}
if(which_mess > 0)

View File

@@ -180,8 +180,7 @@ void cMonster::addAbil(eMonstAbilTemplate what, int param) {
abil[eMonstAbil::DRAIN_SP].gen = {true, eMonstGen::GAZE, 8, 50, 8, 625};
break;
case eMonstAbilTemplate::RAY_HEAT:
abil[eMonstAbil::DAMAGE].gen = {true, eMonstGen::RAY, 13, 7, 6, 625};
abil[eMonstAbil::DAMAGE].gen.dmg = eDamageType::FIRE;
abil[eMonstAbil::RAY_HEAT].special = {true, 6, 625, 7};
break;
case eMonstAbilTemplate::RAY_PARALYSIS:
abil[eMonstAbil::STATUS].gen = {true, eMonstGen::RAY, -1, 100, 6, 750};
@@ -216,8 +215,7 @@ void cMonster::addAbil(eMonstAbilTemplate what, int param) {
abil[eMonstAbil::STATUS].gen.stat = eStatus::ACID;
break;
case eMonstAbilTemplate::SHOOTS_WEB:
abil[eMonstAbil::FIELD].gen = {true, eMonstGen::SPIT, 8, PAT_SINGLE, 4, 375};
abil[eMonstAbil::FIELD].gen.fld = eFieldType::FIELD_WEB;
abil[eMonstAbil::MISSILE_WEB].special = {true, 4, 375};
break;
// Touch abilities
case eMonstAbilTemplate::TOUCH_POISON:
@@ -600,63 +598,59 @@ std::string uAbility::to_string(eMonstAbil key) const {
}
break;
case eMonstAbilCat::GENERAL:
if(key == eMonstAbil::FIELD && gen.type == eMonstGen::SPIT && gen.fld == eFieldType::FIELD_WEB) {
sout << "Throws webs";
} else {
switch(key) {
case eMonstAbil::STUN: sout << "Stunning"; break;
case eMonstAbil::PETRIFY: sout << "Petrifying"; break;
case eMonstAbil::DRAIN_SP: sout << "Spell point drain"; break;
case eMonstAbil::DRAIN_XP: sout << "Experience drain"; break;
case eMonstAbil::KILL: sout << "Death"; break;
case eMonstAbil::STEAL_FOOD: sout << "Steals food"; break;
case eMonstAbil::STEAL_GOLD: sout << "Steals gold!"; break;
case eMonstAbil::FIELD:
switch(gen.fld) {
case eFieldType::CLOUD_SLEEP: sout << "Sleep"; break;
case eFieldType::CLOUD_STINK: sout << "Foul"; break;
case eFieldType::WALL_FIRE: sout << "Fiery"; break;
case eFieldType::WALL_FORCE: sout << "Charged"; break;
case eFieldType::WALL_ICE: sout << "Frosted"; break;
case eFieldType::WALL_BLADES: sout << "Thorny"; break;
case eFieldType::FIELD_ANTIMAGIC: sout << "Null"; break;
case eFieldType::FIELD_WEB: sout << "Web"; break;
case eFieldType::FIELD_QUICKFIRE: sout << "Incendiary"; break;
}
break;
case eMonstAbil::DAMAGE:
switch(gen.dmg) {
case eDamageType::FIRE: sout << "Heat"; break;
case eDamageType::COLD: sout << "Icy"; break;
case eDamageType::MAGIC: sout << "Shock"; break;
case eDamageType::UNBLOCKABLE: sout << "Wounding"; break;
case eDamageType::POISON: sout << "Pain"; break;
case eDamageType::WEAPON: sout << "Stamina drain"; break;
case eDamageType::DEMON: sout << "Unholy"; break;
case eDamageType::UNDEAD: sout << "Necrotic"; break;
}
break;
case eMonstAbil::STATUS: case eMonstAbil::STATUS2:
switch(gen.stat) {
case eStatus::POISON: sout << "Poison"; break;
case eStatus::DISEASE: sout << "Infectious"; break;
case eStatus::DUMB: sout << "Dumbfounding"; break;
case eStatus::WEBS: sout << "Glue"; break;
case eStatus::ASLEEP: sout << "Sleep"; break;
case eStatus::PARALYZED: sout << "Paralysis"; break;
case eStatus::ACID: sout << "Acid"; break;
case eStatus::HASTE_SLOW: sout << "Slowing"; break;
case eStatus::BLESS_CURSE: sout << "Curse"; break;
}
break;
}
switch(gen.type) {
case eMonstGen::RAY: sout << " ray"; break;
case eMonstGen::TOUCH: sout << " touch"; break;
case eMonstGen::GAZE: sout << " gaze"; break;
case eMonstGen::BREATH: sout << " breath"; break;
case eMonstGen::SPIT: sout << " spit"; break;
}
switch(key) {
case eMonstAbil::STUN: sout << "Stunning"; break;
case eMonstAbil::PETRIFY: sout << "Petrifying"; break;
case eMonstAbil::DRAIN_SP: sout << "Spell point drain"; break;
case eMonstAbil::DRAIN_XP: sout << "Experience drain"; break;
case eMonstAbil::KILL: sout << "Death"; break;
case eMonstAbil::STEAL_FOOD: sout << "Steals food"; break;
case eMonstAbil::STEAL_GOLD: sout << "Steals gold!"; break;
case eMonstAbil::FIELD:
switch(gen.fld) {
case eFieldType::CLOUD_SLEEP: sout << "Sleep"; break;
case eFieldType::CLOUD_STINK: sout << "Foul"; break;
case eFieldType::WALL_FIRE: sout << "Fiery"; break;
case eFieldType::WALL_FORCE: sout << "Charged"; break;
case eFieldType::WALL_ICE: sout << "Frosted"; break;
case eFieldType::WALL_BLADES: sout << "Thorny"; break;
case eFieldType::FIELD_ANTIMAGIC: sout << "Null"; break;
case eFieldType::FIELD_WEB: sout << "Web"; break;
case eFieldType::FIELD_QUICKFIRE: sout << "Incendiary"; break;
}
break;
case eMonstAbil::DAMAGE:
switch(gen.dmg) {
case eDamageType::FIRE: sout << "Heat"; break;
case eDamageType::COLD: sout << "Icy"; break;
case eDamageType::MAGIC: sout << "Shock"; break;
case eDamageType::UNBLOCKABLE: sout << "Wounding"; break;
case eDamageType::POISON: sout << "Pain"; break;
case eDamageType::WEAPON: sout << "Stamina drain"; break;
case eDamageType::DEMON: sout << "Unholy"; break;
case eDamageType::UNDEAD: sout << "Necrotic"; break;
}
break;
case eMonstAbil::STATUS: case eMonstAbil::STATUS2:
switch(gen.stat) {
case eStatus::POISON: sout << "Poison"; break;
case eStatus::DISEASE: sout << "Infectious"; break;
case eStatus::DUMB: sout << "Dumbfounding"; break;
case eStatus::WEBS: sout << "Glue"; break;
case eStatus::ASLEEP: sout << "Sleep"; break;
case eStatus::PARALYZED: sout << "Paralysis"; break;
case eStatus::ACID: sout << "Acid"; break;
case eStatus::HASTE_SLOW: sout << "Slowing"; break;
case eStatus::BLESS_CURSE: sout << "Curse"; break;
}
break;
}
switch(gen.type) {
case eMonstGen::RAY: sout << " ray"; break;
case eMonstGen::TOUCH: sout << " touch"; break;
case eMonstGen::GAZE: sout << " gaze"; break;
case eMonstGen::BREATH: sout << " breath"; break;
case eMonstGen::SPIT: sout << " spit"; break;
}
if(key == eMonstAbil::DAMAGE) {
sout << " (" << gen.strength << ")";
@@ -700,6 +694,12 @@ std::string uAbility::to_string(eMonstAbil key) const {
case eMonstAbil::ABSORB_SPELLS:
sout << "Absorbs spells";
break;
case eMonstAbil::MISSILE_WEB:
sout << "Throws webs";
break;
case eMonstAbil::RAY_HEAT:
sout << "Heat ray (" << special.extra3 << "d6)";
break;
case eMonstAbil::SPECIAL:
case eMonstAbil::DEATH_TRIGGER:
sout << "Unusual ability";

View File

@@ -103,7 +103,7 @@ union uAbility {
} radiate;
struct {
bool active;
int extra1, extra2;
int extra1, extra2, extra3;
} special;
std::string to_string(eMonstAbil myKey) const;
};

View File

@@ -151,6 +151,8 @@ enum class eMonstAbil {
SPLITS,
MARTYRS_SHIELD,
ABSORB_SPELLS,
MISSILE_WEB,
RAY_HEAT,
SPECIAL,
DEATH_TRIGGER,