diff --git a/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidGame.java b/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidGame.java index 2d621dbb1..a2702fba0 100644 --- a/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidGame.java +++ b/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidGame.java @@ -79,7 +79,6 @@ public class AndroidGame extends AndroidApplication { - FileUtils.setDefaultFileProperties(Files.FileType.Local, ""); // grab preferences directly using our instance first diff --git a/build.gradle b/build.gradle index c40c8e4aa..77ec22b24 100644 --- a/build.gradle +++ b/build.gradle @@ -18,8 +18,8 @@ allprojects { appName = 'Magic Ling Pixel Dungeon' appPackageName = 'com.ansdomagiclingpixeldungeon.ling' - appVersionCode =900927 - appVersionName = '0.6.3.0-Beta5.2' + appVersionCode =901000 + appVersionName = '0.6.4.0-Beta1' appJavaCompatibility = JavaVersion.VERSION_11 diff --git a/core/src/main/assets/interfaces/badges.png b/core/src/main/assets/interfaces/badges.png index 548925cba..3b9be2f25 100644 Binary files a/core/src/main/assets/interfaces/badges.png and b/core/src/main/assets/interfaces/badges.png differ diff --git a/core/src/main/assets/interfaces/banners.png b/core/src/main/assets/interfaces/banners.png index e54a1775f..db01433c9 100644 Binary files a/core/src/main/assets/interfaces/banners.png and b/core/src/main/assets/interfaces/banners.png differ diff --git a/core/src/main/assets/interfaces/bosslogo/sakabjy-clear.png b/core/src/main/assets/interfaces/bosslogo/sakabjy-clear.png new file mode 100644 index 000000000..579c89519 Binary files /dev/null and b/core/src/main/assets/interfaces/bosslogo/sakabjy-clear.png differ diff --git a/core/src/main/assets/interfaces/bosslogo/sakabjy-title.png b/core/src/main/assets/interfaces/bosslogo/sakabjy-title.png new file mode 100644 index 000000000..70d6c04ac Binary files /dev/null and b/core/src/main/assets/interfaces/bosslogo/sakabjy-title.png differ diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties index 7e38d9e4b..41c43762a 100644 --- a/core/src/main/assets/messages/actors/actors.properties +++ b/core/src/main/assets/messages/actors/actors.properties @@ -1,8 +1,31 @@ #####MLPD-P3文本 -actors.mobs.bosses.sakafishboss.name=”远古意志“\n萨卡班甲鱼 +actors.mobs.bosses.sakafishboss.name=萨卡班甲鱼 actors.mobs.bosses.sakafishboss.desc=曾经远古时代的海洋王者,因为不可避免的末日来临时,潜入了地底的阴暗水潭进入了沉睡。想着有朝一日回到大海,然而地牢的魔力和陆上的变化,它再也不可能回到那片理想的海洋。 +actors.mobs.bosses.sakafishboss.notice=sakasaka……saka?腻……系……甚磨?! +actors.mobs.bosses.sakafishboss.attack=吧嗒吧嗒—呜呜……好怀念上面的风景和底栖生物 +actors.mobs.bosses.sakafishboss.leap=萨卡班甲鱼正在蓄力泥头车冲撞!哦——创似——李——!!! +actors.mobs.bosses.sakafishboss.king=泰山压顶!biu—— +actors.mobs.npcs.nxhy.talk=交谈 +actors.mobs.npcs.nxhy.buyback=回忆很爽快的退还了相应的商品。 + +actors.mobs.npcs.nxhy.talk_prison_intro=冒险者,欢迎来到这个危机四伏的地牢。 +actors.mobs.npcs.nxhy.talk_prison_warrior=蕾零安洁,你也是前往这里寻找水晶之心的吗?哦,嗯,我知道,地表三巨头的行动我可是了如指掌的,但本人已经不想参与这些事情,现在,我还是当个商人最好吧。 +actors.mobs.npcs.nxhy.talk_prison_mage=茉莉姐,我知道你来到这里的目的不是寻找那个东西,而是听到了来自深渊的求救。但我能告诉你的事,别去参和他们的事情,这里毕竟不是你的家,你的力量无法完全展露的。 +actors.mobs.npcs.nxhy.talk_prison_rogue=哦,这不是人人歌颂的皇家盗贼吗?你打算在我这里偷点东西吗?哈哈哈,骗你的,事实上,我很敬佩你,为了穷人,你不惜舍去皇室血脉也要和穷人一起同甘共苦。你的父王可能早就知道了,不信的话,你的斗篷已经被他秘密改造了,什么,你还不知道?哈哈哈,我为什么知道,这是秘密哦! +actors.mobs.npcs.nxhy.talk_prison_huntress=我曾经和小姐一样也是一位侠客,只不过瞬时变迁,我现在已经不再追求这些。小姐,你知道自从你走后你的部族就发生……,哎呀,别拿弓指着我,我不说就是了。还是希望小姐能在地牢中试炼中找到自己的目标吧。 +actors.mobs.npcs.nxhy.talk_caves=这里的矿洞常年都是这么的冷,但曾经并不是这样。曾经有一位蓝发少女在我这里留了一本书,此后矿洞就变得如此寒冷,但那位少女再也找不到人影…… +actors.mobs.npcs.nxhy.talk_city=矮人都市是我最后给你的物资中转站,再往下,已经不是我可以涉及的区域,曾经这里也是一片繁华,但是那场事变后,一切都变了…… + +actors.mobs.npcs.nxhy.guards=看来你需要更加艰难的试炼了。 +actors.mobs.npcs.nxhy.thief=看来你需要更加艰难的试炼了。 +actors.mobs.npcs.nxhy.why=抢劫商店?你可真有趣! + +actors.mobs.npcs.nxhy.sell=选择一件要出售的物品 +actors.mobs.npcs.nxhy.name=那些回忆 +actors.mobs.npcs.nxhy.desc=这是一个拥有很多东西的商人,他的名字叫那些回忆。据说他知道300年前这地牢究竟发生了什么事情的,他在这里等着每一位冒险者的前来。他会给予冒险者相应的补给,但是他从来不告诉冒险者这个地牢的危险程度是多么的高。传言说,他曾经是一个侠客,只不过现在他已经成为了一个商人了。 +actors.mobs.npcs.nxhy.greetings=你好,%s。欢迎来到我的大商店。 actors.hero.hero.heartdied=死亡不是终点,而是新的开始。 @@ -705,15 +728,6 @@ actors.mobs.npcs.slyl.def_verb=风暴将临 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=看来你需要更加艰难的试炼了。 -actors.mobs.npcs.nxhy.thief=看来你需要更加艰难的试炼了。 -actors.mobs.npcs.nxhy.why=抢劫商店?你可真有趣! - -actors.mobs.npcs.nxhy.sell=选择一件要出售的物品 -actors.mobs.npcs.nxhy.name=那些回忆 -actors.mobs.npcs.nxhy.desc=这是一个拥有很多东西的商人,他的名字叫那些回忆。据说他知道300年前这地牢究竟发生了什么事情的,他在这里等着每一位冒险者的前来。他会给予冒险者相应的补给,但是他从来不告诉冒险者这个地牢的危险程度是多么的高。传言说,他曾经是一个侠客,只不过现在他已经成为了一个商人了。\n\n{ 请不要攻击他!!!否则他会让你痛不欲生!!! { -actors.mobs.npcs.nxhy.greetings=你好,%s。欢迎来到我的大商店。 - actors.mobs.npcs.renshop.guards=看来你并不是好人。 actors.mobs.npcs.renshop.thief=看来你的命运多舛。 actors.mobs.npcs.renshop.sell=选择一件要出售的物品 @@ -1750,6 +1764,7 @@ actors.mobs.npcs.impshopkeeper.name=野心勃勃的小恶魔 actors.mobs.npcs.impshopkeeper.greetings=你好,%s! actors.mobs.npcs.impshopkeeper.thief=我以为我可以相信你! actors.mobs.npcs.impshopkeeper.desc=小恶魔是一种低等恶魔。它们既没有强大的力量也没有魔法天赋,但她们相当聪明而且善于交际,因此许多小恶魔喜欢生活在没有其他恶魔存在的地方。 +actors.mobs.npcs.impshopkeeper.buyback=小恶魔很爽快的退还了相应的商品。 actors.mobs.npcs.mirrorimage.name=镜像 actors.mobs.npcs.mirrorimage.desc=这个幻象和你非常相似,甚至还装备着你当前的武器和护甲。\n\n镜像会猎寻敌人,并用它们的镜像武器对其发动攻击。镜像武器的使用方式与特性和你手中的一样,但造成的伤害会低些。镜像出生的时候没有实体,但攻击后会显形。\n\n镜像有一定的攻击能力,但非常脆弱,受到伤害就会瞬间消散。 @@ -1792,6 +1807,17 @@ actors.mobs.npcs.shopkeeper.zcz=商人喊来了制裁者! actors.mobs.npcs.shopkeeper.eye=商人喊来了真眼者! actors.mobs.npcs.shopkeeper.dead=商人为敌人们购买了精英系统,选好东西,迅速离开本层!!! actors.mobs.npcs.shopkeeper.live=商人还为首领购买了精英系统,选好东西,迅速离开本层!!! +actors.mobs.npcs.shopkeeper.talk=交谈 +actors.mobs.npcs.shopkeeper.buyback=店主不情不愿地退还了你的物品。 +actors.mobs.npcs.shopkeeper.talk_prison_intro=我这有你成功冒险所需的一切东西! +actors.mobs.npcs.shopkeeper.talk_prison_warrior=你的那个纹章挺有意思的嘛,它们通常来讲都是一整个的。难不成你是一位蒙受了耻辱的英雄,还是别的什么人物?好啦,不管你做了些什么,都与我无关。我只对你的金币感兴趣。 +actors.mobs.npcs.shopkeeper.talk_prison_mage=嘻嘻,我想我在城里的什么地方有见过你的通缉令。在逃亡对吧?哦?你说你是无辜的,真的吗?行行行...放轻松,比起举报你,我还有更值得做的事情。但也许你应该消费消费以确保这一点? +actors.mobs.npcs.shopkeeper.talk_prison_rogue=你是盗贼公会指派来清理这片区域的吗?不是?只是来交易?好吧,虽然你确实在这杀了些怪物,但也别指望我会给你打折。我已经交足了保护费,而你们几乎不能确保这里的安全。 +actors.mobs.npcs.shopkeeper.talk_prison_huntress=小姐,这似乎不是你该待的地方。狭窄的地牢走廊想来不如城镇大厅或者市郊森林那样宽敞,不是吗?嘿嘿,哦,请别在意我这碎嘴巴,为什么不买点东西呢? +actors.mobs.npcs.shopkeeper.talk_prison_duelist=哇偶,这不是闯荡天下的大英雄嘛!如果你在尝试着拯救又一个小镇,那我只能说祝你好运了。毕竟这里的危机可比土匪帮派什么的糟糕多了。当然,我相信你会比任何人做得更棒,只是千万别死在我的店门口。 +actors.mobs.npcs.shopkeeper.talk_caves=花钱,你才能活得更久。\n\n哦,如果你看到那个巨魔铁匠,代我向他问好。顺便提醒这个笨蛋,他上周从我这买锤子的钱还没结清呢! +actors.mobs.npcs.shopkeeper.talk_city=我的货可以保你平安。\n\n…另外,劳烦您别在这瞎晃悠。我花了很长很长时间才让这里的怪物离我远点,可不希望你把麻烦惹回来! +actors.mobs.npcs.shopkeeper.talk_halls=嘿,那边那位!我为狩猎恶魔的人提供特别优惠!\n\n哦还有,在下面可要当心!底下的恶魔可不在乎你有多勇敢。而且如果你挂掉了,你就没法回来花掉金币啦!(>ω^)\n\n那些恶魔都和我一样吗?嘿嘿,并不。我只是一个小小跟班儿,算不上战士,况且我还设法保全了心智呢。下面那些恶魔都比我猛得多,并且它们都遭到了...呃......的奴役,总之,你在下面当心点吧。 actors.mobs.npcs.wandmaker.name=老杖匠 actors.mobs.npcs.wandmaker.intro_warrior=啊,能在这片压抑的地方遇见一位英雄可真是个惊喜!如果你愿意帮助我这个老人家脱离苦海的话,你可以帮忙做一个任务。 diff --git a/core/src/main/assets/messages/items/items.properties b/core/src/main/assets/messages/items/items.properties index 70df7f597..5ed08e9c8 100644 --- a/core/src/main/assets/messages/items/items.properties +++ b/core/src/main/assets/messages/items/items.properties @@ -2248,6 +2248,9 @@ items.heap.skeleton_desc=某个不幸的冒险者存在过的唯一证明。或 items.heap.remains=英雄遗骸 items.heap.remains_desc=你的某个先辈存在过的唯一证明。或许能找到点什么值钱的东西。 +items.heap.wtomb=苍白之墓 +items.heap.wtomb_desc=这个坟墓相对于其他的坟墓很不对劲,直觉告诉你不应该挖这里的东西。 + items.honeypot.name=蜂蜜罐 items.honeypot.ac_shatter=击碎 items.honeypot.desc=这个巨型蜜罐只是薄薄地涂了一圈蜂蜜,作为替代里头住着一只巨型蜜蜂!这种大型蜜蜂一般只待在蜂巢里,也许罐子本身就是某种特殊陷阱屋?蜜蜂看起来对罐子很满意,当你看向它时它非常警惕地对你回以嗡鸣。 diff --git a/core/src/main/assets/messages/misc/misc.properties b/core/src/main/assets/messages/misc/misc.properties index ef28fcacc..afc7417c8 100644 --- a/core/src/main/assets/messages/misc/misc.properties +++ b/core/src/main/assets/messages/misc/misc.properties @@ -277,6 +277,13 @@ badges$badge.read_book_three.desc=一局累计阅读五本不同的书籍。 badges$badge.read_book_four.title=书籍博学家 badges$badge.read_book_four.desc=一局累计阅读七本不同的书籍。 +badges$badge.saka_died.title=远古生物档案调查员 +badges$badge.saka_died.desc=击败栖息在阴暗水潭的神秘古生物 + +badges$badge.reset_day.title=重见天日? +badges$badge.reset_day.desc=携带神秘生物的遗物离开地牢,完成它未尽的心愿。 + + diff --git a/core/src/main/assets/messages/scenes/scenes.properties b/core/src/main/assets/messages/scenes/scenes.properties index e9f207103..f482e6368 100644 --- a/core/src/main/assets/messages/scenes/scenes.properties +++ b/core/src/main/assets/messages/scenes/scenes.properties @@ -174,6 +174,7 @@ scenes.interlevelscene$mode.fall=跌落中… scenes.interlevelscene$mode.reset=重置中… scenes.interlevelscene$mode.exboss=你突然眼前一黑\n\n,随后便是守卫低沉的声音:\n\n将此人押送到雪凛峡谷处置。 scenes.interlevelscene$mode.frgirlboss=正在前往雪凛峡谷深处…… +scenes.interlevelscene$mode.ancityboss=正在前往远古遗迹深处…… scenes.interlevelscene.install=安装游戏 scenes.interlevelscene.file_not_found=未能找到存档文件。如果重启后问题依旧存在, 那这个存档可能已经损坏。节哀顺变。 scenes.interlevelscene.io_error=未能找到存档文件。如果重启后问题依旧存在, 那这个存档可能已经损坏。节哀顺变。 diff --git a/core/src/main/assets/messages/ui/ui.properties b/core/src/main/assets/messages/ui/ui.properties index c7a13aa57..4fd64d8ca 100644 --- a/core/src/main/assets/messages/ui/ui.properties +++ b/core/src/main/assets/messages/ui/ui.properties @@ -548,4 +548,6 @@ ui.changelist.mlpd.vm0_6_7_x_changes.bug_06x79=-V0.6.3-Beta4.8\n1.修复一些 ui.changelist.mlpd.vm0_6_7_x_changes.bug_06x80=1.修复灯火值不扣减的错误\n2.其他小错误修复 +ui.changelist.mlpd.vm0_6_7_x_changes.bug_06x81=1.优化灯火体验\n其他错误修复。 + //ui.changelist.mlpd.vm0_5_x_changes.xxx// \ No newline at end of file diff --git a/core/src/main/assets/sprites/bluedragon.png b/core/src/main/assets/sprites/bluedragon.png index 10793c930..0607ac088 100644 Binary files a/core/src/main/assets/sprites/bluedragon.png and b/core/src/main/assets/sprites/bluedragon.png differ diff --git a/core/src/main/assets/sprites/boss/DictFish.png b/core/src/main/assets/sprites/boss/DictFish.png new file mode 100644 index 000000000..d1ba984ec Binary files /dev/null and b/core/src/main/assets/sprites/boss/DictFish.png differ diff --git a/core/src/main/assets/sprites/boss/RoomStone.png b/core/src/main/assets/sprites/boss/RoomStone.png new file mode 100644 index 000000000..dcba17722 Binary files /dev/null and b/core/src/main/assets/sprites/boss/RoomStone.png differ diff --git a/core/src/main/assets/sprites/boss/SakaFishBoss.png b/core/src/main/assets/sprites/boss/SakaFishBoss.png index f5763ff00..5ccf24669 100644 Binary files a/core/src/main/assets/sprites/boss/SakaFishBoss.png and b/core/src/main/assets/sprites/boss/SakaFishBoss.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 51517f845..96b9b47bf 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java @@ -29,6 +29,9 @@ public class Assets { public static final String BGM_5 = "music/Level5.ogg"; public static final String BGM_0 = "music/Level0.ogg"; public static final String SNOWCYON = "music/SnowCyon.ogg"; + + public static final String SKBJY = "music/Boss-Saka.ogg"; + public static final String TOWN = "music/town.ogg"; public static final String BGM_BOSSA = "music/Boss1.ogg"; public static final String BGM_BOSSB = "music/Boss2.ogg"; @@ -103,7 +106,8 @@ public class Assets { public static final String QliPhoth_Title = "interfaces/bosslogo/qliphoth-title.png"; public static final String QliPhoth_Clear = "interfaces/bosslogo/qliphoth-clear.png"; - + public static final String SakaBJY_Title = "interfaces/bosslogo/sakabjy-title.png"; + public static final String SakaBJY_Clear = "interfaces/bosslogo/sakabjy-clear.png"; public static final String ARCS_BG = "interfaces/arcs1.png"; public static final String ARCS_FG = "interfaces/arcs2.png"; @@ -310,7 +314,9 @@ public class Assets { //BOSS public static final String FRDG = "sprites/boss/fireDragon.png"; + public static final String DICT = "sprites/boss/DictFish.png"; + public static final String ROOMSTONE = "sprites/boss/RoomStone.png"; public static final String VSGR = "sprites/boss/SeaVastGirl.png"; public static final String SKFS = "sprites/boss/SakaFishBoss.png"; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/BGMPlayer.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/BGMPlayer.java index 9d1e884e3..3bf86a1cf 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/BGMPlayer.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/BGMPlayer.java @@ -10,6 +10,7 @@ import com.watabou.utils.Callback; public class BGMPlayer { + //解决电脑端高质量ogg的闪退问题 public static void playBGM(String name, boolean loop) { Game.runOnRenderThread(new Callback() { @Override @@ -33,7 +34,7 @@ public class BGMPlayer { if (d == -1) { playBGM(Assets.SNOWCYON, true); }else if (d == 0||d==27) { - playBGM(Assets.SNOWCYON, true); + playBGM(Assets.SKBJY, true); } else if (d > 0 && d <= 5) { playBGM(Assets.BGM_1, true); } else if (d > 5 && d <= 10) { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Badges.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Badges.java index 9015986e5..466387fe5 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Badges.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Badges.java @@ -209,7 +209,11 @@ public class Badges { EXSG (135), BRCLER (136), - HIGH_SCORE_5 ( 137 ); + HIGH_SCORE_5 ( 137 ), + + SAKA_DIED ( 138 ), + + RESET_DAY ( 139 ); public boolean meta; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java index 4bc694022..5705513fe 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java @@ -23,20 +23,19 @@ package com.shatteredpixel.shatteredpixeldungeon; import static com.shatteredpixel.shatteredpixeldungeon.Challenges.PRO; import static com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass.ROGUE; +import static com.shatteredpixel.shatteredpixeldungeon.levels.LevelRules.createBossRushLevel; +import static com.shatteredpixel.shatteredpixeldungeon.levels.LevelRules.createStandardLevel; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Amok; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Awareness; -import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.ClearBleesdGoodBuff.BlessAnmy; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.LighS; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Light; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MagicalSight; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MindVision; -import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.RandomBuff; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.RevealedArea; -import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.TestDwarfMasterLock; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.huntress.SpiritHawk; @@ -59,34 +58,11 @@ import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfRegrowth; import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfWarding; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.MagicTorch; import com.shatteredpixel.shatteredpixeldungeon.journal.Notes; -import com.shatteredpixel.shatteredpixeldungeon.levels.AncityLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.CaveTwoBossLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.CavesGirlDeadLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.CavesLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.CityLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.ColdChestBossLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.DM920BossLevel; import com.shatteredpixel.shatteredpixeldungeon.levels.DeadEndLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.DimandKingLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.DwarfMasterBossLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.ForestBossLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.HallsLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.ItemLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.LastLevel; import com.shatteredpixel.shatteredpixeldungeon.levels.Level; import com.shatteredpixel.shatteredpixeldungeon.levels.LinkLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.NewCavesBossLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.NewCityBossLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.NewHallsBossLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.PrisonBossLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.PrisonLevel; import com.shatteredpixel.shatteredpixeldungeon.levels.RegularLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.SLMKingLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.SewerBossLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.SewerLevel; import com.shatteredpixel.shatteredpixeldungeon.levels.ShopBossLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.YogGodHardBossLevel; -import com.shatteredpixel.shatteredpixeldungeon.levels.ZeroLevel; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.secret.SecretRoom; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.special.SpecialRoom; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; @@ -143,7 +119,28 @@ public class Dungeon { return level; } - //雪凛峡谷B + //远古副本 + public static Level AncityWaterLevel(){ + + + Dungeon.level = null; + Actor.clear(); + + depth = -20; + + if (depth > Statistics.realdeepestFloor) { + Statistics.realdeepestFloor = depth;} + + Level level; + level = new ShopBossLevel(); + + level.create(); + + Statistics.qualifiedForNoKilling = !bossLevel(); + + return level; + } + public static Level ColdFlowerCanyonDie(){ @@ -391,145 +388,9 @@ public class Dungeon { Level level; if (branch == 0) { if (Dungeon.isDLC(Conducts.Conduct.BOSSRUSH)) { - switch (depth) { - case 17: - case 27: - case 0: - level = new AncityLevel(); - Buff.affect(hero, RandomBuff.class).set((5), 1); - break; - case 1: - case 3: - case 6: - case 7: - case 9: - case 11: - case 13: - case 15: - case 18: - case 20: - case 24: - level = new ItemLevel(); - break; - case 2: - level = new ForestBossLevel(); - break; - case 4: - level = new SewerBossLevel(); - break; - case 5: - level = new SLMKingLevel(); - break; - case 8: - level = new PrisonBossLevel(); - break; - case 10: - level = new DimandKingLevel(); - break; - case 12: - level = new NewCavesBossLevel(); - break; - case 14: - level = new CaveTwoBossLevel(); - break; - case 16: - level = new CavesGirlDeadLevel(); - break; - case 19: - level = new ShopBossLevel(); - break; - case 21: - level = new NewCityBossLevel(); - break; - case 22: - case 23: - level = new CityLevel(); - Buff.affect(hero, TestDwarfMasterLock.class).set((10), 1); - break; - //TODO FIXED LIST:矮人将军那里用没祝福的十字架复活,Boss会消失不见 - case 25: - level = new DwarfMasterBossLevel(); - break; - case 26: - level = new YogGodHardBossLevel(); - break; - case 28: - level = new DM920BossLevel(); - Buff.affect(hero, TestDwarfMasterLock.class).set((1), 1); - break; - default: - level = new DeadEndLevel(); - Statistics.deepestFloor--; - } + level = createBossRushLevel(); } else - switch (depth) { - case 0: - level = new ZeroLevel(); - break; - case 1: - case 2: - case 3: - case 4: - level = new SewerLevel(); - break; - case 5: - level = new ForestBossLevel(); - break; - case 6: - case 7: - case 8: - case 9: - level = new PrisonLevel(); - break; - case 10: - if ((Statistics.boss_enhance & 0x2) != 0 || Statistics.mimicking) { - level = new ColdChestBossLevel(); - } else - level = new PrisonBossLevel(); - break; - case 11: - case 12: - case 13: - case 14: - level = new CavesLevel(); - break; - case 15: - if ((Statistics.boss_enhance & 0x4) != 0) { - level = new CavesGirlDeadLevel(); - } else - level = Random.Float() <= 0.4f ? new CaveTwoBossLevel() : new NewCavesBossLevel(); - break; - case 16: - case 17: - case 18: - case 19: - level = new CityLevel(); - break; - case 20: - if ((Statistics.boss_enhance & 0x8) != 0) { - Buff.affect(hero, TestDwarfMasterLock.class).set((1), 1); - level = new DwarfMasterBossLevel(); - break; - } else - level = new NewCityBossLevel(); - break; - case 21: - case 22: - case 23: - case 24: - level = new HallsLevel(); - break; - case 25: - if ((Statistics.boss_enhance & 0x10) != 0) level = new YogGodHardBossLevel(); - else level = new NewHallsBossLevel(); - break; - case 26: - level = new LastLevel(); - break; - default: - level = new DeadEndLevel(); - Statistics.deepestFloor--; - } + level = createStandardLevel(); } else { level = new DeadEndLevel(); Statistics.deepestFloor--; @@ -574,7 +435,7 @@ public class Dungeon { } public static boolean NxhyshopOnLevel() { - return depth == 9 || depth == 18; + return depth == 9 || depth == 13 || depth == 18; } public static boolean FireLevel() { @@ -738,7 +599,7 @@ public class Dungeon { int souLeftThisSet; //3 SOU each floor set, 1.5 (rounded) on forbidden runes challenge if (isChallenged(Challenges.NO_SCROLLS)){ - souLeftThisSet = Math.round(1.5f - (LimitedDrops.UPGRADE_SCROLLS.count - (depth / 5) * 1.5f)); + souLeftThisSet = Math.round(1.5f - (LimitedDrops.UPGRADE_SCROLLS.count - (depth / 5f) * 1.5f)); } else { souLeftThisSet = 3 - (LimitedDrops.UPGRADE_SCROLLS.count - (depth / 5) * 3); } 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 7d4424d02..e1ab2f940 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 @@ -955,7 +955,7 @@ public class Hero extends Char { } ///测试坐标用 - //GLog.w(String.valueOf(hero.pos)); + GLog.w(String.valueOf(hero.pos)); //携带该物品时,玩家血量低于一半后自动隐身一段回合。 //actMove实现 @@ -1166,7 +1166,7 @@ public class Hero extends Char { } switch (heap.type) { - case TOMB: + case TOMB: case WHITETOMB: Sample.INSTANCE.play( Assets.Sounds.TOMB ); Camera.main.shake( 1, 0.5f ); break; 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 dbf7a0b81..9a883764b 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 @@ -169,6 +169,9 @@ public enum HeroClass { new PotionOfDragonKingBreath().quantity(50).identify().collect(); new PotionOfHealing().quantity(50).identify().collect(); + + new PotionOfMindVision().quantity(50).identify().collect(); + new PotionOfLiquidFlame().quantity(50).identify().collect(); new DimandBook().quantity(50).identify().collect(); new PotionOfExperience().quantity(100).identify().collect(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/CrystalMimic.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/CrystalMimic.java index abdee50ea..69c277b01 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/CrystalMimic.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/CrystalMimic.java @@ -54,7 +54,7 @@ public class CrystalMimic extends Mimic { { spriteClass = MimicSprite.Crystal.class; - + flying = true; FLEEING = new Fleeing(); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogDzewa.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogDzewa.java index 713739007..41c94336a 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogDzewa.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogDzewa.java @@ -43,35 +43,28 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Paralysis; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Sleep; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Terror; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Vertigo; -import com.shatteredpixel.shatteredpixeldungeon.effects.Beam; import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; import com.shatteredpixel.shatteredpixeldungeon.effects.Pushing; -import com.shatteredpixel.shatteredpixeldungeon.effects.TargetedCell; -import com.shatteredpixel.shatteredpixeldungeon.effects.particles.PurpleParticle; import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ShadowParticle; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.DriedRose; import com.shatteredpixel.shatteredpixeldungeon.levels.Level; -import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.LarvaSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.YogSprite; -import com.shatteredpixel.shatteredpixeldungeon.tiles.DungeonTilemap; import com.shatteredpixel.shatteredpixeldungeon.ui.BossHealthBar; import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; import com.watabou.noosa.Game; import com.watabou.noosa.audio.Music; import com.watabou.utils.Bundle; import com.watabou.utils.Callback; -import com.watabou.utils.GameMath; import com.watabou.utils.PathFinder; import com.watabou.utils.Random; import com.watabou.utils.Reflection; import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; public class YogDzewa extends Mob { @@ -196,98 +189,7 @@ public class YogDzewa extends Mob { return true; } else { - boolean terrainAffected = false; - HashSet affected = new HashSet<>(); - //delay fire on a rooted hero - if (!Dungeon.hero.rooted) { - for (int i : targetedCells) { - Ballistica b = new Ballistica(pos, i, Ballistica.WONT_STOP); - //shoot beams - sprite.parent.add(new Beam.DeathRay(sprite.center(), DungeonTilemap.raisedTileCenterToWorld(b.collisionPos))); - for (int p : b.path) { - Char ch = Actor.findChar(p); - if (ch != null && (ch.alignment != alignment || ch instanceof Bee)) { - affected.add(ch); - } - if (Dungeon.level.flamable[p]) { - Dungeon.level.destroy(p); - GameScene.updateMap(p); - terrainAffected = true; - } - } - } - if (terrainAffected) { - Dungeon.observe(); - } - for (Char ch : affected) { - if (ch == Dungeon.hero) { - Statistics.bossScores[4] -= 1000; - } - if (Dungeon.isChallenged(Challenges.STRONGER_BOSSES)){ - ch.damage(Random.NormalIntRange(30, 50), new Eye.DeathGaze()); - } else { - ch.damage(Random.NormalIntRange(20, 30), new Eye.DeathGaze()); - } - if (Dungeon.level.heroFOV[pos]) { - ch.sprite.flash(); - CellEmitter.center(pos).burst(PurpleParticle.BURST, Random.IntRange(1, 2)); - } - if (!ch.isAlive() && ch == Dungeon.hero) { - Dungeon.fail(getClass()); - GLog.n(Messages.get(Char.class, "kill", name())); - } - } - targetedCells.clear(); - } - - if (abilityCooldown <= 0){ - - int beams = 1 + (HT - HP)/400; - HashSet affectedCells = new HashSet<>(); - for (int i = 0; i < beams; i++){ - - int targetPos = Dungeon.hero.pos; - if (i != 0){ - do { - targetPos = Dungeon.hero.pos + PathFinder.NEIGHBOURS8[Random.Int(8)]; - } while (Dungeon.level.trueDistance(pos, Dungeon.hero.pos) - > Dungeon.level.trueDistance(pos, targetPos)); - } - targetedCells.add(targetPos); - Ballistica b = new Ballistica(pos, targetPos, Ballistica.WONT_STOP); - affectedCells.addAll(b.path); - } - - //remove one beam if multiple shots would cause every cell next to the hero to be targeted - boolean allAdjTargeted = true; - for (int i : PathFinder.NEIGHBOURS9){ - if (!affectedCells.contains(Dungeon.hero.pos + i) && Dungeon.level.passable[Dungeon.hero.pos + i]){ - allAdjTargeted = false; - break; - } - } - if (allAdjTargeted){ - targetedCells.remove(targetedCells.size()-1); - } - for (int i : targetedCells){ - Ballistica b = new Ballistica(pos, i, Ballistica.WONT_STOP); - for (int p : b.path){ - sprite.parent.add(new TargetedCell(p, 0xFF0000)); - affectedCells.add(p); - } - } - - //don't want to overly punish players with slow move or attack speed - spend(GameMath.gate(TICK, Dungeon.hero.cooldown(), 3*TICK)); - Dungeon.hero.interrupt(); - - abilityCooldown += Random.NormalFloat(MIN_ABILITY_CD, MAX_ABILITY_CD); - abilityCooldown -= (phase - 1); - - } else { - spend(TICK); - } while (summonCooldown <= 0){ @@ -640,4 +542,6 @@ public class YogDzewa extends Mob { maxLvl = -2; } } + + } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/bosses/SakaFishBoss.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/bosses/SakaFishBoss.java index 44956f32c..3873f2844 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/bosses/SakaFishBoss.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/bosses/SakaFishBoss.java @@ -1,22 +1,643 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.mobs.bosses; +import static com.shatteredpixel.shatteredpixeldungeon.Dungeon.hero; + +import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.shatteredpixel.shatteredpixeldungeon.Badges; +import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Boss; +import com.shatteredpixel.shatteredpixeldungeon.actors.Char; +import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob; +import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.HalomethaneFire; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Bleeding; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Frost; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.LockedFloor; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.NewDM720; +import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; +import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile; +import com.shatteredpixel.shatteredpixeldungeon.effects.Pushing; +import com.shatteredpixel.shatteredpixeldungeon.effects.TargetedCell; +import com.shatteredpixel.shatteredpixeldungeon.effects.particles.RainbowParticle; +import com.shatteredpixel.shatteredpixeldungeon.items.keys.SkeletonKey; +import com.shatteredpixel.shatteredpixeldungeon.items.quest.GooBlob; +import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfBlastWave; +import com.shatteredpixel.shatteredpixeldungeon.levels.CaveTwoBossLevel; +import com.shatteredpixel.shatteredpixeldungeon.levels.Level; +import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; +import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; +import com.shatteredpixel.shatteredpixeldungeon.mechanics.ConeAOE; +import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; +import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.SakaFishBossSprites; +import com.shatteredpixel.shatteredpixeldungeon.ui.BossHealthBar; +import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; +import com.watabou.noosa.Camera; +import com.watabou.noosa.audio.Sample; +import com.watabou.utils.Bundle; +import com.watabou.utils.Callback; +import com.watabou.utils.GameMath; +import com.watabou.utils.PathFinder; +import com.watabou.utils.Random; public class SakaFishBoss extends Boss { + private int leapPos = -1; + private float leapCooldown = 0; + private int lastEnemyPos = -1; + private Ballistica beam; + private int beamTarget = -1; + private int beamCooldown; + public boolean beamCharged; + + + /**隐藏Boss 萨卡班甲鱼*/ { spriteClass = SakaFishBossSprites.class; - initBaseStatus(19, 25, 6, 0, 700, 5, 12); + initBaseStatus(19, 25, 6, 0, 480, 5, 12); state = SLEEPING; initProperty(); + HUNTING = new Hunting(); + baseSpeed = 1.75f; initStatus(76); - HP=700; + HP=480; defenseSkill = 10; - HT=700; - baseSpeed=1.5f; + HT=480; + + properties.add(Property.ICY); + viewDistance = 30; } + private int pumpedUp = 0; + private int healInc = 1; + + public void damage(int dmg, Object src) { + if (!Dungeon.level.mobs.contains(this)){ + return; + } + + int hpBracket = HT / 8; + + int beforeHitHP = HP; + super.damage(dmg, src); + dmg = beforeHitHP - HP; + + //tengu cannot be hit through multiple brackets at a time + if ((beforeHitHP/hpBracket - HP/hpBracket) >= 2){ + HP = hpBracket * ((beforeHitHP/hpBracket)-1) + 1; + } + + LockedFloor lock = hero.buff(LockedFloor.class); + if (lock != null) { + lock.addTime(dmg*3f); + } + + //phase 1 of the fight is over + if (HP <= HT/2){ + HP = (HT/2); + yell(Messages.get(this, "interesting")); +// ((PrisonBossLevel)Dungeon.level).progress(); + BossHealthBar.bleed(true); + } + } + + @Override + protected boolean canAttack( Char enemy ) { + + if (beamCooldown == 0) { + Ballistica aim = new Ballistica(pos, enemy.pos, Ballistica.STOP_SOLID); + + if (enemy.invisible == 0 && !isCharmedBy(enemy) && fieldOfView[enemy.pos] && aim.subPath(1, aim.dist).contains(enemy.pos)){ + beam = aim; + beamTarget = aim.collisionPos; + return true; + } else + //if the beam is charged, it has to attack, will aim at previous location of target. + return beamCharged; + } else + return super.canAttack(enemy); + } + + @Override + public int damageRoll() { + int min = 1; + int max = (HP*2 <= HT) ? 12 : 8; + if (pumpedUp > 0) { + pumpedUp = 0; + return Random.NormalIntRange( min*3, max*3 ); + } else { + return Random.NormalIntRange( min, max ); + } + } + + @Override + public int attackSkill( Char target ) { + int attack = 10; + if (HP*2 <= HT) attack = 15; + if (pumpedUp > 0) attack *= 2; + return attack; + } + + @Override + public int defenseSkill(Char enemy) { + return (int)(super.defenseSkill(enemy) * ((HP*2 <= HT)? 1.5 : 1)); + } + + @Override + public int drRoll() { + return Random.NormalIntRange(0, 2); + } + + + public void activate(){ + ((SakaFishBossSprites) sprite).activate(); + } + + @Override + protected boolean act() { + AiState lastState = state; + + boolean result = super.act(); + if (paralysed <= 0) leapCooldown --; + + //if state changed from wandering to hunting, we haven't acted yet, don't update. + if (!(lastState == WANDERING && state == HUNTING)) { + if (enemy != null) { + lastEnemyPos = enemy.pos; + } else { + lastEnemyPos = hero.pos; + } + } + if (beamCharged && state != HUNTING){ + beamCharged = false; + sprite.operate(this.pos); + } + if (beam == null && beamTarget != -1) { + beam = new Ballistica(pos, beamTarget, Ballistica.STOP_SOLID); + sprite.turnTo(pos, beamTarget); + } + if (beamCooldown > 0) + beamCooldown--; + return result; + } + + @Override + protected boolean doAttack( Char enemy ) { + + if (beamCooldown > 0) { + return super.doAttack(enemy); + } else if (!beamCharged){ + ((SakaFishBossSprites)sprite).charge( enemy.pos ); + spend( attackDelay()*2f ); + beamCharged = true; + return true; + } else if(HP*2>=HT) { + + spend( attackDelay()*3f ); + + beam = new Ballistica(pos, beamTarget, Ballistica.STOP_SOLID); + if (Dungeon.level.heroFOV[pos] || Dungeon.level.heroFOV[beam.collisionPos] ) { + sprite.zap( beam.collisionPos ); + return false; + } else { + sprite.operate(this.pos); + deathGaze(); + + return true; + } + } else { + + return true; + } + + } + +// @Override +// public boolean attack( Char enemy, float dmgMulti, float dmgBonus, float accMulti ) { +// boolean result = super.attack( enemy, dmgMulti, dmgBonus, accMulti ); +// pumpedUp = 0; +// return result; +// } +// +// @Override +// protected boolean getCloser( int target ) { +// if (pumpedUp != 0) { +// pumpedUp = 0; +// sprite.idle(); +// } +// return super.getCloser( target ); +// } +// +// @Override +// public void damage(int dmg, Object src) { +// if (!BossHealthBar.isAssigned()){ +// BossHealthBar.assignBoss( this ); +// Dungeon.level.seal(); +// } +// boolean bleeding = (HP*2 <= HT); +// super.damage(dmg, src); +// if ((HP*2 <= HT) && !bleeding){ +// BossHealthBar.bleed(true); +// sprite.showStatus(CharSprite.NEGATIVE, Messages.get(this, "enraged")); +// ((GooSprite)sprite).spray(true); +// yell(Messages.get(this, "gluuurp")); +// } +// LockedFloor lock = Dungeon.hero.buff(LockedFloor.class); +// if (lock != null) lock.addTime(dmg*2); +// } + + @Override + public void die( Object cause ) { + + super.die( cause ); + + if(Dungeon.depth!=28){ + Dungeon.level.unseal(); + + GetBossLoot(); + + GameScene.bossSlain(); + Dungeon.level.drop( new SkeletonKey( Dungeon.depth ), pos ).sprite.drop(); + + //60% chance of 2 blobs, 30% chance of 3, 10% chance for 4. Average of 2.5 + int blobs = Random.chances(new float[]{0, 0, 6, 3, 1}); + for (int i = 0; i < blobs; i++){ + int ofs; + do { + ofs = PathFinder.NEIGHBOURS8[Random.Int(8)]; + } while (!Dungeon.level.passable[pos + ofs]); + Dungeon.level.drop( new GooBlob(), pos + ofs ).sprite.drop( pos ); + } + + Badges.validateBossSlain(); + + yell( Messages.get(this, "defeated") ); + } + + } + + @Override + public void notice() { + super.notice(); + if (!BossHealthBar.isAssigned()) { + BossHealthBar.assignBoss(this); + Dungeon.level.seal(); + yell(Messages.get(this, "notice")); + Camera.main.shake(1f,3f); + GameScene.bossReady(); + activate(); + } + } + + private final String PUMPEDUP = "pumpedup"; + private final String HEALINC = "healinc"; + + private static final String LAST_ENEMY_POS = "last_enemy_pos"; + private static final String LEAP_POS = "leap_pos"; + private static final String LEAP_CD = "leap_cd"; + + private static final String BEAM_TARGET = "beamTarget"; + private static final String BEAM_COOLDOWN = "beamCooldown"; + private static final String BEAM_CHARGED = "beamCharged"; + + @Override + public void storeInBundle( Bundle bundle ) { + + super.storeInBundle( bundle ); + bundle.put( BEAM_TARGET, beamTarget); + bundle.put( BEAM_COOLDOWN, beamCooldown ); + bundle.put( BEAM_CHARGED, beamCharged ); + bundle.put( PUMPEDUP , pumpedUp ); + bundle.put( HEALINC, healInc ); + bundle.put(LAST_ENEMY_POS, lastEnemyPos); + bundle.put(LEAP_POS, leapPos); + bundle.put(LEAP_CD, leapCooldown); + } + + @Override + public void restoreFromBundle( Bundle bundle ) { + + super.restoreFromBundle( bundle ); + + pumpedUp = bundle.getInt( PUMPEDUP ); + if (state != SLEEPING) BossHealthBar.assignBoss(this); + if ((HP*2 <= HT)) BossHealthBar.bleed(true); + + //if check is for pre-0.9.3 saves + healInc = bundle.getInt(HEALINC); + + if (bundle.contains(BEAM_TARGET)) + beamTarget = bundle.getInt(BEAM_TARGET); + beamCooldown = bundle.getInt(BEAM_COOLDOWN); + beamCharged = bundle.getBoolean(BEAM_CHARGED); + + lastEnemyPos = bundle.getInt(LAST_ENEMY_POS); + leapPos = bundle.getInt(LEAP_POS); + leapCooldown = bundle.getFloat(LEAP_CD); + + } + + public void dropRocks( Char target ) { + + hero.interrupt(); + final int rockCenter; + if (Dungeon.level.adjacent(pos, target.pos)){ + int oppositeAdjacent = target.pos + (target.pos - pos); + Ballistica trajectory = new Ballistica(target.pos, oppositeAdjacent, Ballistica.MAGIC_BOLT); + WandOfBlastWave.throwChar(target, trajectory, 20, false, false, getClass()); + if (target == hero){ + hero.interrupt(); + } + rockCenter = trajectory.path.get(Math.min(trajectory.dist, 200)); + } else { + rockCenter = target.pos; + } + + //we handle this through an actor as it gives us fine-grainted control over when the blog acts vs. when the hero acts + //FIXME this is really messy to just get some fine-grained control. would be nice to build this into blob functionality, or just not use blobs for this at all + Actor a = new Actor() { + + { + actPriority = HERO_PRIO+1; + } + private static final float TIME_TO_ZAP = 1f; + + @Override + protected boolean act() { + + //pick an adjacent cell to the hero as a safe cell. This cell is less likely to be in a wall or containing hazards + int safeCell; + do { + safeCell = rockCenter + PathFinder.NEIGHBOURS8[Random.Int(8)]; + } while (safeCell == pos + || (Dungeon.level.solid[safeCell] && Random.Int(2) == 0) + || (Blob.volumeAt(safeCell, CaveTwoBossLevel.PylonEnergy.class) > 0 && Random.Int(2) == 0)); + + int start = rockCenter - Dungeon.level.width() * 3 - 3; + int pos; + for (int y = 0; y < 7; y++) { + pos = start + Dungeon.level.width() * y; + for (int x = 0; x < 7; x++) { + if (!Dungeon.level.insideMap(pos)) { + pos++; + continue; + } + //add rock cell to pos, if it is not solid, and isn't the safecell + if (!Dungeon.level.solid[pos] && pos != safeCell && Random.Int(Dungeon.level.distance(rockCenter, pos)) == 0) { + //don't want to overly punish players with slow move or attack speed + GameScene.add(Blob.seed(pos, 1, NewDM720.FallingRocks.class)); + } + pos++; + } + } + Actor.remove(this); + return true; + } + }; + Actor.addDelayed(a, Math.min(target.cooldown(), 3*TICK)); + + } + + public class Hunting extends Mob.Hunting { + + @Override + public boolean act( boolean enemyInFOV, boolean justAlerted ) { + + if (leapPos != -1){ + + leapCooldown = Random.NormalIntRange(2, 4); + Ballistica b = new Ballistica(pos, leapPos, Ballistica.STOP_TARGET | Ballistica.STOP_SOLID); + + //check if leap pos is not obstructed by terrain + if (rooted || b.collisionPos != leapPos){ + leapPos = -1; + return true; + } + + final Char leapVictim = Actor.findChar(leapPos); + final int endPos; + + //ensure there is somewhere to land after leaping + if (leapVictim != null){ + int bouncepos = -1; + for (int i : PathFinder.NEIGHBOURS8){ + if ((bouncepos == -1 || Dungeon.level.trueDistance(pos, leapPos+i) < Dungeon.level.trueDistance(pos, bouncepos)) + && Actor.findChar(leapPos+i) == null && Dungeon.level.passable[leapPos+i]){ + bouncepos = leapPos+i; + } + } + if (bouncepos == -1) { + leapPos = -1; + return true; + } else { + endPos = bouncepos; + } + } else { + endPos = leapPos; + } + //do leap + sprite.visible = Dungeon.level.heroFOV[pos] || Dungeon.level.heroFOV[leapPos] || Dungeon.level.heroFOV[endPos]; + sprite.dirtcar(pos, leapPos, new Callback() { + @Override + public void call() { + + if (leapVictim != null && alignment != leapVictim.alignment){ + Buff.affect(leapVictim, Bleeding.class).set(0.75f*damageRoll()); + dropRocks(enemy); + Sample.INSTANCE.play(Assets.Sounds.ROCKS); + leapVictim.sprite.flash(); + Sample.INSTANCE.play(Assets.Sounds.HIT); + } + + if (endPos != leapPos){ + Actor.addDelayed(new Pushing(SakaFishBoss.this, leapPos, endPos), -1); + } + + pos = endPos; + leapPos = -1; + sprite.operate(pos); + Dungeon.level.occupyCell(SakaFishBoss.this); + next(); + } + }); + sprite.visible = Dungeon.level.heroFOV[pos] || Dungeon.level.heroFOV[leapPos] || Dungeon.level.heroFOV[endPos]; + sprite.dirtcar(pos, leapPos, new Callback() { + @Override + public void call() { + + if (leapVictim != null && alignment != leapVictim.alignment){ + Buff.affect(leapVictim, Bleeding.class).set(0.75f*damageRoll()); + //TODO 魔法风暴 + FishStorm(enemy); + enemy.damage( Random.NormalIntRange( 10, 20 ), this ); + Sample.INSTANCE.play(Assets.Sounds.ROCKS); + leapVictim.sprite.flash(); + Sample.INSTANCE.play(Assets.Sounds.HIT); + } + + if (endPos != leapPos){ + Actor.addDelayed(new Pushing(SakaFishBoss.this, leapPos, endPos), -1); + } + + pos = endPos; + leapPos = -1; + sprite.operate(pos); + Dungeon.level.occupyCell(SakaFishBoss.this); + next(); + } + }); + + + return false; + } + + enemySeen = enemyInFOV; + if (enemyInFOV && !isCharmedBy( enemy ) && canAttack( enemy )) { + + return doAttack( enemy ); + + } else { + + if (enemyInFOV) { + target = enemy.pos; + } else if (enemy == null) { + state = WANDERING; + target = Dungeon.level.randomDestination( SakaFishBoss.this ); + return true; + } + + if (leapCooldown <= 0 && enemyInFOV && !rooted + && Dungeon.level.distance(pos, enemy.pos) >= 3) { + + int targetPos = enemy.pos; + if (lastEnemyPos != enemy.pos){ + int closestIdx = 0; + for (int i = 1; i < PathFinder.CIRCLE8.length; i++){ + if (Dungeon.level.trueDistance(lastEnemyPos, enemy.pos+PathFinder.CIRCLE8[i]) + < Dungeon.level.trueDistance(lastEnemyPos, enemy.pos+PathFinder.CIRCLE8[closestIdx])){ + closestIdx = i; + } + } + targetPos = enemy.pos + PathFinder.CIRCLE8[(closestIdx+4)%8]; + } + + Ballistica b = new Ballistica(pos, targetPos, Ballistica.STOP_TARGET | Ballistica.STOP_SOLID); + //try aiming directly at hero if aiming near them doesn't work + if (b.collisionPos != targetPos && targetPos != enemy.pos){ + targetPos = enemy.pos; + b = new Ballistica(pos, targetPos, Ballistica.STOP_TARGET | Ballistica.STOP_SOLID); + } + if (b.collisionPos == targetPos){ + //get ready to leap + leapPos = targetPos; + //don't want to overly punish players with slow move or attack speed + spend(GameMath.gate(TICK, enemy.cooldown(), 3*TICK)); + if (Dungeon.level.heroFOV[pos] || Dungeon.level.heroFOV[leapPos]){ + GLog.w(Messages.get(SakaFishBoss.this, "leap")); + sprite.parent.addToBack(new TargetedCell(leapPos, 0xFF0000)); + ((SakaFishBossSprites)sprite).leapPrep( leapPos ); + hero.interrupt(); + } + return true; + } + } + + int oldPos = pos; + if (target != -1 && getCloser( target )) { + + spend( 6f ); + return moveSprite( oldPos, pos ); + + } else { + spend(TICK); + if (!enemyInFOV) { + sprite.showLost(); + state = WANDERING; + target = Dungeon.level.randomDestination( SakaFishBoss.this ); + } + return true; + } + } + } + + } + public static class DeathGaze{} + public void deathGaze(){ + if (!beamCharged || beamCooldown > 0 || beam == null) + return; + + beamCharged = false; + beamCooldown = Random.IntRange(4, 6); + + boolean terrainAffected = false; + + for (int pos : beam.subPath(1, beam.dist)) { + + if (Dungeon.level.flamable[pos]) { + + Dungeon.level.destroy( pos ); + GameScene.updateMap( pos ); + terrainAffected = true; + + } + + Char ch = Actor.findChar( pos ); + if (ch == null) { + continue; + } + + if (hit( this, ch, true )) { + ch.damage( Random.NormalIntRange( 20, 40 ), new DeathGaze() ); + + if (Dungeon.level.heroFOV[pos]) { + ch.sprite.flash(); + CellEmitter.center( pos ).burst( RainbowParticle.BURST, Random.IntRange( 1, 2 ) ); + } + + if (!ch.isAlive() && ch == hero) { + Dungeon.fail( getClass() ); + GLog.n( Messages.get(this, "deathgaze_kill") ); + } + } else { + ch.sprite.showStatus( CharSprite.NEUTRAL, ch.defenseVerb() ); + } + } + + if (terrainAffected) { + Dungeon.observe(); + } + + beam = null; + beamTarget = -1; + } + + public void FishStorm(Char ch){ + Ballistica aim; + aim = new Ballistica(ch.pos, ch.pos - 1, Ballistica.WONT_STOP); + int projectileProps = Ballistica.STOP_SOLID | Ballistica.STOP_TARGET; + int aoeSize = 4; + ConeAOE aoe = new ConeAOE(aim, aoeSize, 360, projectileProps); + + for (Ballistica ray : aoe.outerRays){ + ((MagicMissile)ch.sprite.parent.recycle( MagicMissile.class )).reset( + MagicMissile.FROST, + ch.sprite, + ray.path.get(ray.dist), + null + ); + if( ray.collisionPos == hero.pos){ + Buff.prolong(enemy, Frost.class, Frost.DURATION); + } else { + GameScene.add(Blob.seed(ray.path.get(ray.dist),5, HalomethaneFire.class)); + Level.set(ray.path.get(ray.dist), Terrain.EMPTY); + GameScene.updateMap( ray.path.get(ray.dist) ); + } + + } + } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/bosses/v.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/bosses/v.java new file mode 100644 index 000000000..d9e0bef08 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/bosses/v.java @@ -0,0 +1,476 @@ +//package com.shatteredpixel.shatteredpixeldungeon.actors.mobs.bosses; +// +//import static com.shatteredpixel.shatteredpixeldungeon.Dungeon.hero; +// +//import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +//import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; +//import com.shatteredpixel.shatteredpixeldungeon.actors.Char; +//import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Adrenaline; +//import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Amok; +//import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Blindness; +//import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; +//import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.ChaosTime; +//import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Charm; +//import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.FireImbue; +//import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MaxGuard; +//import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Paralysis; +//import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Sleep; +//import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.SoulMark; +//import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Terror; +//import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Vertigo; +//import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Weakness; +//import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; +//import com.shatteredpixel.shatteredpixeldungeon.effects.Beam; +//import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; +//import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; +//import com.shatteredpixel.shatteredpixeldungeon.effects.TargetedCell; +//import com.shatteredpixel.shatteredpixeldungeon.effects.particles.PurpleParticle; +//import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; +//import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +//import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; +//import com.shatteredpixel.shatteredpixeldungeon.sprites.PillarSprite; +//import com.shatteredpixel.shatteredpixeldungeon.tiles.DungeonTilemap; +//import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; +//import com.watabou.utils.Bundle; +//import com.watabou.utils.GameMath; +//import com.watabou.utils.PathFinder; +//import com.watabou.utils.Random; +// +//import java.util.ArrayList; +//import java.util.HashSet; +// +//public abstract class SeptiumPillar extends Mob { +// +// private boolean firstactive = false; +// private boolean secondactive = false; +// private boolean thirdactive = false; +// +// { +// HP = HT = 100; +// +// viewDistance = 99; +// +// //for doomed resistance +// EXP = 25; +// maxLvl = -2; +// baseSpeed = 0; +// +// state = PASSIVE; +// alignment = Alignment.NEUTRAL; +// +// properties.add(Property.BOSS); +// properties.add(Property.KISEKI); +// properties.add(Property.IMMOVABLE); +// properties.add(Property.INORGANIC); +// immunities.add( Terror.class ); +// immunities.add( Amok.class ); +// immunities.add( Charm.class ); +// immunities.add( Sleep.class ); +// immunities.add( Vertigo.class ); +// immunities.add( Paralysis.class ); +// immunities.add( SoulMark.class ); +// immunities.add( Weakness.class ); +// immunities.add( Blindness.class ); +// } +// +// @Override +// protected boolean act() +// +// { +// if (alignment == Alignment.NEUTRAL){ +// next(); +// } +// else +// { +// onZapComplete(); +// state = PASSIVE; +// } +// return super.act(); +// } +// +// @Override +// public void notice() { +// //do nothing +// } +// +// +// +// @Override +// public void add(Buff buff) { +// //immune to all buffs/debuffs when inactive +// if (alignment != Alignment.NEUTRAL) { +// super.add(buff); +// } +// } +// +// private static final String ALIGNMENT = "alignment"; +// +// @Override +// public void storeInBundle(Bundle bundle) { +// super.storeInBundle(bundle); +// bundle.put(ALIGNMENT, alignment); +// +// } +// +// @Override +// public void restoreFromBundle(Bundle bundle) { +// super.restoreFromBundle(bundle); +// alignment = bundle.getEnum(ALIGNMENT, Alignment.class); +// +// } +// +// @Override +// public boolean interact(Char c) { +// return true; +// } +// +// protected abstract void zap(); +// +// +// +// public void onZapComplete(){ +// zap(); +// next(); +// } +// +// +// +// public void activate(){ +// alignment = Alignment.ENEMY; +// ((PillarSprite) sprite).activate(); +// } +// +// @Override +// public String description() { +// return Messages.get(SeptiumPillar.class, "desc") + "\n\n" + Messages.get(this, "desc"); +// } +// +// { +// immunities.add( Terror.class ); +// immunities.add( Amok.class ); +// immunities.add( Charm.class ); +// immunities.add( Sleep.class ); +// immunities.add( Vertigo.class ); +// immunities.add( Paralysis.class ); +// immunities.add( SoulMark.class ); +// immunities.add( Weakness.class ); +// immunities.add( Blindness.class ); +// } +// +// public static class FlamePillar extends SeptiumPillar { +// +// { +// spriteClass = PillarSprite.Flame.class; +// } +// +// @Override +// protected boolean act() { +// { +// state = PASSIVE; +// } +// return super.act(); +// } +// +// @Override +// protected void zap() { +// for (Mob mob : Dungeon.level.mobs.toArray(new Mob[0])) { +// if(!mob.properties().contains(Property.KISEKI)) { +// Buff.affect(mob, FireImbue.class).set( 10f); +// } +// next(); +// } +// GLog.w(Messages.get( this, "message") ); +// spend(15f); +// } +// +// } +// +// public static class GroundPillar extends SeptiumPillar { +// +// { +// spriteClass = PillarSprite.Ground.class; +// } +// +// @Override +// protected boolean act() { +// { +// state = PASSIVE; +// } +// return super.act(); +// } +// +// +// @Override +// protected void zap() { +// for (Mob mob : Dungeon.level.mobs.toArray(new Mob[0])) { +// if(!mob.properties().contains(Property.KISEKI)) { +// Buff.affect(mob, MaxGuard.class); +// } +// next(); +// } +// GLog.w(Messages.get( this, "message") ); +// spend(15f); +// }; +// +// +// +// +// +// } +// +// public static class WaterPillar extends SeptiumPillar { +// +// { +// spriteClass = PillarSprite.Water.class; +// +// } +// +// @Override +// protected boolean act() { +// { +// state = PASSIVE; +// } +// return super.act(); +// } +// +// @Override +// protected void zap() { +// for (Mob mob : Dungeon.level.mobs.toArray(new Mob[0])) { +// if(!mob.properties().contains(Property.KISEKI)) { +// if (mob.HP < mob.HT/3){ +// +// mob.HP = mob.HP+20; +// +// } +// +// +// } +// +// } +// GLog.w(Messages.get( this, "message") ); +// spend(15f); +// }; +// +// +// +// } +// +// public static class WindPillar extends SeptiumPillar { +// +// { +// spriteClass = PillarSprite.Wind.class; +// +// } +// +// @Override +// protected boolean act() { +// { +// state = PASSIVE; +// } +// return super.act(); +// } +// +// @Override +// protected void zap() { +// for (Mob mob : Dungeon.level.mobs.toArray(new Mob[0])) { +// if(!mob.properties().contains(Property.KISEKI)) { +// Buff.affect(mob, Adrenaline.class,3f); +// } +// next(); +// } +// GLog.w(Messages.get( this, "message") ); +// spend(15f); +// } +// } +// +// public static class ChronosPillar extends SeptiumPillar { +// +// { +// spriteClass = PillarSprite.Chronos.class; +// +// } +// +// @Override +// protected boolean act() { +// { +// state = PASSIVE; +// } +// return super.act(); +// } +// +// @Override +// protected void zap() { +// +// spend(15f); +// Buff.affect( hero, ChaosTime.class, 15f); +// GLog.w(Messages.get( this, "message") ); +// +// } +// +// +// } +// +// +// public static class HeavenPillar extends SeptiumPillar { +// +// { +// spriteClass = PillarSprite.Heaven.class; +// } +// +// private ArrayList targetedCells = new ArrayList<>(); +// +// private float abilityCooldown; +// private static final int MIN_ABILITY_CD = 10; +// private static final int MAX_ABILITY_CD = 15; +// +// // 添加一个计数器,用来记录回合数 +// private int turnCount = 0; +// +// @Override +// protected boolean act() { +// boolean terrainAffected = false; +// HashSet affected = new HashSet<>(); +// //delay fire on a rooted hero +// if (!hero.rooted && alignment == Alignment.ENEMY && firstActive) { +// for (int i : targetedCells) { +// Ballistica b = new Ballistica(pos, i, Ballistica.WONT_STOP); +// //shoot beams +// sprite.parent.add(new Beam.DeathRay(sprite.center(), DungeonTilemap.raisedTileCenterToWorld(b.collisionPos))); +// for (int p : b.path) { +// Char ch = Actor.findChar(p); +// if (ch != null && (ch.alignment != alignment || ch instanceof Bee)) { +// affected.add(ch); +// } +// if (Dungeon.level.flamable[p]) { +// Dungeon.level.destroy(p); +// GameScene.updateMap(p); +// terrainAffected = true; +// } +// } +// } +// if (terrainAffected) { +// Dungeon.observe(); +// } +// for (Char ch : affected) { +// ch.damage(Random.NormalIntRange(20, 30), new Eye.DeathGaze()); +// +// if (Dungeon.level.heroFOV[pos]) { +// ch.sprite.flash(); +// CellEmitter.center(pos).burst(PurpleParticle.BURST, Random.IntRange(1, 2)); +// } +// if (!ch.isAlive() && ch == hero) { +// Dungeon.fail(getClass()); +// GLog.n(Messages.get(Char.class, "kill", name())); +// } +// } +// targetedCells.clear(); +// } +// +// if (abilityCooldown <= 0 && alignment == Alignment.ENEMY && firstActive) { +// int beams = 1; +// GLog.w(Messages.get(this, "message")); +// HashSet affectedCells = new HashSet<>(); +// for (int i = 0; i < beams; i++) { +// +// int targetPos = hero.pos; +// if (i != 0) { +// do { +// targetPos = hero.pos + PathFinder.NEIGHBOURS8[Random.Int(8)]; +// } while (Dungeon.level.trueDistance(pos, hero.pos) +// > Dungeon.level.trueDistance(pos, targetPos)); +// } +// targetedCells.add(targetPos); +// Ballistica b = new Ballistica(pos, targetPos, Ballistica.WONT_STOP); +// affectedCells.addAll(b.path); +// } +// +// //remove one beam if multiple shots would cause every cell next to the hero to be targeted +// boolean allAdjTargeted = true; +// for (int i : PathFinder.NEIGHBOURS9) { +// if (!affectedCells.contains(hero.pos + i) && Dungeon.level.passable[hero.pos + i]) { +// allAdjTargeted = false; +// break; +// } +// } +// if (allAdjTargeted) { +// targetedCells.remove(targetedCells.size() - 1); +// } +// for (int i : targetedCells) { +// Ballistica b = new Ballistica(pos, i, Ballistica.WONT_STOP); +// for (int p : b.path) { +// sprite.parent.add(new TargetedCell(p, 0xFF0000)); +// affectedCells.add(p); +// } +// } +// +// // 在14回合时发出警告 +// if (turnCount == 14) { +// for (int i : affectedCells) { +// sprite.parent.add(new TargetedCell(i, 0xFF0000)); +// } +// } +// +// // don't want to overly punish players with slow move or attack speed +// spend(GameMath.gate(TICK, hero.cooldown(), 3 * TICK)); +// hero.interrupt(); +// +// abilityCooldown += Random.NormalFloat(MIN_ABILITY_CD, MAX_ABILITY_CD); +// +// } else { +// spend(TICK); +// if (abilityCooldown > 0) abilityCooldown--; +// } +// +// turnCount++; // 回合数自增 +// +// +// return true; +// } +// +// @Override +// protected void zap() { +// next(); +// } +// } +// +// +// +// +// +// +// public static class PhantomPillar extends SeptiumPillar { +// +// { +// spriteClass = PillarSprite.Phantom.class; +// +// } +// +// @Override +// protected boolean act() { +// { +// state = PASSIVE; +// } +// return super.act(); +// } +// +// @Override +// protected void zap() { +// +// Buff.affect( hero, Vertigo.class, 3f); +// for (Mob mob : Dungeon.level.mobs.toArray( new Mob[0] )) { +// mob.beckon( hero.pos ); +// } +// hero.sprite.centerEmitter().start( Speck.factory( Speck.SCREAM ), 0.3f, 3 ); +// GLog.w(Messages.get( this, "message") ); +// spend(15f); +// } +// +// +// +// +// } +// +// +// +//} +// diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/ImpShopkeeper.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/ImpShopkeeper.java index 85163b528..2c5896f2a 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/ImpShopkeeper.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/ImpShopkeeper.java @@ -21,10 +21,7 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs; -import static com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Shopkeeper.sell; - import com.shatteredpixel.shatteredpixeldungeon.Dungeon; -import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; @@ -32,10 +29,8 @@ import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ElmoParticle; import com.shatteredpixel.shatteredpixeldungeon.items.Heap; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.sprites.ImpSprite; -import com.watabou.noosa.Game; -import com.watabou.utils.Callback; -public class ImpShopkeeper extends NPC { +public class ImpShopkeeper extends Shopkeeper { { spriteClass = ImpSprite.class; @@ -54,20 +49,6 @@ public class ImpShopkeeper extends NPC { return super.act(); } - @Override - public boolean interact(Char c) { - if (c != Dungeon.hero) { - return true; - } - Game.runOnRenderThread(new Callback() { - @Override - public void call() { - sell(); - } - }); - return true; - } - @Override public void damage( int dmg, Object src ) { //flee(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Nxhy.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Nxhy.java index 4d45e60aa..fb75c2b4b 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Nxhy.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Nxhy.java @@ -1,22 +1,15 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; -import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ElmoParticle; import com.shatteredpixel.shatteredpixeldungeon.items.Heap; -import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.journal.Notes; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; -import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.sprites.NxhySprite; -import com.shatteredpixel.shatteredpixeldungeon.windows.WndBag; -import com.shatteredpixel.shatteredpixeldungeon.windows.WndTradeItem; -import com.watabou.noosa.Game; -import com.watabou.utils.Callback; -public class Nxhy extends NPC { +public class Nxhy extends Shopkeeper { { spriteClass = NxhySprite.class; @@ -74,48 +67,5 @@ public class Nxhy extends NPC { } } } - - @Override - public boolean reset() { - return true; - } - - public static WndBag sell() { - return GameScene.selectItem( itemSelector ); - } - - private static WndBag.ItemSelector itemSelector = new WndBag.ItemSelector() { - @Override - public String textPrompt() { - return Messages.get(Shopkeeper.class, "sell"); - } - - @Override - public boolean itemSelectable(Item item) { - return Shopkeeper.canSell(item); - } - - @Override - public void onSelect( Item item ) { - if (item != null) { - WndBag parentWnd = sell(); - GameScene.show( new WndTradeItem( item, parentWnd ) ); - } - } - }; - - @Override - public boolean interact(Char c) { - if (c != Dungeon.hero) { - return true; - } - Game.runOnRenderThread(new Callback() { - @Override - public void call() { - sell(); - } - }); - return true; - } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Shopkeeper.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Shopkeeper.java index 962d0b732..3aca34f54 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Shopkeeper.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Shopkeeper.java @@ -21,142 +21,92 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs; -import static com.shatteredpixel.shatteredpixeldungeon.Dungeon.hero; - import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; +import com.shatteredpixel.shatteredpixeldungeon.Statistics; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; -import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.ClearBleesdGoodBuff.BlessNoMoney; -import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MagicGirlDebuff.MagicGirlSayMoneyMore; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ElmoParticle; -import com.shatteredpixel.shatteredpixeldungeon.items.Ankh; import com.shatteredpixel.shatteredpixeldungeon.items.Heap; import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.armor.Armor; -import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.DriedRose; -import com.shatteredpixel.shatteredpixeldungeon.items.food.Food; -import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfHealing; +import com.shatteredpixel.shatteredpixeldungeon.journal.Notes; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; +import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.ShopkeeperSprite; +import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; import com.shatteredpixel.shatteredpixeldungeon.windows.WndBag; +import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions; +import com.shatteredpixel.shatteredpixeldungeon.windows.WndTitledMessage; import com.shatteredpixel.shatteredpixeldungeon.windows.WndTradeItem; import com.watabou.noosa.Game; +import com.watabou.noosa.Image; +import com.watabou.utils.Bundlable; import com.watabou.utils.Bundle; import com.watabou.utils.Callback; +import java.util.ArrayList; + public class Shopkeeper extends NPC { { spriteClass = ShopkeeperSprite.class; + properties.add(Property.IMMOVABLE); } - public static boolean seenBefore = false; - @Override - public boolean interact(Char c) { - if (c != hero) { - return true; - } - Game.runOnRenderThread(new Callback() { - @Override - public void call() { - sell(); - } - }); - return true; - } - - @Override - public void storeInBundle(Bundle bundle) { - super.storeInBundle(bundle); - } + public static int MAX_BUYBACK_HISTORY = 4; + public ArrayList buybackItems = new ArrayList<>(); @Override protected boolean act() { - if (!seenBefore && Dungeon.level.heroFOV[pos]) { - yell(Messages.get(this, "greetings", Dungeon.hero.name())); - seenBefore = true; - //Buff.affect(this, ChampionEnemy.AntiMagic.class); - //Buff.affect(this, ChampionEnemy.Halo.class); - } else if(seenBefore && !Dungeon.level.heroFOV[pos]) { - seenBefore = false; - yell(Messages.get(this, "goodbye", Dungeon.hero.name())); + + if (Dungeon.level.visited[pos]){ + Notes.add(Notes.Landmark.SHOP); } - throwItem(); + sprite.turnTo( pos, Dungeon.hero.pos ); spend( TICK ); - return true; + return super.act(); } @Override public void damage( int dmg, Object src ) { + flee(); } @Override - public int defenseSkill( Char enemy ) { - return INFINITE_EVASION; + public void add(Buff buff ) { } - /* - Buff.prolong(Dungeon.hero, Blindness.class, Blindness.DURATION * 4f); - GameScene.flash(0x80FFFFFF); - Buff.affect(hero, Burning.class).reignite(hero, 15f); - Dungeon.level.seal(); - Mob moa = new MoloHR(); - moa.pos = pos; - GameScene.add(moa); - yell(Messages.get(this, "arise")); - new ShopGuardEye().spawnAround(pos); - new ShopGuard().spawnAround(pos); - Buff.affect(moa, ChampionEnemy.Growing.class); - Buff.affect(moa, ChampionEnemy.Projecting.class); - Buff.affect(moa, ChampionEnemy.AntiMagic.class); - Buff.affect(moa, ChampionEnemy.Giant.class); - Buff.affect(moa, ChampionEnemy.Blessed.class); - Buff.affect(moa, ChampionEnemy.Halo.class); - for (Mob mob : Dungeon.level.mobs) { - switch (Random.Int(7)) { - case 0: - default: - Buff.affect(mob, ChampionEnemy.Blazing.class); - break; - case 1: - Buff.affect(mob, ChampionEnemy.Projecting.class); - break; - case 2: - Buff.affect(mob, ChampionEnemy.AntiMagic.class); - break; - case 3: - Buff.affect(mob, ChampionEnemy.Giant.class); - break; - case 4: - Buff.affect(mob, ChampionEnemy.Blessed.class); - break; - case 5: - Buff.affect(mob, ChampionEnemy.Growing.class); - break; - case 6: - Buff.affect(mob, ChampionEnemy.Halo.class); - break; - } - } - yell(Messages.get(this, "dead"));*/ - public void flee() { destroy(); - CellEmitter.get(pos).burst(ElmoParticle.FACTORY, 6); - hero.sprite.burst(15597568, 9); - sprite.killAndErase(); + + Notes.remove(Notes.Landmark.SHOP); + + if (sprite != null) { + sprite.killAndErase(); + CellEmitter.get(pos).burst(ElmoParticle.FACTORY, 6); + } } - private DriedRose.GhostHero ghost = null; + + @Override public void destroy() { super.destroy(); for (Heap heap: Dungeon.level.heaps.valueList()) { if (heap.type == Heap.Type.FOR_SALE) { - CellEmitter.get( heap.pos ).burst( ElmoParticle.FACTORY, 4 ); - heap.type = Heap.Type.HEAP;//Allow them to be picked up + if (ShatteredPixelDungeon.scene() instanceof GameScene) { + CellEmitter.get(heap.pos).burst(ElmoParticle.FACTORY, 4); + } + if (heap.size() == 1) { + heap.destroy(); + } else { + heap.items.remove(heap.size()-1); + heap.type = Heap.Type.HEAP; + } } } } @@ -168,18 +118,7 @@ public class Shopkeeper extends NPC { //shopkeepers are greedy! public static int sellPrice(Item item){ - int price = item.value() * 5 * (Dungeon.depth / 5 + 1); - - if(Dungeon.hero.buff(MagicGirlSayMoneyMore.class) != null){ - if(item instanceof Ankh ||item instanceof Food || item instanceof PotionOfHealing){ - price *= 0.1; - } - price *= 1.5; - //todo 3折 - } else if (Dungeon.hero.buff(BlessNoMoney.class) != null) { - price *= 0.3; - } - return price; + return item.value() * 5 * (Dungeon.depth / 5 + 1); } public static WndBag sell() { @@ -213,4 +152,100 @@ public class Shopkeeper extends NPC { } } }; -} + + @Override + public boolean interact(Char c) { + if (c != Dungeon.hero) { + return true; + } + Game.runOnRenderThread(new Callback() { + @Override + public void call() { + String[] options = new String[2+ buybackItems.size()]; + int i = 0; + options[i++] = Messages.get(Shopkeeper.this, "sell"); + options[i++] = Messages.get(Shopkeeper.this, "talk"); + for (Item item : buybackItems){ + options[i] = Messages.get(Heap.class, "for_sale", item.value(), + Messages.titleCase(item.trueName()+"x"+item.quantity())); + if (options[i].length() > 26) options[i] = options[i].substring(0, 23) + "..."; + i++; + } + GameScene.show(new WndOptions(sprite(), Messages.titleCase(name()), description(), options){ + @Override + protected void onSelect(int index) { + super.onSelect(index); + if (index == 0){ + sell(); + } else if (index == 1){ + GameScene.show(new WndTitledMessage(sprite(), Messages.titleCase(name()), chatText())); + } else if (index > 1){ + GLog.i(Messages.get(Shopkeeper.this, "buyback")); + Item returned = buybackItems.remove(index-2); + Dungeon.gold -= returned.value(); + Statistics.goldCollected -= returned.value(); + if (!returned.doPickUp(Dungeon.hero)){ + Dungeon.level.drop(returned, Dungeon.hero.pos); + } + } + } + + @Override + protected boolean enabled(int index) { + if (index > 1){ + return Dungeon.gold >= buybackItems.get(index-2).value(); + } else { + return super.enabled(index); + } + } + + @Override + protected boolean hasIcon(int index) { + return index > 1; + } + + @Override + protected Image getIcon(int index) { + if (index > 1){ + return new ItemSprite(buybackItems.get(index-2)); + } + return null; + } + }); + } + }); + return true; + } + + public String chatText(){ + switch (Dungeon.depth){ + case 6: default: + return Messages.get(this, "talk_prison_intro") + "\n\n" + Messages.get(this, "talk_prison_" + Dungeon.hero.heroClass.name()); + case 11:case 13: + return Messages.get(this, "talk_caves"); + case 16: case 18: + return Messages.get(this, "talk_city"); + case 20: + return Messages.get(this, "talk_halls"); + } + } + + public static String BUYBACK_ITEMS = "buyback_items"; + + @Override + public void storeInBundle(Bundle bundle) { + super.storeInBundle(bundle); + bundle.put(BUYBACK_ITEMS, buybackItems); + } + + @Override + public void restoreFromBundle(Bundle bundle) { + super.restoreFromBundle(bundle); + buybackItems.clear(); + if (bundle.contains(BUYBACK_ITEMS)){ + for (Bundlable i : bundle.getCollection(BUYBACK_ITEMS)){ + buybackItems.add((Item) i); + } + } + } +} \ No newline at end of file diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Heap.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Heap.java index 5f4e8678b..e68b42268 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Heap.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Heap.java @@ -21,8 +21,9 @@ package com.shatteredpixel.shatteredpixeldungeon.items; +import static com.shatteredpixel.shatteredpixeldungeon.Dungeon.level; + import com.shatteredpixel.shatteredpixeldungeon.Assets; -import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Wraith; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Shopkeeper; @@ -42,6 +43,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.potions.Potion; import com.shatteredpixel.shatteredpixeldungeon.items.rings.Ring; import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfWealth; import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.Scroll; +import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTeleportation; import com.shatteredpixel.shatteredpixeldungeon.items.wands.Wand; import com.shatteredpixel.shatteredpixeldungeon.journal.Document; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; @@ -56,7 +58,7 @@ import java.util.Collections; import java.util.LinkedList; public class Heap implements Bundlable { - + public enum Type { HEAP, FOR_SALE, @@ -64,6 +66,8 @@ public class Heap implements Bundlable { LOCKED_CHEST, CRYSTAL_CHEST, TOMB, + TELECRYSTL, + WHITETOMB, SKELETON, REMAINS, BLACK @@ -85,6 +89,12 @@ public class Heap implements Bundlable { case TOMB: Wraith.spawnAround( hero.pos ); break; + case WHITETOMB: + ScrollOfTeleportation.appear( hero,hero.pos+5 ); + break; + case TELECRYSTL: + ScrollOfTeleportation.appear( hero,level.entrance ); + break; case REMAINS: case SKELETON: CellEmitter.center( pos ).start(Speck.factory(Speck.RATTLE), 0.1f, 3); @@ -227,7 +237,7 @@ public class Heap implements Bundlable { if (burnt || evaporated) { - if (Dungeon.level.heroFOV[pos]) { + if (level.heroFOV[pos]) { if (burnt) { burnFX( pos ); } else { @@ -248,7 +258,7 @@ public class Heap implements Bundlable { public void explode() { //breaks open most standard containers, mimics die. - if (type == Type.CHEST || type == Type.SKELETON) { + if (type == Type.CHEST || type == Type.SKELETON || type == Type.TELECRYSTL) { type = Type.HEAP; sprite.link(); sprite.drop(); @@ -343,7 +353,7 @@ public class Heap implements Bundlable { } public void destroy() { - Dungeon.level.heaps.remove( this.pos ); + level.heaps.remove( this.pos ); if (sprite != null) { sprite.kill(); } @@ -364,10 +374,12 @@ public class Heap implements Bundlable { return Messages.get(this, "chest"); case LOCKED_CHEST: return Messages.get(this, "locked_chest"); - case CRYSTAL_CHEST: + case CRYSTAL_CHEST: case TELECRYSTL: return Messages.get(this, "crystal_chest"); case TOMB: return Messages.get(this, "tomb"); + case WHITETOMB: + return Messages.get(this, "wtomb"); case SKELETON: return Messages.get(this, "skeleton"); case REMAINS: @@ -381,7 +393,7 @@ public class Heap implements Bundlable { public String info(){ switch(type){ - case CHEST: + case CHEST:case TELECRYSTL: return Messages.get(this, "chest_desc"); case LOCKED_CHEST: return Messages.get(this, "locked_chest_desc"); @@ -396,6 +408,8 @@ public class Heap implements Bundlable { return Messages.get(this, "crystal_chest_desc", Messages.get(this, "unknow") ); case TOMB: return Messages.get(this, "tomb_desc"); + case WHITETOMB: + return Messages.get(this, "wtomb_desc"); case BLACK: return Messages.get(this, "black_chest_desc"); case SKELETON: diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/Alchemize.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/Alchemize.java index 227e7cd9b..f16879f68 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/Alchemize.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/Alchemize.java @@ -23,6 +23,8 @@ package com.shatteredpixel.shatteredpixeldungeon.items.spells; 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.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Shopkeeper; import com.shatteredpixel.shatteredpixeldungeon.items.Item; @@ -108,14 +110,21 @@ public class Alchemize extends Spell { this.owner = owner; float pos = height; - + Shopkeeper shop = null; + for (Char ch : Actor.chars()){ + if (ch instanceof Shopkeeper){ + shop = (Shopkeeper) ch; + break; + } + } + final Shopkeeper finalShop = shop; if (Shopkeeper.canSell(item)) { if (item.quantity() == 1) { RedButton btnSell = new RedButton(Messages.get(this, "sell", item.value())) { @Override protected void onClick() { - WndTradeItem.sell(item); + WndTradeItem.sell(item,finalShop); hide(); consumeAlchemize(); } @@ -143,7 +152,7 @@ public class Alchemize extends Spell { RedButton btnSellAll = new RedButton(Messages.get(this, "sell_all", priceAll)) { @Override protected void onClick() { - WndTradeItem.sell(item); + WndTradeItem.sell(item,finalShop); hide(); consumeAlchemize(); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/LockSword.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/LockSword.java index 5fcf38a58..56a69eb11 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/LockSword.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/LockSword.java @@ -18,11 +18,17 @@ import com.watabou.utils.Bundle; import com.watabou.utils.Random; public class LockSword extends MeleeWeapon { + + + + private int lvl = 0; public LockSword() { super.image = ItemSpriteSheet.DG3; super.tier = 5; +// InterlevelScene.mode = InterlevelScene.Mode.ANCITYBOSS; +// Game.switchScene(InterlevelScene.class); } @Override diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/AncientMysteryCityBossLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/AncientMysteryCityBossLevel.java index 14acfe2dd..077c6a547 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/AncientMysteryCityBossLevel.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/AncientMysteryCityBossLevel.java @@ -1,7 +1,13 @@ package com.shatteredpixel.shatteredpixeldungeon.levels; 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.mobs.bosses.SakaFishBoss; +import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; +import com.watabou.utils.PathFinder; +import com.watabou.utils.Random; public class AncientMysteryCityBossLevel extends Level{ @@ -26,7 +32,7 @@ public class AncientMysteryCityBossLevel extends Level{ private static final short E = Terrain.STATUE; private static final short C = Terrain.HIGH_GRASS; private static final short M = Terrain.CRYSTAL_DOOR; - private static final short G = Terrain.LOCKED_DOOR; + private static final short G = Terrain.DOOR; private static final short K = Terrain.WELL; @@ -76,14 +82,54 @@ public class AncientMysteryCityBossLevel extends Level{ return true; } + @Override + public int randomRespawnCell( Char ch ) { + int pos = WIDTH + 16; //random cell adjacent to the entrance. + int cell; + do { + cell = pos + PathFinder.NEIGHBOURS8[Random.Int(8)]; + } while (!passable[cell] + || (Char.hasProp(ch, Char.Property.LARGE) && !openSpace[cell]) + || Actor.findChar(cell) != null); + return cell; + } + + + + private static final int getBossDoor = 688; + private static final int LDBossDoor = 661; + @Override + public void occupyCell( Char ch ) { + + super.occupyCell( ch ); + + boolean isTrue = ch.pos == LDBossDoor && ch == Dungeon.hero; + + //如果有生物来到BossDoor的下一个坐标,且生物是玩家,那么触发seal(). + if (map[getBossDoor] == Terrain.DOOR && isTrue || map[getBossDoor] == Terrain.EMBERS && isTrue) { + seal(); + } + } + + @Override + public void seal() { + super.seal(); + + set( getBossDoor, Terrain.WALL ); + GameScene.updateMap( getBossDoor ); + set( 688, Terrain.LOCKED_DOOR ); + GameScene.updateMap( 688 ); + Dungeon.observe(); + } + /** * */ @Override protected void createMobs() { - SakaFishBoss saka= new SakaFishBoss(); - saka.pos = (WIDTH*20+13); - mobs.add(saka); + SakaFishBoss boss = new SakaFishBoss(); + boss.pos = 337; + mobs.add(boss); } /** diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/LevelRules.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/LevelRules.java new file mode 100644 index 000000000..a1233eeb1 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/LevelRules.java @@ -0,0 +1,146 @@ +/* + * 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.levels; + +import static com.shatteredpixel.shatteredpixeldungeon.Dungeon.depth; +import static com.shatteredpixel.shatteredpixeldungeon.Dungeon.hero; + +import com.shatteredpixel.shatteredpixeldungeon.Statistics; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.RandomBuff; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.TestDwarfMasterLock; +import com.watabou.utils.Random; + +//Level Rules +public class LevelRules { + public static Level createBossRushLevel() { + switch (depth) { + case 0: + case 17: + case 27: + Buff.affect(hero, RandomBuff.class).set(5, 1); + return new AncientMysteryCityBossLevel(); + case 1: case 3: case 6: case 7: case 9: + case 11: case 13: case 15: case 18: case 20: case 24: + return new ItemLevel(); + case 2: + return new ForestBossLevel(); + case 4: + return new SewerBossLevel(); + case 5: + return new SLMKingLevel(); + case 8: + return new PrisonBossLevel(); + case 10: + return new DimandKingLevel(); + case 12: + return new NewCavesBossLevel(); + case 14: + return new CaveTwoBossLevel(); + case 16: + return new CavesGirlDeadLevel(); + case 19: + return new ShopBossLevel(); + case 21: + return new NewCityBossLevel(); + case 22: case 23: + Buff.affect(hero, TestDwarfMasterLock.class).set(10, 1); + return new CityLevel(); + case 25: + return new DwarfMasterBossLevel(); + case 26: + return new YogGodHardBossLevel(); + case 28: + Buff.affect(hero, TestDwarfMasterLock.class).set(1, 1); + return new DM920BossLevel(); + default: + Statistics.deepestFloor--; + return new DeadEndLevel(); + } + } + + public static Level createStandardLevel() { + switch (depth) { + case 0: + return new ZeroLevel(); + case 1: + case 2: + case 3: + case 4: + return new SewerLevel(); + case 5: + return new ForestBossLevel(); + case 6: + case 7: + case 8: + case 9: + return new PrisonLevel(); + case 10: + if ((Statistics.boss_enhance & 0x2) != 0 || Statistics.mimicking) { + return new ColdChestBossLevel(); + } else { + return new PrisonBossLevel(); + } + case 11: + case 12: + case 13: + case 14: + return new CavesLevel(); + case 15: + if ((Statistics.boss_enhance & 0x4) != 0) { + return new CavesGirlDeadLevel(); + } else { + return Random.Float() <= 0.4f ? new CaveTwoBossLevel() : new NewCavesBossLevel(); + } + case 16: + case 17: + case 18: + case 19: + return new CityLevel(); + case 20: + if ((Statistics.boss_enhance & 0x8) != 0) { + Buff.affect(hero, TestDwarfMasterLock.class).set(1, 1); + return new DwarfMasterBossLevel(); + } else { + return new NewCityBossLevel(); + } + case 21: + case 22: + case 23: + case 24: + return new HallsLevel(); + case 25: + if ((Statistics.boss_enhance & 0x10) != 0) { + return new YogGodHardBossLevel(); + } else { + return new NewHallsBossLevel(); + } + case 26: + return new LastLevel(); + default: + Statistics.deepestFloor--; + return new DeadEndLevel(); + } + } + + +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/RegularLevel.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/RegularLevel.java index 22930cc4c..0cecd1f2c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/RegularLevel.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/RegularLevel.java @@ -256,6 +256,9 @@ public abstract class RegularLevel extends Level { initRooms.add(new MagicDimandRoom()); } +// initRooms.add(new EyeRoom()); +// initRooms.add(new YinYangRoom()); + if (Dungeon.NxhyshopOnLevel()) { initRooms.add(new NxhyShopRoom()); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/painters/Painter.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/painters/Painter.java index 12660e2c0..51bd0dcfb 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/painters/Painter.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/painters/Painter.java @@ -39,6 +39,22 @@ public abstract class Painter { // Static methods + + //绘制圆形 + public static void drawCircle(Level level, Point center, int radius, int terrain) { + int cx = center.x; + int cy = center.y; + for (int x = cx - radius; x <= cx + radius; x++) { + for (int y = cy - radius; y <= cy + radius; y++) { + int dx = x - cx; + int dy = y - cy; + if (dx * dx + dy * dy <= radius * radius) { + Painter.set(level, x, y, terrain); + } + } + } + } + public static void set( Level level, int cell, int value ) { level.map[cell] = value; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/special/SpecialRoom.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/special/SpecialRoom.java index 2026ee373..2671a2ba1 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/special/SpecialRoom.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/special/SpecialRoom.java @@ -25,6 +25,8 @@ import com.shatteredpixel.shatteredpixeldungeon.Conducts; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room; +import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.EyeRoom; +import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.YinYangRoom; import com.watabou.utils.Bundle; import com.watabou.utils.Random; import com.watabou.utils.Reflection; @@ -85,12 +87,13 @@ public abstract class SpecialRoom extends Room { new ArrayList<>( Dungeon.isDLC(Conducts.Conduct.BOSSRUSH) ? Arrays.asList( CryptRoom.class, PoolRoom.class, ArmoryRoom.class, SentryRoom.class, StatueRoom.class, CrystalVaultRoom.class, CrystalPathRoom.class, CrystalChoiceRoom.class, - SacrificeRoom.class + YinYangRoom.class, + SacrificeRoom.class, EyeRoom.class ) : Arrays.asList( WeakFloorRoom.class, CryptRoom.class, PoolRoom.class, ArmoryRoom.class, SentryRoom.class, - StatueRoom.class, CrystalVaultRoom.class, CrystalPathRoom.class, CrystalChoiceRoom.class, - SacrificeRoom.class + StatueRoom.class, CrystalVaultRoom.class, CrystalPathRoom.class, CrystalChoiceRoom.class, YinYangRoom.class, + SacrificeRoom.class,EyeRoom.class )); //9 special rooms which give consumables more often than equipment diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/EyeRoom.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/EyeRoom.java new file mode 100644 index 000000000..ca4df7ca3 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/EyeRoom.java @@ -0,0 +1,147 @@ +package com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard; + +import static com.shatteredpixel.shatteredpixeldungeon.Dungeon.depth; +import static com.shatteredpixel.shatteredpixeldungeon.levels.Terrain.EMPTY; + +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.BruteBot; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Crab; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.CrystalMimic; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.DM201; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Eye; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mimic; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.SRPDHBLR; +import com.shatteredpixel.shatteredpixeldungeon.items.Generator; +import com.shatteredpixel.shatteredpixeldungeon.items.Gold; +import com.shatteredpixel.shatteredpixeldungeon.items.Heap; +import com.shatteredpixel.shatteredpixeldungeon.levels.Level; +import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; +import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter; +import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.special.SpecialRoom; +import com.watabou.utils.Point; + +public class EyeRoom extends SpecialRoom { + + @Override + public int minWidth() { + return 13; + } + + @Override + public int minHeight() { + return 13; + } + + @Override + public int maxWidth() { + return 13; + } + + @Override + public int maxHeight() { + return 13; + } + + @Override + public boolean canMerge(Level l, Point p, int mergeTerrain) { + return false; + } + + @Override + public void paint(Level level) { + Point center = new Point((left + right) / 2, (top + bottom) / 2); + int eyeRadius = (right - left) / 4; + Painter.fill(level,this, EMPTY); + + // 绘制外围墙壁 + Painter.drawLine(level, new Point(left, top), new Point(right, top), Terrain.WALL); + Painter.drawLine(level, new Point(right, top), new Point(right, bottom), Terrain.WALL); + Painter.drawLine(level, new Point(right, bottom), new Point(left, bottom), Terrain.WALL); + Painter.drawLine(level, new Point(left, bottom), new Point(left, top), Terrain.WALL); + + // 绘制眼睛外圈和门 + Painter.drawCircle(level, center, eyeRadius, Terrain.EMPTY_SP); + Painter.drawCircle(level, center, eyeRadius + 1, Terrain.WALL); + + int doorX = center.x; + int doorY = center.y + eyeRadius; + + // 绘制眼睛中心和瞳孔 + Painter.set(level, center, Terrain.EMPTY_SP); + int pupilRadius = eyeRadius / 2; + Point pupilPos = center.offset(0, pupilRadius / 2); + Painter.drawCircle(level, pupilPos, pupilRadius+1, Terrain.EMPTY_SP); + + // 绘制眼睛眉毛 + Point browStart = center.offset(-eyeRadius - 1, -3); + Point browEnd = center.offset(eyeRadius + 1, -3); + + // 绘制眼瞳 + Painter.set(level, doorX, doorY - 3, Terrain.PEDESTAL); + + int chestPos = (top + 6) * level.width() + left + 6; + + /** 套五个宝箱 */ + level.drop( new Gold(),chestPos).type = Heap.Type.TELECRYSTL; + level.mobs.add(Mimic.spawnAt(chestPos,( Generator.randomUsingDefaults( Generator.Category.POTION ) ), CrystalMimic.class)); + level.mobs.add(Mimic.spawnAt(chestPos,( Generator.randomUsingDefaults( Generator.Category.SCROLL ) ), CrystalMimic.class)); + level.mobs.add(Mimic.spawnAt(chestPos,( Generator.randomUsingDefaults( Generator.Category.WEAPON ) ), + CrystalMimic.class)); + level.mobs.add(Mimic.spawnAt(chestPos,( Generator.randomUsingDefaults( Generator.Category.ARMOR ) ), CrystalMimic.class)); + + //四大恶人 + int[] MBTPOS = new int[]{ + (top + 4) * level.width() + left + 6, + (top + 8) * level.width() + left + 6, + (top + 6) * level.width() + left + 4, + (top + 6) * level.width() + left + 8, + }; + + + for (int i : MBTPOS) { + Mob n = new Crab(); + if(depth >= 20){ + n = new Eye(); + } else if(depth >= 15) { + n = new BruteBot(); + } else if(depth >= 10) { + n = new DM201(); + } else if(depth >= 6){ + n = new SRPDHBLR(); + } + + n.pos = i; + level.mobs.add(n); + } + + + int TopPos = (top + 1) * level.width() + left + 6; + + int BotPos = (top + 11) * level.width() + left + 6; + + int LeftPos = (top + 6) * level.width() + left + 1; + + int RightPos = (top + 6) * level.width() + left + 11; + + /** 小时候诋毁cocoa,长大后质疑cocoa,成年后认可cocoa,现在成为cocoa + /** Watabou看看你的房间是多么的恶心 + /** 由于房间类的特殊性质,无法直接从外部调用 */ + level.drop( ( Generator.randomUsingDefaults( Generator.Category.ARTIFACT )),LeftPos).type = Heap.Type.WHITETOMB; + level.drop( ( Generator.randomUsingDefaults( Generator.Category.GOLD )),RightPos).type = Heap.Type.TOMB; + level.drop( ( Generator.randomUsingDefaults( Generator.Category.GOLD )),BotPos).type = Heap.Type.TOMB; + level.drop( ( Generator.randomUsingDefaults( Generator.Category.GOLD )),TopPos).type = Heap.Type.TOMB; + + // 添加边界检查 + browStart.x = Math.max(browStart.x, left + 1); + browStart.x = Math.min(browStart.x, right - 1); + browEnd.x = Math.max(browEnd.x, left + 1); + browEnd.x = Math.min(browEnd.x, right - 1); + Painter.drawLine(level, browStart, browEnd, Terrain.WALL); + + for (Door door : connected.values()) { + door.set(Door.Type.HIDDEN); + } + + } + +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/YinYangRoom.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/YinYangRoom.java new file mode 100644 index 000000000..783b06b0c --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/YinYangRoom.java @@ -0,0 +1,128 @@ +package com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard; + +import com.shatteredpixel.shatteredpixeldungeon.Challenges; +import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.CrystalMimic; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mimic; +import com.shatteredpixel.shatteredpixeldungeon.items.Generator; +import com.shatteredpixel.shatteredpixeldungeon.items.Heap; +import com.shatteredpixel.shatteredpixeldungeon.items.Item; +import com.shatteredpixel.shatteredpixeldungeon.items.keys.CrystalKey; +import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfLevitation; +import com.shatteredpixel.shatteredpixeldungeon.levels.Level; +import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; +import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter; +import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.special.SpecialRoom; +import com.watabou.utils.Point; +import com.watabou.utils.Random; +import com.watabou.utils.Rect; + +import java.util.ArrayList; +import java.util.Arrays; + +public class YinYangRoom extends SpecialRoom { + + @Override + public int minWidth() { return 11; } + @Override + public int minHeight() { + return 11; + } + @Override + public int maxWidth() { return 11; } + @Override + public int maxHeight() { + return 11; + } + @Override + public boolean canMerge(Level l, Point p, int mergeTerrain) { + return false; + } + + @Override + public Rect resize(int w, int h) { + super.resize(w, h); + return this; + } + + private Item prize() { + Generator.Category cat = prizeClasses.remove(0); + prizeClasses.add(cat); + Item prize; + do { + prize = Generator.random(cat); + prize.level= Random.NormalIntRange(1,2); + prize.cursed = false; + } while (Challenges.isItemBlocked(prize)); + return prize; + } + + private Item Blackprize() { + Generator.Category cat = prizeClasses.remove(0); + prizeClasses.add(cat); + Item prize; + do { + prize = Generator.random(cat); + prize.level= Random.NormalIntRange(2,3); + prize.cursed = true; + } while (Challenges.isItemBlocked(prize)); + return prize; + } + + private ArrayList prizeClasses = new ArrayList<>( + Arrays.asList(Generator.Category.WAND, + Generator.Category.RING, + Generator.Category.ARTIFACT)); + + @Override + public void paint(Level level) { + Point a = new Point((left + right) / 2 + (right - left + 2) / 4 - 1,top + (right - left + 2) / 4 - 1); + Point b = new Point((left + right) / 2 - (right - left + 2) / 4 + 1,bottom - (right - left + 2) / 4 + 1); + + Painter.fill(level,this,Terrain.WALL); + Painter.fill(level,left + 1,top + 1,width() - 2,height() - 2,Terrain.WATER); + + for (int i = 1;i < right - left;i++) { + for (int j =1;j < bottom - top;j++) { + if (i + j < right - left + 1) { + Painter.set(level,left + i,top + j,Terrain.CHASM); + } + } + } + + Painter.fill(level,a.x,top + 1,right - a.x,a.y - top + 1,Terrain.WATER); + Painter.fill(level,left + 1,b.y,b.x - left,bottom - b.y,Terrain.CHASM); + + Painter.drawLine(level,new Point((left + right) / 2,top),a,Terrain.WALL); + Painter.drawLine(level,new Point((left + right) / 2,bottom),b,Terrain.WALL); + Painter.drawLine(level,a.offset(0,1),b.offset(0,-1),Terrain.WALL); + + int chestPos = left + right - a.x + a.y * level.width(); + + int chestPos2 = left + right - b.x + b.y * level.width(); + + Painter.set(level,chestPos,Terrain.PEDESTAL); + level.drop(prize(), chestPos).type = Heap.Type.CRYSTAL_CHEST; + Painter.set(level,chestPos2,Terrain.EMPTY_SP); + + if (Random.Int(10) == 0){ + level.mobs.add(Mimic.spawnAt(chestPos2,Blackprize(), CrystalMimic.class)); + } else { + level.drop(prize(), chestPos2).type = Heap.Type.CRYSTAL_CHEST; + } + + Painter.set(level,left + 1,top + 1,Terrain.WALL); + Painter.set(level,right - 1,top + 1,Terrain.WALL); + Painter.set(level,left + 1,bottom - 1,Terrain.WALL); + Painter.set(level,right - 1,bottom - 1,Terrain.WALL); + + for (Door door : connected.values()) { + door.set(Door.Type.HIDDEN); + } + + level.addItemToSpawn( new CrystalKey( Dungeon.depth ) ); + level.addItemToSpawn( new PotionOfLevitation()); + + } + +} 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 816341ee0..848de8301 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -1423,7 +1423,7 @@ public class GameScene extends PixelScene { Buff.detach( ch, MagicGirlSayTimeLast.class ); } - + /** Boss 出场的Logo显示 灵感:泰拉瑞亚灾厄炼狱 */ public static void bossReady() { if (Dungeon.hero.isAlive()) { Banner bossSlain = new Banner( BannerSprites.get( BannerSprites.Type.NULL ) ); @@ -1438,10 +1438,10 @@ public class GameScene extends PixelScene { scene.showBanner( bossSlain ); } break; - case 5: - if(!Dungeon.isDLC(Conducts.Conduct.BOSSRUSH) ) { - bossSlain.texture(Assets.Interfaces.QliPhoth_Title); - bossSlain.show(0xFFFFFF, 0.3f, 5f); + case 0: + if(Dungeon.isDLC(Conducts.Conduct.BOSSRUSH) ) { + bossSlain.texture(Assets.Interfaces.SakaBJY_Title); + bossSlain.show( Window.CYELLOW, 0.3f, 5f); scene.showBanner(bossSlain); } break; @@ -1472,10 +1472,10 @@ public class GameScene extends PixelScene { scene.showBanner( bossSlain ); } break; - case 5: - if(!Dungeon.isDLC(Conducts.Conduct.BOSSRUSH) ) { - bossSlain.texture(Assets.Interfaces.QliPhoth_Clear); - bossSlain.show(0xFFFFFF, 0.3f, 5f); + case 0: + if(Dungeon.isDLC(Conducts.Conduct.BOSSRUSH) ) { + bossSlain.texture(Assets.Interfaces.SakaBJY_Clear); + bossSlain.show( Window.CYELLOW, 0.3f, 5f); scene.showBanner(bossSlain); } break; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java index 8918712ee..19f50b1e8 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java @@ -73,7 +73,7 @@ public class InterlevelScene extends PixelScene { public static int returnBranch; public enum Mode { - DESCEND, ASCEND, CONTINUE, RESURRECT, RETURN, FALL, RESET, NONE,EXBOSS,GOBACK,FRGIRLBOSS,DR, + DESCEND, ASCEND, CONTINUE, RESURRECT, RETURN, FALL, RESET, NONE,EXBOSS,GOBACK,FRGIRLBOSS,ANCITYBOSS,DR, } public static Mode mode; @@ -285,6 +285,9 @@ public class InterlevelScene extends PixelScene { case FRGIRLBOSS: exboss(2); break; + case ANCITYBOSS: + exboss(3); + break; } @@ -563,6 +566,9 @@ public class InterlevelScene extends PixelScene { case 2: level=Dungeon.ColdFlowerCanyonDie(); break; + case 3: + level=Dungeon.AncityWaterLevel(); + break; default: level = Dungeon.newLevel(); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CharSprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CharSprite.java index 6af560e9c..7da7f8dd5 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CharSprite.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CharSprite.java @@ -329,6 +329,13 @@ public class CharSprite extends MovieClip implements Tweener.Listener, MovieClip jump( from, to, callback, distance * 2, distance * 0.1f ); } + public void dirtcar( int from, int to, Callback callback ) { + float distance = Dungeon.level.trueDistance( from, to ); + jump( from, to, callback, 0, distance * 0.1f ); + } + + + public void jump( int from, int to, Callback callback, float height, float duration ) { jumpCallback = callback; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/DictFishSprites.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/DictFishSprites.java new file mode 100644 index 000000000..9566fa732 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/DictFishSprites.java @@ -0,0 +1,31 @@ +package com.shatteredpixel.shatteredpixeldungeon.sprites; + +import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.watabou.noosa.TextureFilm; + +public class DictFishSprites extends MobSprite { + + public DictFishSprites() { + super(); + + texture( Assets.Sprites.DICT ); + + TextureFilm frames = new TextureFilm( texture, 24, 11 ); + + idle = new Animation( 2, true ); + idle.frames( frames, 0, 0, 0, 1 ); + + run = new Animation( 10, true ); + run.frames( frames, 6, 7, 8, 9, 10 ); + + attack = new Animation( 15, false ); + attack.frames( frames, 2, 3, 4, 5, 0 ); + + die = new Animation( 10, false ); + die.frames( frames, 11, 12, 13, 14,15 ); + + play( idle ); + } + +} + diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSprite.java index d77e3ff6e..8ff32d2c0 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSprite.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSprite.java @@ -207,10 +207,12 @@ public class ItemSprite extends MovieClip { return view( ItemSpriteSheet.CHEST, null ); case LOCKED_CHEST: return view( ItemSpriteSheet.LOCKED_CHEST, null ); - case CRYSTAL_CHEST: + case CRYSTAL_CHEST:case TELECRYSTL: return view( ItemSpriteSheet.CRYSTAL_CHEST, null ); case TOMB: return view( ItemSpriteSheet.TOMB, null ); + case WHITETOMB: + return view( ItemSpriteSheet.GRAVE, null ); case SKELETON: return view( ItemSpriteSheet.BONES, null ); case REMAINS: diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/RoomStoneSprites.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/RoomStoneSprites.java new file mode 100644 index 000000000..9b6619228 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/RoomStoneSprites.java @@ -0,0 +1,32 @@ +package com.shatteredpixel.shatteredpixeldungeon.sprites; + +import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.watabou.noosa.MovieClip; +import com.watabou.noosa.TextureFilm; + +public class RoomStoneSprites extends MobSprite { + + public RoomStoneSprites() { + super(); + + texture( Assets.Sprites.ROOMSTONE); + + TextureFilm frames = new TextureFilm( texture, 18, 20 ); + + idle = new MovieClip.Animation( 2, true ); + idle.frames( frames, 0, 0, 0, 1 ); + + run = new MovieClip.Animation( 10, true ); + run.frames( frames, 6, 7, 8, 9, 10 ); + + attack = new MovieClip.Animation( 15, false ); + attack.frames( frames, 2, 3, 4, 5, 0 ); + + die = new MovieClip.Animation( 10, false ); + die.frames( frames, 11, 12, 13, 14 ); + + play( idle ); + } + +} + diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/SakaFishBossSprites.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/SakaFishBossSprites.java index 5ff3d2ee4..c8aa73f12 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/SakaFishBossSprites.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/SakaFishBossSprites.java @@ -1,10 +1,24 @@ package com.shatteredpixel.shatteredpixeldungeon.sprites; import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; +import com.shatteredpixel.shatteredpixeldungeon.actors.Char; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.bosses.SakaFishBoss; +import com.shatteredpixel.shatteredpixeldungeon.effects.Beam; +import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile; +import com.shatteredpixel.shatteredpixeldungeon.tiles.DungeonTilemap; import com.watabou.noosa.TextureFilm; +import com.watabou.noosa.audio.Sample; +import com.watabou.noosa.particles.Emitter; public class SakaFishBossSprites extends MobSprite { + private Animation leap; + private int zapPos; + private Animation activeIdle; + + private Animation charging; + private Emitter chargeParticles; public SakaFishBossSprites() { super(); @@ -15,17 +29,120 @@ public class SakaFishBossSprites extends MobSprite { idle = new Animation( 4, true ); idle.frames( frames, 14,15,16,17 ); + activeIdle = new Animation( 4, true ); + activeIdle.frames( frames, 18,19,20,21); + run = new Animation( 10, true ); run.frames( frames, 2,3 ); attack = new Animation( 15, false ); attack.frames( frames, 4,5,6 ); + zap = attack.clone(); die = new Animation( 10, false ); die.frames( frames, 1 ); + leap = new Animation( 2, true ); + leap.frames( frames, 52,53,54,55 ); + + charging = new Animation( 20, true); + charging.frames( frames, 28, 29,30,31,32,33,29,30,31,29,30,31,29,30,31,29,30,31,29,30,31,29,30,31,29,30,31,29,30,31,29,30,31,29,30,31,29,30,31,29,30,31,29,30,31,29,30,31,29,30,31,29,30,31,29,30,31,29,30,31,29,30,31,29,30,31,29,30,31,29,30,31,29,30,31 ); + play( idle ); + } + //哦 创死你 + public void leapPrep( int cell ){ + turnTo( ch.pos, cell ); + play( leap ); + } + + public void activate(){ + idle = activeIdle.clone(); + idle(); + } + + @Override + public void zap( int pos ) { + zapPos = pos; + super.zap( pos ); + } + + //超级激光 + public void charge( int pos ){ + turnTo(ch.pos, pos); + play(charging); + if (visible) Sample.INSTANCE.play( Assets.Sounds.CHARGEUP ); + } + + @Override + public void link(Char ch) { + super.link(ch); + + chargeParticles = centerEmitter(); + chargeParticles.autoKill = false; + chargeParticles.pour(MagicMissile.MagicParticle.ATTRACTING, 0.05f); + chargeParticles.on = false; + + if (((SakaFishBoss)ch).beamCharged) play(charging); + + if (((SakaFishBoss) ch).state != ((SakaFishBoss) ch).SLEEPING){ + activate(); + } + renderShadow = false; + } + + @Override + public void update() { + super.update(); + if (chargeParticles != null){ + chargeParticles.pos( center() ); + chargeParticles.visible = visible; + } + } + + @Override + public void die() { + super.die(); + if (chargeParticles != null){ + chargeParticles.on = false; + } + } + + @Override + public void kill() { + super.kill(); + if (chargeParticles != null){ + chargeParticles.killAndErase(); + } + } + + @Override + public void play(Animation anim) { + if (chargeParticles != null) chargeParticles.on = anim == charging; + super.play(anim); + } + + @Override + public void onComplete( Animation anim ) { + super.onComplete( anim ); + + if (anim == zap) { + idle(); + if (Actor.findChar(zapPos) != null){ + parent.add(new Beam.DeathRayS(center(), Actor.findChar(zapPos).sprite.center())); + } else { + parent.add(new Beam.DeathRayS(center(), DungeonTilemap.raisedTileCenterToWorld(zapPos))); + } + ((SakaFishBoss)ch).deathGaze(); + ch.next(); + } else if (anim == die){ + chargeParticles.killAndErase(); + } + } + + + } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/SalamanderSprites.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/SalamanderSprites.java index 989ccc454..372a267ba 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/SalamanderSprites.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/SalamanderSprites.java @@ -32,7 +32,7 @@ public class SalamanderSprites extends MobSprite { cast = attack.clone(); die = new MovieClip.Animation( 12, false ); - die.frames( frames, 7 ); + die.frames( frames, 7,8,9 ); 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 f6ba42fcb..5a9894a6a 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 @@ -38,6 +38,7 @@ import com.shatteredpixel.shatteredpixeldungeon.sprites.RedSwarmSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.SRPDHBLRTT; import com.shatteredpixel.shatteredpixeldungeon.sprites.SalamanderSprites; import com.shatteredpixel.shatteredpixeldungeon.sprites.ShopkKingSprite; +import com.shatteredpixel.shatteredpixeldungeon.sprites.ShopkeeperSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.SlimeKingSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.SnakeSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.WFSprite; @@ -54,6 +55,7 @@ import java.util.ArrayList; public class vM0_6_7_X_Changes { public static void addAllChanges(ArrayList changeInfos) { + add_v0_6_54_Changes(changeInfos); add_v0_6_53_Changes(changeInfos); add_v0_6_52_Changes(changeInfos); add_v0_6_51_Changes(changeInfos); @@ -110,6 +112,34 @@ public class vM0_6_7_X_Changes { add_v0_6_0_Changes(changeInfos); } + public static void add_v0_6_54_Changes( ArrayList changeInfos ) { + ChangeInfo changes = new ChangeInfo("v0.6.4.0-Beta1", 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 Image(Assets.Environment.TILES_SEWERS, 48, 48, 16 + , 16), "房间改动", + "全新房间:慧眼墓碑房/太极八卦房加入")); + + changes.addButton(new ChangeButton(new ShopkeeperSprite(), ("回购系统"), + ("商店追加回购系统,除了商人领主和奈亚子均可原价退回商品"))); + + changes = new ChangeInfo("改动", false, null); + changes.hardlight(Window.CYELLOW); + changeInfos.add(changes); + + changes.addButton(new ChangeButton(new PinkLingSprite(), ("杂项改动"), + ("优化地牢部分数据,并且为即将更新的每日狩猎等设好底层。"))); + + 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_06X81"))); + + } + public static void add_v0_6_53_Changes( ArrayList changeInfos ) { ChangeInfo changes = new ChangeInfo("v0.6.3.0-Beta5-5.1", true, ""); changes.hardlight(Window.TITLE_COLOR); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndRedDragon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndRedDragon.java index c8963d0a1..497e9f258 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndRedDragon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndRedDragon.java @@ -195,7 +195,7 @@ public class WndRedDragon extends Window { @Override protected void onClick() { RewardWindow.this.hide(); - if (rewardObtained == false) { + if (!rewardObtained) { WndRedDragon.this.selectReward(item); } else { GLog.b(Messages.get(this, "why")); 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 5b28e887b..5c345de9f 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndTradeItem.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndTradeItem.java @@ -26,6 +26,8 @@ import static com.shatteredpixel.shatteredpixeldungeon.Dungeon.shopOnLevel; import com.shatteredpixel.shatteredpixeldungeon.Conducts; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.Statistics; +import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; +import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.ShopGuardDead; @@ -61,13 +63,20 @@ public class WndTradeItem extends WndInfoItem { this.owner = owner; float pos = height; - + Shopkeeper shop = null; + for (Char ch : Actor.chars()){ + if (ch instanceof Shopkeeper){ + shop = (Shopkeeper) ch; + break; + } + } + final Shopkeeper finalShop = shop; if (item.quantity() == 1) { RedButton btnSell = new RedButton( Messages.get(this, "sell", item.value()) ) { @Override protected void onClick() { - sell( item ); + sell( item,finalShop ); hide(); } }; @@ -93,7 +102,7 @@ public class WndTradeItem extends WndInfoItem { RedButton btnSellAll = new RedButton( Messages.get(this, "sell_all", priceAll ) ) { @Override protected void onClick() { - sell( item ); + sell( item,finalShop ); hide(); } }; @@ -217,11 +226,11 @@ public class WndTradeItem extends WndInfoItem { } if (selling) Shopkeeper.sell(); } - - public static void sell( Item item ) { - + + public static void sell( Item item, Shopkeeper shop ) { + Hero hero = Dungeon.hero; - + if (item.isEquipped( hero ) && !((EquipableItem)item).doUnequip( hero, false )) { return; } @@ -229,24 +238,42 @@ public class WndTradeItem extends WndInfoItem { //selling items in the sell interface doesn't spend time hero.spend(-hero.cooldown()); - Statistics.totalScore += 400; + new Gold( item.value() ).doPickUp( hero ); + + if (shop != null){ + shop.buybackItems.add(item); + while (shop.buybackItems.size() > Shopkeeper.MAX_BUYBACK_HISTORY){ + shop.buybackItems.remove(0); + } + } } public static void sellOne( Item item ) { - + sellOne( item, null ); + } + + public static void sellOne( Item item, Shopkeeper shop ) { + if (item.quantity() <= 1) { - sell( item ); + sell( item, shop ); } else { - + Hero hero = Dungeon.hero; - Statistics.totalScore += 100; + item = item.detach( hero.belongings.backpack ); //selling items in the sell interface doesn't spend time hero.spend(-hero.cooldown()); new Gold( item.value() ).doPickUp( hero ); + + if (shop != null){ + shop.buybackItems.add(item); + while (shop.buybackItems.size() > Shopkeeper.MAX_BUYBACK_HISTORY){ + shop.buybackItems.remove(0); + } + } } }