diff --git a/core/src/main/assets/messages/items/items.properties b/core/src/main/assets/messages/items/items.properties index de3e2fe20..3eaea3ef4 100644 --- a/core/src/main/assets/messages/items/items.properties +++ b/core/src/main/assets/messages/items/items.properties @@ -1324,6 +1324,9 @@ items.trinkets.thirteenleafclover.desc=Somehow stewing in the alchemy pot has ca items.trinkets.trapmechanism.name=trap mechanism items.trinkets.trapmechanism.desc=The core mechanism of one of the dungeon's pitfall traps, carefully carved out of the floor so it can be carried. It seems to be magically tied to the dungeon itself, making terrain more hazardous for you and the dungeon's inhabitants.\n\nAt its current level this trinket will make _%d%%_ of regular floors become filled with either traps or chasms instead. +items.trinkets.wondrousresin.name=wondrous resin +items.trinkets.wondrousresin.desc=This shimmering blue resin appears to have the distilled essence of a cursed wand's magic. The magic from the alchemy post has seemed to stabilize it somewhat, and its now affecting your wands.\n\nAt its current level this trinket will cause cursed wand effects to be forced positive _%1$s%%_ of the time, and will cause uncursed wands to fire an additional cursed zap _%2$s%%_ of the time.\n\nThis trinket costs a relatively large amount of energy to upgrade. + items.trinkets.trinketcatalyst.name=magical catalyst items.trinkets.trinketcatalyst.window_text=The water begins to glow as you add the catalyst. There are a few nearby items you could imbue with energy to turn into a magical trinket. items.trinkets.trinketcatalyst.desc=This ball of magical golden dust glimmers in the darkness of the dungeon. This catalyst can be used at an alchemy pot with a little alchemical energy to produce a unique trinket item.\n\nTrinkets provide various different effects that slightly alter the dungeon or its inhabitants. Trinkets can be upgraded with more energy to make their effect more powerful, or dropped to forego the effect entirely. diff --git a/core/src/main/assets/sprites/items.png b/core/src/main/assets/sprites/items.png index 3f1a41f26..7cab0ebe1 100644 Binary files a/core/src/main/assets/sprites/items.png and b/core/src/main/assets/sprites/items.png differ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Generator.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Generator.java index e592d3d97..1497737d6 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Generator.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Generator.java @@ -117,6 +117,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.ThirteenLeafClove import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.TrapMechanism; import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.Trinket; import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.TrinketCatalyst; +import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.WondrousResin; import com.shatteredpixel.shatteredpixeldungeon.items.wands.Wand; import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfBlastWave; import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfCorrosion; @@ -566,9 +567,10 @@ public class Generator { MossyClump.class, DimensionalSundial.class, ThirteenLeafClover.class, - TrapMechanism.class + TrapMechanism.class, + WondrousResin.class }; - TRINKET.defaultProbs = new float[]{ 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + TRINKET.defaultProbs = new float[]{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; TRINKET.probs = TRINKET.defaultProbs.clone(); for (Category cat : Category.values()){ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/trinkets/WondrousResin.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/trinkets/WondrousResin.java new file mode 100644 index 000000000..32b02776a --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/trinkets/WondrousResin.java @@ -0,0 +1,73 @@ +/* + * 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 + */ + +package com.shatteredpixel.shatteredpixeldungeon.items.trinkets; + +import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; + +public class WondrousResin extends Trinket { + + { + image = ItemSpriteSheet.WONDROUS_RESIN; + } + + @Override + protected int upgradeEnergyCost() { + //5 -> 10(15) -> 15(30) -> 20(50) + return 10+5*level(); + } + + @Override + public String desc() { + return Messages.get(this, "desc", + Messages.decimalFormat("#.##", 100*positiveCurseEffectChance(buffedLvl())), + Messages.decimalFormat("#.##", 100*extraCurseEffectChance(buffedLvl()))); + } + + //TODO currently this trims most rare/v.rare wand effects entirely. Need to improve variety there + // certain effects might also be extremely good with no negatives + + public static float positiveCurseEffectChance(){ + return positiveCurseEffectChance( trinketLevel(WondrousResin.class) ); + } + + public static float positiveCurseEffectChance(int level ){ + if (level >= 0){ + return 0.25f + 0.25f * level; + } else { + return 0; + } + } + + public static float extraCurseEffectChance(){ + return extraCurseEffectChance( trinketLevel(WondrousResin.class) ); + } + + public static float extraCurseEffectChance( int level ){ + if (level >= 0){ + return 0.125f + 0.125f * level; + } else { + return 0; + } + } + +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/CursedWand.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/CursedWand.java index 844ce000e..109d1ce0e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/CursedWand.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/CursedWand.java @@ -54,6 +54,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.bombs.Bomb; import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfRecharging; import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTeleportation; +import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.WondrousResin; import com.shatteredpixel.shatteredpixeldungeon.levels.Level; import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; import com.shatteredpixel.shatteredpixeldungeon.levels.traps.CursingTrap; @@ -123,6 +124,7 @@ public class CursedWand { } private static boolean commonEffect(final Item origin, final Char user, final int targetPos){ + boolean positiveOnly = Random.Float() < WondrousResin.positiveCurseEffectChance(); switch(Random.Int(4)){ //anti-entropy @@ -130,9 +132,9 @@ public class CursedWand { Char target = Actor.findChar(targetPos); if (Random.Int(2) == 0) { if (target != null) Buff.affect(target, Burning.class).reignite(target); - Buff.affect(user, Frost.class, Frost.DURATION); + if (!positiveOnly) Buff.affect(user, Frost.class, Frost.DURATION); } else { - Buff.affect(user, Burning.class).reignite(user); + if (!positiveOnly)Buff.affect(user, Burning.class).reignite(user); if (target != null) Buff.affect(target, Frost.class, Frost.DURATION); } tryForWandProc(target, origin); @@ -146,7 +148,7 @@ public class CursedWand { //random teleportation case 2: - if(Random.Int(2) == 0) { + if(!positiveOnly && Random.Int(2) == 0) { if (user != null && !user.properties().contains(Char.Property.IMMOVABLE)) { ScrollOfTeleportation.teleportChar(user); } else { @@ -183,6 +185,7 @@ public class CursedWand { } private static boolean uncommonEffect(final Item origin, final Char user, final int targetPos){ + boolean positiveOnly = Random.Float() < WondrousResin.positiveCurseEffectChance(); switch(Random.Int(4)){ //Random plant @@ -208,7 +211,7 @@ public class CursedWand { int damage = Dungeon.scalingDepth() * 2; Char toHeal, toDamage; - if (Random.Int(2) == 0){ + if (positiveOnly || Random.Int(2) == 0){ toHeal = user; toDamage = target; } else { @@ -251,7 +254,7 @@ public class CursedWand { //shock and recharge case 3: - new ShockingTrap().set( user.pos ).activate(); + if (!positiveOnly) new ShockingTrap().set( user.pos ).activate(); Buff.prolong(user, Recharging.class, Recharging.DURATION); ScrollOfRecharging.charge(user); SpellSprite.show(user, SpellSprite.CHARGE); @@ -261,7 +264,8 @@ public class CursedWand { } private static boolean rareEffect(final Item origin, final Char user, final int targetPos){ - switch(Random.Int(4)){ + boolean positiveOnly = Random.Float() < WondrousResin.positiveCurseEffectChance(); + switch(positiveOnly ? 0 : Random.Int(4)){ //sheep transformation case 0: default: @@ -325,20 +329,24 @@ public class CursedWand { } private static boolean veryRareEffect(final Item origin, final Char user, final int targetPos){ - switch(Random.Int(4)){ + boolean positiveOnly = Random.Float() < WondrousResin.positiveCurseEffectChance(); + switch( positiveOnly ? 0 : Random.Int(4) ){ //great forest fire! case 0: default: for (int i = 0; i < Dungeon.level.length(); i++){ GameScene.add( Blob.seed(i, 15, Regrowth.class)); } - do { - GameScene.add(Blob.seed(Dungeon.level.randomDestination(null), 10, Fire.class)); - } while (Random.Int(5) != 0); + new Flare(8, 32).color(0xFFFF66, true).show(user.sprite, 2f); Sample.INSTANCE.play(Assets.Sounds.TELEPORT); GLog.p(Messages.get(CursedWand.class, "grass")); - GLog.w(Messages.get(CursedWand.class, "fire")); + if (!positiveOnly) { + GLog.w(Messages.get(CursedWand.class, "fire")); + do { + GameScene.add(Blob.seed(Dungeon.level.randomDestination(null), 10, Fire.class)); + } while (Random.Int(5) != 0); + } return true; //golden mimic diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/Wand.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/Wand.java index 7f41e3426..801686693 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/Wand.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/Wand.java @@ -48,6 +48,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.bags.Bag; import com.shatteredpixel.shatteredpixeldungeon.items.bags.MagicalHolster; import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfEnergy; import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfRecharging; +import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.WondrousResin; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.MagesStaff; import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; @@ -683,9 +684,21 @@ public abstract class Wand extends Item { curWand.fx(shot, new Callback() { public void call() { curWand.onZap(shot); - curWand.wandUsed(); + if (Random.Float() < WondrousResin.extraCurseEffectChance()){ + CursedWand.cursedZap(curWand, + curUser, + new Ballistica(curUser.pos, target, Ballistica.MAGIC_BOLT), new Callback() { + @Override + public void call() { + curWand.wandUsed(); + } + }); + } else { + curWand.wandUsed(); + } } }); + } curWand.cursedKnown = true; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java index ad10a4e24..c9ddc23c0 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java @@ -481,6 +481,7 @@ public class ItemSpriteSheet { public static final int CLOVER = TRINKETS+6; public static final int TRAP_MECHANISM = TRINKETS+7; public static final int MIMIC_TOOTH = TRINKETS+8; + public static final int WONDROUS_RESIN = TRINKETS+9; static{ assignItemRect(RAT_SKULL, 16, 11); assignItemRect(PARCHMENT_SCRAP, 10, 14); @@ -491,6 +492,7 @@ public class ItemSpriteSheet { assignItemRect(CLOVER, 11, 15); assignItemRect(TRAP_MECHANISM, 13, 15); assignItemRect(MIMIC_TOOTH, 8, 15); + assignItemRect(WONDROUS_RESIN, 12, 11); } private static final int SCROLLS = xy(1, 19); //16 slots