From d39a062246876cc9ad1a5bd3bf5fe466dd65bb5b Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Mon, 17 Nov 2025 18:29:25 -0500 Subject: [PATCH] v3.3.0: initial impl of skeleton key, missing lots of polish --- .../assets/messages/actors/actors.properties | 2 + .../assets/messages/items/items.properties | 15 + core/src/main/assets/sprites/items.png | Bin 24956 -> 25011 bytes .../actors/hero/Hero.java | 47 +- .../actors/hero/abilities/cleric/Trinity.java | 3 +- .../actors/hero/spells/SpiritForm.java | 4 + .../items/Generator.java | 13 +- .../items/artifacts/SkeletonKey.java | 475 ++++++++++++++++++ .../sprites/ItemSpriteSheet.java | 2 + 9 files changed, 550 insertions(+), 11 deletions(-) create mode 100644 core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/SkeletonKey.java diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties index 294455efd..49a109efb 100644 --- a/core/src/main/assets/messages/actors/actors.properties +++ b/core/src/main/assets/messages/actors/actors.properties @@ -573,6 +573,7 @@ actors.hero.abilities.cleric.trinity.etherealchains_use=Trinity will apply this actors.hero.abilities.cleric.trinity.hornofplenty_use=Trinity will apply this artifact's snacking effect, at the cost of _%2$s charge._ actors.hero.abilities.cleric.trinity.masterthievesarmband_use=Trinity will apply this artifact's enemy robbing effect at _+%1$d_, at the cost of _%2$s charge._ actors.hero.abilities.cleric.trinity.sandalsofnature_use=Trinity will apply this artifact's root effect with a random harmful seed, at the cost of _%2$s charge._ +actors.hero.abilities.cleric.trinity.skeletonkey=Trinity will apply this artifact's insert effect, at the cost of _%2$s charge._ actors.hero.abilities.cleric.trinity.talismanofforesight_use=Trinity will apply this artifact's scry effect at _+%1$d_, at the cost of _%2$s charge._ actors.hero.abilities.cleric.trinity.timekeepershourglass_use=Trinity will apply this artifact's time freeze effect with a _%1$d_ turn duration, at the cost of _%2$s charge._ actors.hero.abilities.cleric.trinity.unstablespellbook_use=Trinity will apply this artifact's random scroll effect with a _%1$d/10_ chance to offer the exotic version at no additional cost, at the cost of _%2$s charge._ @@ -795,6 +796,7 @@ actors.hero.hero.noticed_smth=You noticed something. actors.hero.hero.wait=... actors.hero.hero.search=search actors.hero.hero.search_distracted=It's hard to concentrate, searching is exhausting. +actors.hero.hero.key_distracted=You fiddle with the lock but can't quite open it this time. actors.hero.hero.pain_resist=The pain helps you resist the urge to sleep. actors.hero.hero.revive=The ankh explodes with life-giving energy! diff --git a/core/src/main/assets/messages/items/items.properties b/core/src/main/assets/messages/items/items.properties index d4de9d424..a005e6f1e 100644 --- a/core/src/main/assets/messages/items/items.properties +++ b/core/src/main/assets/messages/items/items.properties @@ -424,6 +424,21 @@ items.artifacts.sandalsofnature.desc_cursed=The cursed sandals are blocking any items.artifacts.sandalsofnature.desc_ability=The footwear ripples with the color of the last seed you fed them. They can briefly root into the ground and produce that plant's effect anywhere in a 3 tile radius.\nSeed: _%s_\nCharge needed: _%d%%_ items.artifacts.sandalsofnature.desc_seeds=You have fed the footwear %d seeds. +items.artifacts.skeletonkey.name=skeleton key +items.artifacts.skeletonkey.ac_insert=INSERT +items.artifacts.skeletonkey.no_charge=Your key does not have enough charge. +items.artifacts.skeletonkey.cursed=You can't use a cursed skeleton key. +items.artifacts.skeletonkey.prompt=Choose a target +items.artifacts.skeletonkey.invalid_target=There's nothing to lock or unlock there. +items.artifacts.skeletonkey.gold_charges=Opening a gold lock requires 2 charges. +items.artifacts.skeletonkey.lock_charges=Locking a door requires 2 charges. +items.artifacts.skeletonkey.wall_charges=Creating a temporary wall requires 2 charges. +items.artifacts.skeletonkey.crystal_charges=Opening a crystal lock requires 4 charges. +items.artifacts.skeletonkey.wont_open=The key refuses to fit into this lock for some reason. +items.artifacts.skeletonkey.desc=An important-looking key with a head shaped like a skull. Its teeth seem to be different every time you look at them. +items.artifacts.skeletonkey.desc_worn=This magical key seems to gain power as you explore the dungeon and open more locks.\n\nThe key can be inserted into any of the dungeon's locks to either open or close them. This includes most special locks and doors that were never locked previously. The key can even be used on empty space in a cardinal or diagonal direction to 'lock' the air in front of you, creating a temporary solid wall. Locking will push away enemies if there is space to do so. +items.artifacts.skeletonkey.desc_cursed=The cursed key seems to be actively avoiding fitting into any lock, and is even making it difficult (but not impossible) for you to use your other keys. + items.artifacts.talismanofforesight.name=talisman of foresight items.artifacts.talismanofforesight.ac_scry=SCRY items.artifacts.talismanofforesight.low_charge=The talisman requires at least 5% charge to scry. diff --git a/core/src/main/assets/sprites/items.png b/core/src/main/assets/sprites/items.png index bf1f33fbdabaeeac87067b2c8f044ec8acec4f29..4028be31ef150987317cca2c545c5f44a45a9d3b 100644 GIT binary patch literal 25011 zcmb5Uc|4Tg`#*l)GYn%dmE9;W6hhgznJJYPThS{OhE(<~WS<#JX+uTU7^O&sM0PV{ zDYA`1l$e<;L&7kY!I=3@@Av2XTOQxPzW|~ujh5$b+EG*7m*hM06_fI z$z$gL0OUVH0AUzE3&?%H1ppq=r;Z(QiUj}s_!7{jCnn&an{D{sv80(>joYg^ee0ng z8z}O*diudj^T$bPh!=Ip_$w(NmO#RfP{RUow#hGCaL^EUW^8V&jA*2bq2fs24@x~g z`>;VC$Khh)czb^d6xh2%h3|749V#sq-DMh$Il&%Vp4(zvZdV{2T!le)PwH}?3wJ`h zMDwnsmmDu-g2K?y7bqhmOeb+M6yx2~VFP0t?E8>Ta+~&kJcz9Lnch;3T8-3t zyk3YRo)2OE47On|N4kPn{D>#Eq(WH z2=ls-sXM~^o=%39e0<#7Lkp08D>4$xEq3a?8=-v_Fg%8Ds-GzJLT%e`*MC6FTC*1Z@H=rxrd9ju&JW%u_3z&WHo1&y z0`&zzWV5&&8M|yO>leqY_`O%!12)U?HhPRwtO!zPrqGFYZY8w*%mTvfy#^bJ?9H3Dkkc8-7dJE_!DZdrR(^z?(& z-|i<~FE)W4@XzSE*?riqe^<7ikLT@+ZD!YnPkUUN4q{}4zjn)yj$>fs7_Vb4t-mo_ zWzJ!@$G7rDB{y4N!d!8^H_SJ(Rp-C5Q1BG7ys#55WKeV0cdoZojSe5W$2zx6A)>uo zRf3T2LMu|@v}Yt&4_W0sNFYTlJ?!@4*PIFUUAi3UZt79B9DrT|_6sz~TY>CDFYLH| zuEr(V0G;HYuax&Y+}z5lX8eA^wXI&aiVINTI6XXI$z@MS_T(8af)8|^-;woJT6yQI zgvuKOd+bcs*pr<68fu?6pxM*0+#Er@B`*g{nR$@Z_=K~bZZ3vrdY-%sKPHJ(!EHUV zmo1t2^bldo4mjM9i~fhuUj;+2o?Etz96DfhAd_?P#8GCcA)NR2VwF1}*$*@^38tkH z_L?67z~FRD1{1GnWkZPUp`T!zB3LR9Btyl?hl3O^z3tvUk2~A6N6JYAC63qh0QO~p zCl8YS0B|3Bu(~B}2FfuW3zNPLp1y^6NoIt>f69a=kT!M6T=pNRclvY`&1(oDAI*L_={1B>L%0tBBjXw?DSNj- zz|z)ze=cO{H_oEx{HFPj?WBUQ*M78U1lQJV#4)$Tfp=P*QW$V;1(d=X;%~#nlsRHI z+4Xd<_BY#mUyf1#{PAl|x%Nkf_P+S`Gr4|0A(baQi<+9PYfYnv=jj?hzZj9c8_Yp? zbF1W&rlb)FsRKBQp~*l^7V0K?1W`q2SJ%muhdY&N(%5_IWFnX=kd@MN)lj1e_Ar9* zUKW440`h7SD5=>P%@v)}g=VGz;LY7x^*XCZ{EQ$mTYLEj2SiTxYS8NXB$>M-#rF1f zSbUTEb^_`?VnB@5KQ_AU%DcyIH1r*G_A{$YIQjfUiu~U4=No&E3of_)D3dpoSNR#U*!->7 z2_Q93#(jJ4jm)yOv2nI>JmSAJlZnVYc=>3yCk^rPVy&bb zQ(Z=eHieeLys`@ggPOT$2nQ+cz}{AuQjTRFfetcKiJ$lX?I4Hh#>U+Pe^1nmjQsZn zYjI;q6FOK?&^!hIpEl6ghVU0%1HfTS7p-1hrAo zL~u>Pe(a-@25)tbt2jU)_yW!sKqD`2E|s@URVd{C_KA_d<k*_iS67q$TG}a?9Kl_B?n`uyTX%+`+E-h+S&U6 zXR>q*?@UlR)5duNXQ2+2+xD|J_=An|GITEd|BDqchr}KG(aMgYuDvBYj=k9M1q778 z&SuC1@yS1mi(tWjDm#pB8DZy4Uc#8)C-USy6sRf>=583`ZxJ@`8QwBNvJRDZ4*`9f zGjQ9=6iE-4tP9XrU+$dvOxfwC_7dlZJhNTH`Sz7c6##lJ+5+UK{Q~`8$4CDrWB>b! zXau^PU4(>bclVZn?|x81>^!rt0&mwsU2;JK{0lqulUiwqsRaS2C^K;4HB3+Mtd%(4 zN-6oV*x%H`5O`7xD_s5tIF-wzU4{Udrmp}wCv-R9z;F{}o)#x-83Gl9z*Bxt{UUkb zTZ#gnB& z1bq^>D=Xz3!3iDXuKBT18j(Xll{EIeA~aFY;g~Z!?u+N9Lf2P1?;N~b zwykl?M@LIQSJhdA*~qCk8hsG$-JUCtX;A%0A@p&`8uDLAN1}jljeGVY-)20fH16JD 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 AD*ylh literal 24956 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 diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java index 3c6969963..1533dfacd 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java @@ -105,6 +105,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.EtherealChains; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HornOfPlenty; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.MasterThievesArmband; +import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.SkeletonKey; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.TalismanOfForesight; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.TimekeepersHourglass; import com.shatteredpixel.shatteredpixeldungeon.items.bags.MagicalHolster; @@ -2331,22 +2332,41 @@ public class Hero extends Char { int doorCell = ((HeroAction.Unlock)curAction).dst; int door = Dungeon.level.map[doorCell]; - - if (Dungeon.level.distance(pos, doorCell) <= 1) { + + SkeletonKey.keyRecharge skele = buff(SkeletonKey.keyRecharge.class); + + if (skele != null && skele.isCursed() && Random.Int(6) != 0){ + GLog.n(Messages.get(this, "key_distracted")); + spendAndNext(2*Key.TIME_TO_UNLOCK); + Buff.affect(this, Hunger.class).affectHunger(-4); + } else if (Dungeon.level.distance(pos, doorCell) <= 1) { boolean hasKey = true; if (door == Terrain.LOCKED_DOOR) { hasKey = Notes.remove(new IronKey(Dungeon.depth)); - if (hasKey) Level.set(doorCell, Terrain.DOOR); + if (hasKey) { + Level.set(doorCell, Terrain.DOOR); + if (skele != null && !skele.isCursed()){ + skele.keyUsed(new IronKey(Dungeon.depth)); + } + } } else if (door == Terrain.CRYSTAL_DOOR) { hasKey = Notes.remove(new CrystalKey(Dungeon.depth)); if (hasKey) { Level.set(doorCell, Terrain.EMPTY); Sample.INSTANCE.play(Assets.Sounds.TELEPORT); CellEmitter.get( doorCell ).start( Speck.factory( Speck.DISCOVER ), 0.025f, 20 ); + if (skele != null && !skele.isCursed()){ + skele.keyUsed(new CrystalKey(Dungeon.depth)); + } } } else { hasKey = Notes.remove(new WornKey(Dungeon.depth)); - if (hasKey) Level.set(doorCell, Terrain.UNLOCKED_EXIT); + if (hasKey) { + Level.set(doorCell, Terrain.UNLOCKED_EXIT); + if (skele != null && !skele.isCursed()){ + skele.keyUsed(new WornKey(Dungeon.depth)); + } + } } if (hasKey) { @@ -2359,17 +2379,30 @@ public class Hero extends Char { } else if (curAction instanceof HeroAction.OpenChest) { Heap heap = Dungeon.level.heaps.get( ((HeroAction.OpenChest)curAction).dst ); - - if (Dungeon.level.distance(pos, heap.pos) <= 1){ + SkeletonKey.keyRecharge skele = buff(SkeletonKey.keyRecharge.class); + + if (skele != null && skele.isCursed() + && (heap.type == Type.LOCKED_CHEST || heap.type == Type.CRYSTAL_CHEST) + && Random.Int(6) != 0){ + GLog.n(Messages.get(this, "key_distracted")); + spend(2*Key.TIME_TO_UNLOCK); + Buff.affect(this, Hunger.class).affectHunger(-4); + } else if (Dungeon.level.distance(pos, heap.pos) <= 1){ boolean hasKey = true; if (heap.type == Type.SKELETON || heap.type == Type.REMAINS) { Sample.INSTANCE.play( Assets.Sounds.BONES ); } else if (heap.type == Type.LOCKED_CHEST){ hasKey = Notes.remove(new GoldenKey(Dungeon.depth)); + if (hasKey && skele != null && !skele.isCursed()){ + skele.keyUsed(new GoldenKey(Dungeon.depth)); + } } else if (heap.type == Type.CRYSTAL_CHEST){ hasKey = Notes.remove(new CrystalKey(Dungeon.depth)); + if (hasKey && skele != null && !skele.isCursed()){ + skele.keyUsed(new CrystalKey(Dungeon.depth)); + } } - + if (hasKey) { GameScene.updateKeyDisplay(); heap.open(this); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/cleric/Trinity.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/cleric/Trinity.java index 910ec1ab3..e2baa63b1 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/cleric/Trinity.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/cleric/Trinity.java @@ -45,6 +45,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.ChaliceOfBlood; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.DriedRose; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.EtherealChains; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome; +import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.SkeletonKey; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.TalismanOfForesight; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.TimekeepersHourglass; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.UnstableSpellbook; @@ -540,7 +541,7 @@ public class Trinity extends ArmorAbility { return 2*chargeUse; } if (Artifact.class.isAssignableFrom(cls)){ - if (cls.equals(DriedRose.class) || cls.equals(UnstableSpellbook.class)){ + if (cls.equals(DriedRose.class) || cls.equals(UnstableSpellbook.class) || cls.equals(SkeletonKey.class)){ return 2*chargeUse; //50 charge } if (cls.equals(EtherealChains.class) || cls.equals(TalismanOfForesight.class) || cls.equals(TimekeepersHourglass.class)){ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/SpiritForm.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/SpiritForm.java index 2f618baf8..7a1b0b9e6 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/SpiritForm.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/SpiritForm.java @@ -39,6 +39,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HornOfPlenty; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.MasterThievesArmband; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.SandalsOfNature; +import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.SkeletonKey; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.TalismanOfForesight; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.TimekeepersHourglass; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.UnstableSpellbook; @@ -248,6 +249,9 @@ public class SpiritForm extends ClericSpell { } else if (effect instanceof UnstableSpellbook){ ((UnstableSpellbook) effect).doReadEffect(Dungeon.hero); + + } else if (effect instanceof SkeletonKey){ + GameScene.selectCell(((SkeletonKey) effect).targeter); } } 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 9d339bc72..b5b513555 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Generator.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Generator.java @@ -44,6 +44,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HornOfPlenty; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.MasterThievesArmband; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.SandalsOfNature; +import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.SkeletonKey; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.TalismanOfForesight; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.TimekeepersHourglass; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.UnstableSpellbook; @@ -566,11 +567,12 @@ public class Generator { HornOfPlenty.class, MasterThievesArmband.class, SandalsOfNature.class, + SkeletonKey.class, TalismanOfForesight.class, TimekeepersHourglass.class, UnstableSpellbook.class }; - ARTIFACT.defaultProbs = new float[]{ 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1 }; + ARTIFACT.defaultProbs = new float[]{ 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }; ARTIFACT.probs = ARTIFACT.defaultProbs.clone(); //Trinkets are unique like artifacts, but unlike them you can only have one at once @@ -950,14 +952,19 @@ public class Generator { cat.dropped = bundle.getInt(cat.name().toLowerCase() + CATEGORY_DROPPED); } - //pre-v3.0.0 conversion for artifacts specifically + //pre-v3.0.0 and pre-v3.3.0 conversion for artifacts (addition of tome and key) if (cat == Category.ARTIFACT && probs.length != cat.defaultProbs.length){ int tomeIDX = 5; + int keyIDX = 9; int j = 0; for (int i = 0; i < probs.length; i++){ - if (i == tomeIDX){ + //we do a specific check here for holy tome pre-v3.0.0 + if (j == tomeIDX && probs.length == cat.defaultProbs.length-2){ cat.probs[j] = 0; j++; + } else if (j == keyIDX){ + cat.probs[j] = 1; + j++; } cat.probs[j] = probs[i]; j++; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/SkeletonKey.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/SkeletonKey.java new file mode 100644 index 000000000..c21b25aca --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/SkeletonKey.java @@ -0,0 +1,475 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2025 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.artifacts; + +import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; +import com.shatteredpixel.shatteredpixeldungeon.actors.Char; +import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MagicImmune; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Regeneration; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; +import com.shatteredpixel.shatteredpixeldungeon.effects.BlobEmitter; +import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; +import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile; +import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; +import com.shatteredpixel.shatteredpixeldungeon.items.Heap; +import com.shatteredpixel.shatteredpixeldungeon.items.keys.IronKey; +import com.shatteredpixel.shatteredpixeldungeon.items.keys.Key; +import com.shatteredpixel.shatteredpixeldungeon.items.keys.WornKey; +import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfEnergy; +import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfBlastWave; +import com.shatteredpixel.shatteredpixeldungeon.levels.Level; +import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; +import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; +import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.scenes.CellSelector; +import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; +import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; +import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; +import com.watabou.noosa.audio.Sample; +import com.watabou.utils.Callback; +import com.watabou.utils.PathFinder; + +import java.util.ArrayList; + +//TODO needs a way to handle the excess keys it can general +public class SkeletonKey extends Artifact { + + { + image = ItemSpriteSheet.ARTIFACT_KEY; + + levelCap = 5; + + charge = 3+level(); + partialCharge = 0; + chargeCap = 3+level(); + + defaultAction = AC_INSERT; + } + + public static final String AC_INSERT = "INSERT"; + + @Override + public ArrayList actions(Hero hero) { + ArrayList actions = super.actions(hero); + if (isEquipped(hero) + && charge > 0 + && hero.buff(MagicImmune.class) == null + && !cursed) { + actions.add(AC_INSERT); + } + return actions; + } + + @Override + public void execute(Hero hero, String action) { + super.execute(hero, action); + + if (hero.buff(MagicImmune.class) != null) return; + + if (action.equals(AC_INSERT)){ + + curUser = hero; + + if (!isEquipped( hero )) { + GLog.i( Messages.get(Artifact.class, "need_to_equip") ); + + } else if (charge < 1) { + GLog.i( Messages.get(this, "no_charge") ); + + } else if (cursed) { + GLog.w( Messages.get(this, "cursed") ); + + } else { + GameScene.selectCell(targeter); + } + + } + } + + public CellSelector.Listener targeter = new CellSelector.Listener(){ + + @Override + public void onSelect(Integer target) { + + if (target != null && (Dungeon.level.visited[target] || Dungeon.level.mapped[target])){ + + if (target == curUser.pos){ + GLog.w(Messages.get(SkeletonKey.class, "invalid_target")); + return; + } + + if (Dungeon.level.adjacent(target, curUser.pos)) { + if (Dungeon.level.map[target] == Terrain.LOCKED_EXIT){ + GLog.w(Messages.get(SkeletonKey.class, "wont_open")); + return; + } + if (Dungeon.level.map[target] == Terrain.LOCKED_DOOR){ + if (Dungeon.level.locked){ + GLog.w(Messages.get(SkeletonKey.class, "wont_open")); + return; + } + Sample.INSTANCE.play(Assets.Sounds.UNLOCK); + curUser.sprite.operate(target, new Callback() { + @Override + public void call() { + Level.set(target, Terrain.DOOR); + GameScene.updateMap(target); + charge -= 1; + curUser.spendAndNext(Actor.TICK); + curUser.sprite.idle(); + } + }); + curUser.busy(); + return; + + } else if (Dungeon.level.map[target] == Terrain.CRYSTAL_DOOR) { + + if (charge < 4) { + GLog.w(Messages.get(SkeletonKey.class, "crystal_charges")); + return; + } + Sample.INSTANCE.play(Assets.Sounds.UNLOCK); + curUser.sprite.operate(target, new Callback() { + @Override + public void call() { + Level.set(target, Terrain.EMPTY); + GameScene.updateMap(target); + charge -= 4; + Sample.INSTANCE.play(Assets.Sounds.TELEPORT); + CellEmitter.get( target ).start( Speck.factory( Speck.DISCOVER ), 0.025f, 20 ); + curUser.spendAndNext(Actor.TICK); + curUser.sprite.idle(); + } + }); + curUser.busy(); + return; + } else if (Dungeon.level.map[target] == Terrain.DOOR || Dungeon.level.map[target] == Terrain.OPEN_DOOR){ + + if (charge < 2) { + GLog.w(Messages.get(SkeletonKey.class, "lock_charges")); + return; + } + + //attempt to knock back char + if (Actor.findChar(target) != null){ + int pushDIR = target - curUser.pos; + Ballistica push = new Ballistica(target, target + pushDIR, Ballistica.PROJECTILE); + WandOfBlastWave.throwChar(Actor.findChar(target), push, 1, false, false, this); + //TODO what about pushing to the side? + //TODO fail if there's no push DIR? + } + + Sample.INSTANCE.play(Assets.Sounds.UNLOCK); + curUser.sprite.operate(target, new Callback() { + @Override + public void call() { + Level.set(target, Terrain.LOCKED_DOOR); + GameScene.updateMap(target); + charge -= 2; + curUser.spendAndNext(Actor.TICK); + curUser.sprite.idle(); + } + }); + curUser.busy(); + return; + + } else if (Dungeon.level.heaps.get(target) != null && Dungeon.level.heaps.get(target).type == Heap.Type.LOCKED_CHEST){ + if (charge < 2) { + GLog.w(Messages.get(SkeletonKey.class, "gold_charges")); + return; + } + Sample.INSTANCE.play(Assets.Sounds.UNLOCK); + curUser.sprite.operate(target, new Callback() { + @Override + public void call() { + Dungeon.level.heaps.get(target).open(curUser); + charge -= 2; + curUser.spendAndNext(Actor.TICK); + curUser.sprite.idle(); + } + }); + curUser.busy(); + return; + + } else if (Dungeon.level.heaps.get(target) != null && Dungeon.level.heaps.get(target).type == Heap.Type.CRYSTAL_CHEST){ + if (charge < 4) { + GLog.w(Messages.get(SkeletonKey.class, "crystal_charges")); + return; + } + Sample.INSTANCE.play(Assets.Sounds.UNLOCK); + curUser.sprite.operate(target, new Callback() { + @Override + public void call() { + Dungeon.level.heaps.get(target).open(curUser); + charge -= 4; + curUser.spendAndNext(Actor.TICK); + curUser.sprite.idle(); + } + }); + curUser.busy(); + return; + + } + } + + if (charge < 2){ + GLog.w(Messages.get(SkeletonKey.class, "wall_charges")); + return; + } + + int closest = curUser.pos; + int closestIdx = -1; + + for (int i = 0; i < PathFinder.CIRCLE8.length; i++){ + int ofs = PathFinder.CIRCLE8[i]; + if (Dungeon.level.trueDistance(target, curUser.pos+ofs) < Dungeon.level.trueDistance(target, closest)){ + closest = curUser.pos+ofs; + closestIdx = i; + } + } + + int knockBackDir = PathFinder.CIRCLE8[closestIdx]; + + if (Dungeon.level.solid[closest]){ + GLog.w(Messages.get(SkeletonKey.class, "invalid_target")); + return; + } + + int finalClosestIdx = closestIdx; + Sample.INSTANCE.play(Assets.Sounds.UNLOCK); + curUser.sprite.operate(target, new Callback() { + @Override + public void call() { + placeWall(curUser.pos+PathFinder.CIRCLE8[finalClosestIdx], knockBackDir); + placeWall(curUser.pos+PathFinder.CIRCLE8[(finalClosestIdx +7)%8], knockBackDir); + placeWall(curUser.pos+PathFinder.CIRCLE8[(finalClosestIdx +1)%8], knockBackDir); + + //if we're in a diagonal direction + if (finalClosestIdx % 2 == 0){ + placeWall(curUser.pos+2*PathFinder.CIRCLE8[(finalClosestIdx +7)%8], knockBackDir); + placeWall(curUser.pos+2*PathFinder.CIRCLE8[(finalClosestIdx +1)%8], knockBackDir); + } + + charge -= 2; + + Dungeon.observe(); + GameScene.updateFog(); + Sample.INSTANCE.play(Assets.Sounds.TELEPORT); + + curUser.spendAndNext(Actor.TICK); + curUser.sprite.idle(); + } + }); + curUser.busy(); + + } + + } + + @Override + public String prompt() { + return Messages.get(SkeletonKey.class, "prompt"); + } + }; + + @Override + protected ArtifactBuff passiveBuff() { + return new keyRecharge(); + } + + @Override + public void charge(Hero target, float amount) { + super.charge(target, amount); //TODO + } + + @Override + public String desc() { + String desc = super.desc(); + + if ( isEquipped (Dungeon.hero) ){ + if (cursed){ + desc += "\n\n" + Messages.get(this, "desc_cursed"); + } else { + desc += "\n\n" + Messages.get(this, "desc_worn"); //TODO probably want more info on making walls + } + } + + return desc; + } + + public class keyRecharge extends ArtifactBuff { + @Override + public boolean act() { + if (charge < chargeCap + && !cursed + && target.buff(MagicImmune.class) == null + && Regeneration.regenOn()) { + //120 turns to charge at full, 60 turns to charge at 0/8 + float chargeGain = 1 / (120f - (chargeCap - charge)*7.5f); + chargeGain *= RingOfEnergy.artifactChargeMultiplier(target); + partialCharge += chargeGain; + + while (partialCharge >= 1) { + partialCharge --; + charge ++; + + if (charge == chargeCap){ + partialCharge = 0; + } + } + } + + updateQuickslot(); + + spend( TICK ); + + return true; + } + + //TODO either finish this or think of a different levelling mechanic + public void keyUsed(Key key ){ + if (level() == levelCap){ + return; + } + + if (key instanceof IronKey){ + exp += 3; + } else if (key instanceof WornKey){ + exp += 5; + } else { + exp += 2; + } + + if (exp >= 5 + 5*level()){ + exp -= 5 + 5*level(); + upgrade(); + } + + } + } + + private void placeWall( int pos, int knockbackDIR ){ + if (!Dungeon.level.solid[pos]) { //TODO this prevents wall stacking + //TODO 10 or 20 turns? + GameScene.add(Blob.seed(pos, 20, KeyWall.class)); + + Char ch = Actor.findChar(pos); + if (ch != null && ch.alignment == Char.Alignment.ENEMY){ + WandOfBlastWave.throwChar(ch, new Ballistica(pos, pos+knockbackDIR, Ballistica.PROJECTILE), 1, false, false, this); + } + } + } + + public static class KeyWall extends Blob { + + { + alwaysVisible = true; + } + + @Override + protected void evolve() { + + int cell; + boolean cellEnded = false; + + Level l = Dungeon.level; + for (int i = area.left; i < area.right; i++){ + for (int j = area.top; j < area.bottom; j++){ + cell = i + j*l.width(); + off[cell] = cur[cell] > 0 ? cur[cell] - 1 : 0; + + if (cur[cell] > 0 && off[cell] == 0){ + cellEnded = true; + } + + //caps at 20 + //TODO or just one wall at a time? + off[cell] = Math.min(off[cell], 19); + + volume += off[cell]; + + l.losBlocking[cell] = off[cell] > 0 || (Terrain.flags[l.map[cell]] & Terrain.LOS_BLOCKING) != 0; + l.solid[cell] = off[cell] > 0 || (Terrain.flags[l.map[cell]] & Terrain.SOLID) != 0; + l.passable[cell] = off[cell] == 0 && (Terrain.flags[l.map[cell]] & Terrain.PASSABLE) != 0; + l.avoid[cell] = off[cell] == 0 && (Terrain.flags[l.map[cell]] & Terrain.AVOID) != 0; + } + } + + if (cellEnded){ + Dungeon.observe(); + } + } + + @Override + public void seed(Level level, int cell, int amount) { + super.seed(level, cell, amount); + level.losBlocking[cell] = cur[cell] > 0 || (Terrain.flags[level.map[cell]] & Terrain.LOS_BLOCKING) != 0; + level.solid[cell] = cur[cell] > 0 || (Terrain.flags[level.map[cell]] & Terrain.SOLID) != 0; + level.passable[cell] = cur[cell] == 0 && (Terrain.flags[level.map[cell]] & Terrain.PASSABLE) != 0; + level.avoid[cell] = cur[cell] == 0 && (Terrain.flags[level.map[cell]] & Terrain.AVOID) != 0; + } + + @Override + public void clear(int cell) { + super.clear(cell); + if (cur == null) return; + Level l = Dungeon.level; + l.losBlocking[cell] = cur[cell] > 0 || (Terrain.flags[l.map[cell]] & Terrain.LOS_BLOCKING) != 0; + l.solid[cell] = cur[cell] > 0 || (Terrain.flags[l.map[cell]] & Terrain.SOLID) != 0; + l.passable[cell] = cur[cell] == 0 && (Terrain.flags[l.map[cell]] & Terrain.PASSABLE) != 0; + l.avoid[cell] = cur[cell] == 0 && (Terrain.flags[l.map[cell]] & Terrain.AVOID) != 0; + } + + @Override + public void fullyClear() { + super.fullyClear(); + Dungeon.level.buildFlagMaps(); + } + + @Override + public void onBuildFlagMaps(Level l) { + if (volume > 0){ + for (int i=0; i < l.length(); i++) { + l.losBlocking[i] = l.losBlocking[i] || cur[i] > 0; + l.solid[i] = l.solid[i] || cur[i] > 0; + l.passable[i] = l.passable[i] && cur[i] == 0; + l.avoid[i] = l.avoid[i] && cur[i] == 0; + } + } + } + + @Override + public void use(BlobEmitter emitter) { + super.use( emitter ); + emitter.pour( MagicMissile.WhiteParticle.WALL, 0.02f ); //TODO + } + + @Override + public String tileDesc() { + return Messages.get(this, "desc"); + } + + } +} 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 0b44641d1..76e4b5902 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java @@ -459,6 +459,7 @@ public class ItemSpriteSheet { public static final int ARTIFACT_ROSE2 = ARTIFACTS+21; public static final int ARTIFACT_ROSE3 = ARTIFACTS+22; public static final int ARTIFACT_TOME = ARTIFACTS+23; + public static final int ARTIFACT_KEY = ARTIFACTS+24; static{ assignItemRect(ARTIFACT_CLOAK, 9, 15); assignItemRect(ARTIFACT_ARMBAND, 16, 13); @@ -484,6 +485,7 @@ public class ItemSpriteSheet { assignItemRect(ARTIFACT_ROSE2, 14, 14); assignItemRect(ARTIFACT_ROSE3, 14, 14); assignItemRect(ARTIFACT_TOME, 14, 16); + assignItemRect(ARTIFACT_KEY, 8, 16); } private static final int TRINKETS = xy(1, 18); //32 slots