v0.8.0: substantially improved logic for damage immunity:

- now referred to as invulnerability, with standardized logic for all chars
- chars now ignore enemies who are invulnerable
- combo no longer builds on invulnerable targets
- allies can now target Yog's eye when it is vulnerable
This commit is contained in:
Evan Debenham 2020-03-27 16:11:01 -04:00
parent 97236333d8
commit b5989ee4f6
8 changed files with 75 additions and 55 deletions

View File

@ -416,6 +416,11 @@ public abstract class Char extends Actor {
return;
}
if(isInvulnerable(src.getClass())){
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "invulnerable"));
return;
}
if (!(src instanceof LifeLink) && buff(LifeLink.class) != null){
HashSet<LifeLink> links = buffs(LifeLink.class);
for (LifeLink link : links.toArray(new LifeLink[0])){
@ -697,6 +702,12 @@ public abstract class Char extends Actor {
return false;
}
//similar to isImmune, but only factors in damage.
//Is used in AI decision-making
public boolean isInvulnerable( Class effect ){
return false;
}
protected HashSet<Property> properties = new HashSet<>();
public HashSet<Property> properties() {

View File

@ -74,7 +74,8 @@ public class Combo extends Buff implements ActionIndicator.Action {
public void hit( Char enemy ) {
count++;
//doesn't increment combo count if enemy invulnerable
if (!enemy.isInvulnerable(target.getClass())) count++;
comboTime = 4f;
misses = 0;
BuffIndicator.refreshHero();

View File

@ -354,10 +354,15 @@ public class DwarfKing extends Mob {
}
}
@Override
public boolean isInvulnerable(Class effect) {
return phase == 2 && effect != KingDamager.class;
}
@Override
public void damage(int dmg, Object src) {
if (phase == 2 && !(src instanceof KingDamager)){
sprite.showStatus( CharSprite.POSITIVE, Messages.get(this, "immune") );
if (isInvulnerable(src.getClass())){
super.damage(dmg, src);
return;
} else if (phase == 3 && !(src instanceof Viscosity.DeferedDamage)){
Viscosity.DeferedDamage deferred = Buff.affect( this, Viscosity.DeferedDamage.class );
@ -378,7 +383,7 @@ public class DwarfKing extends Mob {
summonCooldown -= dmgTaken/8f;
if (HP <= 50) {
HP = 50;
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "immune"));
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "invulnerable"));
ScrollOfTeleportation.appear(this, NewCityBossLevel.throne);
properties.add(Property.IMMOVABLE);
phase = 2;

View File

@ -215,17 +215,21 @@ public abstract class Mob extends Char {
//find a new enemy if..
boolean newEnemy = false;
//we have no enemy, or the current one is dead/missing
if ( enemy == null || !enemy.isAlive() || !Actor.chars().contains(enemy) || state == WANDERING)
if ( enemy == null || !enemy.isAlive() || !Actor.chars().contains(enemy) || state == WANDERING) {
newEnemy = true;
//We are an ally, and current enemy is another ally.
else if (alignment == Alignment.ALLY && enemy.alignment == Alignment.ALLY)
} else if (alignment == Alignment.ALLY && enemy.alignment == Alignment.ALLY) {
newEnemy = true;
//We are amoked and current enemy is the hero
else if (buff( Amok.class ) != null && enemy == Dungeon.hero)
} else if (buff( Amok.class ) != null && enemy == Dungeon.hero) {
newEnemy = true;
//We are charmed and current enemy is what charmed us
else if (buff(Charm.class) != null && buff(Charm.class).object == enemy.id())
} else if (buff(Charm.class) != null && buff(Charm.class).object == enemy.id()) {
newEnemy = true;
//we aren't amoked and current enemy is invulnerable to us
} else if (buff( Amok.class ) == null && enemy.isInvulnerable(getClass())) {
newEnemy = true;
}
if ( newEnemy ) {
@ -285,6 +289,15 @@ public abstract class Mob extends Char {
}
}
//if we are not amoked, remove any enemies which are invulnerable to us.
if (buff(Amok.class) == null) {
for (Char enemy : enemies.toArray(new Char[0])) {
if (enemy.isInvulnerable(getClass())){
enemies.remove(enemy);
}
}
}
//neutral characters in particular do not choose enemies.
if (enemies.isEmpty()){
return null;

View File

@ -407,13 +407,11 @@ public class NewDM300 extends Mob {
@Override
public void damage(int dmg, Object src) {
if (supercharged){
sprite.showStatus( CharSprite.POSITIVE, Messages.get(this, "immune") );
super.damage(dmg, src);
if (isInvulnerable(src.getClass())){
return;
}
super.damage(dmg, src);
LockedFloor lock = Dungeon.hero.buff(LockedFloor.class);
if (lock != null && !isImmune(src.getClass())) lock.addTime(dmg);
@ -426,6 +424,11 @@ public class NewDM300 extends Mob {
}
@Override
public boolean isInvulnerable(Class effect) {
return supercharged;
}
public void supercharge(){
supercharged = true;
((NewCavesBossLevel)Dungeon.level).activatePylon();
@ -433,7 +436,7 @@ public class NewDM300 extends Mob {
spend(3f);
yell(Messages.get(this, "charging"));
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "immune"));
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "invulnerable"));
sprite.resetColor();
chargeAnnounced = false;
}

View File

@ -69,7 +69,8 @@ public class YogDzewa extends Mob {
EXP = 50;
state = PASSIVE;
//so that allies can attack it. States are never actually used.
state = HUNTING;
properties.add(Property.BOSS);
properties.add(Property.IMMOVABLE);
@ -113,8 +114,10 @@ public class YogDzewa extends Mob {
@Override
protected boolean act() {
if (phase == 0 && Dungeon.hero.viewDistance >= Dungeon.level.distance(pos, Dungeon.hero.pos)){
if (phase == 0){
if (Dungeon.hero.viewDistance >= Dungeon.level.distance(pos, Dungeon.hero.pos)) {
Dungeon.observe();
}
if (Dungeon.level.heroFOV[pos]) {
notice();
}
@ -269,13 +272,13 @@ public class YogDzewa extends Mob {
}
@Override
public void damage( int dmg, Object src ) {
if (phase == 0 || findFist() != null){
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "immune"));
return;
public boolean isInvulnerable(Class effect) {
return phase == 0 || findFist() != null;
}
@Override
public void damage( int dmg, Object src ) {
int preHP = HP;
super.damage( dmg, src );
int dmgTaken = preHP - HP;
@ -292,7 +295,7 @@ public class YogDzewa extends Mob {
}
Dungeon.observe();
GLog.n(Messages.get(this, "darkness"));
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "immune"));
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "invulnerable"));
YogFist fist = (YogFist) Reflection.newInstance(fistSummons.remove(0));
fist.pos = Dungeon.level.exit;
@ -319,7 +322,7 @@ public class YogDzewa extends Mob {
}
LockedFloor lock = Dungeon.hero.buff(LockedFloor.class);
if (lock != null) lock.addTime(dmg);
if (lock != null) lock.addTime(dmgTaken);
}

View File

@ -91,7 +91,7 @@ public abstract class YogFist extends Mob {
}
}
boolean immuneWarned = false;
boolean invulnWarned = false;
protected boolean isNearYog(){
int yogPos = Dungeon.level.exit + 3*Dungeon.level.width();
@ -99,14 +99,17 @@ public abstract class YogFist extends Mob {
}
@Override
public void damage(int dmg, Object src) {
if (isNearYog()){
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "immune"));
if (!immuneWarned){
immuneWarned = true;
GLog.w(Messages.get(this, "immune_hint"));
public boolean isInvulnerable(Class effect) {
return isNearYog();
}
@Override
public void damage(int dmg, Object src) {
if (isInvulnerable(src.getClass())){
if (!invulnWarned){
invulnWarned = true;
GLog.w(Messages.get(this, "invuln_warn"));
}
return;
}
super.damage(dmg, src);
}
@ -344,15 +347,7 @@ public abstract class YogFist extends Mob {
@Override
public void damage(int dmg, Object src) {
if (isNearYog()){
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "immune"));
if (!immuneWarned){
immuneWarned = true;
GLog.w(Messages.get(this, "immune_hint"));
}
return;
}
if (!(src instanceof Bleeding)){
if (!isInvulnerable(src.getClass()) && !(src instanceof Bleeding)){
Bleeding b = buff(Bleeding.class);
if (b == null){
b = new Bleeding();
@ -406,15 +401,7 @@ public abstract class YogFist extends Mob {
@Override
public void damage(int dmg, Object src) {
if (isNearYog()){
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "immune"));
if (!immuneWarned){
immuneWarned = true;
GLog.w(Messages.get(this, "immune_hint"));
}
return;
}
if (!(src instanceof Viscosity.DeferedDamage)){
if (!isInvulnerable(src.getClass()) && !(src instanceof Viscosity.DeferedDamage)){
Buff.affect(this, Viscosity.DeferedDamage.class).prolong(dmg);
sprite.showStatus( CharSprite.WARNING, Messages.get(Viscosity.class, "deferred", dmg) );
} else{

View File

@ -511,7 +511,6 @@ actors.mobs.newdm300.supercharged=SUPERCHARGE COMPLETE, OPERATING AT 200% POWER!
actors.mobs.newdm300.charge_lost=POWER GRID DAMAGED, REVERTING TO LOCAL POWER!
actors.mobs.newdm300.pylons_destroyed=ALERT, INSTABILITY DETECTED IN POWER GRID!
actors.mobs.newdm300.rankings_desc=Crushed by the DM-300
actors.mobs.newdm300.immune=IMMUNE
actors.mobs.newdm300.def_verb=blocked
actors.mobs.newdm300.defeated=CRITICAL DAMAGE! ATTEMPTING SHUTDO-
actors.mobs.newdm300.desc=The DM-300 is the largest and most powerful 'defense machine' that the dwarves ever built. Such an awesome machine is difficult to manufacture, so the dwarves only ever made a few to guard the entrances to their underground metropolis.\n\nIt is equipped with vents to jet its toxic exhaust fumes and a high power drill that it can use both to attack and disrupt the earth. DM-300 can also connect to an energy grid, further enhancing its power.
@ -524,7 +523,6 @@ actors.mobs.dwarfking.lifelink_1=I need of your essence, slave!
actors.mobs.dwarfking.lifelink_2=Bleed for me, slave!
actors.mobs.dwarfking.teleport_1=Deal with them, slave!
actors.mobs.dwarfking.teleport_2=Keep them busy, slave!
actors.mobs.dwarfking.immune=IMMUNE
actors.mobs.dwarfking.wave_1=Enough! Arise my slaves!
actors.mobs.dwarfking.wave_2=More! Bleed for your king!
actors.mobs.dwarfking.wave_3=Useless! KILL THEM NOW!
@ -747,7 +745,6 @@ actors.mobs.yog$larva.desc=Yog-Dzewa is an Old God, a powerful entity from the r
actors.mobs.yogdzewa.name=Yog-Dzewa
actors.mobs.yogdzewa.notice=I. SEE. YOU.
actors.mobs.yogdzewa.immune=IMMUNE
actors.mobs.yogdzewa.darkness=The darkness pulls in closer...
actors.mobs.yogdzewa.hope=YOUR. HOPE. IS. AN. ILLUSION!
actors.mobs.yogdzewa.defeated=...
@ -759,8 +756,7 @@ actors.mobs.yogdzewa$larva.rankings_desc=Devoured by Yog-Dzewa
actors.mobs.yogdzewa$larva.desc=These tiny spawn of Yog-Dzewa are simple minions that are easy to produce. While individually weak, they are summoned quickly and can become overwhelming in large numbers.
actors.mobs.yogdzewa$yogripper.rankings_desc=Devoured by Yog-Dzewa
actors.mobs.yogfist.immune=IMMUNE
actors.mobs.yogfist.immune_hint=The fist is immune while near to the eye!
actors.mobs.yogfist.invuln_warn=The fist is invulnerable while near to the eye!
actors.mobs.yogfist.rankings_desc=Devoured by Yog-Dzewa
actors.mobs.yogfist.desc=This fist is an aspect of Yog-Dzewa's power. Fists are linked to the power of Yog-Dzewa, and will be protected from all damage when they are close to the eye.
actors.mobs.yogfist$burning.name=burning fist
@ -782,3 +778,4 @@ actors.mobs.yogfist$dark.desc=This fist is formed out of pure dark energy. It is
actors.char.kill=%s killed you...
actors.char.defeat=You defeated %s.
actors.char.def_verb=dodged
actors.char.invulnerable=invulnerable