diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties index 99751520f..d125de096 100644 --- a/core/src/main/assets/messages/actors/actors.properties +++ b/core/src/main/assets/messages/actors/actors.properties @@ -5,11 +5,17 @@ text.herostat.duration = 总回合数 text.herostat.score = 分数 text.herostat.real_time = 总时间 text.herostat.seed_dungeon = 种子序列号 -text.herostat.seed_custom_no = SD +text.herostat.seed_custom_no = text.textchallenges.seed_custom_title = 种子 text.textchallenges.hint = 不输入即为随机种子 text.textchallenges.delete_seed_input = 清除 +actors.mobs.bloodbat$bloodbatrecharge.name=血影充能 +actors.mobs.bloodbat$bloodbatrecharge.desc=小血影正在充能,等待下一次和主人并肩作战的时候! + +actors.mobs.bloodbat.name=血影蝙蝠 +actors.mobs.bloodbat.desc=极影铃虹的随身伙伴,为了主人的安全将会让一切试图伤害主人的家伙万劫不复。\n\n它的能力和主人紧密相连,主人的成长也会让小血影成长! + actors.buffs.halomethaneburning.name=磷火缠身 actors.buffs.halomethaneburning.heromsg=磷火像恶魔一样缠在了你的身上! actors.buffs.halomethaneburning.burnsup=%s被烧的渣都不剩了! @@ -387,7 +393,7 @@ actors.mobs.npcs.slyl.message1=我叫冷群,这是我的真名。 actors.mobs.npcs.slyl.message2=地牢最深处的黑暗……似乎有点忘记了。但据说最近有冒险者在地牢新发现了一批特别的书籍,它们或多或少都沾染过魔法。 actors.mobs.npcs.slyl.def_verb=风暴将临 -actors.mobs.npcs.slyl.desc=_冷群_是一位掌握冰系力量的魔人族,是300年前_寒冰圣都_的管理者。\n由于地下异常的不断出现,她来到这里调查异常的原因。\n看起来她似乎摸鱼。 +actors.mobs.npcs.slyl.desc=_冷群_是一位掌握冰系力量的魔女,是300年前_寒冰圣都_的管理者。\n由于地下异常的不断出现,她来到这里调查异常的原因。\n看起来她似乎正在摸鱼。 actors.mobs.npcs.slyl.howuse=你好,我是冷群。\n\n欢迎使用我们_寒冰圣都_的可以扰乱_魔力流_的_魔法金币_,通过它我们可以看见_特定的首领_。\n\n其中_抛动一次_会出现_天痕粘咕(5层),天狗(10层),DM300(15层),矮人国王(20层),Yog(25层)_\nΠ抛动两次Π是_史莱姆王(5层),钻石宝箱王(10层),DM720(15层),矮人大师领主(20层),Yog-Zot(25层)_\nΞ抛动三次Ξ是_(15层 寒冰魔女)_(抛动三次次仅在_特定楼层显示_)\n\n同时,仅在Boss前一楼层显示,每一次的最后的一次抛动将会决定下一层Boss的生成。\n\n好的,以上就是_使用方法和介绍了_,祝你_地牢冒险愉快_。 actors.mobs.npcs.nxhy.guards=看来你需要更加艰难的试炼了。 diff --git a/core/src/main/assets/messages/items/items.properties b/core/src/main/assets/messages/items/items.properties index 9a3c66ad2..f7ec6a3b8 100644 --- a/core/src/main/assets/messages/items/items.properties +++ b/core/src/main/assets/messages/items/items.properties @@ -448,6 +448,7 @@ items.artifacts.cloakofshadows$cloakstealth.no_charge=你的斗篷耗尽了能 items.artifacts.cloakofshadows$cloakstealth.levelup=你的斗篷变得更强大了! items.artifacts.cloakofshadows$cloakstealth.name=斗篷之下 items.artifacts.cloakofshadows$cloakstealth.desc=你身上的暗影斗篷正给予你隐形效果。\n\n当你在隐形时敌人无法追踪或攻击你。大部分物理攻击和魔法(比如卷轴和法杖)会不可避免地消除隐形效果。\n\n你会一直拥有该状态,直到你自行取消或斗篷耗尽能量。 +items.artifacts.cloakofshadows.ac_bloodbat=召唤伙伴 items.artifacts.driedrose.name=干枯玫瑰 items.artifacts.driedrose.ac_summon=召唤 @@ -1951,10 +1952,10 @@ items.weapon.weapon$enchantment.enchant=附魔 ###misc items -items.amulet.name=Yendor护身符 -items.amulet.ac_end=结束游戏 -items.amulet.rankings_desc=获得Yendor护身符 -items.amulet.desc=Yendor护身符是人类与矮人所知的最强大的神器。其上镶嵌的闪闪发光的水晶蕴含着不可思议的神奇力量。\n\n护身符的来历不详。根据历史记载,矮人国王夸口说他在矮人文明与外界切断一切联系之前不久就发现了这件神器。那他是怎么找到的?古神又是怎么从他那里拿走的?也许这些问题不需要现在解答,真正重要的是:护身符正属于你! +items.amulet.name=水晶之心 +items.amulet.ac_end=返回主城 +items.amulet.rankings_desc=获得水晶之心,而危机仍在 +items.amulet.desc=击败了古神后,你发现了水晶之心。但是,前面不再有前进的道路了。莫非,本次旅程已经宣告结束了吗? items.ankh.name=重生十字架 items.ankh.ac_bless=祝福 diff --git a/core/src/main/assets/messages/ui/ui.properties b/core/src/main/assets/messages/ui/ui.properties index 0ffbe2cc4..d04864a8b 100644 --- a/core/src/main/assets/messages/ui/ui.properties +++ b/core/src/main/assets/messages/ui/ui.properties @@ -450,5 +450,6 @@ ui.changelist.mlpd.vm0_5_x_changes.frlogs=尚待调查…… ui.changelist.mlpd.vm0_6_7_x_changes.bug_06x20=-1.支离破碎bug已修复\n2.部分符石文本缺失已修复\n3.0层饱食度问题已修复\n4.炼金移植有问题已修复\n5.药水文本缺失已修复\n6.钥匙材质有问题已修复\n7.怨灵血量异常已修复\n8.种子显示问题已修复\n9.快捷栏优化问题已修复\n10.初始升级卷轴,以及初始物品已修复\n12.奈亚子初始奖励异常已修复\n13.由于V1.2.3楼层名字导致部分BOSS超类闪退已修复\n14.精英强敌鬼磷文本缺失已修复\n15.炼金合成表已移植\n16.风行水上部分buff已经重做\n17.部分原始Java类已合并\n18.英雄类逻辑楼层应该为0已修复\n19.光Buff有问题已修复\n20.恶魔层贴图有问题已修复\n21.部分buff尚未定义在破碎123英雄类里面已修复\n22.尚方宝剑属性问题已修复 +ui.changelist.mlpd.vm0_6_7_x_changes.bug_06x21=-1.修复了矮人国王的闪退问题\n-2.游戏性能优化\n-3.修复了钻石宝箱王的错误刷怪\n-去除了重生十字架的金色光环。 //ui.changelist.mlpd.vm0_5_x_changes.xxx// \ No newline at end of file diff --git a/core/src/main/assets/messages/windows/windows.properties b/core/src/main/assets/messages/windows/windows.properties index 242181bea..59c8076c5 100644 --- a/core/src/main/assets/messages/windows/windows.properties +++ b/core/src/main/assets/messages/windows/windows.properties @@ -285,11 +285,50 @@ windows.wndsettings$langstab.credits=制作名单 windows.wndsettings$langstab.reviewers=审核员 windows.wndsettings$langstab.translators=翻译员 -windows.wndstory.sewers=这片地牢位于城市的正下方,它的较上层其实是由城市的下水道系统组成的。\n\n由于下方不断渗透的黑暗能量,这些本应无害的下水道生物变得越来越危险。城市向这里派出巡逻队并试图以此保护其上方的区域,但他们的影响也在逐渐式微。\n\n这片区域已经具有一定的危险性,不过至少邪恶魔法对这里的影响尚且是薄弱的。 -windows.wndstory.prison=多年以前一座地下监狱为了收容危险的犯罪者而建立于此。由于其严格的监管和高安全性,地表各处的囚犯都被带到这里经受时间的折磨。 \n\n但不久之后下方充斥着黑暗的瘴气在这里弥漫开来,扭曲了罪犯和狱卒的心智。\n\n监狱里充斥开来的混乱使其彻底失去了秩序,于是城市封锁了整个监狱。现今已经没有人知道这些高墙之下经历过无数死亡的生物究竟会是什么样子... -windows.wndstory.caves=这座从废弃监狱延伸而下的洞穴,早已空无一人。矿产丰富的洞穴曾经是下方矮人国度的一个贸易与工业中心。然而随着矮人逐渐堕入黑暗魔法的深渊,这里也慢慢被废弃了。\n\n荒凉的洞穴中大抵只有地下生物与豺狼人居住,偶尔能见到废弃的机械。与之前的区域类似,这里的活物似乎也被同一种邪恶力量所扭曲。 -windows.wndstory.city=矮人都市曾经是最宏伟的矮人城邦。在其鼎盛时期矮人制造了一批注入魔力的奇特机械,借此快速扩张矮人城邦。\n\n然而突然有一天,城邦的大门被紧闭,从此外界再也得不到矮人的消息。据几位侥幸逃脱的矮人讲,有一位癫狂的矮人篡夺了王位,并利用他掌控的黑暗魔法巩固统治的地位。 -windows.wndstory.halls=这些遍布矮人王国深处的大厅已经被恶魔力量扭曲。在过去,这里由矮人王旗下的精英术士们做主,但他们似乎已经为某些更加邪恶强大的存在所取代...\n\n恶魔生物们盘踞着这些大厅。令人胆寒的黑暗意志主宰着它们。既然矮人王不是腐化的根源,那真正的它一定就藏在这里!\n\n路上要小心,很少有冒险者能一路走到这里... +windows.wndstory.sewers=这里是荒废已久的地牢\n\n相传这地牢以前曾经繁荣昌盛过\n\n直到她的介入后,这个地牢变得危机四伏\n\n现在这个地牢的居民都是被黑魔法感染的怪物\n\n你现在来到这里是为了寻找300年前的真相\n\n你必须一路走下去\n\n现在,已经不可能再回头了。 + +windows.wndstory.sewersboss=这里人迹罕至,这里寒冷降至。\n\n但这里却被它的烈焰燃烧! + +windows.wndstory.prison=多年以前一座地下监狱为了收容危险的犯罪者而建立于此。由于其严格的监管和高安全性,地表各处的囚犯都被带到这里经受时间的折磨。 \n\n但不久之后下方充斥着黑暗的瘴气在这里弥漫开来,扭曲了罪犯和狱卒的心智。\n\n监狱里充斥开来的混乱使其彻底失去了秩序,于是城市封锁了整个监狱。现今已经没有人知道这些高墙之下经历过无数死亡的生物究竟会是什么样子...\n\n现在这里已经乱套,你只能将所有东西全部杀掉。 + +windows.wndstory.prisonboss=如果你做了坏事,就会付出与之相匹配的代价。\n\n希望与绝望,是一个相对量\n\n这是她曾经对天狗说过的话\n\n\ + 作为这个世界的第一个刺客,天狗的职责是什么?他究竟是否还在遵守那个契约?\n\n没有人知道这些。\n\n不过,你并不是天狗等待的那个人\n\n\ + 因此,如果你想要去矿洞。必须要先想办法离开这里。\n\n虽然天狗与你无冤无仇,但,真正的钥匙在天狗那里,您必须为这一战付出艰辛的努力。\n\n不过,你究竟是常量吗?\n\n如果是,请拿出证明。 + +windows.wndstory.caves=这座从废弃监狱延伸而下的洞穴,早已空无一人。这里对于城市而言过于深入且很难开发,其中极度匮乏的矿物也无法激起矮人的兴趣。曾经在这里有一个为两个势力建立的贸易站,但在矮人国度衰落之后,只有无所不在的豺狼人和地下生物还居住在这里。\n\n但这里早已经被邪恶的魔力控制\n\n这里已经十分危险了。 + +windows.wndstory.cavesboss=起源,发展,盛世,腐朽,危机,暴乱,谋权,灭亡\n\n这便是这个矮人王国的发展历程\n\n现在,矮人王国的人似乎已经知道你正在前来的路上、\n\n\ + 他们为你准备了一份大礼,你是否看见了前面的那台机器?\n\n那是DM,是矮人王国的中的一台巨型采矿机器。\n\n不过,现在这个机器只是在守卫这里。\n\n它在等待什么?\n\n我们又在这里干什么?\n\n 按照你曾经在家看见的古书记载,这里过去就是曾经繁荣昌盛的矮人国度。\n\nDM似乎并没有发现你,虽然这不是DM的错,但你是想寻找到地牢的深处。\n\n为此,你不得不得向这台机器进行殊死搏斗。\n\n记住,要相信自己,能够活下来! + +windows.wndstory.icedead=死亡不是我们的终点,而是我们的起点。\n\n-在堕落的那一瞬间,我就已经与世隔绝。现在,谁还能帮助我? + +windows.wndstory.gamehappy=你已启用娱乐模式,玩的愉快!!! + +windows.wndstory.city=矮人都市曾经是最宏伟的矮人城邦。在其鼎盛时期矮人的机械化部队曾成功击退过古神及其恶魔军队的入侵。但是也有传闻说,凯旋而归的战士同时带来了腐坏的种子,矮人王国的胜利正是其毁灭的开端。\n\n这里的魔力越来越强烈,谁才是幕后主谋? + +windows.wndstory.cityboss=一路杀出重围\n\n一路直逼矮人国王议事厅\n\n你的心中一直明白:“这里已经不是矮人王国,这里是恶魔的乐园”\n\n矮人国度的幕后主谋应该知道你来了\n\n而你也知道,这将是你第一次同时也是最后一次见到矮人国王\n\n你已经准备好了,那么,就请杀出一条血路吧! + +windows.wndstory.halls=很久以前这片区域曾是矮人都市的郊区。在与古神的战争中取得惨胜的矮人已经无力掌控并清理这片地区。于是存活的恶魔逐渐巩固了对这里的控制,现在,这里被称作恶魔大厅。\n\n很少有冒险者能够深入到这种地方... + +windows.wndstory.hallsboss=这里空无一物\n\n这里了无生机\n\n这里是起始之初\n\n这里真的太安静了\n\n不过,你明白,这是试炼!\n\n但你必须面对,你准备好了吗? + +windows.wndstory.new=在击败了Yog古神后,似乎一切变得平静下来了。\n\n但你总感觉,这事情,并不会这么快的结束。\n\n\ + 不过,至少现在,一切都还不错。你将下到古神的宫殿,并拿走最终的战利品以荣耀的姿态离开这里。\n\n不过,这个地下城,你一直抱着一种相信的态度。\n\n\ + 嗯,是的,我会再次前往这里。但是下次,这里将不会再有怪物。\n\ + \nMLPD\ + -上半段-完。\n\n敬请期待下半段-真相。 + +windows.wndstory.forest=300年前,一场大火让这个地牢不复存在。地牢的创始人:翼绫也不见踪影。\n\n300年后,随着地牢原住民对地牢的维修和重建,地牢渐渐的有了生机。\n特别是和矮人他们共同从300年的灾难逃出来的古神YOG,是让地牢重新振兴的核心人员。\n随着时间的推移,YOG他们有了一个疯狂的想法,并将这个想法交给了地表三巨头。\n霜落女帝当即批准该建议,并发布猎杀的悬赏令。\n然而,人人都知道亵渎她的后果,可仍然顶风作案。\n你也是参与的一员,你现在来到了地牢的入口,现在,开始你的旅途了。 +windows.wndtradeitem.stole=抢劫商店 +windows.wndstory.dm920=Yog-Dzewa的陨落,其实背后有太多的秘密。\nYog的后面,是一个连Yog都害怕的一个DM终极实验品,\n它是造成矮人国度堕落的元凶,它是灾难的象征!!!\n它是曾经的死灵军团的杀手锏,它是死亡的代言词!!!\n它是连Yog-Dzewa都要敬畏它三分的DM920,\n你需直面,你不可逃避,你的路途就是为此而来。\n已经没有退路,唯有放手一搏,无论它是真是假!!!\n但你明白,不击败他,死的就只能是自己!!! + +windows.wndgoshop.szo=地牢商人 +windows.wndgoshop.ary=哦,我注意到你对我的东西蠢蠢欲动。如果你想动什么歪心思,我劝你还是放弃吧!!!\n\n商人正在非常警惕的看见你,如果你想抢劫商店本层恐怕会发生奇妙的变换。\n\n那么,对于商人的警告,你的选择是? +windows.wndgoshop.yes=抢劫 +windows.wndgoshop.no=放弃 +windows.wndgoshop.notbad=好吧,我以为你想抢劫商店的…… + +windows.wndstory.drawfmaster=庄严的大厅,死寂的环境。\n\n这里曾经是矮人王国的最大议事厅,而如今的死寂恐怖气氛却令这里显得十分诡异。\n\n并且这里似乎机关重重……\n有一个破旧不堪的石碑依稀的写着不要踏入这里,裂缝会变为地板,大将将会醒来……\n这在预示着什么? windows.wndsupportprompt.title=来自开发者的留言 windows.wndsupportprompt.intro=欢迎~希望您能在破碎的像素地牢中玩得开心! diff --git a/core/src/main/assets/sprites/bloodbat.png b/core/src/main/assets/sprites/bloodbat.png new file mode 100644 index 000000000..f2ec4ee92 Binary files /dev/null and b/core/src/main/assets/sprites/bloodbat.png differ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java index 2225ea64c..3c52832ab 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java @@ -294,6 +294,7 @@ public class Assets { public static final String REDSWARM = "sprites/RedSearm.png"; public static final String REN = "Ren/ren.png"; public static final String WHITE = "Npcs/White.png"; + public static final String BBAT = "sprites/bloodbat.png"; public static final String RAT = "sprites/rat.png"; public static final String BRUTE = "sprites/brute.png"; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java index 3d0001100..c193b4ec0 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java @@ -23,6 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon; import static com.shatteredpixel.shatteredpixeldungeon.Challenges.ALLBOSS; import static com.shatteredpixel.shatteredpixeldungeon.Challenges.RLPT; +import static com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass.ROGUE; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; @@ -35,6 +36,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.RevealedArea; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.huntress.SpiritHawk; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.BloodBat; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Blacksmith; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Ghost; @@ -123,6 +125,7 @@ public class Dungeon { STRENGTH_POTIONS, UPGRADE_SCROLLS, ARCANE_STYLI, + BBAT, //Health potion sources //enemies @@ -217,7 +220,7 @@ public class Dungeon { Actor.resetNextID(); Random.pushGenerator(seed); - + BloodBat.level = 1; Scroll.initLabels(); Potion.initColors(); Ring.initGems(); @@ -551,6 +554,25 @@ public class Dungeon { Mob.restoreAllies( level, pos ); Actor.init(); + if (!LimitedDrops.BBAT.dropped() && hero.isClass(ROGUE)){ + LimitedDrops.BBAT.drop(); + ArrayList respawnPoints = new ArrayList<>(); + + for (int i = 0; i < PathFinder.NEIGHBOURS8.length; i++) { + int p = 0; + if (Actor.findChar( p ) == null && Dungeon.level.passable[p]) { + respawnPoints.add( p ); + } + } + if (respawnPoints.size() > 0) { + BloodBat bat = new BloodBat(); + bat.pos = respawnPoints.get(Random.index(respawnPoints)); + bat.state = bat.WANDERING; + Dungeon.level.mobs.add( bat ); + Actor.add( bat ); + } + } + level.addRespawner(); hero.pos = pos; @@ -707,7 +729,7 @@ public class Dungeon { Bundle badges = new Bundle(); Badges.saveLocal( badges ); bundle.put( BADGES, badges ); - + BloodBat.saveLevel(bundle); FileUtils.bundleToFile( GamesInProgress.gameFile(save), bundle); } catch (IOException e) { @@ -762,7 +784,7 @@ public class Dungeon { Scroll.restore( bundle ); Potion.restore( bundle ); Ring.restore( bundle ); - + BloodBat.loadLevel(bundle); quickslot.restorePlaceholders( bundle ); if (fullLoad) { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java index 3f4b546b5..812db23b8 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java @@ -390,7 +390,7 @@ public abstract class Char extends Actor { if (buff(FireImbue.class) != null) buff(FireImbue.class).proc(enemy); if (buff(FrostImbue.class) != null) buff(FrostImbue.class).proc(enemy); - if (buff(FrostImbueEX.class) != null) buff(FrostImbue.class).proc(enemy); + if (buff(FrostImbueEX.class) != null) buff(FrostImbueEX.class).proc(enemy); if (enemy.isAlive() && enemy.alignment != alignment && prep != null && prep.canKO(enemy)){ enemy.HP = 0; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/AnkhInvulnerability.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/AnkhInvulnerability.java index c8df6f11c..24f693fe7 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/AnkhInvulnerability.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/AnkhInvulnerability.java @@ -34,8 +34,7 @@ public class AnkhInvulnerability extends FlavourBuff { @Override public void fx(boolean on) { - if (on) target.sprite.aura( 0xFFFF00 ); - else target.sprite.clearAura(); + // } @Override diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Marked.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Marked.java new file mode 100644 index 000000000..a4641d366 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Marked.java @@ -0,0 +1,210 @@ +package com.shatteredpixel.shatteredpixeldungeon.actors.buffs; + +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.hero.HeroAction; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.BloodBat; +import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; +import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; +import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.scenes.CellSelector; +import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; +import com.shatteredpixel.shatteredpixeldungeon.ui.ActionIndicator; +import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator; +import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; +import com.watabou.noosa.Image; +import com.watabou.noosa.audio.Sample; +import com.watabou.utils.Bundle; +import com.watabou.utils.PathFinder; + +import java.text.DecimalFormat; + +public class Marked extends Buff implements ActionIndicator.Action { + { + type = buffType.NEGATIVE; + announced = true; + } + + public int stack = 0; + + @Override + public void storeInBundle(Bundle bundle) { + super.storeInBundle(bundle); + bundle.put("stack", stack); + } + + @Override + public void restoreFromBundle(Bundle bundle) { + super.restoreFromBundle(bundle); + stack = bundle.getInt("stack"); + if (stack > 0) ActionIndicator.setAction(this); + } + + public float bonusDamage(){ + return (float) Math.pow(1.085f, stack); + } + + @Override + public int icon() { + return BuffIndicator.PREPARATION; + } + + @Override + public void tintIcon(Image icon) { + switch (stack){ + case 1: case 2: case 3: + icon.hardlight(0f, 1f, 0f); + break; + case 4: case 5: case 6: + icon.hardlight(1f, 1f, 0f); + break; + case 7: case 8: case 9: + icon.hardlight(1f, 0.6f, 0f); + break; + case 10: case 11: default: + icon.hardlight(1f, 0f, 0f); + break; + } + } + + @Override + public boolean act() { + if (stack > 0){ + ActionIndicator.setAction(this); + } + spend(TICK); + return true; + } + + @Override + public void detach() { + super.detach(); + ActionIndicator.clearAction(this); + } + + @Override + public String toString() { + return Messages.get(this, "name"); + } + + @Override + public String desc() { + String desc = Messages.get(this, "desc"); + + desc += "\n\n" + Messages.get(this, "desc_dmg", new DecimalFormat("#.##").format(100f * Math.pow(1.085f, stack) - 100f)); + if (stack >= 2) desc += "\n\n" + Messages.get(this, "desc_poison"); + if (stack >= 3) desc += "\n" + Messages.get(this, "desc_cripple"); + if (stack >= 4) desc += "\n" + Messages.get(this, "desc_blinding"); + if (stack >= 5) desc += "\n" + Messages.get(this, "desc_bleeding"); + if (stack >= 6) desc += "\n" + Messages.get(this, "desc_vulnerable"); + if (stack >= 7) desc += "\n" + Messages.get(this, "desc_hexed"); + if (stack >= 8) desc += "\n" + Messages.get(this, "desc_slow"); + if (stack >= 9) desc += "\n" + Messages.get(this, "desc_ooze"); + if (stack >= 10) desc += "\n" + Messages.get(this, "desc_paralysis"); + if (stack >= 11) desc += "\n" + Messages.get(this, "desc_doom"); + return desc; + } + + @Override + public String actionName() { + return null; + } + + @Override + public Image actionIcon() { + return null; + } + + @Override + public void doAction() { + GameScene.selectCell(attack); + } + + private CellSelector.Listener attack = new CellSelector.Listener() { + + @Override + public void onSelect(Integer cell) { + if (cell == null) return; + final Char enemy = Actor.findChar( cell ); + if (enemy == null || enemy.buff(Marked.class) == null){ + GLog.w(Messages.get(Marked.class, "no_target")); + } else { + + if (Dungeon.hero.canAttack(enemy)){ + effect(enemy); + Dungeon.hero.curAction = new HeroAction.Attack( enemy ); + Dungeon.hero.next(); + return; + } + + boolean[] passable = Dungeon.level.passable.clone(); + //need to consider enemy cell as passable in case they are on a trap or chasm + passable[cell] = true; + PathFinder.buildDistanceMap(Dungeon.hero.pos, passable, 100_000_000); + if (PathFinder.distance[cell] == Integer.MAX_VALUE){ + GLog.w(Messages.get(Preparation.class, "out_of_reach")); + return; + } + + //we can move through enemies when determining blink distance, + // but not when actually jumping to a location + for (Char ch : Actor.chars()){ + if (ch != Dungeon.hero) passable[ch.pos] = false; + } + + PathFinder.Path path = PathFinder.find(Dungeon.hero.pos, cell, passable); + int attackPos = path == null ? -1 : path.get(path.size()-2); + + if (attackPos == -1 || + Dungeon.level.distance(attackPos, Dungeon.hero.pos) > 100_000_000){ + GLog.w(Messages.get(Preparation.class, "out_of_reach")); + return; + } + + Dungeon.hero.pos = attackPos; + Dungeon.level.occupyCell(Dungeon.hero); + //prevents the hero from being interrupted by seeing new enemies + Dungeon.observe(); + Dungeon.hero.checkVisibleMobs(); + + Dungeon.hero.sprite.place( Dungeon.hero.pos ); + Dungeon.hero.sprite.turnTo( Dungeon.hero.pos, cell); + CellEmitter.get( Dungeon.hero.pos ).burst( Speck.factory( Speck.WOOL ), 6 ); + Sample.INSTANCE.play( Assets.Sounds.PUFF ); + effect(enemy); + Dungeon.hero.curAction = new HeroAction.Attack( enemy ); + Dungeon.hero.next(); + } + } + + @Override + public String prompt() { + return Messages.get(Marked.class, "prompt"); + } + }; + + public static void effect(Char enemy){ + Marked mark = enemy.buff(Marked.class); + if (mark.stack >= 2) Buff.affect(enemy, Poison.class).set(Dungeon.escalatingDepth()); + if (mark.stack >= 3) Buff.affect(enemy, Cripple.class, 4f); + if (mark.stack >= 4) Buff.affect(enemy, Blindness.class, 4f); + if (mark.stack >= 5) Buff.affect(enemy, Bleeding.class).level = Dungeon.escalatingDepth(); + if (mark.stack >= 6) Buff.affect(enemy, Vulnerable.class, 4f); + if (mark.stack >= 7) Buff.affect(enemy, Hex.class, 4f); + if (mark.stack >= 8) Buff.affect(enemy, Slow.class, 4f); + if (mark.stack >= 9) Buff.affect(enemy, Ooze.class).set(20f); + if (mark.stack >= 10) Buff.affect(enemy, Paralysis.class, 5f); + if (mark.stack >= 11) Buff.affect(enemy, Doom.class); + + for (Char ch : Actor.chars()){ + if (ch instanceof BloodBat){ + ch.sprite.emitter().burst(Speck.factory(Speck.SMOKE), 10); + ch.HP = Math.min(ch.HT, ch.HP + ch.HT / 5 * mark.stack); + } + } + enemy.buff(Marked.class).detach(); + } +} + 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 1dd457e40..2577383ab 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 @@ -65,6 +65,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Vertigo; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.ArmorAbility; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.huntress.NaturesPower; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.warrior.Endure; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.BloodBat; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Monk; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Snake; @@ -164,13 +165,23 @@ import java.util.Collections; import java.util.LinkedHashMap; public class Hero extends Char { - public int shadeID; + { actPriority = HERO_PRIO; alignment = Alignment.ALLY; } + public boolean isClass(HeroClass clazz){ + if (heroClass == HeroClass.ROGUE) return true; + return clazz == this.heroClass; + } + + public boolean isSubclass(HeroSubClass subClass) { + if (this.subClass == HeroSubClass.ASSASSIN || this.subClass == HeroSubClass.FREERUNNER) return true; + return subClass == this.subClass; + } + public ArrayList visibleEnemiesList() { return visibleEnemies; } @@ -1596,6 +1607,8 @@ public class Hero extends Char { WndHero.lastIdx = 1; } } + + BloodBat.updateHP(); Item.updateQuickslot(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/HeroClass.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/HeroClass.java index 37f62be17..fd96e95dd 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/HeroClass.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/HeroClass.java @@ -98,9 +98,11 @@ import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.exotic.ScrollOfRos import com.shatteredpixel.shatteredpixeldungeon.items.spells.AquaBlast; import com.shatteredpixel.shatteredpixeldungeon.items.spells.BeaconOfReturning; import com.shatteredpixel.shatteredpixeldungeon.items.spells.MagicalInfusion; +import com.shatteredpixel.shatteredpixeldungeon.items.spells.SummonElemental; import com.shatteredpixel.shatteredpixeldungeon.items.stones.StoneOfFlock; import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfBlueFuck; import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfCorruption; +import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfFireblast; import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfFrost; import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfGodIce; import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfMagicMissile; @@ -129,6 +131,7 @@ import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.plants.AikeLaier; import com.shatteredpixel.shatteredpixeldungeon.plants.Blindweed; import com.shatteredpixel.shatteredpixeldungeon.plants.Firebloom; +import com.watabou.utils.Random; public enum HeroClass { @@ -319,7 +322,7 @@ public enum HeroClass { ThrowingStone stones = new ThrowingStone(); stones.quantity(3).collect(); Dungeon.quickslot.setSlot(0, stones); - + new SummonElemental().quantity(2).identify().collect(); if (hero.belongings.armor != null){ hero.belongings.armor.affixSeal(new BrokenSeal()); } @@ -336,7 +339,17 @@ public enum HeroClass { (hero.belongings.weapon = staff).identify(); hero.belongings.weapon.activate(hero); + WandOfFireblast woc = new WandOfFireblast(); + woc.level(Random.NormalIntRange(0,2)); + woc.identify().quantity(1); + + WandOfFrost wox = new WandOfFrost(); + wox.level(Random.NormalIntRange(0,2)); + wox.identify().quantity(1); + Dungeon.quickslot.setSlot(0, staff); + Dungeon.quickslot.setSlot(1, wox); + Dungeon.quickslot.setSlot(2, woc); new ScrollOfUpgrade().identify(); new PotionOfLiquidFlame().identify(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java index 9200ab1af..58086cedc 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java @@ -58,10 +58,8 @@ import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.MeleeWeapon; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.MissileWeapon; import com.shatteredpixel.shatteredpixeldungeon.levels.Level; import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; -import com.shatteredpixel.shatteredpixeldungeon.messages.Languages; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; -import com.shatteredpixel.shatteredpixeldungeon.scenes.HeroSelectScene; import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator; import com.watabou.noosa.Image; import com.watabou.noosa.audio.Sample; @@ -399,6 +397,8 @@ public enum Talent { } } + + public static void onArtifactUsed( Hero hero ){ if (hero.hasTalent(ENHANCED_RINGS)){ Buff.prolong(hero, EnhancedRings.class, 3f*hero.pointsInTalent(ENHANCED_RINGS)); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/BloodBat.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/BloodBat.java new file mode 100644 index 000000000..9a12a8275 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/BloodBat.java @@ -0,0 +1,240 @@ +package com.shatteredpixel.shatteredpixeldungeon.actors.mobs; + +import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.actors.Char; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.ArtifactRecharge; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Blindness; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Degrade; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.FlavourBuff; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Marked; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass; +import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.sprites.BlueBatSprite; +import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; +import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator; +import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; +import com.watabou.noosa.Image; +import com.watabou.noosa.audio.Sample; +import com.watabou.utils.Bundle; +import com.watabou.utils.Callback; +import com.watabou.utils.Random; + +public class BloodBat extends Mob implements Callback { + + { + HP = HT = 20; + defenseSkill = 7; + baseSpeed = 1.5f; + spriteClass = BlueBatSprite.class; + alignment = Alignment.ALLY; + WANDERING = new Wandering(); + intelligentAlly = true; + maxLvl = -30; + } + + public void onZapComplete() { + zap(); + next(); + } + + @Override + public void call() { + next(); + } + + public static class DarkBolt{} + public static int level = 1; + private static final float TIME_TO_ZAP = 2f; + private void zap() { + spend( TIME_TO_ZAP ); + + if (hit( this, enemy, true )) { + //TODO would be nice for this to work on ghost/statues too + if (enemy == Dungeon.hero && Random.Int( 2 ) == 0) { + Buff.prolong( enemy, Blindness.class, Degrade.DURATION ); + Sample.INSTANCE.play( Assets.Sounds.DEBUFF ); + } + + int dmg = Random.NormalIntRange( 2, 4 ); + enemy.damage( dmg, new BloodBat.DarkBolt() ); + + if (enemy == Dungeon.hero && !enemy.isAlive()) { + Dungeon.fail( getClass() ); + GLog.n( Messages.get(this, "frost_kill") ); + } + } else { + enemy.sprite.showStatus( CharSprite.NEUTRAL, enemy.defenseVerb() ); + } + } + + public static void saveLevel(Bundle bundle){ + bundle.put("BloodBatLevel", level); + } + + public static void loadLevel(Bundle bundle){ + level = bundle.getInt("BloodBatLevel"); + } + + @Override + public int damageRoll() { + if (Dungeon.hero.isSubclass(HeroSubClass.ASSASSIN)){ + int i = Random.NormalIntRange(0, level * 2); + if (enemy.buff(Marked.class) != null) i *= enemy.buff(Marked.class).bonusDamage(); + return i; + } + return Random.NormalIntRange( level, 1 + level * 2 ); + } + + @Override + public float attackDelay() { + return super.attackDelay() * (Dungeon.hero.isSubclass(HeroSubClass.ASSASSIN) ? 0.33f : 0.5f); + } + + @Override + public int attackSkill(Char target) { + return 4 + level * 2; + } + + @Override + public int attackProc(Char enemy, int damage) { + if(level >= 2){ + zap(); + } else { + if (Dungeon.hero.isSubclass(HeroSubClass.ASSASSIN)) Buff.affect(enemy, Marked.class).stack++; + } + + + return super.attackProc(enemy, damage); + } + + @Override + protected Char chooseEnemy() { + Char enemy = super.chooseEnemy(); + + int targetPos = Dungeon.hero.pos; + int distance = Dungeon.hero.isSubclass(HeroSubClass.ASSASSIN) ? 99999 : 8; + + //will never attack something far from their target + if (enemy != null + && Dungeon.level.mobs.contains(enemy) + && (Dungeon.level.distance(enemy.pos, targetPos) <= distance)){ + ((Mob)enemy).aggro(this); + return enemy; + } + + return null; + } + + public static void updateHP(){ + level += 1; + if (Dungeon.level != null) { + for (Mob mob : Dungeon.level.mobs.toArray(new Mob[0])) { + if (mob instanceof BloodBat) { + mob.HP = mob.HT = 18 + level * 2; + ((BloodBat) mob).defenseSkill = 3 + level * 2; + } + } + } + } + + @Override + public void damage(int dmg, Object src) { + super.damage(dmg, src); + Buff.affect(Dungeon.hero, ArtifactRecharge.class).prolong(dmg*2); + } + + @Override + public void die(Object cause) { + super.die(cause); + Buff.affect(Dungeon.hero, BloodBatRecharge.class, 800f); + } + + private class Wandering extends Mob.Wandering { + + @Override + public boolean act( boolean enemyInFOV, boolean justAlerted ) { + if ( enemyInFOV ) { + + enemySeen = true; + + notice(); + alerted = true; + state = HUNTING; + target = enemy.pos; + + } else { + + enemySeen = false; + + int oldPos = pos; + target = Dungeon.hero.pos; + //always move towards the hero when wandering + if (getCloser( target )) { + spend( 1 / speed() ); + return moveSprite( oldPos, pos ); + } else { + spend( TICK ); + } + + } + return true; + } + + } + + protected boolean doAttack( Char enemy ) { + + if (Dungeon.level.adjacent( pos, enemy.pos )) { + + return super.doAttack( enemy ); + + } else { + + if (sprite != null && (sprite.visible || enemy.sprite.visible)) { + sprite.zap( enemy.pos ); + return false; + } else { + zap(); + return true; + } + } + } + + public static class BloodBatRecharge extends FlavourBuff { + + public static final float DURATION = 800f; + + { + type = buffType.NEGATIVE; + announced = true; + } + + @Override + public int icon() { + return BuffIndicator.TIME; + } + + @Override + public void tintIcon(Image icon) { + icon.tint(0, 0, 0, 0.05f); + } + + @Override + public float iconFadePercent() { + return Math.max(0, (DURATION - visualcooldown()) / DURATION); + } + + @Override + public String toString() { + return Messages.get(this, "name"); + } + + @Override + public String desc() { + return Messages.get(this, "desc", dispTurns()); + } + + } +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DimandKing.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DimandKing.java index d74fcca8d..f6e47e20c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DimandKing.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DimandKing.java @@ -570,7 +570,7 @@ public class DimandKing extends Boss { } } - public static class DKWarlock extends DimandMimic { + public static class DKWarlock extends SRPDHBLR { { state = HUNTING; immunities.add(Corruption.class); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DwarfKing.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DwarfKing.java index 3248d1a43..df537de84 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DwarfKing.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DwarfKing.java @@ -47,7 +47,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.armor.glyphs.Viscosity; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.DriedRose; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.LloydsBeacon; import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTeleportation; -import com.shatteredpixel.shatteredpixeldungeon.levels.CityBossLevel; +import com.shatteredpixel.shatteredpixeldungeon.levels.NewCityBossLevel; import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; @@ -55,7 +55,6 @@ import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.KingSprite; import com.shatteredpixel.shatteredpixeldungeon.ui.BossHealthBar; import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator; -import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; import com.watabou.noosa.audio.Sample; import com.watabou.noosa.particles.Emitter; import com.watabou.utils.Bundle; @@ -138,7 +137,7 @@ public class DwarfKing extends Mob { @Override protected boolean act() { - if (pos == CityBossLevel.throne){ + if (pos == NewCityBossLevel.throne){ throwItems(); } @@ -312,7 +311,7 @@ public class DwarfKing extends Mob { private boolean summonSubject( int delay, Class type ){ Summoning s = new Summoning(); - s.pos = ((CityBossLevel)Dungeon.level).getSummoningPos(); + s.pos = ((NewCityBossLevel)Dungeon.level).getSummoningPos(); if (s.pos == -1) return false; s.summon = type; s.delay = delay; @@ -460,7 +459,7 @@ public class DwarfKing extends Mob { if (HP <= (Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 100 : 50)) { HP = (Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 100 : 50); sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "invulnerable")); - ScrollOfTeleportation.appear(this, CityBossLevel.throne); + ScrollOfTeleportation.appear(this, NewCityBossLevel.throne); properties.add(Property.IMMOVABLE); phase = 2; summonsMade = 0; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/CloakOfShadows.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/CloakOfShadows.java index f3d9b032d..2f8cfd448 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/CloakOfShadows.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/CloakOfShadows.java @@ -3,7 +3,7 @@ * Copyright (C) 2012-2015 Oleg Dolya * * Shattered Pixel Dungeon - * Copyright (C) 2014-2022 Evan Debenham + * Copyright (C) 2014-2019 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 @@ -24,24 +24,28 @@ 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.buffs.Barrier; -import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.LockedFloor; -import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Preparation; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; -import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.BloodBat; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; +import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; import com.shatteredpixel.shatteredpixeldungeon.items.Item; -import com.shatteredpixel.shatteredpixeldungeon.items.bags.Bag; import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfEnergy; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator; import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; import com.watabou.noosa.audio.Sample; +import com.watabou.noosa.tweeners.AlphaTweener; import com.watabou.utils.Bundle; +import com.watabou.utils.Callback; +import com.watabou.utils.PathFinder; +import com.watabou.utils.Random; import java.util.ArrayList; @@ -53,9 +57,9 @@ public class CloakOfShadows extends Artifact { exp = 0; levelCap = 10; - charge = Math.min(level()+3, 10); + charge = level()+3; partialCharge = 0; - chargeCap = Math.min(level()+3, 10); + chargeCap = level()+3; defaultAction = AC_STEALTH; @@ -63,15 +67,27 @@ public class CloakOfShadows extends Artifact { bones = false; } + private boolean stealthed = false; + public static final String AC_STEALTH = "STEALTH"; + public static final String AC_BloodBat = "BloodBat"; @Override public ArrayList actions( Hero hero ) { ArrayList actions = super.actions( hero ); - if ((isEquipped( hero ) || hero.hasTalent(Talent.LIGHT_CLOAK)) - && !cursed && (charge > 0 || activeBuff != null)) { + if (isEquipped( hero ) && !cursed && (charge > 0 || stealthed)) actions.add(AC_STEALTH); + boolean needToSpawn = true; + for (Mob mob : Dungeon.level.mobs.toArray( new Mob[0] )) { + if (mob instanceof BloodBat) { + needToSpawn = false; + break; + } } + if (needToSpawn) { + if (hero.buff(BloodBat.BloodBatRecharge.class) != null) needToSpawn = false; + } + if (needToSpawn) actions.add(AC_BloodBat); return actions; } @@ -82,35 +98,65 @@ public class CloakOfShadows extends Artifact { if (action.equals( AC_STEALTH )) { - if (activeBuff == null){ - if (!isEquipped(hero) && !hero.hasTalent(Talent.LIGHT_CLOAK)) GLog.i( Messages.get(Artifact.class, "need_to_equip") ); + if (!stealthed){ + if (!isEquipped(hero)) GLog.i( Messages.get(Artifact.class, "need_to_equip") ); else if (cursed) GLog.i( Messages.get(this, "cursed") ); else if (charge <= 0) GLog.i( Messages.get(this, "no_charge") ); else { + stealthed = true; hero.spend( 1f ); hero.busy(); Sample.INSTANCE.play(Assets.Sounds.MELD); activeBuff = activeBuff(); activeBuff.attachTo(hero); - Talent.onArtifactUsed(Dungeon.hero); + if (hero.sprite.parent != null) { + hero.sprite.parent.add(new AlphaTweener(hero.sprite, 0.4f, 0.4f)); + } else { + hero.sprite.alpha(0.4f); + } hero.sprite.operate(hero.pos); } } else { + stealthed = false; activeBuff.detach(); activeBuff = null; - if (hero.invisible <= 0 && hero.buff(Preparation.class) != null){ - hero.buff(Preparation.class).detach(); - } + hero.spend( 1f ); hero.sprite.operate( hero.pos ); } + } else if (action.equals(AC_BloodBat)){ + hero.sprite.operate(hero.pos, new Callback() { + @Override + public void call() { + ArrayList respawnPoints = new ArrayList<>(); + + for (int i = 0; i < PathFinder.NEIGHBOURS8.length; i++) { + int p = hero.pos + PathFinder.NEIGHBOURS8[i]; + if (Actor.findChar( p ) == null && Dungeon.level.passable[p]) { + respawnPoints.add( p ); + } + } + + if (respawnPoints.size() > 0){ + BloodBat bat = new BloodBat(); + bat.pos = respawnPoints.get(Random.index( respawnPoints )); + bat.HP = bat.HT = 18 + BloodBat.level * 2; + ((BloodBat) bat).defenseSkill = 4 + BloodBat.level*2; + bat.state = bat.WANDERING; + GameScene.add(bat); + bat.sprite.emitter().burst(Speck.factory(Speck.STAR), 10); + hero.sprite.idle(); + } + } + }); } } @Override public void activate(Char ch){ super.activate(ch); - if (activeBuff != null && activeBuff.target == null){ + if (stealthed){ + activeBuff = activeBuff(); activeBuff.attachTo(ch); } } @@ -118,46 +164,12 @@ public class CloakOfShadows extends Artifact { @Override public boolean doUnequip(Hero hero, boolean collect, boolean single) { if (super.doUnequip(hero, collect, single)){ - if (!collect || !hero.hasTalent(Talent.LIGHT_CLOAK)){ - if (activeBuff != null){ - activeBuff.detach(); - activeBuff = null; - } - } else { - activate(hero); - } - + stealthed = false; return true; } else return false; } - @Override - public boolean collect( Bag container ) { - if (super.collect(container)){ - if (container.owner instanceof Hero - && passiveBuff == null - && ((Hero) container.owner).hasTalent(Talent.LIGHT_CLOAK)){ - activate((Hero) container.owner); - } - return true; - } else{ - return false; - } - } - - @Override - protected void onDetach() { - if (passiveBuff != null){ - passiveBuff.detach(); - passiveBuff = null; - } - if (activeBuff != null && !isEquipped((Hero) activeBuff.target)){ - activeBuff.detach(); - activeBuff = null; - } - } - @Override protected ArtifactBuff passiveBuff() { return new cloakRecharge(); @@ -167,7 +179,7 @@ public class CloakOfShadows extends Artifact { protected ArtifactBuff activeBuff( ) { return new cloakStealth(); } - + @Override public void charge(Hero target, float amount) { if (charge < chargeCap) { @@ -181,55 +193,52 @@ public class CloakOfShadows extends Artifact { } } + @Override + public int value() { + return 0; + } + public void overCharge(int amount){ charge = Math.min(charge+amount, chargeCap+amount); updateQuickslot(); } - + @Override public Item upgrade() { - chargeCap = Math.min(chargeCap + 1, 10); + chargeCap = chargeCap+1; return super.upgrade(); } private static final String STEALTHED = "stealthed"; - private static final String BUFF = "buff"; @Override public void storeInBundle( Bundle bundle ) { super.storeInBundle(bundle); - if (activeBuff != null) bundle.put(BUFF, activeBuff); + bundle.put( STEALTHED, stealthed ); } @Override public void restoreFromBundle( Bundle bundle ) { super.restoreFromBundle(bundle); - if (bundle.contains(BUFF)){ - activeBuff = new cloakStealth(); - activeBuff.restoreFromBundle(bundle.getBundle(BUFF)); - } + stealthed = bundle.getBoolean( STEALTHED ); } - @Override - public int value() { - return 0; - } public class cloakRecharge extends ArtifactBuff{ @Override public boolean act() { if (charge < chargeCap) { LockedFloor lock = target.buff(LockedFloor.class); - if (activeBuff == null && (lock == null || lock.regenOn())) { + if (!stealthed && (lock == null || lock.regenOn())) { float missing = (chargeCap - charge); if (level() > 7) missing += 5*(level() - 7)/3f; float turnsToCharge = (45 - missing); - turnsToCharge /= RingOfEnergy.artifactChargeMultiplier(target); - float chargeToGain = (1f / turnsToCharge); - if (!isEquipped(Dungeon.hero)){ - chargeToGain *= 0.75f*Dungeon.hero.pointsInTalent(Talent.LIGHT_CLOAK)/3f; + if (turnsToCharge <= 0) { + turnsToCharge = 1 / (missing - 44); } - partialCharge += chargeToGain; + turnsToCharge /= RingOfEnergy.artifactChargeMultiplier(target); + if (turnsToCharge <= 0) turnsToCharge = 1; + partialCharge += (1f / turnsToCharge); } if (partialCharge >= 1) { @@ -256,11 +265,11 @@ public class CloakOfShadows extends Artifact { } public class cloakStealth extends ArtifactBuff{ - + { type = buffType.POSITIVE; } - + int turnsToCost = 0; @Override @@ -270,45 +279,23 @@ public class CloakOfShadows extends Artifact { @Override public float iconFadePercent() { - return (4f - turnsToCost) / 4f; - } - - @Override - public String iconTextDisplay() { - return Integer.toString(turnsToCost); + return (5f - turnsToCost) / 5f; } @Override public boolean attachTo( Char target ) { if (super.attachTo( target )) { target.invisible++; - if (target instanceof Hero && ((Hero) target).subClass == HeroSubClass.ASSASSIN){ - Buff.affect(target, Preparation.class); - } return true; } else { return false; } } - float barrierInc = 0.5f; - @Override public boolean act(){ turnsToCost--; - //barrier every 2/1 turns, to a max of 3/5 - if (((Hero)target).hasTalent(Talent.PROTECTIVE_SHADOWS)){ - Barrier barrier = Buff.affect(target, Barrier.class); - if (barrier.shielding() < 1 + 2*((Hero)target).pointsInTalent(Talent.PROTECTIVE_SHADOWS)) { - barrierInc += 0.5f * ((Hero) target).pointsInTalent(Talent.PROTECTIVE_SHADOWS); - } - if (barrierInc >= 1 ){ - barrierInc = 0; - barrier.incShield(1); - } - } - if (turnsToCost <= 0){ charge--; if (charge < 0) { @@ -328,14 +315,14 @@ public class CloakOfShadows extends Artifact { } else { exp += Math.round(10f * Math.pow(0.75f, -lvlDiffFromTarget)); } - + if (exp >= (level() + 1) * 50 && level() < levelCap) { upgrade(); exp -= level() * 50; GLog.p(Messages.get(this, "levelup")); - + } - turnsToCost = 4; + turnsToCost = 5; } updateQuickslot(); } @@ -350,6 +337,11 @@ public class CloakOfShadows extends Artifact { detach(); } + public void dispelAssassin(){ + updateQuickslot(); + charge = Math.min(0, charge - 2); + } + @Override public void fx(boolean on) { if (on) target.sprite.add( CharSprite.State.INVISIBLE ); @@ -368,31 +360,28 @@ public class CloakOfShadows extends Artifact { @Override public void detach() { - activeBuff = null; - - if (target.invisible > 0) target.invisible--; + if (target.invisible > 0) + target.invisible--; + stealthed = false; updateQuickslot(); super.detach(); } - + private static final String TURNSTOCOST = "turnsToCost"; - private static final String BARRIER_INC = "barrier_inc"; - + @Override public void storeInBundle(Bundle bundle) { super.storeInBundle(bundle); - + bundle.put( TURNSTOCOST , turnsToCost); - bundle.put( BARRIER_INC, barrierInc); } - + @Override public void restoreFromBundle(Bundle bundle) { super.restoreFromBundle(bundle); - + turnsToCost = bundle.getInt( TURNSTOCOST ); - barrierInc = bundle.getFloat( BARRIER_INC ); } } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/SummonElemental.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/SummonElemental.java index 101c1e77d..b25037a6b 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/SummonElemental.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/SummonElemental.java @@ -109,7 +109,7 @@ public class SummonElemental extends Spell { GameScene.add( elemental ); Buff.affect(elemental, InvisAlly.class); elemental.setSummonedALly(); - elemental.HP = elemental.HT; + elemental.HP = elemental.HT = 20; ScrollOfTeleportation.appear( elemental, Random.element(spawnPoints) ); curUser.spendAndNext(Actor.TICK); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/SpiritBow.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/SpiritBow.java index 68c105598..f6777b0c8 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/SpiritBow.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/SpiritBow.java @@ -184,7 +184,7 @@ public class SpiritBow extends Weapon { @Override public int min(int lvl) { - int dmg = 1 + Dungeon.hero.lvl/5 + int dmg = 4 + Dungeon.hero.lvl/5 + RingOfSharpshooting.levelDamageBonus(Dungeon.hero) + (curseInfusionBonus ? 1 + Dungeon.hero.lvl/30 : 0); return Math.max(0, dmg); @@ -192,7 +192,7 @@ public class SpiritBow extends Weapon { @Override public int max(int lvl) { - int dmg = 6 + (int)(Dungeon.hero.lvl/2.5f) + int dmg = 9 + (int)(Dungeon.hero.lvl/2.5f) + 2*RingOfSharpshooting.levelDamageBonus(Dungeon.hero) + (curseInfusionBonus ? 2 + Dungeon.hero.lvl/15 : 0); return Math.max(0, dmg); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index 214e0f9d2..1f756c9a9 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -21,6 +21,8 @@ package com.shatteredpixel.shatteredpixeldungeon.scenes; +import static com.shatteredpixel.shatteredpixeldungeon.Challenges.ALLBOSS; + import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.BGMPlayer; import com.shatteredpixel.shatteredpixeldungeon.Badges; @@ -407,24 +409,49 @@ public class GameScene extends PixelScene { case RETURN: ScrollOfTeleportation.appear( Dungeon.hero, Dungeon.hero.pos ); break; - case DESCEND: case FALL: - switch (Dungeon.depth) { - case 1: - WndStory.showChapter( WndStory.ID_SEWERS ); - break; - case 6: - WndStory.showChapter( WndStory.ID_PRISON ); - break; - case 11: - WndStory.showChapter( WndStory.ID_CAVES ); - break; - case 16: - WndStory.showChapter( WndStory.ID_CITY ); - break; - case 21: - WndStory.showChapter( WndStory.ID_HALLS ); - break; + case DESCEND: + if (Dungeon.isChallenged(ALLBOSS)){ + switch (Dungeon.depth) { + case 0: + WndStory.showChapter( WndStory.ID_GAME ); + case 3: + WndStory.showChapter( WndStory.ID_DM920 ); + } + } else { + switch (Dungeon.depth) { + case 0: + WndStory.showChapter( WndStory.ID_FOREST ); + break; + case 1: + WndStory.showChapter( WndStory.ID_SEWERS ); + break; + case 5: + WndStory.showChapter( WndStory.ID_SEWERSBOSS ); + break; + case 6: + WndStory.showChapter( WndStory.ID_PRISON ); + break; + case 11: + WndStory.showChapter( WndStory.ID_CAVES ); + break; + case 16: + WndStory.showChapter( WndStory.ID_CITY ); + break; + case 20: + if((Statistics.boss_enhance & 0x8) != 0) WndStory.showChapter( WndStory.ID_DWADA ); + else WndStory.showChapter( WndStory.ID_CITYSBOSS ); + break; + case 21: + WndStory.showChapter( WndStory.ID_HALLS ); + break; + case 25: + WndStory.showChapter( WndStory.ID_HALLSBOOS ); + break; + case 26: + WndStory.showChapter( WndStory.ID_CHAPTONEEND ); + break; + } } if (Dungeon.hero.isAlive()) { Badges.validateNoKilling(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/BlueBatSprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/BlueBatSprite.java new file mode 100644 index 000000000..a1d8bf68f --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/BlueBatSprite.java @@ -0,0 +1,97 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2022 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.sprites; + +import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.BloodBat; +import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile; +import com.watabou.noosa.TextureFilm; +import com.watabou.noosa.audio.Sample; +import com.watabou.utils.Callback; + +public class BlueBatSprite extends MobSprite { + + public void zap( int cell ) { + + turnTo( ch.pos , cell ); + play( zap ); + + MagicMissile.boltFromChar( parent, + MagicMissile.FROST, + this, + cell, + new Callback() { + @Override + public void call() { + ((BloodBat)ch).onZapComplete(); + } + } ); + Sample.INSTANCE.play( Assets.Sounds.ZAP ); + } + + public BlueBatSprite() { + super(); + + texture( Assets.Sprites.BBAT ); + + TextureFilm frames = new TextureFilm( texture, 15, 15 ); + + idle = new Animation( 8, true ); + idle.frames( frames, 0, 1 ); + + run = new Animation( 12, true ); + run.frames( frames, 0, 1 ); + + attack = new Animation( 12, false ); + attack.frames( frames, 2, 3, 0, 1 ); + + die = new Animation( 12, false ); + die.frames( frames, 4, 5, 6 ); + + play( idle ); + } + + public static class BatEDSprite extends MobSprite { + + public BatEDSprite() { + super(); + + texture(Assets.Sprites.BATEX); + + TextureFilm frames = new TextureFilm(texture, 15, 15); + + idle = new Animation(8, true); + idle.frames(frames, 0, 1); + + run = new Animation(12, true); + run.frames(frames, 0, 1); + + attack = new Animation(12, false); + attack.frames(frames, 2, 3, 0, 1); + + die = new Animation(12, false); + die.frames(frames, 4, 5, 6); + + play(idle); + } + } +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/mlpd/vM0_6_7_X_Changes.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/mlpd/vM0_6_7_X_Changes.java index ce85e3315..8b4a92b75 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/mlpd/vM0_6_7_X_Changes.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/mlpd/vM0_6_7_X_Changes.java @@ -3,6 +3,7 @@ package com.shatteredpixel.shatteredpixeldungeon.ui.changelist.mlpd; import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.scenes.ChangesScene; +import com.shatteredpixel.shatteredpixeldungeon.sprites.BlueBatSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.FlameBoiSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; @@ -17,9 +18,48 @@ import java.util.ArrayList; public class vM0_6_7_X_Changes { public static void addAllChanges(ArrayList changeInfos) { + add_v0_6_1_Changes(changeInfos); add_v0_6_0_Changes(changeInfos); } + public static void add_v0_6_1_Changes( ArrayList changeInfos ) { + ChangeInfo changes = new ChangeInfo("v0.6.0.0-BetaXV", true, ""); + changes.hardlight(Window.TITLE_COLOR); + changeInfos.add(changes); + + changes = new ChangeInfo("新内容", false, null); + changes.hardlight(Window.GREEN_COLOR); + changeInfos.add(changes); + + changes.addButton(new ChangeButton(new BlueBatSprite(), ("血影蝙蝠"), + ("极影铃虹的宠物,为主人而战"))); + + changes = new ChangeInfo("改动", false, null); + changes.hardlight(Window.SKYBULE_COLOR); + changeInfos.add(changes); + + changes.addButton(new ChangeButton(new Image("sprites/spinner.png", 144, 0, 16, 16), (Messages.get(ChangesScene.class, "bugfixes")), + Messages.get(vM0_6_7_X_Changes.class, "bug_06X21"))); + + changes = new ChangeInfo("调整", false, null); + changes.hardlight(Window.CYELLOW); + changeInfos.add(changes); + + changes.addButton(new ChangeButton(new ItemSprite(ItemSpriteSheet.SPIRIT_ARROW), ("女猎初始改动"), + ("灵能短弓伤害面板从1-6提升到4-9,成长系数不变"))); + + changes.addButton(new ChangeButton(new ItemSprite(ItemSpriteSheet.WAND_FROST), ("法师初始改动"), + ("茉莉伊洛是双属性的魔法少女,拥有强大的魔力,她将会把烈焰法杖和冰雪法杖幻化到快捷栏里,这两个法杖不能升级,不能灌注,但是开局随机0-2级。\n\n且一旦替换幻化的快捷栏将消失。\n\n" + + "低语:错误的选择将让你万劫不复的,茉莉!"))); + + changes.addButton(new ChangeButton(new ItemSprite(ItemSpriteSheet.SUMMON_ELE), ("战士初始改动"), + ("蕾零安洁虽然本身没有魔力,但家族世世代代都在研究一种高超的技术,这项技术足以让她在地牢里面有冒险的资本。\n\n使用战士将追加2个唤魔晶柱"))); + + changes.addButton(new ChangeButton(new BlueBatSprite(), ("盗贼初始改动"), + ("极影铃虹的潜能非常强大,她的小蝙蝠经常与她为伴。\n\n盗贼将在开局追加一个小蝙蝠。"))); + + } + public static void add_v0_6_0_Changes( ArrayList changeInfos ) { ChangeInfo changes = new ChangeInfo("v0.6.0.0-BetaX", true, ""); changes.hardlight(Window.TITLE_COLOR); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndStory.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndStory.java index 297c1fe0b..99e66698c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndStory.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndStory.java @@ -3,7 +3,7 @@ * Copyright (C) 2012-2015 Oleg Dolya * * Shattered Pixel Dungeon - * Copyright (C) 2014-2022 Evan Debenham + * Copyright (C) 2014-2021 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 @@ -35,39 +35,63 @@ import com.watabou.utils.SparseArray; public class WndStory extends Window { + private static final int WIDTH_P = 125; private static final int WIDTH_L = 160; private static final int MARGIN = 2; - + private static final float bgR = 0.77f; private static final float bgG = 0.73f; private static final float bgB = 0.62f; - + + public static final int ID_FOREST = -1; public static final int ID_SEWERS = 0; public static final int ID_PRISON = 1; public static final int ID_CAVES = 2; public static final int ID_CITY = 3; public static final int ID_HALLS = 4; - + + public static final int ID_SEWERSBOSS = 5; + public static final int ID_PRISONBOSS = 6; + public static final int ID_CAVESBOSS = 7; + public static final int ID_CITYSBOSS = 8; + public static final int ID_HALLSBOOS = 9; + public static final int ID_CHAPTONEEND = 10; + public static final int ID_ICEBOSS = 11; + public static final int ID_GAME = 12; + public static final int ID_DM920 = 12; + public static final int ID_DWADA = 13; + private static final SparseArray CHAPTERS = new SparseArray<>(); - + static { + CHAPTERS.put( ID_FOREST, "forest" ); CHAPTERS.put( ID_SEWERS, "sewers" ); CHAPTERS.put( ID_PRISON, "prison" ); CHAPTERS.put( ID_CAVES, "caves" ); CHAPTERS.put( ID_CITY, "city" ); CHAPTERS.put( ID_HALLS, "halls" ); + CHAPTERS.put( ID_SEWERSBOSS, "sewersboss" ); + CHAPTERS.put( ID_PRISONBOSS, "prisonboss" ); + CHAPTERS.put( ID_CAVESBOSS, "cavesboss" ); + CHAPTERS.put( ID_CITYSBOSS, "cityboss" ); + CHAPTERS.put( ID_HALLSBOOS, "hallsboss" ); + CHAPTERS.put( ID_CHAPTONEEND, "new" ); + CHAPTERS.put( ID_ICEBOSS, "icedead" ); + CHAPTERS.put( ID_GAME, "gamehappy" ); + CHAPTERS.put( ID_DM920, "dm920" ); + CHAPTERS.put( ID_DWADA, "drawfmaster" ); } private IconTitle ttl; private RenderedTextBlock tf; - + private float delay; public WndStory( String text ) { this( null, null, text ); } - + public WndStory(Image icon, String title, String text ) { super( 0, 0, Chrome.get( Chrome.Type.SCROLL ) ); @@ -81,41 +105,39 @@ public class WndStory extends Window { add(ttl); ttl.tfLabel.invert(); } - + tf = PixelScene.renderTextBlock( text, 6 ); tf.maxWidth(width); tf.invert(); tf.setPos(MARGIN, y); add( tf ); - PointerArea blocker = new PointerArea( 0, 0, PixelScene.uiCamera.width, PixelScene.uiCamera.height ) { + add( new PointerArea( chrome ) { @Override protected void onClick( PointerEvent event ) { - onBackPressed(); + hide(); } - }; - blocker.camera = PixelScene.uiCamera; - add(blocker); - + } ); + resize( (int)(tf.width() + MARGIN * 2), (int)Math.min( tf.bottom()+MARGIN, 180 ) ); } - + @Override public void update() { super.update(); - + if (delay > 0 && (delay -= Game.elapsed) <= 0) { shadow.visible = chrome.visible = tf.visible = true; if (ttl != null) ttl.visible = true; } } - + public static void showChapter( int id ) { - + if (Dungeon.chapters.contains( id )) { return; } - + String text = Messages.get(WndStory.class, CHAPTERS.get( id )); if (text != null) { WndStory wnd = new WndStory( text ); @@ -123,9 +145,9 @@ public class WndStory extends Window { wnd.shadow.visible = wnd.chrome.visible = wnd.tf.visible = false; if (wnd.ttl != null) wnd.ttl.visible = false; } - + Game.scene().add( wnd ); - + Dungeon.chapters.add( id ); } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndTradeItem.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndTradeItem.java index 5f7ce409d..6a63bdc0e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndTradeItem.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndTradeItem.java @@ -24,6 +24,9 @@ package com.shatteredpixel.shatteredpixeldungeon.windows; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.ShopGuardDead; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.ImpShopkeeper; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Nxhy; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Shopkeeper; import com.shatteredpixel.shatteredpixeldungeon.items.EquipableItem; import com.shatteredpixel.shatteredpixeldungeon.items.Gold; @@ -31,6 +34,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.Heap; import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.MasterThievesArmband; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; import com.shatteredpixel.shatteredpixeldungeon.ui.RedButton; @@ -128,6 +132,30 @@ public class WndTradeItem extends WndInfoItem { pos = btnBuy.bottom(); + RedButton btnStole = new RedButton( Messages.get(this, "stole", price) ) { + @Override + protected void onClick() { + hide(); + for (Mob mob : Dungeon.level.mobs) { + if (mob instanceof Shopkeeper) { + GameScene.show(new WndGoShop(this)); + break; + } else if (mob instanceof Nxhy) { + mob.yell(Messages.get(mob, "why")); + break; + }else if (mob instanceof ImpShopkeeper) { + mob.yell(Messages.get(mob, "why")); + break; + } + } + } + }; + btnStole.setRect( 0, pos + GAP, width, BTN_HEIGHT ); + btnStole.icon(new ShopGuardDead.ShopGuardianRedSprite()); + add( btnStole ); + + pos = btnStole.bottom(); + final MasterThievesArmband.Thievery thievery = Dungeon.hero.buff(MasterThievesArmband.Thievery.class); if (thievery != null && !thievery.isCursed() && thievery.chargesToUse(item) > 0) { final float chance = thievery.stealChance(item);