v2.4.0: finished impl of mimic tooth

This commit is contained in:
Evan Debenham
2024-05-07 14:01:09 -04:00
parent d45cc9cae4
commit ef2fec4c8c
9 changed files with 197 additions and 6 deletions

View File

@@ -1198,6 +1198,12 @@ actors.mobs.dwarfking$dkmonk.rankings_desc=Fell Before the King of Dwarves
actors.mobs.dwarfking$dkwarlock.rankings_desc=Fell Before the King of Dwarves
actors.mobs.dwarfking$dkgolem.rankings_desc=Fell Before the King of Dwarves
actors.mobs.ebonymimic.name=ebony mimic
actors.mobs.ebonymimic.reveal=There was a mimic there!
actors.mobs.ebonymimic.hidden_name=suspicious outline
actors.mobs.ebonymimic.hidden_desc=There seems to be something here, but it's almost totally transparent.
actors.mobs.ebonymimic.desc=Mimics are magical creatures which can take any shape they wish. In dungeons they almost always choose a shape of a treasure chest, in order to lure in unsuspecting adventurers.\n\nEbony mimics are extremely tough mimics with the ability to make themselves almost invisible. They lurk on things that adventurers are likely to interact with, but do contain loot of their own as well.
actors.mobs.elemental$fireelemental.name=fire elemental
actors.mobs.elemental$fireelemental.desc=Elementals are chaotic creatures that are often created when powerful occult magic isn't properly controlled. Elementals have minimal intelligence, and are usually associated with a particular type of magic.\n\nFire elementals are a common type of elemental which deals damage with fiery magic. They will set their target ablaze with melee attacks, and can occasionally shoot bolts of fire as well.
actors.mobs.elemental$newbornfireelemental.name=newborn fire elemental

View File

@@ -1304,7 +1304,7 @@ items.trinkets.exoticcrystals.name=exotic crystals
items.trinkets.exoticcrystals.desc=These small pink crystals have the same shape as crystals of alchemical energy. While they can't be used for energy directly, they seem to be somehow influencing the potions and scrolls you find.\n\nAt its current level this trinket will replace _%d%%_ of potion or scroll drops with their exotic equivalents. This does not affect potions of strength, scrolls of upgrade, or items that are generated to help solve hazard rooms.
items.trinkets.mimictooth.name=mimic tooth
items.trinkets.mimictooth.desc=TODO\n\nAt its current level this trinket will make all kinds of mimics _%sx_ more common, and will make mimics more difficult to detect.
items.trinkets.mimictooth.desc=This large sharp tooth must have been pulled from a very unhappy mimic. It seems to be influencing the mimics of the dungeon, making them more frequent and dangerous.\n\nAt its current level this trinket will make all kinds of mimic _%1$sx_ more common, will make mimics much more difficult to detect, and will give each floor a _%2$s%%_ chance to contain an ebony mimic.
items.trinkets.mossyclump.name=mossy clump
items.trinkets.mossyclump.desc=This clump of wet moss seems to hold onto its moisture no matter how hard you squeeze it. It seems to be magically tied to the dungeon itself, making grass and water more likely to appear.\n\nAt its current level this trinket will make _%d%%_ of regular floors become filled with either water or grass instead.\n\nThis trinket costs a relatively large amount of energy to upgrade.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -0,0 +1,118 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2024 Evan Debenham
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package com.shatteredpixel.shatteredpixeldungeon.actors.mobs;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
import com.shatteredpixel.shatteredpixeldungeon.items.EquipableItem;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.armor.Armor;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.Artifact;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.Wand;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.Weapon;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.MissileWeapon;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.Door;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.sprites.MimicSprite;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
import com.watabou.noosa.audio.Sample;
import com.watabou.utils.Random;
public class EbonyMimic extends Mimic {
{
spriteClass = MimicSprite.Ebony.class;
}
@Override
public String name() {
if (alignment == Alignment.NEUTRAL){
return Messages.get(this, "hidden_name");
} else {
return super.name();
}
}
@Override
public String description() {
if (alignment == Alignment.NEUTRAL){
return Messages.get(this, "hidden_desc");
} else {
return super.description();
}
}
public void stopHiding(){
state = HUNTING;
if (sprite != null) sprite.idle();
if (Actor.chars().contains(this) && Dungeon.level.heroFOV[pos]) {
enemy = Dungeon.hero;
target = Dungeon.hero.pos;
GLog.w(Messages.get(this, "reveal") );
CellEmitter.get(pos).burst(Speck.factory(Speck.STAR), 10);
Sample.INSTANCE.play(Assets.Sounds.MIMIC, 1, 0.85f);
}
if (Dungeon.level.map[pos] == Terrain.DOOR){
Door.enter( pos );
}
}
@Override
public int damageRoll() {
if (alignment == Alignment.NEUTRAL){
return Math.round(super.damageRoll()*1.5f); //BIG damage on surprise
} else {
return super.damageRoll();
}
}
@Override
public void setLevel(int level) {
super.setLevel(Math.round(level*1.5f));
}
@Override
protected void generatePrize( boolean useDecks ) {
super.generatePrize( useDecks );
//all existing prize items are guaranteed uncursed, and have a 50% chance to be +1 if they were +0
for (Item i : items){
if (i instanceof EquipableItem || i instanceof Wand){
i.cursed = false;
i.cursedKnown = true;
if (i instanceof Weapon && ((Weapon) i).hasCurseEnchant()){
((Weapon) i).enchant(null);
}
if (i instanceof Armor && ((Armor) i).hasCurseGlyph()){
((Armor) i).inscribe(null);
}
if (!(i instanceof MissileWeapon || i instanceof Artifact) && i.level() == 0 && Random.Int(2) == 0){
i.upgrade();
}
}
}
}
}

View File

@@ -296,6 +296,8 @@ public class Mimic extends Mob {
m = new GoldenMimic();
} else if (mimicType == CrystalMimic.class) {
m = new CrystalMimic();
} else if (mimicType == EbonyMimic.class) {
m = new EbonyMimic();
} else {
m = new Mimic();
}

View File

@@ -38,7 +38,9 @@ public class MimicTooth extends Trinket {
@Override
public String desc() {
return Messages.get(this, "desc", Float.toString(mimicChanceMultiplier(buffedLvl())));
return Messages.get(this, "desc",
Messages.decimalFormat("#.##", mimicChanceMultiplier(buffedLvl())),
Messages.decimalFormat("#.##", 100*ebonyMimicChance(buffedLvl())));
}
public static float mimicChanceMultiplier(){
@@ -57,4 +59,16 @@ public class MimicTooth extends Trinket {
return trinketLevel(MimicTooth.class) >= 0;
}
public static float ebonyMimicChance(){
return ebonyMimicChance(trinketLevel(MimicTooth.class));
}
public static float ebonyMimicChance( int level ){
if (level >= 0){
return 0.125f + 0.125f * level;
} else {
return 0;
}
}
}

View File

@@ -31,6 +31,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.SacrificialFire;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.EbonyMimic;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.GoldenMimic;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mimic;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
@@ -630,6 +631,35 @@ public abstract class RegularLevel extends Level {
}
Random.popGenerator();
//ebony mimics >:)
Random.pushGenerator(Random.Long());
if (Random.Float() < MimicTooth.ebonyMimicChance()){
ArrayList<Integer> candidateCells = new ArrayList<>();
if (Random.Int(2) == 0){
for (Heap h : heaps.valueList()){
if (h.type == Heap.Type.HEAP
&& !(room(h.pos) instanceof SpecialRoom)
&& findMob(h.pos) == null){
candidateCells.add(h.pos);
}
}
} else {
if (Random.Int(5) == 0 && findMob(exit()) == null){
candidateCells.add(exit());
} else {
for (int i = 0; i < length(); i++) {
if (map[i] == Terrain.DOOR && findMob(i) == null) {
candidateCells.add(i);
}
}
}
}
int pos = Random.element(candidateCells);
mobs.add(Mimic.spawnAt(pos, EbonyMimic.class, false));
}
Random.popGenerator();
}
private static HashMap<Document, Dungeon.LimitedDrops> limitedDocs = new HashMap<>();

View File

@@ -490,7 +490,7 @@ public class ItemSpriteSheet {
assignItemRect(SUNDIAL, 16, 12);
assignItemRect(CLOVER, 11, 15);
assignItemRect(TRAP_MECHANISM, 13, 15);
assignItemRect(MIMIC_TOOTH, 7, 13);
assignItemRect(MIMIC_TOOTH, 8, 15);
}
private static final int SCROLLS = xy(1, 19); //16 slots

View File

@@ -28,9 +28,9 @@ import com.watabou.noosa.TextureFilm;
public class MimicSprite extends MobSprite {
private Animation advancedHiding;
protected Animation advancedHiding;
private Animation hiding;
protected Animation hiding;
{
//adjust shadow slightly to account for 1 empty bottom pixel (used for border while hiding)
@@ -68,7 +68,7 @@ public class MimicSprite extends MobSprite {
attack.frames( frames, 3+c, 7+c, 8+c, 9+c );
die = new Animation( 5, false );
die.frames( frames, 10+c, 111+c, 12+c );
die.frames( frames, 10+c, 11+c, 12+c );
play( idle );
}
@@ -112,4 +112,25 @@ public class MimicSprite extends MobSprite {
}
}
public static class Ebony extends MimicSprite{
@Override
protected int texOffset() {
return 48;
}
@Override
public void hideMimic() {
super.hideMimic();
alpha(0.2f);
}
@Override
public void play(Animation anim) {
if (curAnim == advancedHiding && anim != advancedHiding){
alpha(1f);
}
super.play(anim);
}
}
}