v2.4.0: the rat skull finally returns as the game's first trinket

This commit is contained in:
Evan Debenham
2024-03-12 14:51:10 -04:00
parent 938a78883f
commit fc3cbf395a
14 changed files with 116 additions and 27 deletions

View File

@@ -1291,6 +1291,9 @@ items.stones.stoneofshock.desc=This runestone unleashes a blast of electrical en
###trinkets
items.trinkets.ratskull.name=rat skull
items.trinkets.ratskull.desc=This macabre trinket isn't much larger than the skull of a normal rat, which is somehow a rarity down in this dungeon. The skull's magical influence seems to attract the more rare denizens of the dungeon, making them appear far more often.\n\nAt its current level it will make rare exotic enemies _%dx_ as likely to appear. The skull is only half as effective at attracting crystal mimics and armored statues, however.
items.trinkets.trinketcatalyst.name=trinket catalyst
items.trinkets.trinketcatalyst.window_text=The water begins to glow as you use the catalyst. There are a few nearby items you could imbue with magical energy.
items.trinkets.trinketcatalyst.desc=TODO

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -21,6 +21,7 @@
package com.shatteredpixel.shatteredpixeldungeon.actors.mobs;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.RatSkull;
import com.watabou.utils.Random;
import java.util.ArrayList;
@@ -211,8 +212,9 @@ public class Bestiary {
//switches out regular mobs for their alt versions when appropriate
private static void swapMobAlts(ArrayList<Class<?extends Mob>> rotation){
float altChance = 1/50f * RatSkull.exoticChanceMultiplier();
for (int i = 0; i < rotation.size(); i++){
if (Random.Int( 50 ) == 0) {
if (Random.Float() < altChance) {
Class<? extends Mob> cl = rotation.get(i);
if (cl == Rat.class) {
cl = Albino.class;

View File

@@ -44,6 +44,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfLiquidFlam
import com.shatteredpixel.shatteredpixeldungeon.items.quest.Embers;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfRecharging;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTransmutation;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.RatSkull;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.CursedWand;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Shocking;
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
@@ -561,7 +562,8 @@ public abstract class Elemental extends Mob {
}
public static Class<? extends Elemental> random(){
if (Random.Int( 50 ) == 0){
float altChance = 1/50f * RatSkull.exoticChanceMultiplier();
if (Random.Float() < altChance){
return ChaosElemental.class;
}

View File

@@ -31,6 +31,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.BlobImmunity;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Burning;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.items.food.MysteryMeat;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.RatSkull;
import com.shatteredpixel.shatteredpixeldungeon.sprites.PiranhaSprite;
import com.watabou.utils.PathFinder;
import com.watabou.utils.Random;
@@ -197,7 +198,8 @@ public class Piranha extends Mob {
}
public static Piranha random(){
if (Random.Int(50) == 0){
float altChance = 1/50f * RatSkull.exoticChanceMultiplier();
if (Random.Float() < altChance){
return new PhantomPiranha();
} else {
return new Piranha();

View File

@@ -25,6 +25,7 @@ import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.RatSkull;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.Weapon;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.Weapon.Enchantment;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Grim;
@@ -194,7 +195,9 @@ public class Statue extends Mob {
public static Statue random( boolean useDecks ){
Statue statue;
if (Random.Int(10) == 0){
float altChance = 1/10f * RatSkull.exoticChanceMultiplier();
if (altChance > 0.1f) altChance = (altChance+0.1f)/2f; //rat skull is 1/2 as effective here
if (Random.Float() < altChance){
statue = new ArmoredStatue();
} else {
statue = new Statue();

View File

@@ -26,6 +26,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ChallengeParticle;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ShadowParticle;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.RatSkull;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.shatteredpixel.shatteredpixeldungeon.sprites.WraithSprite;
import com.watabou.noosa.tweeners.AlphaTweener;
@@ -116,7 +117,8 @@ public class Wraith extends Mob {
Wraith w;
//if no wraith type is specified, 1/100 chance for exotic, otherwise normal
if (wraithClass == null){
if (Random.Int(100) == 0){
float altChance = 1/100f * RatSkull.exoticChanceMultiplier();
if (Random.Float() < altChance){
w = new TormentedSpirit();
} else {
w = new Wraith();

View File

@@ -55,6 +55,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.spells.SummonElemental;
import com.shatteredpixel.shatteredpixeldungeon.items.spells.TelekineticGrab;
import com.shatteredpixel.shatteredpixeldungeon.items.spells.UnstableSpell;
import com.shatteredpixel.shatteredpixeldungeon.items.spells.WildEnergy;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.Trinket;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.TrinketCatalyst;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.Wand;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.MissileWeapon;
@@ -191,7 +192,8 @@ public abstract class Recipe {
new TelekineticGrab.Recipe(),
new SummonElemental.Recipe(),
new StewedMeat.oneMeat(),
new TrinketCatalyst.Recipe()
new TrinketCatalyst.Recipe(),
new Trinket.UpgradeTrinket()
};
private static Recipe[] twoIngredientRecipes = new Recipe[]{

View File

@@ -19,28 +19,37 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package com.shatteredpixel.shatteredpixeldungeon.items.quest;
package com.shatteredpixel.shatteredpixeldungeon.items.trinkets;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
//this one's still hanging around to support quests from old saves
//I may reuse it at some point.
public class RatSkull extends Item {
public class RatSkull extends Trinket {
{
image = ItemSpriteSheet.SKULL;
unique = true;
image = ItemSpriteSheet.RAT_SKULL;
}
@Override
public boolean isUpgradable() {
return false;
protected int upgradeEnergyCost() {
return 5 + 10*level();
}
@Override
public boolean isIdentified() {
return true;
public String desc() {
return Messages.get(this, "desc", (int)(exoticChanceMultiplier(buffedLvl())));
}
public static float exoticChanceMultiplier(){
return exoticChanceMultiplier(trinketLevel(RatSkull.class));
}
public static float exoticChanceMultiplier( int level ){
if (level == -1){
return 1f;
} else {
return 2f + 2f*level;
}
}
}

View File

@@ -21,11 +21,21 @@
package com.shatteredpixel.shatteredpixeldungeon.items.trinkets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.Recipe;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
import java.util.ArrayList;
public abstract class Trinket extends Item {
{
levelKnown = true;
unique = true;
}
@Override
public boolean isIdentified() {
return true;
@@ -36,12 +46,33 @@ public abstract class Trinket extends Item {
return false;
}
protected abstract int upgradeEnergyCost();
protected static int trinketLevel(Class<? extends Trinket> trinketType ){
if (Dungeon.hero == null || Dungeon.hero.belongings == null){
return -1;
}
Trinket trinket = Dungeon.hero.belongings.getItem(trinketType);
if (trinket != null){
return trinket.buffedLvl();
} else {
return -1;
}
}
public static class PlaceHolder extends Trinket {
{
image = ItemSpriteSheet.TRINKET_HOLDER;
}
@Override
protected int upgradeEnergyCost() {
return 0;
}
@Override
public boolean isSimilar(Item item) {
return item instanceof Trinket;
@@ -53,4 +84,30 @@ public abstract class Trinket extends Item {
}
}
public static class UpgradeTrinket extends Recipe {
@Override
public boolean testIngredients(ArrayList<Item> ingredients) {
return ingredients.size() == 1 && ingredients.get(0) instanceof Trinket && ingredients.get(0).level() < 3;
}
@Override
public int cost(ArrayList<Item> ingredients) {
return ((Trinket)ingredients.get(0)).upgradeEnergyCost();
}
@Override
public Item brew(ArrayList<Item> ingredients) {
Item result = ingredients.get(0).duplicate();
ingredients.get(0).quantity(0);
result.upgrade();
return result;
}
@Override
public Item sampleOutput(ArrayList<Item> ingredients) {
return ingredients.get(0).duplicate().upgrade();
}
}
}

View File

@@ -44,6 +44,8 @@ public class TrinketCatalyst extends Item {
{
image = ItemSpriteSheet.ARCANE_RESIN;
unique = true;
}
@Override

View File

@@ -30,6 +30,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.CrystalKey;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.IronKey;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.RatSkull;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
@@ -70,7 +71,9 @@ public class CrystalVaultRoom extends SpecialRoom {
} while (level.adjacent(i1Pos, doorPos) || level.adjacent(i2Pos, doorPos));
level.drop( i1, i1Pos ).type = Heap.Type.CRYSTAL_CHEST;
if (Random.Int(10) == 0){
float altChance = 1/10f * RatSkull.exoticChanceMultiplier();
if (altChance > 0.1f) altChance = (altChance+0.1f)/2f; //rat skull is 1/2 as effective here
if (Random.Float() < altChance){
level.mobs.add(Mimic.spawnAt(i2Pos, CrystalMimic.class, i2));
} else {
level.drop(i2, i2Pos).type = Heap.Type.CRYSTAL_CHEST;

View File

@@ -418,7 +418,7 @@ public class ItemSpriteSheet {
assignItemRect(i, 8, 10);
}
private static final int ARTIFACTS = xy(1, 16); //32 slots
private static final int ARTIFACTS = xy(1, 16); //24 slots
public static final int ARTIFACT_CLOAK = ARTIFACTS+0;
public static final int ARTIFACT_ARMBAND = ARTIFACTS+1;
public static final int ARTIFACT_CAPE = ARTIFACTS+2;
@@ -468,7 +468,11 @@ public class ItemSpriteSheet {
assignItemRect(ARTIFACT_ROSE3, 14, 14);
}
//16 free slots
private static final int TRINKETS = xy(9, 17); //24 slots
public static final int RAT_SKULL = TRINKETS+0;
static{
assignItemRect(RAT_SKULL, 16, 11);
}
private static final int SCROLLS = xy(1, 19); //16 slots
public static final int SCROLL_KAUNAN = SCROLLS+0;
@@ -694,7 +698,6 @@ public class ItemSpriteSheet {
}
private static final int QUEST = xy(1, 30); //16 slots
public static final int SKULL = QUEST+0;
public static final int DUST = QUEST+1;
public static final int CANDLE = QUEST+2;
public static final int EMBER = QUEST+3;
@@ -704,7 +707,6 @@ public class ItemSpriteSheet {
public static final int BLOB = QUEST+7;
public static final int SHARD = QUEST+8;
static{
assignItemRect(SKULL, 16, 11);
assignItemRect(DUST, 12, 11);
assignItemRect(CANDLE, 12, 12);
assignItemRect(EMBER, 12, 11);

View File

@@ -63,7 +63,7 @@ public class v2_X_Changes {
"\n" +
"I'd like to try and release v2.4.0 fairly quickly to put us onto a good pace for 2024, but we'll see how well that actually turns out. Expect to hear something from me one way or another later in early to mid March. Please keep in mind that while I always try to keep to the ETAs I provide, they are just estimates. If you don't hear from me by the ETA, it means I'm still busy with the update!"));
changes.addButton( new ChangeButton(new ItemSprite(ItemSpriteSheet.SKULL), "Trinkets",
changes.addButton( new ChangeButton(new ItemSprite(ItemSpriteSheet.RAT_SKULL), "Trinkets",
"Trinkets are a new item type that are more about tweaking gameplay variables than giving direct power or utility. You'll be able to get one trinket per run (with some choice), which will change up the game slightly with effects such as increasing rare enemy spawn rates or making enchantments and curses more likely. Trinkets will be upgradeable via alchemical energy, increasing the strength of their effect."));
changes.addButton( new ChangeButton(Icons.get(Icons.PREFS), "Smaller Changes/Fixes",