From febcd8d840d56ebba49d1f30c613ce51e4aec026 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Mon, 25 May 2015 02:16:15 -0400 Subject: [PATCH] v0.3.0: added Ethereal Chains --- assets/effects.png | Bin 3116 -> 3052 bytes .../actors/hero/Hero.java | 8 +- .../shatteredpixeldungeon/effects/Chains.java | 84 ++++++++ .../effects/Effects.java | 4 + .../items/Generator.java | 6 +- .../items/artifacts/EtherealChains.java | 196 ++++++++++++++++++ 6 files changed, 293 insertions(+), 5 deletions(-) create mode 100644 src/com/shatteredpixel/shatteredpixeldungeon/effects/Chains.java create mode 100644 src/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/EtherealChains.java diff --git a/assets/effects.png b/assets/effects.png index b3277d234c498892009de3c3e95b16f9cf8ca9ff..2fbcce907408f061407e16878cc64f7333542fdb 100644 GIT binary patch delta 384 zcmZ1@@kV@tBnLAC1A|XM>zs{>9$b^Fxn%1lI25fN%OX{Q;`RYPA+A80L7l;3_3C%; z-Ze1%2a^988i3sY{~7)R0RsbAgaOEN>G%&+$zaF8;11*hWkCvNzU5E`n!sNY`;eH55%`XKOg8RIPN&t;ucLK6T}i=#IH delta 447 zcmV;w0YLuj7pxeN83+ad004WAb*`}?ND2=IVoOIv0RI600RN!9r<0Rr3Lt+D1S$@Q zS+(i_00DGKL_t(&-tCr6Qo}F|g`YaP2UqEWT%|n%OgA_ih8_W~0t-&$96@YqY82J6 z;}FA)zL_i%D}J(mY!eii`J{a(qGzlO$*>qHQK zf50LB-h;0Zh$o+$SlY^!Nu+I7N16xup+ zLOg;s<5&>~GlRF< z2SgF3Pc97y-miEe`Cj>v=;!H`sC>6p=nqT6&y`GaUz&zm2S|pWsH~4`Q$V$;t1ZIK z+ivv>iTA!L0$pj&74}VQAoo`MXRl<{H876j&@2Vs`|28KPJI!=HSPkivo>tnh9C@W p9l-Dj!!QiPFbu;m4C5C+^9AX4Szza625|rY002ovPDHLkV1lF_%OU^( diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java index 33778b606..cc5cc1937 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java @@ -65,6 +65,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.KindOfWeapon; import com.shatteredpixel.shatteredpixeldungeon.items.armor.glyphs.Viscosity; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.CapeOfThorns; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.DriedRose; +import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.EtherealChains; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.TalismanOfForesight; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.TimekeepersHourglass; import com.shatteredpixel.shatteredpixeldungeon.items.keys.GoldenKey; @@ -1092,10 +1093,13 @@ public class Hero extends Char { public void earnExp( int exp ) { this.exp += exp; + float percent = exp/(float)maxExp(); + + EtherealChains.chainsRecharge chains = buff(EtherealChains.chainsRecharge.class); + if (chains != null) chains.gainExp(percent); if (subClass == HeroSubClass.WARLOCK) { - float percent = exp/(float)maxExp(); int healed = Math.round(Math.min(HT - HP, HT * percent * 0.3f)); if (healed > 0) { HP += healed; @@ -1121,7 +1125,7 @@ public class Hero extends Char { Buff.prolong(this, Bless.class, 30f); this.exp = 0; - GLog.p( "You cannot grow stronger, but your experiences do give you a surge of power!" ); + GLog.p( "You cannot grow stronger, but your experiences do give you a surge of power!"); Sample.INSTANCE.play( Assets.SND_LEVELUP ); } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/effects/Chains.java b/src/com/shatteredpixel/shatteredpixeldungeon/effects/Chains.java new file mode 100644 index 000000000..aad4cb673 --- /dev/null +++ b/src/com/shatteredpixel/shatteredpixeldungeon/effects/Chains.java @@ -0,0 +1,84 @@ +package com.shatteredpixel.shatteredpixeldungeon.effects; + +import com.shatteredpixel.shatteredpixeldungeon.DungeonTilemap; +import com.watabou.noosa.Game; +import com.watabou.noosa.Group; +import com.watabou.noosa.Image; +import com.watabou.utils.Callback; +import com.watabou.utils.PointF; + +/** + * Created by Evan on 23/05/2015. + */ +public class Chains extends Group { + + private static final double A = 180 / Math.PI; + + private float spent = 0f; + private float duration; + + private Callback callback; + + private Image[] chains; + private int numChains; + private float distance; + private float rotation = 0; + + private PointF from, to; + + public Chains(int from, int to, Callback callback){ + this(DungeonTilemap.tileCenterToWorld(from), + DungeonTilemap.tileCenterToWorld(to), + callback); + } + + public Chains(PointF from, PointF to, Callback callback){ + super(); + + this.callback = callback; + + this.from = from; + this.to = to; + + float dx = to.x - from.x; + float dy = to.y - from.y; + distance = (float)Math.hypot(dx, dy); + + + duration = distance/300f + 0.1f; + + rotation = (float)(Math.atan2( dy, dx ) * A) + 90f; + + numChains = Math.round(distance/6f)+1; + + chains = new Image[numChains]; + for (int i = 0; i < chains.length; i++){ + chains[i] = new Image(Effects.get(Effects.Type.CHAIN)); + chains[i].angle = rotation; + chains[i].origin.set( chains[i].width()/ 2, chains[i].height() ); + add(chains[i]); + } + } + + @Override + public void update() { + if ((spent += Game.elapsed) > duration) { + + killAndErase(); + if (callback != null) { + callback.call(); + } + + } else { + float dx = to.x - from.x; + float dy = to.y - from.y; + for (int i = 0; i < chains.length; i++) { + chains[i].center(new PointF( + from.x + ((dx * (i / (float)chains.length)) * (spent/duration)), + from.y + ((dy * (i / (float)chains.length)) * (spent/duration)) + )); + } + } + } + +} diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/effects/Effects.java b/src/com/shatteredpixel/shatteredpixeldungeon/effects/Effects.java index 638d62ea3..98fa15dff 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/effects/Effects.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/effects/Effects.java @@ -27,6 +27,7 @@ public class Effects { LIGHTNING, WOUND, EXCLAMATION, + CHAIN, DEATH_RAY, LIGHT_RAY, HEALTH_RAY @@ -47,6 +48,9 @@ public class Effects { case EXCLAMATION: icon.frame(icon.texture.uvRect(0, 16, 6, 25)); break; + case CHAIN: + icon.frame(icon.texture.uvRect(6, 16, 11, 22)); + break; case DEATH_RAY: icon.frame(icon.texture.uvRect(16, 16, 32, 24)); break; diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/Generator.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/Generator.java index 79421821c..83b66cec8 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/Generator.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/Generator.java @@ -193,10 +193,10 @@ public class Generator { UnstableSpellbook.class, AlchemistsToolkit.class, //currently removed from drop tables, pending rework. DriedRose.class, //starts with no chance of spawning, chance is set directly after beating ghost quest. - LloydsBeacon.class - /*EtherealChains.class*/ + LloydsBeacon.class, + EtherealChains.class }; - Category.ARTIFACT.probs = new float[]{ 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0 /*, 1*/}; + Category.ARTIFACT.probs = new float[]{ 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0 , 1}; Category.SEED.classes = new Class[]{ Firebloom.Seed.class, diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/EtherealChains.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/EtherealChains.java new file mode 100644 index 000000000..c58ee1e00 --- /dev/null +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/EtherealChains.java @@ -0,0 +1,196 @@ +package com.shatteredpixel.shatteredpixeldungeon.items.artifacts; + +import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; +import com.shatteredpixel.shatteredpixeldungeon.actors.Char; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; +import com.shatteredpixel.shatteredpixeldungeon.effects.Chains; +import com.shatteredpixel.shatteredpixeldungeon.effects.Pushing; +import com.shatteredpixel.shatteredpixeldungeon.levels.Level; +import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; +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.utils.Callback; + +import java.util.ArrayList; + +/** + * Created by Evan on 23/05/2015. + */ +public class EtherealChains extends Artifact { + + public static final String AC_CAST = "CAST"; + + { + name = "ethereal chains"; + image = ItemSpriteSheet.ARTIFACT_CHAINS; + + level = 0; + levelCap = 5; + exp = 0; + + charge = 0; + + defaultAction = AC_CAST; + } + + @Override + public ArrayList actions(Hero hero) { + ArrayList actions = super.actions( hero ); + if (isEquipped(hero) && charge > 0 && !cursed) + actions.add(AC_CAST); + return actions; + } + + @Override + public void execute(Hero hero, String action) { + if (action.equals(AC_CAST)){ + + curUser = hero; + + if (!isEquipped( hero )) GLog.i("You need to equip the chains to do that."); + else if (charge < 1) GLog.i("Your chains do not have any available charge."); + else if (cursed) GLog.w("You can't use cursed chains."); + else { + GameScene.selectCell(caster); + } + + } else + super.execute(hero, action); + } + + private CellSelector.Listener caster = new CellSelector.Listener(){ + + @Override + public void onSelect(Integer target) { + if (target != null && (Dungeon.level.visited[target] || Dungeon.level.mapped[target])){ + final Ballistica chain = new Ballistica(curUser.pos, target, Ballistica.STOP_CHARS | Ballistica.STOP_TARGET); + + //determine if we're grabbing an enemy, pulling to a location, or doing nothing. + if (Actor.findChar( chain.collisionPos ) != null){ + int newPos = -1; + for (int i : chain.subPath(1, chain.dist)){ + if (!Level.solid[i] && Actor.findChar(i) == null){ + newPos = i; + break; + } + } + if (newPos == -1){ + GLog.w("That won't do anything"); + } else { + final int newMobPos = newPos; + final Char affected = Actor.findChar( chain.collisionPos ); + int chargeUse = Level.distance(affected.pos, newMobPos); + if (chargeUse > charge){ + GLog.w("Your chains do not have enough charge."); + return; + } else { + charge -= chargeUse; + updateQuickslot(); + } + curUser.busy(); + curUser.sprite.parent.add(new Chains(curUser.pos, affected.pos, new Callback() { + public void call() { + Actor.add(new Pushing(affected, affected.pos, newMobPos)); + affected.pos = newMobPos; + Dungeon.observe(); + curUser.spendAndNext(1f); + Dungeon.level.press(newMobPos, affected); + } + })); + } + + } else if (Level.solid[chain.path.get(chain.dist)] + || (chain.dist > 0 && Level.solid[chain.path.get(chain.dist-1)]) + || (chain.path.size() > chain.dist+1 && Level.solid[chain.path.get(chain.dist+1)]) + //if the player is trying to grapple the edge of the map, let them. + || (chain.path.size() == chain.dist+1)) { + int newPos = -1; + for (int i : chain.subPath(1, chain.dist)){ + if (!Level.solid[i] && Actor.findChar(i) == null) newPos = i; + } + if (newPos == -1) { + GLog.w("That won't do anything"); + } else { + final int newHeroPos = newPos; + int chargeUse = Level.distance(curUser.pos, newHeroPos); + if (chargeUse > charge){ + GLog.w("Your chains do not have enough charge."); + return; + } else { + charge -= chargeUse; + updateQuickslot(); + } + curUser.busy(); + curUser.sprite.parent.add(new Chains(curUser.pos, target, new Callback() { + public void call() { + Actor.add(new Pushing(curUser, curUser.pos, newHeroPos)); + curUser.pos = newHeroPos; + Dungeon.observe(); + curUser.spendAndNext(1f); + Dungeon.level.press(newHeroPos, curUser); + } + })); + } + + } else { + GLog.i("There is nothing to grab there"); + } + + } + + } + + @Override + public String prompt() { + return "Choose a location to target"; + } + }; + + @Override + protected ArtifactBuff passiveBuff() { + return new chainsRecharge(); + } + + //TODO: description + @Override + public String desc() { + return super.desc(); + } + + public class chainsRecharge extends ArtifactBuff{ + + @Override + public boolean act() { + int chargeTarget = 5+level; + if (charge < chargeTarget) { + partialCharge += 1 / (40f - (chargeTarget - charge)*3f); + } + + if (partialCharge >= 1) { + partialCharge --; + charge ++; + } + + updateQuickslot(); + + spend( TICK ); + + return true; + } + + public void gainExp( float levelPortion ) { + exp += Math.round(levelPortion*100); + partialCharge += levelPortion*10f; + + if (exp > 100+level*50){ + exp -= 100+level*50; + GLog.p("Your chains grow stronger!"); + upgrade(); + } + + } + } +}