v2.5.0: implemented the shard of oblivion trinket

This commit is contained in:
Evan Debenham
2024-09-03 15:02:33 -04:00
parent f5c4ccf20b
commit a47baab4a3
9 changed files with 287 additions and 24 deletions

View File

@@ -1372,12 +1372,15 @@ items.trinkets.saltcube.stats_desc=At its current level this trinket will increa
items.trinkets.shardofoblivion.name=shard of oblivion
items.trinkets.shardofoblivion.desc=After stewing in the alchemy pot, this small shard of cursed metal has changed to be made of... nothing? Light seems to bend around it, and it hovers in place when you aren't holding it. The shard seems to be magically drawing power from your ignorance, so it's probably best to not think about it too much.
items.trinkets.shardofoblivion.typical_stats_desc=Typically this trinket will increase the rate that enemies drop loot by 10% for each unidentified item you have equipped, to a max of _%d_ item(s). The shard will also prevent you from automatically identifying equipment, but can be used to manually identify items that are ready for it.
items.trinkets.shardofoblivion.stats_desc=At its current level this trinket will increase the rate that enemies drop loot by 10% for each unidentified item you have equipped, to a max of _%d_ item(s). The shard will also prevent you from automatically identifying equipment, but can be used to manually identify items that are ready for it.
items.trinkets.shardofoblivion.typical_stats_desc=Typically this trinket will increase the rate that enemies drop loot by 12.5%% for each unidentified item you have equipped or recently used, to a max of _%d item(s)_. The shard will also prevent you from automatically identifying equipment, but can be used to manually identify items that are ready for it.
items.trinkets.shardofoblivion.stats_desc=At its current level this trinket will increase the rate that enemies drop loot by 12.5%% for each unidentified item you have equipped or recently used, to a max of _%d item(s)_. The shard will also prevent you from automatically identifying equipment, but can be used to manually identify items that are ready for it.
items.trinkets.shardofoblivion.ac_identify=IDENTIFY
items.trinkets.shardofoblivion.identify_prompt=Identify an Item
items.trinkets.shardofoblivion.identify_ready=An item is ready to identify: %s.
items.trinkets.shardofoblivion.identify_not_yet=That item isn't ready to be identified yet.
items.trinkets.shardofoblivion.identify=You identify the item!
items.trinkets.shardofoblivion$wandusetracker.name=Unidentified Wand Used
items.trinkets.shardofoblivion$wandusetracker.desc=You have recently used an unidentified wand, which counts as one piece of used unidentified equipment for the shard of oblivion for a little while.\n\nTurns remaining: %s
items.trinkets.thirteenleafclover.name=thirteen leaf clover
items.trinkets.thirteenleafclover.desc=Somehow stewing in the alchemy pot has caused this clover to grow a bunch of extra leaves! It's not really clear if this trinket is lucky or unlucky, perhaps this trinket will make your luck more chaotic?

View File

@@ -56,6 +56,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.CloakOfShadows;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HornOfPlenty;
import com.shatteredpixel.shatteredpixeldungeon.items.rings.Ring;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfRecharging;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.ShardOfOblivion;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.Wand;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.SpiritBow;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.Weapon;
@@ -451,11 +452,17 @@ public enum Talent {
}
if (talent == VETERANS_INTUITION && hero.pointsInTalent(VETERANS_INTUITION) == 2){
if (hero.belongings.armor() != null) hero.belongings.armor.identify();
if (hero.belongings.armor() != null && !ShardOfOblivion.passiveIDDisabled()) {
hero.belongings.armor.identify();
}
}
if (talent == THIEFS_INTUITION && hero.pointsInTalent(THIEFS_INTUITION) == 2){
if (hero.belongings.ring instanceof Ring) hero.belongings.ring.identify();
if (hero.belongings.misc instanceof Ring) hero.belongings.misc.identify();
if (hero.belongings.ring instanceof Ring && !ShardOfOblivion.passiveIDDisabled()) {
hero.belongings.ring.identify();
}
if (hero.belongings.misc instanceof Ring && !ShardOfOblivion.passiveIDDisabled()) {
hero.belongings.misc.identify();
}
for (Item item : Dungeon.hero.belongings){
if (item instanceof Ring){
((Ring) item).setKnown();
@@ -467,7 +474,9 @@ public enum Talent {
if (hero.belongings.misc instanceof Ring) ((Ring) hero.belongings.misc).setKnown();
}
if (talent == ADVENTURERS_INTUITION && hero.pointsInTalent(ADVENTURERS_INTUITION) == 2){
if (hero.belongings.weapon() != null) hero.belongings.weapon().identify();
if (hero.belongings.weapon() != null && !ShardOfOblivion.passiveIDDisabled()){
hero.belongings.weapon().identify();
}
}
if (talent == PROTECTIVE_SHADOWS && hero.invisible > 0){
@@ -686,17 +695,21 @@ public enum Talent {
}
public static void onItemEquipped( Hero hero, Item item ){
boolean identify = false;
if (hero.pointsInTalent(VETERANS_INTUITION) == 2 && item instanceof Armor){
item.identify();
identify = true;
}
if (hero.hasTalent(THIEFS_INTUITION) && item instanceof Ring){
if (hero.pointsInTalent(THIEFS_INTUITION) == 2){
item.identify();
} else {
((Ring) item).setKnown();
identify = true;
}
((Ring) item).setKnown();
}
if (hero.pointsInTalent(ADVENTURERS_INTUITION) == 2 && item instanceof Weapon){
identify = true;
}
if (identify && !ShardOfOblivion.passiveIDDisabled()){
item.identify();
}
}

View File

@@ -68,6 +68,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfWealth;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.exotic.ExoticScroll;
import com.shatteredpixel.shatteredpixeldungeon.items.stones.StoneOfAggression;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.ExoticCrystals;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.ShardOfOblivion;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.SpiritBow;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.Weapon;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Lucky;
@@ -885,6 +886,8 @@ public abstract class Mob extends Char {
}
}
dropBonus += ShardOfOblivion.lootChanceMultiplier()-1f;
return lootChance * dropBonus;
}

View File

@@ -116,6 +116,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.ParchmentScrap;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.PetrifiedSeed;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.RatSkull;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.SaltCube;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.ShardOfOblivion;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.ThirteenLeafClover;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.TrapMechanism;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.Trinket;
@@ -578,9 +579,10 @@ public class Generator {
WondrousResin.class,
EyeOfNewt.class,
SaltCube.class,
VialOfBlood.class
VialOfBlood.class,
ShardOfOblivion.class
};
TRINKET.defaultProbs = new float[]{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
TRINKET.defaultProbs = new float[]{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
TRINKET.probs = TRINKET.defaultProbs.clone();
for (Category cat : Category.values()){

View File

@@ -60,6 +60,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.armor.glyphs.Viscosity;
import com.shatteredpixel.shatteredpixeldungeon.items.bags.Bag;
import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfArcana;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.ParchmentScrap;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.ShardOfOblivion;
import com.shatteredpixel.shatteredpixeldungeon.journal.Catalog;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
@@ -223,6 +224,10 @@ public class Armor extends EquipableItem {
return super.identify(byHero);
}
public boolean readyToIdentify(){
return !isIdentified() && usesLeftToID <= 0;
}
@Override
public boolean doEquip( Hero hero ) {
@@ -468,9 +473,16 @@ public class Armor extends EquipableItem {
availableUsesToID -= uses;
usesLeftToID -= uses;
if (usesLeftToID <= 0) {
identify();
GLog.p( Messages.get(Armor.class, "identify") );
Badges.validateItemLevelAquired( this );
if (ShardOfOblivion.passiveIDDisabled()){
if (usesLeftToID > -1){
GLog.p(Messages.get(ShardOfOblivion.class, "identify_ready"), name());
}
usesLeftToID = -1;
} else {
identify();
GLog.p(Messages.get(Armor.class, "identify"));
Badges.validateItemLevelAquired(this);
}
}
}

View File

@@ -33,6 +33,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.ItemStatusHandler;
import com.shatteredpixel.shatteredpixeldungeon.items.KindofMisc;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.ShardOfOblivion;
import com.shatteredpixel.shatteredpixeldungeon.journal.Catalog;
import com.shatteredpixel.shatteredpixeldungeon.journal.Notes;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
@@ -247,6 +248,10 @@ public class Ring extends KindofMisc {
levelsToID = 0;
return super.identify(byHero);
}
public boolean readyToIdentify(){
return !isIdentified() && levelsToID <= 0;
}
@Override
public Item random() {
@@ -325,9 +330,16 @@ public class Ring extends KindofMisc {
//becomes IDed after 1 level
levelsToID -= levelPercent;
if (levelsToID <= 0){
identify();
GLog.p( Messages.get(Ring.class, "identify") );
Badges.validateItemLevelAquired( this );
if (ShardOfOblivion.passiveIDDisabled()){
if (levelsToID > -1){
GLog.p(Messages.get(ShardOfOblivion.class, "identify_ready"), name());
}
levelsToID = -1;
} else {
identify();
GLog.p(Messages.get(Ring.class, "identify"));
Badges.validateItemLevelAquired(this);
}
}
}

View File

@@ -0,0 +1,191 @@
/*
* 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.items.trinkets;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Badges;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.FlavourBuff;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
import com.shatteredpixel.shatteredpixeldungeon.effects.Identification;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.armor.Armor;
import com.shatteredpixel.shatteredpixeldungeon.items.rings.Ring;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.Wand;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.Weapon;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndBag;
import com.watabou.noosa.Image;
import com.watabou.noosa.audio.Sample;
import java.util.ArrayList;
public class ShardOfOblivion extends Trinket {
{
image = ItemSpriteSheet.OBLIVION_SHARD;
}
public static final String AC_IDENTIFY = "IDENTIFY";
@Override
protected int upgradeEnergyCost() {
//5 -> 8(13) -> 10(23) -> 12(35)
return 6+2*level();
}
@Override
public String statsDesc() {
if (isIdentified()){
return Messages.get(this, "stats_desc", buffedLvl()+1);
} else {
return Messages.get(this, "stats_desc", 1);
}
}
@Override
public ArrayList<String> actions(Hero hero) {
ArrayList<String> actions = super.actions(hero);
actions.add(AC_IDENTIFY);
return actions;
}
@Override
public void execute(Hero hero, String action) {
if (action.equals(AC_IDENTIFY)){
curUser = hero;
curItem = this;
GameScene.selectItem(identifySelector);
} else {
super.execute(hero);
}
}
public static WndBag.ItemSelector identifySelector = new WndBag.ItemSelector() {
@Override
public String textPrompt() {
return Messages.get(ShardOfOblivion.class, "identify_prompt");
}
@Override
public boolean itemSelectable(Item item) {
return !item.isIdentified() && item.isUpgradable();
}
@Override
public void onSelect(Item item) {
boolean ready = false;
if (item instanceof Weapon){
ready = ((Weapon) item).readyToIdentify();
if (item.isEquipped(curUser) && curUser.pointsInTalent(Talent.ADVENTURERS_INTUITION) == 2){
ready = true;
}
} else if (item instanceof Armor){
ready = ((Armor) item).readyToIdentify();
if (item.isEquipped(curUser) && curUser.pointsInTalent(Talent.VETERANS_INTUITION) == 2){
ready = true;
}
} else if (item instanceof Ring){
ready = ((Ring) item).readyToIdentify();
if (item.isEquipped(curUser) && curUser.pointsInTalent(Talent.THIEFS_INTUITION) == 2){
ready = true;
}
} else if (item instanceof Wand){
ready = ((Wand) item).readyToIdentify();
}
if (ready){
item.identify();
Badges.validateItemLevelAquired(item);
curUser.sprite.operate(curUser.pos);
Sample.INSTANCE.play(Assets.Sounds.TELEPORT);
curUser.sprite.parent.add( new Identification( curUser.sprite.center().offset( 0, -16 ) ) );
GLog.p(Messages.get(ShardOfOblivion.class, "identify"));
} else {
GLog.w(Messages.get(ShardOfOblivion.class, "identify_not_yet"));
}
}
};
public static boolean passiveIDDisabled(){
return trinketLevel(ShardOfOblivion.class) >= 0;
}
public static class WandUseTracker extends FlavourBuff{
{
type = buffType.POSITIVE;
}
public static float DURATION = 50f;
@Override
public int icon() {
return BuffIndicator.WAND;
}
@Override
public void tintIcon(Image icon) {
icon.hardlight(0, 0.6f, 1);
}
@Override
public float iconFadePercent() {
return Math.max(0, (DURATION - visualcooldown()) / DURATION);
}
}
public static float lootChanceMultiplier(){
return lootChanceMultiplier(trinketLevel(ShardOfOblivion.class));
}
public static float lootChanceMultiplier(int level){
if (level < 0) return 1f;
int wornUnIDed = 0;
if (Dungeon.hero.belongings.weapon() != null && !Dungeon.hero.belongings.weapon().isIdentified()){
wornUnIDed++;
}
if (Dungeon.hero.belongings.armor() != null && !Dungeon.hero.belongings.armor().isIdentified()){
wornUnIDed++;
}
if (Dungeon.hero.belongings.ring() != null && !Dungeon.hero.belongings.ring().isIdentified()){
wornUnIDed++;
}
if (Dungeon.hero.belongings.misc() != null && !Dungeon.hero.belongings.misc().isIdentified()){
wornUnIDed++;
}
if (Dungeon.hero.buff(WandUseTracker.class) != null){
wornUnIDed++;
}
wornUnIDed = Math.min(wornUnIDed, level+1);
return 1f + .125f*wornUnIDed;
}
}

View File

@@ -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.ShardOfOblivion;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.WondrousResin;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.MagesStaff;
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
@@ -242,6 +243,10 @@ public abstract class Wand extends Item {
return this;
}
public boolean readyToIdentify(){
return !isIdentified() && usesLeftToID <= 0;
}
public void onHeroGainExp( float levelPercent, Hero hero ){
levelPercent *= Talent.itemIDSpeedFactor(hero, this);
@@ -424,9 +429,19 @@ public abstract class Wand extends Item {
availableUsesToID -= uses;
usesLeftToID -= uses;
if (usesLeftToID <= 0 || Dungeon.hero.pointsInTalent(Talent.SCHOLARS_INTUITION) == 2) {
identify();
GLog.p( Messages.get(Wand.class, "identify") );
Badges.validateItemLevelAquired( this );
if (ShardOfOblivion.passiveIDDisabled()){
if (usesLeftToID > -1){
GLog.p(Messages.get(ShardOfOblivion.class, "identify_ready"), name());
}
usesLeftToID = -1;
} else {
identify();
GLog.p(Messages.get(Wand.class, "identify"));
Badges.validateItemLevelAquired(this);
}
}
if (ShardOfOblivion.passiveIDDisabled()){
Buff.prolong(curUser, ShardOfOblivion.WandUseTracker.class, 50f);
}
}

View File

@@ -36,6 +36,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfArcana;
import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfForce;
import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfFuror;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.ParchmentScrap;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.ShardOfOblivion;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.curses.Annoying;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.curses.Dazzling;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.curses.Displacing;
@@ -122,9 +123,16 @@ abstract public class Weapon extends KindOfWeapon {
availableUsesToID -= uses;
usesLeftToID -= uses;
if (usesLeftToID <= 0) {
identify();
GLog.p( Messages.get(Weapon.class, "identify") );
Badges.validateItemLevelAquired( this );
if (ShardOfOblivion.passiveIDDisabled()){
if (usesLeftToID > -1){
GLog.p(Messages.get(ShardOfOblivion.class, "identify_ready"), name());
}
usesLeftToID = -1;
} else {
identify();
GLog.p(Messages.get(Weapon.class, "identify"));
Badges.validateItemLevelAquired(this);
}
}
}
@@ -198,6 +206,10 @@ abstract public class Weapon extends KindOfWeapon {
}
return super.identify(byHero);
}
public boolean readyToIdentify(){
return !isIdentified() && usesLeftToID <= 0;
}
@Override
public float accuracyFactor(Char owner, Char target) {