diff --git a/core/src/main/AndroidManifest.xml b/core/src/main/AndroidManifest.xml index 250998ba6..487e94acd 100644 --- a/core/src/main/AndroidManifest.xml +++ b/core/src/main/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="37" + android:versionName="0.4.3"> diff --git a/core/src/main/assets/actors/seeker.png b/core/src/main/assets/actors/seeker.png new file mode 100644 index 000000000..fe5a4b26c Binary files /dev/null and b/core/src/main/assets/actors/seeker.png differ diff --git a/core/src/main/assets/actors/slug.png b/core/src/main/assets/actors/slug.png new file mode 100644 index 000000000..bf41399c7 Binary files /dev/null and b/core/src/main/assets/actors/slug.png differ diff --git a/core/src/main/assets/data/CavesBossLevel.map b/core/src/main/assets/data/CavesBossLevel.map index 1c7f1d68a..32b748e7a 100644 --- a/core/src/main/assets/data/CavesBossLevel.map +++ b/core/src/main/assets/data/CavesBossLevel.map @@ -11,27 +11,27 @@ 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 1 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 -4 4 4 4 4 4 4 4 4 4 4 1 1 1 4 4 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 4 -4 4 4 4 4 4 4 4 4 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 -4 4 4 4 4 4 4 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 -4 4 4 4 4 4 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 +4 4 4 4 4 1 1 25 4 4 4 4 1 1 4 4 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 4 +4 4 4 4 1 1 1 1 1 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 +4 4 4 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 +4 4 4 4 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 -4 4 4 4 4 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 +4 4 4 4 4 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 1 1 1 4 4 4 4 1 1 1 1 1 1 1 1 4 4 4 1 1 1 4 1 25 4 4 4 4 4 4 -4 4 4 4 4 4 1 1 1 4 4 4 4 1 1 1 1 1 1 1 1 1 4 4 1 1 1 4 1 1 4 4 4 4 4 4 -4 4 4 4 4 4 1 1 4 4 4 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 +4 4 4 4 4 4 1 1 1 4 4 4 4 1 1 1 1 1 1 1 1 25 4 4 1 1 1 4 1 1 4 4 4 4 4 4 +4 4 4 4 4 4 1 1 25 4 4 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 1 1 1 4 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 1 1 1 1 1 1 1 1 4 4 4 4 4 1 1 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 1 1 1 1 1 1 1 1 4 1 1 1 4 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 -4 4 4 4 4 1 1 1 1 1 1 1 1 1 4 1 7 1 4 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 +4 4 4 4 4 1 1 1 1 1 1 1 1 1 4 1 7 1 4 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 1 1 1 1 1 1 1 1 1 4 1 1 1 4 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 1 1 1 1 1 1 1 1 4 4 5 4 4 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 25 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 1 1 1 4 4 1 1 1 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 4 -4 4 4 4 4 4 1 1 1 4 4 4 4 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 -4 4 4 4 4 4 4 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 -4 4 4 4 4 4 4 4 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 +4 4 4 4 4 4 1 1 1 4 4 4 1 1 1 1 1 1 1 1 1 25 4 4 4 4 4 4 4 4 4 4 4 4 4 4 +4 4 4 4 4 4 4 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 +4 4 4 4 4 4 4 4 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 diff --git a/core/src/main/assets/data/mobs.csv b/core/src/main/assets/data/mobs.csv index 3182aa14b..64a41ff34 100644 --- a/core/src/main/assets/data/mobs.csv +++ b/core/src/main/assets/data/mobs.csv @@ -1,37 +1,38 @@ -NAME,HT,atkSkill,defSkill,EXP,maxLvl,lootChance,loot,minDamage,maxDamage,typeDamage,minDefend,maxDefend,magicalResistance,FIRE,POISON,ICE,LIGHT,SHADOW,HOLY,Properties -Rat,8,8,2,1,5,,,1,4,,0,1,,-0.3,0.1,,,,, -Gnoll,12,10,4,2,8,0.3,Gold,1,5,,0,2,,,,,,,, -Crab,16,12,5,4,9,0.1667,MysteryMeat,2,8,,0,3,-0.2,,,0.1,-0.2,,, -FetidRat,20,12,5,4,5,,,1,4,,0,2,,,0.2,,,0.2,-0.25,MINIBOSS DEMONIC -GnollTrickster,20,16,5,5,8,1,,1,5,,0,2,,,,-0.2,,,,MINIBOSS -GreatCrab,25,12,0,6,9,0.1667,,1,8,,0,4,,,,0.1,-0.2,,,MINIBOSS -Goo,100,,8,10,,0.333,LloydsBeacon,,,,0,2,0.25,-0.25,0.2,,,,-0.3,BOSS DEMONIC -Swarm,50,10,5,3,9,0.1667,PotionOfHealing,,,,,,,,,,,,, -Skeleton,25,12,9,5,10,0.175,,2,10,,1,2,,-0.3,,,,,-0.3,UNDEAD -Thief,20,12,6,5,10,0.01,MasterThievesArmband,1,10,,0,3,0.15,,0.2,-0.15,,,-0.2,DEMONIC -Shaman,18,11,8,6,14,0.25,,2,8,MAGICAL,0,4,0.15,0.1,-0.2,0.2,0.3,,, -Guard,40,14,10,6,14,0.25,,4,12,,0,6,-0.2,,,,,,,DEMONIC -RotHeart,80,,0,4,,,,,,,0,5,0.5,,0.5,,,,,IMMOVABLE MINIBOSS -NewbornElemental,65,25,12,7,20,,,16,26,,0,5,0.2,0.5,,-1,,,-0.25,DEMONIC MINIBOSS -Tengu,150,20,15,20,,,,6,16,,0,5,0.25,,0.2,-0.25,,,,BOSS -SkeletonKnight,50,18,0,8,16,0.1,Wine,6,18,,1,6,-0.2,-0.25,,,,0.25,-0.3,UNDEAD -AshesSkull,20,1000,10,6,15,,,4,12,NORMAL,0,3,0.3,0.3,,-0.2,,0.2,-0.3,UNDEAD -Bat,30,16,15,7,15,0.15,PotionOfHealing,5,15,,0,5,,-0.15,,0.3,,0.2,-0.2, -Brute,40,20,15,8,15,0.2,Gold,8,24,,0,8,,,-0.15,,,0.2,, -Spinner,50,20,14,9,16,0.125,MysteryMeat,10,25,,0,6,,-0.2,0.25,,,,, -DM300,200,28,18,30,,0.3333,CapeOfThorns,20,25,,0,10,0.25,,0.3,0.1,-0.25,,,BOSS MACHINE -Elemental,60,25,20,9,20,0.1,PotionOfLiquidFlame,16,22,,2,6,0.2,0.5,,-1,,,-0.2,DEMONIC -Ballista,65,30,18,12,21,0.3,,16,30,,0,10,,,,0.1,-0.2,,,MACHINE -QuickFiringGun,65,30,18,15,22,0.3,,6,12,,0,10,,,,0.1,-0.2,,,MACHINE -Warlock,70,25,18,10,21,0.75,,12,18,MAGICAL,1,8,0.15,,-0.2,,,0.2,-0.1, -Monk,70,30,30,11,21,0.064,Food,12,25,,0,2,-0.2,,,-0.15,,0.2,-0.1, -Golem,85,28,18,12,22,,,25,40,,2,12,,,,0.2,-0.2,,,MACHINE -King,300,32,25,40,,,,25,40,,0,14,0.2,0.15,0.15,-0.15,,0.2,-0.2,BOSS UNDEAD -King.Undead,30,16,15,0,,,,12,18,,0,5,-0.15,-0.3,,,0.15,0.2,-0.4,UNDEAD PHANTOM -Succubus,80,40,25,12,25,0.05,ScrollOfLullaby,22,30,,0,10,,,,-0.2,-0.2,0.2,-0.25,DEMONIC -Eye,100,30,20,13,26,0.5,Dewdrop,15,25,MAGICAL,0,10,0.15,,,,,,-0.25,DEMONIC -Scorpio,95,36,24,14,26,0.2,PotionOfHealing,26,36,,0,16,-0.25,,0.2,-0.25,,0.2,-0.2,DEMONIC -Yog,300,,,50,,,,,,,,,0.25,,0.2,,,0.2,-0.25,BOSS DEMONIC IMMOVABLE -Yog.RottingFist,300,36,25,0,,,,20,50,,0,15,0.2,,0.2,,,,-0.25,BOSS DEMONIC -Yog.BurningFist,200,36,25,0,,,,22,30,MAGICAL,0,15,0.2,,0.2,-0.5,,0.2,-0.25,BOSS DEMONIC -Yog.Larva,25,30,20,0,,,,22,30,,0,8,-0.15,,0.2,,,,-0.25,DEMONIC +NAME,HT,atkSkill,defSkill,EXP,maxLvl,lootChance,loot,minDamage,maxDamage,typeDamage,critChance,critRatio,minDefend,maxDefend,magicalResistance,FIRE,POISON,ICE,LIGHT,SHADOW,HOLY,Properties +Rat,8,8,2,1,5,,,1,4,,,,0,1,,-0.3,0.1,,,,, +Slug,6,8,2,1,5,,,2,4,,,,0,1,-0.35,-0.5,0.75,,,,, +Gnoll,12,10,4,2,8,0.3,Gold,1,6,,0.09,,0,2,,,,,,,, +Crab,16,12,5,4,9,0.1667,MysteryMeat,2,8,,,,0,3,-0.2,,,0.1,-0.2,,, +FetidRat,20,12,6,4,5,,,1,4,,,,0,2,,,0.2,,,0.2,-0.25,MINIBOSS DEMONIC +GnollTrickster,20,16,6,5,8,1,,1,5,,,,0,2,,,,-0.2,,,,MINIBOSS +GreatCrab,25,12,0,6,9,0.1667,,1,8,,,,0,4,,,,0.1,-0.2,,,MINIBOSS +Goo,100,,8,10,,0.333,LloydsBeacon,,,,,,0,2,0.25,-0.25,0.2,,,,-0.3,BOSS DEMONIC +Swarm,50,10,5,3,9,0.1667,PotionOfHealing,,,,,,,,,,,,,,, +Skeleton,25,12,9,5,10,0.175,,2,10,,,,1,2,,-0.3,,,,,-0.3,UNDEAD +Thief,20,12,6,5,10,0.1,MasterThievesArmband,1,8,,0.1,1.5,0,3,0.15,,0.2,-0.15,,,-0.2,DEMONIC +Shaman,18,11,8,6,14,0.25,,2,8,MAGICAL,,,0,4,0.15,0.1,-0.2,0.2,0.3,,, +Guard,40,14,10,6,14,0.25,,4,12,,0.05,,0,6,-0.2,0.05,0.05,0.05,0.05,0.05,,DEMONIC +RotHeart,80,,0,4,,,,,,,,,0,5,0.5,,0.5,,,,,IMMOVABLE MINIBOSS +NewbornElemental,65,25,12,7,20,,,16,26,,,,0,5,0.2,0.5,,-1,,,-0.25,DEMONIC MINIBOSS +Tengu,150,20,15,20,,,,6,16,,,,0,5,0.25,,0.2,-0.25,,,,BOSS +SkeletonKnight,50,18,0,8,16,0.1,Wine,6,18,,0.1,,1,6,-0.2,-0.25,,,,0.25,-0.3,UNDEAD +AshesSkull,20,1000,10,6,15,,,4,12,NORMAL,,,0,3,0.3,0.3,,-0.2,,0.2,-0.3,UNDEAD +Bat,30,16,16,7,15,0.15,PotionOfHealing,5,15,,,,0,5,,-0.15,,0.3,,0.2,-0.2, +Brute,40,20,15,8,15,0.2,Gold,8,24,,,,0,8,,,-0.15,,,0.2,, +Spinner,50,20,14,9,16,0.125,MysteryMeat,10,25,,0.1,,0,6,,-0.2,0.25,,,,, +DM300,200,28,18,30,,,,20,25,,,,0,10,0.35,,0.3,-0.2,-0.1,,,BOSS MACHINE +Elemental,60,25,20,9,20,0.1,PotionOfLiquidFlame,16,22,,,,2,6,0.2,0.5,,-1,,,-0.2,DEMONIC +Ballista,65,30,18,12,21,0.3,,16,30,,0.075,,0,10,,,,0.1,-0.2,,,MACHINE +QuickFiringGun,65,30,18,15,22,0.3,,6,12,,0.075,,0,10,,,,0.1,-0.2,,,MACHINE +Warlock,70,25,20,10,21,0.75,,12,18,MAGICAL,,,1,8,0.15,,-0.2,,,0.2,-0.1, +Monk,70,30,30,11,21,0.064,Food,12,25,,0.05,1.2,0,2,-0.2,,,-0.15,,0.2,-0.1, +Golem,85,28,18,12,22,,,25,40,,,,2,12,,,,0.2,-0.2,,,MACHINE +King,300,32,25,40,,,,25,40,,,,0,14,0.2,0.15,0.15,-0.15,,0.2,-0.2,BOSS UNDEAD +King.Undead,30,16,15,0,,,,12,18,,,,0,5,-0.15,-0.3,,,0.15,0.2,-0.4,UNDEAD PHANTOM +Succubus,80,40,25,12,25,0.05,ScrollOfLullaby,20,26,,0.1,1.5,0,10,,,,-0.2,-0.2,0.2,-0.25,DEMONIC +Eye,100,30,20,13,26,0.5,Dewdrop,15,25,MAGICAL,,,0,10,0.15,,,,,,-0.25,DEMONIC +Scorpio,95,36,24,14,26,0.2,PotionOfHealing,26,36,,,,0,16,-0.25,,0.2,-0.25,,0.2,-0.2,DEMONIC +Yog,300,,,50,,,,,,,,,,,0.25,,0.2,,,0.2,-0.25,BOSS DEMONIC IMMOVABLE +Yog.RottingFist,300,36,25,0,,,,20,50,,,,0,15,0.2,,0.2,,,,-0.25,BOSS DEMONIC +Yog.BurningFist,200,36,26,0,,,,22,30,MAGICAL,,,0,15,0.2,,0.2,-0.5,,0.2,-0.25,BOSS DEMONIC +Yog.Larva,25,30,20,0,,,,22,30,,,,0,8,-0.15,,0.2,,,,-0.25,DEMONIC diff --git a/core/src/main/assets/miscs/badges.png b/core/src/main/assets/miscs/badges.png index 0d40b47d4..71bbe3ccf 100644 Binary files a/core/src/main/assets/miscs/badges.png and b/core/src/main/assets/miscs/badges.png differ diff --git a/core/src/main/assets/miscs/items.png b/core/src/main/assets/miscs/items.png index 4b9dd28e7..a3556f938 100644 Binary files a/core/src/main/assets/miscs/items.png and b/core/src/main/assets/miscs/items.png differ diff --git a/core/src/main/assets/miscs/perks.png b/core/src/main/assets/miscs/perks.png index 937c988c6..6456b437d 100644 Binary files a/core/src/main/assets/miscs/perks.png and b/core/src/main/assets/miscs/perks.png differ diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/Assets.java b/core/src/main/java/com/egoal/darkestpixeldungeon/Assets.java index b415daac5..f7139ecb4 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/Assets.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/Assets.java @@ -69,6 +69,7 @@ public class Assets { public static final String SCROLL_SELLER = ACTORS + "scroll_seller.png"; public static final String PLAGUE_DOCTOR = ACTORS + "plague_doctor.png"; public static final String UNDEAD_SHOPKEEPER = ACTORS + "undead-shopkeeper.png"; + public static final String SEEKER = ACTORS+ "seeker.png"; // mobs public static final String RAT = ACTORS + "rat.png"; @@ -116,6 +117,7 @@ public class Assets { public static final String KING_STATUARY = ACTORS + "king_statuary.png"; public static final String GLOWWORM = ACTORS + "glowworm.png"; public static final String SKULL = ACTORS + "skull.png"; + public static final String SLUG = ACTORS+ "slug.png"; // levels===================================================================== // tile diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/Badges.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/Badges.kt index e363e3825..f62aa64e9 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/Badges.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/Badges.kt @@ -164,7 +164,8 @@ object Badges { PERK_GAIN_2(65), PERK_GAIN_3(66), PERK_NONE(67, true), - SUICIDE(68, true), + PERK_EMPTY(68, true), //err, this should be none, but it already used... + SUICIDE(69, true), GAMES_PLAYED_1(60, true), GAMES_PLAYED_2(61, true), GAMES_PLAYED_3(62, true), @@ -895,6 +896,12 @@ object Badges { fun validateNoPerk() { if (Dungeon.IsChallenged()) return + if (Dungeon.hero.heroPerk.perks.isEmpty()) displayBadge(Badge.PERK_EMPTY) + } + + fun validateNeverGainPerk() { + if (Dungeon.IsChallenged()) return + if (Dungeon.hero.perkGained == 0) displayBadge(Badge.PERK_NONE) } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/PropertyConfiger.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/PropertyConfiger.kt index 228b7e931..7d51fdd40 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/PropertyConfiger.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/PropertyConfiger.kt @@ -36,6 +36,7 @@ object PropertyConfiger { EXP = int(at("EXP"), 1), maxLvl = int(at("maxLvl"), Hero.MAX_LEVEL), lootChance = float(at("lootChance")), loot = at("loot"), //todo: loot minDamage = int(at("minDamage")), maxDamage = int(at("maxDamage")), typeDamage = damageType(at("typeDamage")), + criticalChance = float(at("critChance")), criticalRatio = float(at("critRatio"), 1f), minDefend = int(at("minDefend")), maxDefend = int(at("maxDefend")), magicalResistance = float(at("magicalResistance"))).apply { elementalResistances[0] = float(at("FIRE")) @@ -68,6 +69,8 @@ object PropertyConfiger { mob.minDamage = mp.minDamage mob.maxDamage = mp.maxDamage mob.typeDamage = mp.typeDamage + mob.criticalChance = mp.criticalChance + mob.criticalRatio = mp.criticalRatio mob.minDefense = mp.minDefend mob.maxDefense = mp.maxDefend @@ -85,6 +88,7 @@ object PropertyConfiger { val EXP: Int = 0, val maxLvl: Int = 0, val lootChance: Float = 0f, val loot: String = "", val minDamage: Int = 0, val maxDamage: Int = 0, val typeDamage: Damage.Type = Damage.Type.NORMAL, + val criticalChance: Float = 0f, val criticalRatio: Float = 1.25f, val minDefend: Int = 0, val maxDefend: Int = 0, val magicalResistance: Float = 0f) { val elementalResistances = FloatArray(Damage.Element.ELEMENT_COUNT) { 0f } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/Char.java b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/Char.java index 6931685dd..0e1d94d4e 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/Char.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/Char.java @@ -382,8 +382,11 @@ public int takeDamage(Damage dmg) { // buffs shall remove when take damage if (this.buff(Frost.class) != null) Buff.detach(this, Frost.class); - if (this.buff(MagicalSleep.class) != null) - Buff.detach(this, MagicalSleep.class); + MagicalSleep ms = buff(MagicalSleep.class); + if(ms!=null){ + if(ms instanceof MagicalSleep.Deep) ((MagicalSleep.Deep) ms).setDamage(dmg); + Buff.detach(ms); + } if (dmg.from instanceof Char && isCharmedBy((Char) dmg.from)) Buff.detach(this, Charm.class); @@ -424,10 +427,11 @@ public int takeDamage(Damage dmg) { if (buff(Ignorant.class) == null) { if (dmg.value > 0 || dmg.from instanceof Char) { String number = Integer.toString(dmg.value); - int color = HP > HT / 4 ? CharSprite.WARNING : CharSprite.NEGATIVE; + if (dmg.isFeatured(Damage.Feature.CRITICAL)) number += "!"; - if (dmg.isFeatured(Damage.Feature.CRITICAL)) - number += "!"; + int color = 0x8c8c8c; // gray + if(dmg.type== Damage.Type.MAGICAL) color = 0x3b94ff; // blue for magical damage. + if(HP< HT/4) color = CharSprite.NEGATIVE; sprite.showStatus(color, number); } @@ -461,7 +465,7 @@ protected Damage resistDamage(Damage dmg) { // elemental resistance for (int of = 0; of < Damage.Element.ELEMENT_COUNT; ++of) - if (dmg.isFeatured(0x01 << of)) + if (dmg.hasElement(0x01 << of)) dmg.value -= Math.round(dmg.value * elementalResistance[of]); if (dmg.type == Damage.Type.MAGICAL) diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Berserk.java b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Berserk.java deleted file mode 100644 index 04c729d69..000000000 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Berserk.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Pixel Dungeon - * Copyright (C) 2012-2015 Oleg Dolya - * - * Shattered Pixel Dungeon - * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.actors.buffs; - -import com.egoal.darkestpixeldungeon.Assets; -import com.egoal.darkestpixeldungeon.Dungeon; -import com.egoal.darkestpixeldungeon.effects.SpellSprite; -import com.egoal.darkestpixeldungeon.items.unclassified.BrokenSeal.WarriorShield; -import com.egoal.darkestpixeldungeon.messages.Messages; -import com.egoal.darkestpixeldungeon.scenes.GameScene; -import com.egoal.darkestpixeldungeon.ui.BuffIndicator; -import com.watabou.noosa.audio.Sample; -import com.watabou.utils.Bundle; - -public class Berserk extends Buff { - - private enum State { - NORMAL, BERSERK, EXHAUSTED, RECOVERING; - } - - private State state = State.NORMAL; - - private static final int EXHAUSTION_START = 40; - private int exhaustion; - - private static final float LEVEL_RECOVER_START = 3f; - private float levelRecovery; - - private static final String STATE = "state"; - private static final String EXHAUSTION = "exhaustion"; - private static final String LEVEL_RECOVERY = "levelrecovery"; - - @Override - public void storeInBundle(Bundle bundle) { - super.storeInBundle(bundle); - bundle.put(STATE, state); - if (state == State.EXHAUSTED) bundle.put(EXHAUSTION, exhaustion); - if (state == State.EXHAUSTED || state == State.RECOVERING) - bundle.put(LEVEL_RECOVERY, levelRecovery); - } - - @Override - public void restoreFromBundle(Bundle bundle) { - super.restoreFromBundle(bundle); - state = bundle.getEnum(STATE, State.class); - if (state == State.EXHAUSTED) exhaustion = bundle.getInt(EXHAUSTION); - if (state == State.EXHAUSTED || state == State.RECOVERING) - levelRecovery = bundle.getFloat(LEVEL_RECOVERY); - } - - @Override - public boolean act() { - if (berserking()) { - if (target.HP <= 0) { - target.SHLD -= Math.min(target.SHLD, 2); - if (target.SHLD == 0) { - target.die(this); - if (!target.isAlive()) Dungeon.fail(this.getClass()); - } - } else { - state = State.EXHAUSTED; - exhaustion = EXHAUSTION_START; - levelRecovery = LEVEL_RECOVER_START; - BuffIndicator.refreshHero(); - target.SHLD = 0; - } - } else if (state == State.EXHAUSTED) { - exhaustion--; - if (exhaustion == 0) { - state = State.RECOVERING; - BuffIndicator.refreshHero(); - } - } - spend(TICK); - return true; - } - - public int damageFactor(int dmg) { - float bonus; - - if (state == State.EXHAUSTED) { - bonus = (50 - exhaustion) / 50f; - } else { - float percentMissing = 1f - target.HP / (float) target.HT; - bonus = 1f + (float) Math.pow(percentMissing, 3); - } - - return Math.round(dmg * bonus); - } - - public boolean berserking() { - if (target.HP == 0 && state == State.NORMAL) { - - WarriorShield shield = target.buff(WarriorShield.class); - if (shield != null) { - state = State.BERSERK; - BuffIndicator.refreshHero(); - target.SHLD = shield.maxShield() * 5; - - SpellSprite.show(target, SpellSprite.BERSERK); - Sample.INSTANCE.play(Assets.SND_CHALLENGE); - GameScene.flash(0xFF0000); - } - - } - - return state == State.BERSERK; - } - - public void recover(float percent) { - if (levelRecovery > 0) { - levelRecovery -= percent; - if (levelRecovery <= 0) { - state = State.NORMAL; - BuffIndicator.refreshHero(); - levelRecovery = 0; - } - } - } - - @Override - public int icon() { - switch (state) { - case NORMAL: - default: - return BuffIndicator.ANGERED; - case BERSERK: - return BuffIndicator.FURY; - case EXHAUSTED: - return BuffIndicator.EXHAUSTED; - case RECOVERING: - return BuffIndicator.RECOVERING; - } - } - - @Override - public String toString() { - switch (state) { - case NORMAL: - default: - return Messages.get(this, "angered"); - case BERSERK: - return Messages.get(this, "berserk"); - case EXHAUSTED: - return Messages.get(this, "exhausted"); - case RECOVERING: - return Messages.get(this, "recovering"); - } - } - - @Override - public String desc() { - float dispDamage = damageFactor(10000) / 100f; - switch (state) { - case NORMAL: - default: - return Messages.get(this, "angered_desc", dispDamage); - case BERSERK: - return Messages.get(this, "berserk_desc"); - case EXHAUSTED: - return Messages.get(this, "exhausted_desc", exhaustion, dispDamage); - case RECOVERING: - return Messages.get(this, "recovering_desc", levelRecovery, dispDamage); - } - } -} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Berserk.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Berserk.kt new file mode 100644 index 000000000..bee1ba072 --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Berserk.kt @@ -0,0 +1,170 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.actors.buffs + +import com.egoal.darkestpixeldungeon.Assets +import com.egoal.darkestpixeldungeon.Dungeon +import com.egoal.darkestpixeldungeon.effects.SpellSprite +import com.egoal.darkestpixeldungeon.items.unclassified.BrokenSeal.WarriorShield +import com.egoal.darkestpixeldungeon.messages.Messages +import com.egoal.darkestpixeldungeon.scenes.GameScene +import com.egoal.darkestpixeldungeon.ui.BuffIndicator +import com.watabou.noosa.audio.Sample +import com.watabou.utils.Bundle +import kotlin.math.max +import kotlin.math.min +import kotlin.math.pow +import kotlin.math.round + +class Berserk : Buff() { + private var state = State.NORMAL + private var exhaustion: Int = 0 + private var levelRecovery: Float = 0f + private var level: Int = 1 + + private enum class State { + NORMAL, BERSERK, EXHAUSTED, RECOVERING + } + + override fun storeInBundle(bundle: Bundle) { + super.storeInBundle(bundle) + bundle.put(STATE, state) + if (state == State.EXHAUSTED) bundle.put(EXHAUSTION, exhaustion) + if (state == State.EXHAUSTED || state == State.RECOVERING) + bundle.put(LEVEL_RECOVERY, levelRecovery) + bundle.put(LEVEL, level) + } + + override fun restoreFromBundle(bundle: Bundle) { + super.restoreFromBundle(bundle) + state = bundle.getEnum(STATE, State::class.java) + if (state == State.EXHAUSTED) exhaustion = bundle.getInt(EXHAUSTION) + if (state == State.EXHAUSTED || state == State.RECOVERING) + levelRecovery = bundle.getFloat(LEVEL_RECOVERY) + + level = bundle.getInt(LEVEL) + if (level == 0) level = 1 + } + + override fun act(): Boolean { + if (berserking()) { + if (target.HP <= 0) { + target.SHLD -= min(target.SHLD, 2) + if (target.SHLD == 0) { + target.die(this) + if (!target.isAlive) Dungeon.fail(this.javaClass) + } + } else { + state = State.EXHAUSTED + exhaustion = EXHAUSTION_START + levelRecovery = LEVEL_RECOVER_START + BuffIndicator.refreshHero() + target.SHLD = 0 + } + } else if (state == State.EXHAUSTED) { + exhaustion-- + if (exhaustion == 0) { + state = State.RECOVERING + BuffIndicator.refreshHero() + level += 1 + } + } + spend(TICK) + return true + } + + fun damageFactor(dmg: Int): Int { + val bonus: Float + + bonus = if (state == State.EXHAUSTED) (50 - exhaustion) / 50f else { + val percentMissing = max(0f, 1f - target.HP / target.HT.toFloat()) + 1f + percentMissing.pow(3.6f - 0.65f * level + 0.05f * level * level) + } + + return round(dmg * bonus).toInt() + } + + fun berserking(): Boolean { + if (target.HP == 0 && state == State.NORMAL) { + + val shield = target.buff(WarriorShield::class.java) + if (shield != null) { + state = State.BERSERK + BuffIndicator.refreshHero() + target.SHLD = shield.maxShield() * 5 + + SpellSprite.show(target, SpellSprite.BERSERK) + Sample.INSTANCE.play(Assets.SND_CHALLENGE) + GameScene.flash(0xFF0000) + } + + } + + return state == State.BERSERK + } + + fun recover(percent: Float) { + if (levelRecovery > 0) { + levelRecovery -= percent + if (levelRecovery <= 0) { + state = State.NORMAL + BuffIndicator.refreshHero() + levelRecovery = 0f + } + } + } + + override fun icon(): Int = when (state) { + State.NORMAL -> BuffIndicator.ANGERED + State.BERSERK -> BuffIndicator.FURY + State.EXHAUSTED -> BuffIndicator.EXHAUSTED + State.RECOVERING -> BuffIndicator.RECOVERING + } + + override fun toString(): String = when (state) { + State.NORMAL -> Messages.get(this, "angered") + State.BERSERK -> Messages.get(this, "berserk") + State.EXHAUSTED -> Messages.get(this, "exhausted") + State.RECOVERING -> Messages.get(this, "recovering") + } + + override fun desc(): String { + val dispDamage = damageFactor(10000) / 100f + return when (state) { + State.NORMAL -> Messages.get(this, "angered_desc", level, dispDamage) + State.BERSERK -> Messages.get(this, "berserk_desc") + State.EXHAUSTED -> Messages.get(this, "exhausted_desc", exhaustion, dispDamage) + State.RECOVERING -> Messages.get(this, "recovering_desc", levelRecovery, dispDamage) + } + } + + companion object { + private const val EXHAUSTION_START = 40 + + private const val LEVEL_RECOVER_START = 2.5f + + private const val STATE = "state" + private const val EXHAUSTION = "exhaustion" + private const val LEVEL_RECOVERY = "levelrecovery" + + private const val LEVEL = "level" + } +} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Burning.java b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Burning.java index 832c231f6..1d76b78d3 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Burning.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Burning.java @@ -143,12 +143,12 @@ public boolean act() { if (target instanceof Thief) { - Item item = ((Thief) target).item; + Item item = ((Thief) target).getItem(); if (item instanceof Scroll && !(item instanceof ScrollOfUpgrade)) { target.sprite.emitter().burst(ElmoParticle.FACTORY, 6); - ((Thief) target).item = null; + ((Thief) target).setItem(null); } } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Chill.java b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Chill.java index c4a862089..4009b8f09 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Chill.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Chill.java @@ -77,12 +77,12 @@ public boolean attachTo(Char target) { } } else if (target instanceof Thief) { - Item item = ((Thief) target).item; + Item item = ((Thief) target).getItem(); if (item instanceof Potion && !(item instanceof PotionOfStrength || item instanceof PotionOfMight)) { - ((Potion) ((Thief) target).item).shatter(target.pos); - ((Thief) target).item = null; + ((Potion) ((Thief) target).getItem()).shatter(target.pos); + ((Thief) target).setItem(null); } } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Frost.java b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Frost.java index f0627930f..f70dea7c9 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Frost.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Frost.java @@ -77,12 +77,12 @@ public boolean attachTo(Char target) { } } else if (target instanceof Thief) { - Item item = ((Thief) target).item; + Item item = ((Thief) target).getItem(); if (item instanceof Potion && !(item instanceof PotionOfStrength || item instanceof PotionOfMight)) { - ((Potion) ((Thief) target).item).shatter(target.pos); - ((Thief) target).item = null; + ((Potion) ((Thief) target).getItem()).shatter(target.pos); + ((Thief) target).setItem(null); } } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Hunger.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Hunger.kt index 3e3b90fdd..6ed0cce7d 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Hunger.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Hunger.kt @@ -71,8 +71,8 @@ class Hunger : Buff(), Hero.Doom { val hero = target as Hero if (isStarving) { - val dhp = if (hero.heroPerk.get(RavenousAppetite::class.java) != null) target.HT / 60f - else target.HT / 80f + val dhp = if (hero.heroPerk.get(RavenousAppetite::class.java) != null) target.HT / 50f + else target.HT / 75f partialDamage += dhp if (partialDamage > 1) { @@ -198,8 +198,8 @@ class Hunger : Buff(), Hero.Doom { private const val STEP = 10f private const val HUNGER_PER_STEP = 11f - const val HUNGRY = 325f - const val STARVING = 450f + const val HUNGRY = 350f + const val STARVING = 500f private const val LEVEL = "level" private const val PARTIALDAMAGE = "partialDamage" diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/MagicalSleep.java b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/MagicalSleep.java deleted file mode 100644 index b48c350f4..000000000 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/MagicalSleep.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Pixel Dungeon - * Copyright (C) 2012-2015 Oleg Dolya - * - * Shattered Pixel Dungeon - * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.actors.buffs; - -import com.egoal.darkestpixeldungeon.actors.Char; -import com.egoal.darkestpixeldungeon.actors.hero.Hero; -import com.egoal.darkestpixeldungeon.actors.mobs.Mob; -import com.egoal.darkestpixeldungeon.messages.Messages; -import com.egoal.darkestpixeldungeon.ui.BuffIndicator; -import com.egoal.darkestpixeldungeon.utils.GLog; - -public class MagicalSleep extends Buff { - - private static final float STEP = 1f; - private static final float MAX_SLEEP_TIME = 40f; - - private float sleeped_ = 0f; - - @Override - public boolean attachTo(Char target) { - if (super.attachTo(target) && !target.immunizedBuffs().contains(Sleep - .class)) { - - if (target instanceof Hero) - GLog.i(Messages.get(this, "fallasleep")); - else if (target instanceof Mob) - ((Mob) target).state = ((Mob) target).SLEEPING; - - target.paralysed++; - - return true; - } else { - return false; - } - } - - @Override - public boolean act() { - if (target instanceof Hero) { - target.HP = Math.min(target.HP + 1, target.HT); - ((Hero) target).setResting(true); - target.buff(Pressure.class).downPressure(.5f); - sleeped_ += STEP; - if (sleeped_ > MAX_SLEEP_TIME) { - GLog.p(Messages.get(this, "wakeup")); - detach(); - } - } - spend(STEP); - return true; - } - - @Override - public void detach() { - if (target.paralysed > 0) - target.paralysed--; - if (target instanceof Hero) - ((Hero) target).setResting(false); - super.detach(); - } - - @Override - public int icon() { - return BuffIndicator.MAGIC_SLEEP; - } - - @Override - public String toString() { - return Messages.get(this, "name"); - } - - @Override - public String desc() { - return Messages.get(this, "desc"); - } -} \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/MagicalSleep.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/MagicalSleep.kt new file mode 100644 index 000000000..2066d2f17 --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/MagicalSleep.kt @@ -0,0 +1,122 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.actors.buffs + +import com.egoal.darkestpixeldungeon.actors.Actor +import com.egoal.darkestpixeldungeon.actors.Char +import com.egoal.darkestpixeldungeon.actors.Damage +import com.egoal.darkestpixeldungeon.actors.hero.Hero +import com.egoal.darkestpixeldungeon.actors.mobs.Mob +import com.egoal.darkestpixeldungeon.messages.M +import com.egoal.darkestpixeldungeon.messages.Messages +import com.egoal.darkestpixeldungeon.ui.BuffIndicator +import com.egoal.darkestpixeldungeon.utils.GLog +import kotlin.math.max +import kotlin.math.min + +open class MagicalSleep : Buff() { + + private var sleeped_ = 0f + + override fun attachTo(target: Char): Boolean { + if (super.attachTo(target) && !target.immunizedBuffs().contains(Sleep::class.java)) { + + if (target is Hero) + GLog.i(Messages.get(this, "fallasleep")) + else if (target is Mob) + target.state = target.SLEEPING + + target.paralysed++ + + return true + } else { + return false + } + } + + override fun act(): Boolean { + if (target is Hero) { + target.HP = min(target.HP + 1, target.HT) + (target as Hero).resting = true + target.buff(Pressure::class.java)!!.downPressure(.5f) + sleeped_ += STEP + if (sleeped_ > MAX_SLEEP_TIME) { + GLog.p(Messages.get(this, "wakeup")) + detach() + } + } + spend(STEP) + return true + } + + override fun detach() { + if (target.paralysed > 0) target.paralysed-- + if (target is Hero) (target as Hero).resting = false + super.detach() + } + + override fun icon(): Int = BuffIndicator.MAGIC_SLEEP + + override fun toString(): String = M.L(this, "name") + + override fun desc(): String = M.L(this, "desc") + + companion object { + private const val STEP = 1f + private const val MAX_SLEEP_TIME = 40f + } + + class Deep : MagicalSleep() { + init { + type = buffType.NEGATIVE + } + + var damage: Damage? = null + var ratio: Float = 0.01f + + override fun icon(): Int = BuffIndicator.NONE + + override fun detach() { + if (damage != null) { + // delay it + Actor.addDelayed(object : Actor() { + override fun act(): Boolean { + if (target.isAlive) { + val dmg = damage!! + if (dmg.value > 0) { + dmg.value = (1 + dmg.value * ratio).toInt() + target.takeDamage(dmg.type(Damage.Type.MAGICAL).addElement(Damage.Element.SHADOW)) + } + + if (dmg.from is Char) + affect(target, Terror::class.java, 3f).`object` = (dmg.from as Char).id() + } + + Actor.remove(this) + return true + } + }, -1f) + } + + super.detach() + } + } +} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Vertigo.java b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Vertigo.kt similarity index 51% rename from core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Vertigo.java rename to core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Vertigo.kt index bbf968b76..6c11b33b8 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Vertigo.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/buffs/Vertigo.kt @@ -18,38 +18,33 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see */ -package com.egoal.darkestpixeldungeon.actors.buffs; +package com.egoal.darkestpixeldungeon.actors.buffs -import com.egoal.darkestpixeldungeon.actors.Char; -import com.egoal.darkestpixeldungeon.items.rings.RingOfResistance.Resistance; -import com.egoal.darkestpixeldungeon.messages.Messages; -import com.egoal.darkestpixeldungeon.ui.BuffIndicator; +import com.egoal.darkestpixeldungeon.actors.Char +import com.egoal.darkestpixeldungeon.items.rings.RingOfResistance.Resistance +import com.egoal.darkestpixeldungeon.messages.M +import com.egoal.darkestpixeldungeon.messages.Messages +import com.egoal.darkestpixeldungeon.ui.BuffIndicator -public class Vertigo extends FlavourBuff { +open class Vertigo : FlavourBuff() { + init { + type = buffType.NEGATIVE + } - public static final float DURATION = 10f; + override fun icon(): Int { + return BuffIndicator.VERTIGO + } - { - type = buffType.NEGATIVE; - } + override fun toString(): String = M.L(this, "name") - @Override - public int icon() { - return BuffIndicator.VERTIGO; - } + override fun desc(): String = M.L(this, "desc", dispTurns()) - @Override - public String toString() { - return Messages.get(this, "name"); - } + companion object { + const val DURATION = 10f - @Override - public String desc() { - return Messages.get(this, "desc", dispTurns()); - } - - public static float duration(Char ch) { - Resistance r = ch.buff(Resistance.class); - return r != null ? r.durationFactor() * DURATION : DURATION; - } + fun duration(ch: Char): Float { + val r = ch.buff(Resistance::class.java) + return if (r != null) r.durationFactor() * DURATION else DURATION + } + } } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/Hero.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/Hero.kt index 6aa0c8085..e7d655a63 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/Hero.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/Hero.kt @@ -162,6 +162,8 @@ class Hero : Char() { val hlvl = buff(Hunger::class.java)!!.hunger() if (hlvl >= Hunger.STARVING) return 0f + if (buff(Berserk::class.java)?.berserking() == true) return 0f + var reg = regeneration reg += heroPerk.get(LowHealthRegeneration::class.java)?.extraRegeneration(this) ?: 0f @@ -342,7 +344,7 @@ class Hero : Char() { return defSkill * evasion / Math.pow(1.5, estr.toDouble()).toFloat() } else { // ligh - bonus = if (heroClass == HeroClass.ROGUE) -estr else 0 + bonus = if (heroPerk.has(LowWeightDexterous::class.java)) -estr else 0 if (belongings.armor?.hasGlyph(Swiftness::class.java) != null) bonus += 5 + belongings.armor.level() * 3 / 2 @@ -534,8 +536,9 @@ class Hero : Char() { speed *= buff(Combo::class.java)?.speedFactor() ?: 1f speed *= heroPerk.get(BaredAngry::class.java)?.speedFactor(this) ?: 1f + speed *= heroPerk.get(Maniac::class.java)?.speedFactor(this) ?: 1f - return speed + return max(0.25f, speed) } override fun attackProc(dmg: Damage): Damage { @@ -552,7 +555,7 @@ class Hero : Char() { // critical damage if (dmg.isFeatured(Damage.Feature.CRITICAL)) { // recover sanity - val str = wep?.STRReq() ?: 10 + val str = wep?.STRReq(0) ?: 10 if (dmg.value > 0 && Random.Int(15 - str / 2) == 0) recoverSanity(min(Random.Int(dmg.value / 6) + 1, 10).toFloat()) @@ -597,10 +600,10 @@ class Hero : Char() { belongings.helmet?.procTakenDamage(dmg) - if (dmg.type == Damage.Type.MENTAL) - return takeMentalDamage(dmg) - buff(CrackedCoin.Shield::class.java)?.procTakenDamage(dmg) + buff(DragonsSquama.Recharge::class.java)?.procTakenDamage(dmg) + + if (dmg.type == Damage.Type.MENTAL) return takeMentalDamage(dmg) val dmgToken = super.takeDamage(dmg) if (isAlive) { @@ -1262,7 +1265,7 @@ class Hero : Char() { GameScene.gameOver() - if(src is Hero) Badges.validateSuicide() + if (src is Hero) Badges.validateSuicide() if (src is Doom) src.onDeath() diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/HeroClass.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/HeroClass.kt index 3a5ae5cf6..274dc5330 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/HeroClass.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/HeroClass.kt @@ -4,15 +4,15 @@ import com.egoal.darkestpixeldungeon.* import com.egoal.darkestpixeldungeon.actors.Damage import com.egoal.darkestpixeldungeon.actors.buffs.Pressure import com.egoal.darkestpixeldungeon.actors.hero.perks.* -import com.egoal.darkestpixeldungeon.items.armor.Armor -import com.egoal.darkestpixeldungeon.items.armor.ClothArmor -import com.egoal.darkestpixeldungeon.items.armor.MailArmor -import com.egoal.darkestpixeldungeon.items.armor.PlateArmor +import com.egoal.darkestpixeldungeon.items.armor.* import com.egoal.darkestpixeldungeon.items.artifacts.* import com.egoal.darkestpixeldungeon.items.bags.SeedPouch +import com.egoal.darkestpixeldungeon.items.books.TomeOfRetrain +import com.egoal.darkestpixeldungeon.items.books.TomeOfUpgrade import com.egoal.darkestpixeldungeon.items.food.Blandfruit import com.egoal.darkestpixeldungeon.items.food.Food import com.egoal.darkestpixeldungeon.items.food.Wine +import com.egoal.darkestpixeldungeon.items.helmets.GuardHelmet import com.egoal.darkestpixeldungeon.items.helmets.MaskOfLider import com.egoal.darkestpixeldungeon.items.potions.* import com.egoal.darkestpixeldungeon.items.rings.* @@ -20,12 +20,16 @@ import com.egoal.darkestpixeldungeon.items.scrolls.* import com.egoal.darkestpixeldungeon.items.unclassified.* import com.egoal.darkestpixeldungeon.items.wands.* import com.egoal.darkestpixeldungeon.items.weapon.Weapon +import com.egoal.darkestpixeldungeon.items.weapon.curses.Bloodthirsty +import com.egoal.darkestpixeldungeon.items.weapon.curses.Provocation +import com.egoal.darkestpixeldungeon.items.weapon.enchantments.Storming import com.egoal.darkestpixeldungeon.items.weapon.melee.* import com.egoal.darkestpixeldungeon.items.weapon.missiles.* import com.egoal.darkestpixeldungeon.messages.M import com.egoal.darkestpixeldungeon.messages.Messages import com.egoal.darkestpixeldungeon.plants.Blindweed import com.egoal.darkestpixeldungeon.plants.Icecap +import com.egoal.darkestpixeldungeon.plants.Stormvine import com.egoal.darkestpixeldungeon.plants.Sungrass import com.watabou.utils.Bundle import com.watabou.utils.Random @@ -140,6 +144,7 @@ enum class HeroClass(private val title: String) { Dungeon.quickslot.setSlot(0, cloak) Dungeon.quickslot.setSlot(1, darts) + hero.heroPerk.add(LowWeightDexterous()) hero.heroPerk.add(Dieting()) hero.heroPerk.add(ExtraCritProbability()) hero.heroPerk.add(Keen()) @@ -255,6 +260,20 @@ enum class HeroClass(private val title: String) { SeedPouch().identify().collect() Dungeon.limitedDrops.seedBag.drop() + +// WandOfHypnosis().identify().collect() +// ScrollOfUpgrade().quantity(10).identify().collect() +// TomeOfMastery().identify().collect() +// RaggedArmor().identify().collect() +// SpiderGland().quantity(10).identify().collect() +// initDebug(hero) +// ScrollOfUpgrade().identify().quantity(10).collect() +// PotionOfHealing().identify().quantity(10).collect() +// ScrollOfTeleportation().identify().quantity(3).collect() +// ScrollOfCurse().identify().collect() +// HomurasShield().identify().collect() +// DragonsSquama().identify().collect() +// Knuckles().enchant(Storming()).identify().collect() } // called when hero level up diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/perks/HeroPerk.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/perks/HeroPerk.kt index b9182860d..c76db3f03 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/perks/HeroPerk.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/perks/HeroPerk.kt @@ -28,8 +28,16 @@ class HeroPerk : Bundlable { fun downgrade(perk: Perk) { val it = perks.find { perk.javaClass == it.javaClass }!! // - if (it.level == 1) perks.remove(it) - else it.downgrade() + if (it.level == 1) { + perks.remove(it) + it.onLose() + } else it.downgrade() + } + + fun remove(perk: Perk) { + val it = perks.find { perk.javaClass == it.javaClass }!! + perks.remove(it) + it.onLose() } override fun storeInBundle(bundle: Bundle) { diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/perks/Perk.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/perks/Perk.kt index fb01a9ed1..c45276903 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/perks/Perk.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/perks/Perk.kt @@ -113,6 +113,7 @@ abstract class Perk(val maxLevel: Int = 1, var level: Int = 1) : Bundlable { HardCrit() to 1f, LowHealthRegeneration() to 1f, LowHealthDexterous() to 1f, + LowWeightDexterous() to 1f, // ExtraDexterous() to 1f, ExtraEvasion() to 1f, CounterStrike() to 1f, @@ -140,8 +141,9 @@ abstract class Perk(val maxLevel: Int = 1, var level: Int = 1) : Bundlable { BaredAngry() to 0.8f, BaredSwiftness() to 1f, ExtraMagicalResistance() to 1f, - QuickLearner() to 1f + QuickLearner() to 1f, // LevelPerception() to 1f + Maniac() to 1f ) } } \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/perks/PerkImageSheet.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/perks/PerkImageSheet.kt index ccc647634..0fc1ab571 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/perks/PerkImageSheet.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/perks/PerkImageSheet.kt @@ -55,6 +55,8 @@ object PerkImageSheet { const val COUNTER_STRIKE = 48 const val GREEDY_MIDAS = 49 const val DIETING = 50 + const val LOW_WEIGHT_DEX = 51 + const val MANIAC = 52 private const val NEGATIVE = 64 diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/perks/Positive.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/perks/Positive.kt index 65a724e86..986af30d0 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/perks/Positive.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/hero/perks/Positive.kt @@ -226,6 +226,10 @@ class ExtraEvasion : Perk(4) { override fun description(): String = M.L(this, "desc", (prob() * 100).toInt()) } +class LowWeightDexterous : Perk(1) { + override fun image(): Int = PerkImageSheet.LOW_WEIGHT_DEX +} + // cs go! class CounterStrike : Perk() { override fun image(): Int = PerkImageSheet.COUNTER_STRIKE @@ -556,3 +560,11 @@ class LevelPerception : Perk() { override fun image(): Int = PerkImageSheet.LEVEL_PERCEPTION } +class Maniac : Perk() { + override fun image(): Int = PerkImageSheet.MANIAC + + fun speedFactor(hero: Hero): Float { + val n = min(hero.visibleEnemies(), 8) + return if (n <= 1) 1f else (0.5f + 0.5f * 0.8f.pow(n)) // no bonus when 1 v 1 + } +} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/AshesSkull.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/AshesSkull.kt index ba08580f2..0d230080d 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/AshesSkull.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/AshesSkull.kt @@ -56,7 +56,7 @@ class AshesSkull : Mob() { } private fun jump(target: Char): Boolean { - jumpcd = COOLDOWN_JUMP + jumpcd = COOLDOWN_JUMP //todo: ... val b = Ballistica(pos, target.pos, Ballistica.PROJECTILE) if (b.collisionPos != target.pos || b.path.size < 3 || b.dist < 1 || !Level.passable[b.path[b.dist - 1]]) diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Bandit.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Bandit.kt index dc52c6dcf..e68626cf3 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Bandit.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Bandit.kt @@ -32,14 +32,11 @@ import com.egoal.darkestpixeldungeon.items.Item import com.watabou.utils.Random class Bandit : Thief() { - - var item: Item? = null - init { spriteClass = BanditSprite::class.java //1 in 30 chance to be a crazy bandit, equates to overall 1/90 chance. - // lootChance = 0.333f; + lootChance = 0.5f } override fun steal(hero: Hero): Boolean { diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Bestiary.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Bestiary.kt index d84aed27a..90b073f90 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Bestiary.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Bestiary.kt @@ -67,20 +67,20 @@ object Bestiary { when (depth) { // sewer 1 -> { - chances = floatArrayOf(1f) - classes = arrayOf(Rat::class.java) + chances = floatArrayOf(0.8f, 0.2f) + classes = arrayOf(Rat::class.java, Slug::class.java) } 2 -> { - chances = floatArrayOf(1f, 1f) - classes = arrayOf(Rat::class.java, Gnoll::class.java) + chances = floatArrayOf(1f, 0.5f, 0.5f) + classes = arrayOf(Rat::class.java, Slug::class.java, Gnoll::class.java) } 3 -> { - chances = floatArrayOf(2f, 4f, 0.5f, 1f) - classes = arrayOf(Rat::class.java, Gnoll::class.java, Crab::class.java, Swarm::class.java) + chances = floatArrayOf(1f, 1f, 4f, 0.5f, 1f) + classes = arrayOf(Rat::class.java, Slug::class.java, Gnoll::class.java, Crab::class.java, Swarm::class.java) } 4 -> { - chances = floatArrayOf(1f, 2f, 3f, 1f, 0.02f) - classes = arrayOf(Rat::class.java, Gnoll::class.java, Crab::class.java, Swarm::class.java, MadMan::class.java) + chances = floatArrayOf(0.5f, 0.5f, 2f, 3f, 1f, 0.02f) + classes = arrayOf(Rat::class.java, Slug::class.java, Gnoll::class.java, Crab::class.java, Swarm::class.java, MadMan::class.java) } 5 -> { chances = floatArrayOf(1f) diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Brute.java b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Brute.java index 493d89c37..5c3d6e668 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Brute.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Brute.java @@ -37,56 +37,56 @@ public class Brute extends Mob { - { - PropertyConfiger.INSTANCE.set(this, "Brute"); - spriteClass = BruteSprite.class; + { + PropertyConfiger.INSTANCE.set(this, "Brute"); + spriteClass = BruteSprite.class; - loot = Gold.class; - } + loot = Gold.class; + } - private boolean enraged = false; - private static final float TIME_TO_ENRAGE = 1f; + private boolean enraged = false; + private static final float TIME_TO_ENRAGE = 1f; - @Override - public void restoreFromBundle(Bundle bundle) { - super.restoreFromBundle(bundle); - enraged = HP < HT / 4; - } + @Override + public void restoreFromBundle(Bundle bundle) { + super.restoreFromBundle(bundle); + enraged = HP < HT / 4; + } - @Override - public Damage giveDamage(Char target) { - Damage damage = super.giveDamage(target); - if (enraged) { - damage.value *= Random.Float(1.25f, 1.75f); - damage.addFeature(Damage.Feature.CRITICAL); + @Override + public Damage giveDamage(Char target) { + Damage damage = super.giveDamage(target); + if (!damage.isFeatured(Damage.Feature.CRITICAL) && enraged) { + damage.value *= Random.Float(1.25f, 1.75f); + damage.addFeature(Damage.Feature.CRITICAL); + } + return damage; } - return damage; - } - @Override - public int takeDamage(Damage dmg) { - int val = super.takeDamage(dmg); + @Override + public int takeDamage(Damage dmg) { + int val = super.takeDamage(dmg); - if (isAlive() && !enraged && HP < HT / 3) { - enraged = true; - if (Dungeon.visible[pos]) { - GLog.w(Messages.get(this, "enraged_text")); - sprite.showStatus(CharSprite.NEGATIVE, Messages.get(this, "enraged")); - } - spend(TIME_TO_ENRAGE); - } + if (isAlive() && !enraged && HP < HT / 3) { + enraged = true; + if (Dungeon.visible[pos]) { + GLog.w(Messages.get(this, "enraged_text")); + sprite.showStatus(CharSprite.NEGATIVE, Messages.get(this, "enraged")); + } + spend(TIME_TO_ENRAGE); + } - return val; - } + return val; + } - private static final HashSet> IMMUNITIES = new HashSet<>(); + private static final HashSet> IMMUNITIES = new HashSet<>(); - static { - IMMUNITIES.add(Terror.class); - } + static { + IMMUNITIES.add(Terror.class); + } - @Override - public HashSet> immunizedBuffs() { - return IMMUNITIES; - } + @Override + public HashSet> immunizedBuffs() { + return IMMUNITIES; + } } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/DM300.java b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/DM300.java deleted file mode 100644 index d7be0cad5..000000000 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/DM300.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Pixel Dungeon - * Copyright (C) 2012-2015 Oleg Dolya - * - * Shattered Pixel Dungeon - * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.actors.mobs; - -import com.egoal.darkestpixeldungeon.Assets; -import com.egoal.darkestpixeldungeon.Badges; -import com.egoal.darkestpixeldungeon.Dungeon; -import com.egoal.darkestpixeldungeon.PropertyConfiger; -import com.egoal.darkestpixeldungeon.actors.Actor; -import com.egoal.darkestpixeldungeon.actors.Char; -import com.egoal.darkestpixeldungeon.actors.Damage; -import com.egoal.darkestpixeldungeon.actors.blobs.Blob; -import com.egoal.darkestpixeldungeon.actors.buffs.Buff; -import com.egoal.darkestpixeldungeon.actors.buffs.Charm; -import com.egoal.darkestpixeldungeon.actors.buffs.Corruption; -import com.egoal.darkestpixeldungeon.actors.buffs.LockedFloor; -import com.egoal.darkestpixeldungeon.actors.buffs.Paralysis; -import com.egoal.darkestpixeldungeon.actors.buffs.Terror; -import com.egoal.darkestpixeldungeon.effects.CellEmitter; -import com.egoal.darkestpixeldungeon.effects.Speck; -import com.egoal.darkestpixeldungeon.effects.particles.ElmoParticle; -import com.egoal.darkestpixeldungeon.items.artifacts.CapeOfThorns; -import com.egoal.darkestpixeldungeon.items.keys.SkeletonKey; -import com.egoal.darkestpixeldungeon.items.wands.WandOfBlastWave; -import com.egoal.darkestpixeldungeon.levels.Level; -import com.egoal.darkestpixeldungeon.levels.Terrain; -import com.egoal.darkestpixeldungeon.mechanics.Ballistica; -import com.egoal.darkestpixeldungeon.messages.Messages; -import com.egoal.darkestpixeldungeon.scenes.GameScene; -import com.egoal.darkestpixeldungeon.sprites.CharSprite; -import com.egoal.darkestpixeldungeon.sprites.DM300Sprite; -import com.egoal.darkestpixeldungeon.utils.GLog; -import com.egoal.darkestpixeldungeon.actors.blobs.ToxicGas; -import com.egoal.darkestpixeldungeon.items.artifacts.LloydsBeacon; -import com.egoal.darkestpixeldungeon.ui.BossHealthBar; -import com.watabou.noosa.Camera; -import com.watabou.noosa.audio.Sample; -import com.watabou.utils.Bundle; -import com.watabou.utils.Random; - -import java.util.HashSet; - -public class DM300 extends Mob { - - { - spriteClass = DM300Sprite.class; - - PropertyConfiger.INSTANCE.set(this, "DM300"); - loot = new CapeOfThorns().identify(); - } - - private boolean overloaded = false; - - @Override - public int viewDistance() { - return 6; - } - - @Override - public Damage giveDamage(Char target) { - Damage dmg = super.giveDamage(target); - if (overloaded) dmg.value *= 1.25; - - return dmg; - } - - @Override - public boolean act() { - GameScene.add(Blob.seed(pos, 30, ToxicGas.class)); - - return super.act(); - } - - @Override - public float attackDelay() { - return overloaded ? .667f : 1f; - } - - public String description() { - String desc = Messages.get(this, "desc"); - if (overloaded) - desc += "\n\n" + Messages.get(this, "overloaded_desc"); - - return desc; - } - - @Override - public void move(int step) { - super.move(step); - - if (Dungeon.level.getMap()[step] == Terrain.INACTIVE_TRAP && HP < HT) { - - HP += Random.Int(1, HT - HP); - sprite.emitter().burst(ElmoParticle.FACTORY, 5); - - if (Dungeon.visible[step] && Dungeon.hero.isAlive()) { - GLog.n(Messages.get(this, "repair")); - } - } - - int[] cells = { - step - 1, step + 1, step - Dungeon.level.width(), step + Dungeon - .level.width(), - step - 1 - Dungeon.level.width(), - step - 1 + Dungeon.level.width(), - step + 1 - Dungeon.level.width(), - step + 1 + Dungeon.level.width() - }; - int cell = cells[Random.Int(cells.length)]; - - if (Dungeon.visible[cell]) { - CellEmitter.get(cell).start(Speck.factory(Speck.ROCK), 0.07f, 10); - Camera.main.shake(3, 0.7f); - Sample.INSTANCE.play(Assets.SND_ROCKS); - - if (Level.Companion.getWater()[cell]) { - GameScene.ripple(cell); - } else if (Dungeon.level.getMap()[cell] == Terrain.EMPTY) { - Level.Companion.set(cell, Terrain.EMPTY_DECO); - GameScene.updateMap(cell); - } - } - - Char ch = Actor.findChar(cell); - if (ch != null && ch != this) { - Buff.prolong(ch, Paralysis.class, 2); - } - } - - @Override - public int takeDamage(Damage dmg) { - int val = super.takeDamage(dmg); - - LockedFloor lock = Dungeon.hero.buff(LockedFloor.class); - if (lock != null && !immunizedBuffs().contains(dmg.from.getClass())) - lock.addTime(dmg.value * 1.5f); - - if (HP < HT * .3 && !overloaded) overload(); - - return val; - } - - @Override - public Damage attackProc(Damage dmg) { - // chance to knock back - if (dmg.to instanceof Char && Random.Float() < .3f) { - Char tgt = (Char) dmg.to; - int opposite = tgt.pos + (tgt.pos - pos); - Ballistica shot = new Ballistica(tgt.pos, opposite, Ballistica - .MAGIC_BOLT); - - WandOfBlastWave.Companion.throwChar(tgt, shot, 1); - } - - return super.attackProc(dmg); - } - - @Override - public void die(Object cause) { - - super.die(cause); - - GameScene.bossSlain(); - Dungeon.level.drop(new SkeletonKey(Dungeon.depth), pos).getSprite().drop(); - - Badges.INSTANCE.validateBossSlain(); - - LloydsBeacon beacon = Dungeon.hero.getBelongings().getItem(LloydsBeacon.class); - if (beacon != null) { - beacon.upgrade(); - } - - yell(Messages.get(this, "defeated")); - } - - @Override - public void notice() { - super.notice(); - BossHealthBar.assignBoss(this); - yell(Messages.get(this, "notice")); - } - - @Override - public Damage resistDamage(Damage dmg) { - if (!overloaded && dmg.type == Damage.Type.NORMAL) - dmg.value *= 0.8; - - return super.resistDamage(dmg); - } - - private void overload() { - overloaded = true; - - // remove ice resistance, immune fire damage - addResistances(Damage.Element.ICE, 1f); - // addResistances(Damage.Element.FIRE, 100f, 1f); - - sprite.showStatus(CharSprite.NEGATIVE, Messages.get(this, "overload")); - sprite.emitter().burst(Speck.factory(Speck.WOOL), 5); - - GLog.w(Messages.get(this, "overload_warning")); - spend(1f); - } - - private static final HashSet> IMMUNITIES = new HashSet<>(); - - static { - IMMUNITIES.add(ToxicGas.class); - IMMUNITIES.add(Terror.class); - IMMUNITIES.add(Corruption.class); - IMMUNITIES.add(Charm.class); - } - - @Override - public HashSet> immunizedBuffs() { - return IMMUNITIES; - } - - private static final String OVERLOADED = "overloaded"; - - @Override - public void storeInBundle(Bundle bundle) { - super.storeInBundle(bundle); - bundle.put(OVERLOADED, overloaded); - } - - @Override - public void restoreFromBundle(Bundle bundle) { - super.restoreFromBundle(bundle); - overloaded = bundle.getBoolean(OVERLOADED); - - BossHealthBar.assignBoss(this); - } -} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/DM300.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/DM300.kt new file mode 100644 index 000000000..79221bb20 --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/DM300.kt @@ -0,0 +1,330 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.actors.mobs + +import com.egoal.darkestpixeldungeon.* +import com.egoal.darkestpixeldungeon.actors.Actor +import com.egoal.darkestpixeldungeon.actors.Char +import com.egoal.darkestpixeldungeon.actors.Damage +import com.egoal.darkestpixeldungeon.actors.blobs.Blob +import com.egoal.darkestpixeldungeon.effects.CellEmitter +import com.egoal.darkestpixeldungeon.effects.Speck +import com.egoal.darkestpixeldungeon.effects.particles.ElmoParticle +import com.egoal.darkestpixeldungeon.items.keys.SkeletonKey +import com.egoal.darkestpixeldungeon.items.wands.WandOfBlastWave +import com.egoal.darkestpixeldungeon.levels.Level +import com.egoal.darkestpixeldungeon.levels.Terrain +import com.egoal.darkestpixeldungeon.mechanics.Ballistica +import com.egoal.darkestpixeldungeon.messages.Messages +import com.egoal.darkestpixeldungeon.scenes.GameScene +import com.egoal.darkestpixeldungeon.sprites.CharSprite +import com.egoal.darkestpixeldungeon.sprites.DM300Sprite +import com.egoal.darkestpixeldungeon.utils.GLog +import com.egoal.darkestpixeldungeon.actors.blobs.ToxicGas +import com.egoal.darkestpixeldungeon.actors.buffs.* +import com.egoal.darkestpixeldungeon.items.artifacts.LloydsBeacon +import com.egoal.darkestpixeldungeon.items.books.TomeOfRetrain +import com.egoal.darkestpixeldungeon.messages.M +import com.egoal.darkestpixeldungeon.ui.BossHealthBar +import com.egoal.darkestpixeldungeon.ui.Icons +import com.watabou.noosa.Camera +import com.watabou.noosa.Image +import com.watabou.noosa.audio.Sample +import com.watabou.utils.Bundle +import com.watabou.utils.PathFinder +import com.watabou.utils.Random + +import java.util.HashSet + +class DM300 : Mob() { + private var overloaded = false + private val cross: Image = Icons.TARGET.get() + //todo: overhaul this, but i may not. + private var onBumped: (() -> Unit)? = null + + private var bumpcd = 0 + private var bumpcell = -1 + + init { + spriteClass = DM300Sprite::class.java + + PropertyConfiger.set(this, "DM300") + loot = TomeOfRetrain() + } + + override fun viewDistance(): Int = 6 + + override fun giveDamage(target: Char): Damage { + val dmg = super.giveDamage(target) + if (overloaded) dmg.value += dmg.value / 4 + + return dmg + } + + public override fun act(): Boolean { + GameScene.add(Blob.seed(pos, 30, ToxicGas::class.java)) + + if (bumpcd > 0) --bumpcd + + Dungeon.level.updateFieldOfView(this, Level.fieldOfView) //todo: optimize this. + + if (bumpcell < 0 && bumpcd <= 0) + if (state == HUNTING && paralysed <= 0 && enemy != null && enemy.invisible == 0 && + Level.fieldOfView[enemy.pos] && Dungeon.level.distance(pos, enemy.pos) <= 8 && + !Dungeon.level.adjacent(pos, enemy.pos) && canBump(enemy.pos)) { + setBumpCell(enemy.pos) + if (Dungeon.visible[pos]) say(M.L(this, "bump")) + else GLog.n("\"${M.L(this, "bump")}\"") // todo + spend(Actor.TICK) + return true + } + if (bumpcell >= 0 && paralysed <= 0) { + val tgt = bumpcell + resetBumpCell() + if (bump(tgt)) + return false + } + + return super.act() + } + + private fun setBumpCell(pos: Int) { + bumpcell = pos + if (cross.parent == null) { + sprite.parent.add(cross) + cross.color(1f, 0.1f, 0.02f) + } + cross.visible = true + val cen = DungeonTilemap.tileCenterToWorld(bumpcell) + cross.point(cen.offset(-cross.width / 2f, -cross.height / 2f)) + } + + private fun resetBumpCell() { + bumpcell = -1 + cross.visible = false + } + + public override fun attackDelay(): Float = if (overloaded) .667f else 1f + + override fun description(): String { + var desc = Messages.get(this, "desc") + if (overloaded) + desc += "\n\n" + Messages.get(this, "overloaded_desc") + + return desc + } + + override fun move(step: Int) { + super.move(step) + + if (Dungeon.level.map[step] == Terrain.INACTIVE_TRAP && HP < HT) { + HP += Random.Int(1, HT - HP) + sprite.emitter().burst(ElmoParticle.FACTORY, 5) + + if (Dungeon.visible[step] && Dungeon.hero.isAlive) + GLog.n(Messages.get(this, "repair")) + } + + val cells = intArrayOf(step - 1, step + 1, step - Dungeon.level.width(), step + Dungeon + .level.width(), step - 1 - Dungeon.level.width(), step - 1 + Dungeon.level.width(), step + 1 - Dungeon.level.width(), step + 1 + Dungeon.level.width()) + val cell = cells[Random.Int(cells.size)] + + if (Dungeon.visible[cell]) { + CellEmitter.get(cell).start(Speck.factory(Speck.ROCK), 0.07f, 10) + Camera.main.shake(3f, 0.7f) + Sample.INSTANCE.play(Assets.SND_ROCKS) + + if (Level.water[cell]) { + GameScene.ripple(cell) + } else if (Dungeon.level.map[cell] == Terrain.EMPTY) { + Level[cell] = Terrain.EMPTY_DECO + GameScene.updateMap(cell) + } + } + + val ch = Actor.findChar(cell) + if (ch != null && ch !== this) { + Buff.prolong(ch, Paralysis::class.java, 2f) + } + } + + override fun takeDamage(dmg: Damage): Int { + val taken = super.takeDamage(dmg) + + val lock = Dungeon.hero.buff(LockedFloor::class.java) + if (lock != null && !immunizedBuffs().contains(dmg.from.javaClass)) + lock.addTime(dmg.value * 1.5f) + + if (HP < HT * .3 && !overloaded) overload() + + return taken + } + + override fun attackProc(dmg: Damage): Damage { + // chance to knock back + if (dmg.to is Char && Random.Float() < .3f) { + val tgt = dmg.to as Char + val opposite = tgt.pos + (tgt.pos - pos) + val shot = Ballistica(tgt.pos, opposite, Ballistica + .MAGIC_BOLT) + + WandOfBlastWave.throwChar(tgt, shot, 1) + } + + return super.attackProc(dmg) + } + + override fun die(cause: Any) { + super.die(cause) + + GameScene.bossSlain() + + resetBumpCell(); + Dungeon.level.drop(SkeletonKey(Dungeon.depth), pos).sprite.drop() + Dungeon.level.drop(TomeOfRetrain(), pos).sprite.drop() + + Badges.validateBossSlain() + + val beacon = Dungeon.hero.belongings.getItem(LloydsBeacon::class.java) + beacon?.upgrade() + + yell(Messages.get(this, "defeated")) + } + + override fun notice() { + super.notice() + BossHealthBar.assignBoss(this) + yell(Messages.get(this, "notice")) + } + + private fun canBump(cell: Int): Boolean { + val bumpPath = Ballistica(pos, cell, Ballistica.STOP_TARGET or Ballistica.STOP_TERRAIN) + return bumpPath.path.size >= 3 && bumpPath.dist >= 2 + } + + private fun bump(cell: Int): Boolean { + bumpcd = 5 + val bumpPath = Ballistica(pos, cell, Ballistica.STOP_TARGET or Ballistica.STOP_TERRAIN) + + if (bumpPath.path.size < 3 || bumpPath.dist < 2) return false + + var dst = bumpPath.collisionPos + if (Actor.findChar(cell) != null) dst = bumpPath.path[bumpPath.dist - 1] //todo: may try knock back it + + onBumped = { + super.move(dst) // super: no moving paralysis + CellEmitter.get(pos).start(Speck.factory(Speck.ROCK), 0.07f, 20) + Camera.main.shake(5f, 1.2f) + Sample.INSTANCE.play(Assets.SND_ROCKS) + + for (i in bumpPath.path) if (Level.water[i]) GameScene.ripple(cell) + + // directly affected + val bumpedChars = bumpPath.path.mapNotNull { + val ch = Actor.findChar(it) + if (ch === this) null + else ch + }.toHashSet() + + for (ch in bumpedChars) { + val dmg = giveDamage(ch) + ch.defendDamage(dmg) + ch.takeDamage(dmg) + Buff.prolong(ch, Paralysis::class.java, 1.1f) + } + // splash + for (i in PathFinder.NEIGHBOURS8) { + val ch = Actor.findChar(pos + i) + if (ch != null && !bumpedChars.contains(ch)) { + // damage only + val dmg = giveDamage(ch) + dmg.value /= 2 + ch.defendDamage(dmg) + ch.takeDamage(dmg) + } + } + + spend(2f) + next() + } + sprite.move(pos, dst) + + return true + } + + override fun onMotionComplete() { + if (onBumped != null) { + onBumped!!.invoke() + onBumped = null + } + } + + override fun defendDamage(dmg: Damage): Damage { + if (!overloaded && dmg.type == Damage.Type.NORMAL) { + dmg.value -= dmg.value / 5 + if (dmg.isFeatured(Damage.Feature.RANGED)) dmg.value -= dmg.value / 5 + } + + return super.defendDamage(dmg) + } + + private fun overload() { + overloaded = true + + // remove ice resistance, immune fire damage + addResistances(Damage.Element.ICE, -0.5f) + addResistances(Damage.Element.FIRE, 0.5f) + // addResistances(Damage.Element.FIRE, 100f, 1f); + + sprite.showStatus(CharSprite.NEGATIVE, Messages.get(this, "overload")) + sprite.emitter().burst(Speck.factory(Speck.WOOL), 5) + + GLog.w(Messages.get(this, "overload_warning")) + spend(1f) + } + + override fun immunizedBuffs(): HashSet> = IMMUNITIES + + override fun storeInBundle(bundle: Bundle) { + super.storeInBundle(bundle) + bundle.put(OVERLOADED, overloaded) + bundle.put(BUMP_CELL, bumpcell) + bundle.put(BUMP_CD, bumpcd) + } + + override fun restoreFromBundle(bundle: Bundle) { + super.restoreFromBundle(bundle) + overloaded = bundle.getBoolean(OVERLOADED) + bumpcell = bundle.getInt(BUMP_CELL) + bumpcd = bundle.getInt(BUMP_CD) + + BossHealthBar.assignBoss(this) + } + + companion object { + private val IMMUNITIES = hashSetOf>(ToxicGas::class.java, Terror::class.java, + Corruption::class.java, Charm::class.java, MagicalSleep::class.java, Cripple::class.java) + + private const val OVERLOADED = "overloaded" + private const val BUMP_CELL = "bumpcell" + private const val BUMP_CD = "bumpcd" + } +} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Goo.java b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Goo.java index 607997c26..70c8c7c03 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Goo.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Goo.java @@ -24,6 +24,7 @@ import com.egoal.darkestpixeldungeon.actors.Damage; import com.egoal.darkestpixeldungeon.actors.buffs.Charm; import com.egoal.darkestpixeldungeon.actors.buffs.Corruption; +import com.egoal.darkestpixeldungeon.actors.buffs.MagicalSleep; import com.egoal.darkestpixeldungeon.actors.buffs.Terror; import com.egoal.darkestpixeldungeon.actors.buffs.Vulnerable; import com.egoal.darkestpixeldungeon.effects.CellEmitter; @@ -293,6 +294,7 @@ public void restoreFromBundle(Bundle bundle) { IMMUNITIES.add(Terror.class); IMMUNITIES.add(Corruption.class); IMMUNITIES.add(Charm.class); + IMMUNITIES.add(MagicalSleep.class); } @Override diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Guard.java b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Guard.java index 0b2d86346..7385fec57 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Guard.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Guard.java @@ -28,6 +28,7 @@ ; import com.egoal.darkestpixeldungeon.items.Generator; import com.egoal.darkestpixeldungeon.items.armor.Armor; +import com.egoal.darkestpixeldungeon.items.helmets.GuardHelmet; import com.egoal.darkestpixeldungeon.levels.Level; import com.egoal.darkestpixeldungeon.sprites.GuardSprite; import com.egoal.darkestpixeldungeon.Dungeon; @@ -125,7 +126,8 @@ public void call() { @Override protected Item createLoot() { //first see if we drop armor, overall chance is 1/8 - if (Random.Int(2) == 0) { + float p = Random.Float(); + if (p<0.5f) { Armor loot; do { loot = (Armor) Generator.ARMOR.INSTANCE.generate(); @@ -136,11 +138,13 @@ protected Item createLoot() { //otherwise, we may drop a health potion. overall chance is 7/(8 * (7 + // potions dropped)) //with 0 potions dropped that simplifies to 1/8 - } else { + } else if(p<0.85f) { if (Random.Int(7 + Dungeon.limitedDrops.guardHP.count) < 6) { Dungeon.limitedDrops.guardHP.drop(); return new PotionOfHealing(); } + }else{ + return new GuardHelmet().random(); } return null; diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/King.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/King.kt index 2e6b63269..92f6366b2 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/King.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/King.kt @@ -11,11 +11,13 @@ import com.egoal.darkestpixeldungeon.actors.buffs.* import com.egoal.darkestpixeldungeon.effects.Flare import com.egoal.darkestpixeldungeon.effects.Speck import com.egoal.darkestpixeldungeon.items.artifacts.LloydsBeacon +import com.egoal.darkestpixeldungeon.items.books.TomeOfUpgrade import com.egoal.darkestpixeldungeon.items.helmets.CrownOfDwarf import com.egoal.darkestpixeldungeon.items.keys.SkeletonKey import com.egoal.darkestpixeldungeon.items.unclassified.ArmorKit import com.egoal.darkestpixeldungeon.items.weapon.enchantments.Grim import com.egoal.darkestpixeldungeon.levels.CityBossLevel +import com.egoal.darkestpixeldungeon.levels.Level import com.egoal.darkestpixeldungeon.messages.M import com.egoal.darkestpixeldungeon.scenes.GameScene import com.egoal.darkestpixeldungeon.sprites.KingSprite @@ -24,6 +26,7 @@ import com.egoal.darkestpixeldungeon.ui.BossHealthBar import com.egoal.darkestpixeldungeon.utils.GLog import com.watabou.noosa.audio.Sample import com.watabou.utils.Bundle +import com.watabou.utils.PathFinder import com.watabou.utils.Random import java.util.* import kotlin.math.min @@ -113,9 +116,15 @@ class King : Mob() { override fun die(cause: Any?) { GameScene.bossSlain() - Dungeon.level.drop(SkeletonKey(Dungeon.depth), pos).sprite.drop() - Dungeon.level.drop(ArmorKit(), pos).sprite.drop() - Dungeon.level.drop(CrownOfDwarf(), pos).sprite.drop() + + val avals = PathFinder.NEIGHBOURS8.map { it + pos }.filter { + (Level.passable[it] || Level.avoid[it]) + } + + for (item in listOf(SkeletonKey(Dungeon.depth), ArmorKit(), CrownOfDwarf(), TomeOfUpgrade())) { + val cell = if (avals.isEmpty()) pos else avals.random() + Dungeon.level.drop(item, cell).sprite.drop(pos) + } // remove undead Dungeon.level.mobs.filter { it is Undead }.forEach { (it as Undead).realDie() } @@ -187,7 +196,7 @@ class King : Mob() { companion object { private val IMMUNITIES = hashSetOf>( Paralysis::class.java, Vertigo::class.java, Corruption::class.java, - Terror::class.java, Charm::class.java + Terror::class.java, Charm::class.java, MagicalSleep::class.java ) private val UNDEAD_IMMUNITIES = hashSetOf>( diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/MadMan.java b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/MadMan.java index 0c3200345..c95b14ffe 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/MadMan.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/MadMan.java @@ -7,6 +7,7 @@ import com.egoal.darkestpixeldungeon.actors.hero.Hero; import com.egoal.darkestpixeldungeon.effects.MagicMissile; import com.egoal.darkestpixeldungeon.items.Item; +import com.egoal.darkestpixeldungeon.items.armor.RaggedArmor; import com.egoal.darkestpixeldungeon.items.food.Humanity; import com.egoal.darkestpixeldungeon.levels.Level; import com.egoal.darkestpixeldungeon.mechanics.Ballistica; @@ -128,9 +129,10 @@ public void call() { @Override protected Item createLoot() { + if(Random.Float()<0.15f) return new RaggedArmor().identify(); + Dungeon.limitedDrops.madManHumanity.drop(); lootChance = 2f / (8 + Dungeon.limitedDrops.madManHumanity.count); - return super.createLoot(); } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Mob.java b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Mob.java index 1bb4180a7..0ea08d126 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Mob.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Mob.java @@ -97,6 +97,8 @@ public abstract class Mob extends Char { public int minDamage = 0, maxDamage = 0; public Damage.Type typeDamage = Damage.Type.NORMAL; public int minDefense = 0, maxDefense = 0; + public float criticalChance = 0f; + public float criticalRatio = 1.25f; // it's not the ratio matters, critical itself however private static final String STATE = "state"; private static final String SEEN = "seen"; @@ -183,7 +185,12 @@ protected boolean act() { @Override public Damage giveDamage(Char enemy) { // default normal damage - return new Damage(Random.NormalIntRange(minDamage, maxDamage), this, enemy).type(typeDamage); + Damage damage = new Damage(Random.NormalIntRange(minDamage, maxDamage), this, enemy).type(typeDamage); + if(Random.Float()< criticalChance){ + damage.value = Math.round(damage.value* criticalRatio); + damage.addFeature(Damage.Feature.CRITICAL); + } + return damage; } @Override diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/SkeletonKnight.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/SkeletonKnight.kt index 57cb02f4b..1f68d9c10 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/SkeletonKnight.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/SkeletonKnight.kt @@ -88,7 +88,7 @@ class SkeletonKnight : Mob() { companion object { private const val COUNTER = .175f - private const val COMBO = .15f + private const val COMBO = .175f private const val COMBO_COOLDOWN = 2 diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Slug.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Slug.kt new file mode 100644 index 000000000..9667d5e39 --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Slug.kt @@ -0,0 +1,63 @@ +package com.egoal.darkestpixeldungeon.actors.mobs + +import com.egoal.darkestpixeldungeon.Assets +import com.egoal.darkestpixeldungeon.PropertyConfiger +import com.egoal.darkestpixeldungeon.actors.Char +import com.egoal.darkestpixeldungeon.actors.Damage +import com.egoal.darkestpixeldungeon.actors.buffs.Bleeding +import com.egoal.darkestpixeldungeon.actors.buffs.Terror +import com.egoal.darkestpixeldungeon.sprites.MobSprite +import com.watabou.noosa.TextureFilm +import kotlin.math.max + +class Slug : Mob() { + init { + spriteClass = SlugSprite::class.java + + PropertyConfiger.set(this, "Slug") + } + + override fun giveDamage(enemy: Char): Damage { + return super.giveDamage(enemy).addElement(Damage.Element.POISON) + } + + override fun defendDamage(dmg: Damage): Damage { + if (dmg.type == Damage.Type.NORMAL) + dmg.value = max(dmg.value * 2 / 5, 1) + + return super.defendDamage(dmg) + } + + override fun attackDelay(): Float = 1.5f + + override fun immunizedBuffs() = IMMUNS + + companion object { + private val IMMUNS = hashSetOf>( + Bleeding::class.java, Terror::class.java) + } +} + +class SlugSprite : MobSprite() { + init { + texture(Assets.SLUG) + + val frames = TextureFilm(texture, 16, 12) + + idle = Animation(2, true) + idle.frames(frames, 0, 0, 0, 1) + + run = Animation(5, true) + run.frames(frames, 0, 1, 2) + + attack = Animation(15, false) + attack.frames(frames, 3, 4, 5, 6, 7) + + die = Animation(10, false) + die.frames(frames, 8, 9, 10, 11) + + play(idle) + } + + override fun blood(): Int = 0x825131 +} \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Spinner.java b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Spinner.java index 9a1257291..bdfe487be 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Spinner.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Spinner.java @@ -29,7 +29,9 @@ import com.egoal.darkestpixeldungeon.actors.blobs.Blob; import com.egoal.darkestpixeldungeon.actors.buffs.Buff; import com.egoal.darkestpixeldungeon.actors.buffs.Roots; +import com.egoal.darkestpixeldungeon.items.Item; import com.egoal.darkestpixeldungeon.items.food.MysteryMeat; +import com.egoal.darkestpixeldungeon.items.unclassified.SpiderGland; import com.egoal.darkestpixeldungeon.scenes.GameScene; import com.egoal.darkestpixeldungeon.sprites.SpinnerSprite; import com.watabou.utils.Random; @@ -38,70 +40,79 @@ public class Spinner extends Mob { - { - PropertyConfiger.INSTANCE.set(this, "Spinner"); + { + PropertyConfiger.INSTANCE.set(this, "Spinner"); - spriteClass = SpinnerSprite.class; - loot = new MysteryMeat(); + spriteClass = SpinnerSprite.class; + loot = new MysteryMeat(); - FLEEING = new Fleeing(); - } - - @Override - public Damage giveDamage(Char target) { - return super.giveDamage(target).addElement(Damage.Element.POISON); - } - - @Override - protected boolean act() { - boolean result = super.act(); + FLEEING = new Fleeing(); + } - if (state == FLEEING && buff(Terror.class) == null && - enemy != null && enemySeen && enemy.buff(Poison.class) == null) { - state = HUNTING; + @Override + public Damage giveDamage(Char target) { + return super.giveDamage(target).addElement(Damage.Element.POISON); } - return result; - } - - @Override - public Damage attackProc(Damage damage) { - Char enemy = (Char) damage.to; - if (Random.Int(2) == 0) { - Buff.affect(enemy, Poison.class).set(Random.Int(7, 9) * Poison - .durationFactor(enemy)); - state = FLEEING; + + @Override + protected boolean act() { + boolean result = super.act(); + + if (state == FLEEING && buff(Terror.class) == null && + enemy != null && enemySeen && enemy.buff(Poison.class) == null) { + state = HUNTING; + } + return result; } - return damage; - } + @Override + public Damage attackProc(Damage damage) { + Char enemy = (Char) damage.to; + if (Random.Int(2) == 0) { + Buff.affect(enemy, Poison.class).set(Random.Int(7, 9) * Poison + .durationFactor(enemy)); + state = FLEEING; + } + + return damage; + } - @Override - public void move(int step) { - if (state == FLEEING) { - GameScene.add(Blob.seed(pos, Random.Int(5, 7), Web.class)); + @Override + public void move(int step) { + if (state == FLEEING) { + GameScene.add(Blob.seed(pos, Random.Int(5, 7), Web.class)); + } + super.move(step); } - super.move(step); - } - private static final HashSet> IMMUNITIES = new HashSet<>(); + @Override + protected Item createLoot() { + if (Random.Float() < 0.3f) { + int q = Random.Float() < 0.3f ? 2 : 1; + return new SpiderGland().quantity(q).identify(); + } + return super.createLoot(); + } - static { - IMMUNITIES.add(Roots.class); - } + private static final HashSet> IMMUNITIES = new HashSet<>(); - @Override - public HashSet> immunizedBuffs() { - return IMMUNITIES; - } + static { + IMMUNITIES.add(Roots.class); + } - private class Fleeing extends Mob.Fleeing { @Override - protected void nowhereToRun() { - if (buff(Terror.class) == null) { - state = HUNTING; - } else { - super.nowhereToRun(); - } + public HashSet> immunizedBuffs() { + return IMMUNITIES; + } + + private class Fleeing extends Mob.Fleeing { + @Override + protected void nowhereToRun() { + if (buff(Terror.class) == null) { + state = HUNTING; + } else { + super.nowhereToRun(); + } + } } - } } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Tengu.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Tengu.kt index a3c99ab44..e40f155f4 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Tengu.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Tengu.kt @@ -143,9 +143,14 @@ class Tengu : Mob() { Buff.detach(Dungeon.hero, Ignorant::class.java) Buff.detach(Dungeon.hero, MoonNight::class.java) - Dungeon.level.drop(TomeOfPerk(), pos).sprite.drop() - Dungeon.level.drop(MoonStone(), pos).sprite.drop() - Dungeon.level.drop(SkeletonKey(Dungeon.depth), pos).sprite.drop() + val avals = PathFinder.NEIGHBOURS8.map { it + pos }.filter { + (Level.passable[it] || Level.avoid[it]) + } + + for (item in listOf(SkeletonKey(Dungeon.depth), MoonStone(), TomeOfPerk())) { + val cell = if (avals.isEmpty()) pos else avals.random() + Dungeon.level.drop(item, cell).sprite.drop(pos) + } GameScene.bossSlain() super.die(cause) @@ -265,7 +270,7 @@ class Tengu : Mob() { } private val IMMUNITIES = hashSetOf>(Terror::class.java, Corruption::class.java, - Charm::class.java, Chill::class.java) + Charm::class.java, Chill::class.java, MagicalSleep::class.java) override fun immunizedBuffs(): HashSet> = IMMUNITIES @@ -288,6 +293,8 @@ class Tengu : Mob() { fun imitate(tengu: Tengu) { HP = tengu.HP HT = tengu.HT + + tengu.magicalResistance = magicalResistance // reset tengu's magical resistance. } override fun attackSkill(target: Char): Float = 20f diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Thief.java b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Thief.java deleted file mode 100644 index 93ecd265c..000000000 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Thief.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Pixel Dungeon - * Copyright (C) 2012-2015 Oleg Dolya - * - * Shattered Pixel Dungeon - * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.actors.mobs; - -import com.egoal.darkestpixeldungeon.PropertyConfiger; -import com.egoal.darkestpixeldungeon.actors.Char; -import com.egoal.darkestpixeldungeon.actors.Damage; -import com.egoal.darkestpixeldungeon.actors.buffs.Corruption; -import com.egoal.darkestpixeldungeon.actors.buffs.Roots; -import com.egoal.darkestpixeldungeon.actors.buffs.Terror; -import com.egoal.darkestpixeldungeon.actors.hero.Hero; -import com.egoal.darkestpixeldungeon.effects.CellEmitter; -import com.egoal.darkestpixeldungeon.effects.Speck; -import com.egoal.darkestpixeldungeon.items.artifacts.MasterThievesArmband; -import com.egoal.darkestpixeldungeon.items.unclassified.Gold; -import com.egoal.darkestpixeldungeon.items.unclassified.Honeypot; -import com.egoal.darkestpixeldungeon.sprites.CharSprite; -import com.egoal.darkestpixeldungeon.utils.GLog; -import com.egoal.darkestpixeldungeon.Dungeon; -import com.egoal.darkestpixeldungeon.items.Item; -import com.egoal.darkestpixeldungeon.messages.Messages; -import com.egoal.darkestpixeldungeon.sprites.ThiefSprite; -import com.watabou.utils.Bundle; -import com.watabou.utils.Random; - -import java.util.HashSet; - -public class Thief extends Mob { - - public Item item; - - { - PropertyConfiger.INSTANCE.set(this, "Thief"); - - spriteClass = ThiefSprite.class; - - loot = new MasterThievesArmband().identify(); - - FLEEING = new Fleeing(); - } - - private static final String ITEM = "item"; - - @Override - public void storeInBundle(Bundle bundle) { - super.storeInBundle(bundle); - bundle.put(ITEM, item); - } - - @Override - public void restoreFromBundle(Bundle bundle) { - super.restoreFromBundle(bundle); - item = (Item) bundle.get(ITEM); - } - - @Override - public float speed() { - if (item != null) return (5 * super.speed()) / 6; - else return super.speed(); - } - - @Override - protected float attackDelay() { - return 0.5f; - } - - @Override - public void die(Object cause) { - - super.die(cause); - - if (item != null) { - Dungeon.level.drop(item, pos).getSprite().drop(); - //updates position - if (item instanceof Honeypot.ShatteredPot) - ((Honeypot.ShatteredPot) item).setHolder(this); - } - } - - @Override - protected Item createLoot() { - if (!Dungeon.limitedDrops.armband.dropped()) { - Dungeon.limitedDrops.armband.drop(); - return super.createLoot(); - } else - return new Gold(Random.NormalIntRange(80, 200)); - } - - @Override - public Damage attackProc(Damage dmg) { - Char enemy = (Char) dmg.to; - if (item == null && enemy instanceof Hero && steal((Hero) enemy)) { - enemy.takeDamage(new Damage(Random.IntRange(1, 5), this, enemy).type(Damage.Type.MENTAL)); - state = FLEEING; - } - - return dmg; - } - - @Override - public Damage defenseProc(Damage damage) { - if (state == FLEEING) { - Dungeon.level.drop(new Gold(), pos).getSprite().drop(); - } - - return super.defenseProc(damage); - } - - protected boolean steal(Hero hero) { - - Item item = hero.getBelongings().randomUnequipped(); - - if (item != null && !item.unique && item.level() < 1) { - - GLog.w(Messages.get(Thief.class, "stole", item.name())); - Dungeon.quickslot.clearItem(item); - item.updateQuickslot(); - - // process on the honey pot - if (item instanceof Honeypot) { - this.item = ((Honeypot) item).shatter(this, this.pos); - item.detach(hero.getBelongings().backpack); - } else { - this.item = item.detach(hero.getBelongings().backpack); - if (item instanceof Honeypot.ShatteredPot) - ((Honeypot.ShatteredPot) item).setHolder(this); - } - - return true; - } else { - return false; - } - } - - @Override - public String description() { - String desc = super.description(); - - if (item != null) { - desc += Messages.get(this, "carries", item.name()); - } - - return desc; - } - - private static final HashSet> IMMUS = new HashSet<>(); - - public HashSet> immunizedBuffs() { - IMMUS.add(Roots.class); - return IMMUS; - } - - private class Fleeing extends Mob.Fleeing { - @Override - protected void nowhereToRun() { - if (buff(Terror.class) == null && buff(Corruption.class) == null) { - if (enemySeen) { - sprite.showStatus(CharSprite.NEGATIVE, Messages.get(Mob.class, - "rage")); - state = HUNTING; - } else { - - int count = 32; - int newPos; - do { - newPos = Dungeon.level.randomRespawnCell(); - if (count-- <= 0) { - break; - } - } - while (newPos == -1 || Dungeon.visible[newPos] || Dungeon.level - .distance(newPos, pos) < (count / 3)); - - if (newPos != -1) { - - if (Dungeon.visible[pos]) - CellEmitter.get(pos).burst(Speck.factory(Speck.WOOL), 6); - pos = newPos; - sprite.place(pos); - sprite.visible = Dungeon.visible[pos]; - if (Dungeon.visible[pos]) - CellEmitter.get(pos).burst(Speck.factory(Speck.WOOL), 6); - - } - - if (item != null) { - GLog.n(Messages.get(Thief.class, "escapes", item.name())); - if(Dungeon.hero.isAlive()) - Dungeon.hero.takeDamage(new Damage(Random.IntRange(2, 6), this, Dungeon.hero). - type(Damage.Type.MENTAL).addFeature(Damage.Feature.PURE)); - } - item = null; - state = WANDERING; - } - } else { - super.nowhereToRun(); - } - } - } -} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Thief.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Thief.kt new file mode 100644 index 000000000..1c8907f10 --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Thief.kt @@ -0,0 +1,201 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.actors.mobs + +import com.egoal.darkestpixeldungeon.PropertyConfiger +import com.egoal.darkestpixeldungeon.actors.Char +import com.egoal.darkestpixeldungeon.actors.Damage +import com.egoal.darkestpixeldungeon.actors.hero.Hero +import com.egoal.darkestpixeldungeon.effects.CellEmitter +import com.egoal.darkestpixeldungeon.effects.Speck +import com.egoal.darkestpixeldungeon.items.artifacts.MasterThievesArmband +import com.egoal.darkestpixeldungeon.items.unclassified.Gold +import com.egoal.darkestpixeldungeon.items.unclassified.Honeypot +import com.egoal.darkestpixeldungeon.sprites.CharSprite +import com.egoal.darkestpixeldungeon.utils.GLog +import com.egoal.darkestpixeldungeon.Dungeon +import com.egoal.darkestpixeldungeon.actors.buffs.* +import com.egoal.darkestpixeldungeon.items.Item +import com.egoal.darkestpixeldungeon.items.weapon.melee.RedHandleDagger +import com.egoal.darkestpixeldungeon.messages.Messages +import com.egoal.darkestpixeldungeon.sprites.ThiefSprite +import com.watabou.utils.Bundle +import com.watabou.utils.Random + +import java.util.HashSet + +open class Thief : Mob() { + var item: Item? = null + + init { + PropertyConfiger.set(this, "Thief") + + spriteClass = ThiefSprite::class.java + + FLEEING = Fleeing() + } + + override fun storeInBundle(bundle: Bundle) { + super.storeInBundle(bundle) + bundle.put(ITEM, item) + } + + override fun restoreFromBundle(bundle: Bundle) { + super.restoreFromBundle(bundle) + item = bundle.get(ITEM) as Item? + } + + override fun speed(): Float = if (item != null) super.speed() * 0.83333f + else super.speed() + + override fun attackDelay(): Float = 0.5f + + override fun die(cause: Any?) { + super.die(cause) + + if (item != null) { + Dungeon.level.drop(item!!, pos).sprite.drop() + //updates position + if (item is Honeypot.ShatteredPot) + (item as Honeypot.ShatteredPot).setHolder(this) + } + } + + override fun createLoot(): Item = + if (!Dungeon.limitedDrops.armband.dropped() && Random.Float() < 0.1f) { + Dungeon.limitedDrops.armband.drop() + MasterThievesArmband().identify() + } else if (Random.Float() < 0.3f) RedHandleDagger().random() + else Gold(Random.NormalIntRange(80, 200)) + + override fun attackProc(dmg: Damage): Damage { + if (!isAlive) return dmg + val enemy = dmg.to as Char + if (item == null && enemy is Hero && steal(enemy)) { + enemy.takeDamage(Damage(Random.IntRange(1, 5), this, enemy).type(Damage.Type.MENTAL)) + state = FLEEING + } else if(Random.Int(4)==0){ + Buff.prolong(enemy, Cripple::class.java, 1.5f) + } + + return dmg + } + + override fun defenseProc(damage: Damage): Damage { + if (state === FLEEING) { + Dungeon.level.drop(Gold(), pos).sprite.drop() + } + + return super.defenseProc(damage) + } + + protected open fun steal(hero: Hero): Boolean { + + val item = hero.belongings.randomUnequipped() + + if (item != null && !item.unique && item.level() < 1) { + + GLog.w(Messages.get(Thief::class.java, "stole", item.name())) + Dungeon.quickslot.clearItem(item) + item.updateQuickslot() + + // process on the honey pot + if (item is Honeypot) { + this.item = item.shatter(this, this.pos) + item.detach(hero.belongings.backpack) + } else { + this.item = item.detach(hero.belongings.backpack) + if (item is Honeypot.ShatteredPot) + item.setHolder(this) + } + + return true + } else { + return false + } + } + + override fun description(): String { + var desc = super.description() + + if (item != null) { + desc += Messages.get(this, "carries", item!!.name()) + } + + return desc + } + + override fun immunizedBuffs(): HashSet> { + IMMUS.add(Roots::class.java) + return IMMUS + } + + private inner class Fleeing : Mob.Fleeing() { + override fun nowhereToRun() { + if (buff(Terror::class.java) == null && buff(Corruption::class.java) == null) { + if (enemySeen) { + sprite.showStatus(CharSprite.NEGATIVE, Messages.get(Mob::class.java, + "rage")) + state = HUNTING + } else { + + var count = 32 + var newPos: Int + do { + newPos = Dungeon.level.randomRespawnCell() + if (count-- <= 0) { + break + } + } while (newPos == -1 || Dungeon.visible[newPos] || Dungeon.level + .distance(newPos, pos) < count / 3) + + if (newPos != -1) { + + if (Dungeon.visible[pos]) + CellEmitter.get(pos).burst(Speck.factory(Speck.WOOL), 6) + pos = newPos + sprite.place(pos) + sprite.visible = Dungeon.visible[pos] + if (Dungeon.visible[pos]) + CellEmitter.get(pos).burst(Speck.factory(Speck.WOOL), 6) + + } + + if (item != null) { + GLog.n(Messages.get(Thief::class.java, "escapes", item!!.name())) + if (Dungeon.hero.isAlive) + Dungeon.hero.takeDamage(Damage(Random.IntRange(2, 6), this, Dungeon.hero).type(Damage.Type.MENTAL).addFeature(Damage.Feature.PURE)) + } + item = null + state = WANDERING + } + } else { + super.nowhereToRun() + } + } + } + + companion object { + private const val ITEM = "item" + + private val IMMUS = HashSet>() + } +} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/WandGuard.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/WandGuard.kt index 1bafe1126..02f166e6a 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/WandGuard.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/WandGuard.kt @@ -5,6 +5,7 @@ import com.egoal.darkestpixeldungeon.Dungeon import com.egoal.darkestpixeldungeon.actors.Char import com.egoal.darkestpixeldungeon.actors.Damage import com.egoal.darkestpixeldungeon.actors.buffs.Buff +import com.egoal.darkestpixeldungeon.actors.hero.Hero import com.egoal.darkestpixeldungeon.effects.CellEmitter import com.egoal.darkestpixeldungeon.effects.particles.ElmoParticle import com.egoal.darkestpixeldungeon.effects.particles.ShadowParticle @@ -54,13 +55,17 @@ class WandGuard : Mob() { override fun doAttack(enemy: Char): Boolean { val shot = Ballistica(pos, enemy.pos, Ballistica.MAGIC_BOLT) - wand.execute(Dungeon.hero, "") //patch: assign curUser + wand.execute(Dungeon.hero, "") //patch: assign curUser + + if(enemy is Hero) enemy.busy() wand.fx(shot) { // hit hero val dmg = giveDamage(enemy) enemy.defendDamage(dmg) enemy.takeDamage(dmg) + if(enemy is Hero) enemy.ready() + if (!enemy.isAlive) { Dungeon.fail(dmg.from.javaClass) GLog.n(Messages.capitalize(Messages.get(Char::class.java, "kill", (dmg.from as Char).name))) @@ -70,7 +75,7 @@ class WandGuard : Mob() { //todo: fire wand performs not well } - spend(TIME_TO_ZAP) + spend(TIME_TO_ZAP) //fixme: this wont wait the above animation return true } @@ -137,23 +142,23 @@ class WandGuard : Mob() { val frames = TextureFilm(texture, 16, 16) - idle = MovieClip.Animation(10, true) + idle = Animation(10, true) idle.frames(frames, 0) - run = MovieClip.Animation(10, true) + run = Animation(10, true) run.frames(frames, 0) - attack = MovieClip.Animation(15, false) + attack = Animation(15, false) attack.frames(frames, 0, 0, 0) - die = MovieClip.Animation(10, false) + die = Animation(10, false) die.frames(frames, 0) play(idle) } - override fun onComplete(anim: MovieClip.Animation) { + override fun onComplete(anim: Animation) { if (anim === die) { emitter().burst(ElmoParticle.FACTORY, 4) } @@ -165,7 +170,7 @@ class WandGuard : Mob() { override fun link(ch: Char) { super.link(ch) - add(CharSprite.State.MARKED) + add(State.MARKED) } override fun die() { @@ -173,7 +178,7 @@ class WandGuard : Mob() { CellEmitter.get(ch.pos).burst(ShadowParticle.UP, 5) - remove(CharSprite.State.MARKED) + remove(State.MARKED) } } } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Wraith.java b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Wraith.java deleted file mode 100644 index 9142fc3fa..000000000 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Wraith.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Pixel Dungeon - * Copyright (C) 2012-2015 Oleg Dolya - * - * Shattered Pixel Dungeon - * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.actors.mobs; - -import com.egoal.darkestpixeldungeon.actors.Char; -import com.egoal.darkestpixeldungeon.actors.Damage; -import com.egoal.darkestpixeldungeon.actors.buffs.Corruption; -import com.egoal.darkestpixeldungeon.actors.buffs.Terror; -import com.egoal.darkestpixeldungeon.levels.Level; -import com.egoal.darkestpixeldungeon.Dungeon; -import com.egoal.darkestpixeldungeon.actors.Actor; -import com.egoal.darkestpixeldungeon.effects.particles.ShadowParticle; -import com.egoal.darkestpixeldungeon.items.weapon.enchantments.Grim; -import com.egoal.darkestpixeldungeon.scenes.GameScene; -import com.egoal.darkestpixeldungeon.sprites.WraithSprite; -import com.watabou.noosa.tweeners.AlphaTweener; -import com.watabou.utils.Bundle; -import com.watabou.utils.PathFinder; -import com.watabou.utils.Random; - -import java.util.HashSet; - -public class Wraith extends Mob { - - private static final float SPAWN_DELAY = 2f; - - protected int level; - - { - spriteClass = WraithSprite.class; - - HP = HT = 1; - EXP = 0; - - flying = true; - - properties.add(Property.UNDEAD); - - defSkill = 1000f; - - addResistances(Damage.Element.SHADOW, 0.25f); - addResistances(Damage.Element.HOLY, -0.5f); - } - - private static final String LEVEL = "level"; - - @Override - public void storeInBundle(Bundle bundle) { - super.storeInBundle(bundle); - bundle.put(LEVEL, level); - } - - @Override - public void restoreFromBundle(Bundle bundle) { - super.restoreFromBundle(bundle); - level = bundle.getInt(LEVEL); - adjustStats(level); - } - - @Override - public Damage giveDamage(Char target) { - return new Damage(Random.NormalIntRange(1 + level / 2, 2 + level), this, target); - } - - @Override - public float attackSkill(Char target) { - return 10 + level; - } - - public void adjustStats(int level) { - this.level = level; - defSkill = attackSkill(null) * 5; - enemySeen = true; - } - - @Override - public boolean reset() { - state = WANDERING; - return true; - } - - public static void spawnAround(int pos) { - for (int n : PathFinder.NEIGHBOURS4) { - int cell = pos + n; - if (Level.Companion.getPassable()[cell] && Actor.findChar(cell) == null) { - spawnAt(cell); - } - } - } - - public static Wraith spawnAt(int pos) { - if (Level.Companion.getPassable()[pos] && Actor.findChar(pos) == null) { - - Wraith w = new Wraith(); - w.adjustStats(Dungeon.depth); - w.pos = pos; - w.state = w.HUNTING; - GameScene.add(w, SPAWN_DELAY); - - w.sprite.alpha(0); - w.sprite.parent.add(new AlphaTweener(w.sprite, 1, 0.5f)); - - w.sprite.emitter().burst(ShadowParticle.CURSE, 5); - - return w; - } else { - return null; - } - } - - private static final HashSet> IMMUNITIES = new HashSet<>(); - - static { - IMMUNITIES.add(Grim.class); - IMMUNITIES.add(Terror.class); - IMMUNITIES.add(Corruption.class); - } - - @Override - public HashSet> immunizedBuffs() { - return IMMUNITIES; - } -} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Wraith.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Wraith.kt new file mode 100644 index 000000000..13ec3ee57 --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Wraith.kt @@ -0,0 +1,130 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.actors.mobs + +import com.egoal.darkestpixeldungeon.actors.Char +import com.egoal.darkestpixeldungeon.actors.Damage +import com.egoal.darkestpixeldungeon.actors.buffs.Corruption +import com.egoal.darkestpixeldungeon.actors.buffs.Terror +import com.egoal.darkestpixeldungeon.levels.Level +import com.egoal.darkestpixeldungeon.Dungeon +import com.egoal.darkestpixeldungeon.actors.Actor +import com.egoal.darkestpixeldungeon.effects.particles.ShadowParticle +import com.egoal.darkestpixeldungeon.items.weapon.enchantments.Grim +import com.egoal.darkestpixeldungeon.scenes.GameScene +import com.egoal.darkestpixeldungeon.sprites.WraithSprite +import com.watabou.noosa.tweeners.AlphaTweener +import com.watabou.utils.Bundle +import com.watabou.utils.PathFinder +import com.watabou.utils.Random + +import java.util.HashSet + +open class Wraith : Mob() { + + protected var level: Int = 0 + + init { + spriteClass = WraithSprite::class.java + + HT = 1 + HP = HT + EXP = 0 + + flying = true + + properties.add(Property.UNDEAD) + + defSkill = 1000f + + addResistances(Damage.Element.SHADOW, 0.25f) + addResistances(Damage.Element.HOLY, -0.5f) + } + + override fun storeInBundle(bundle: Bundle) { + super.storeInBundle(bundle) + bundle.put(LEVEL, level) + } + + override fun restoreFromBundle(bundle: Bundle) { + super.restoreFromBundle(bundle) + level = bundle.getInt(LEVEL) + adjustStats(level) + } + + override fun giveDamage(target: Char): Damage = + Damage(Random.NormalIntRange(1 + level / 2, 2 + level), this, target) + + override fun attackSkill(target: Char?): Float = (10 + level).toFloat() + + open fun adjustStats(level: Int) { + this.level = level + defSkill = attackSkill(null) * 5 + enemySeen = true + } + + override fun reset(): Boolean { + state = WANDERING + return true + } + + override fun immunizedBuffs(): HashSet> = IMMUNITIES + + companion object { + + private const val SPAWN_DELAY = 2f + + private const val LEVEL = "level" + + fun spawnAround(pos: Int) { + for (n in PathFinder.NEIGHBOURS4) { + val cell = pos + n + if (Level.passable[cell] && Actor.findChar(cell) == null) { + spawnAt(cell) + } + } + } + + fun spawnAt(pos: Int): Wraith? { + if (Level.passable[pos] && Actor.findChar(pos) == null) { + + val w = Wraith() + w.adjustStats(Dungeon.depth) + w.pos = pos + w.state = w.HUNTING + GameScene.add(w, SPAWN_DELAY) + + w.sprite.alpha(0f) + w.sprite.parent.add(AlphaTweener(w.sprite, 1f, 0.5f)) + + w.sprite.emitter().burst(ShadowParticle.CURSE, 5) + + return w + } else { + return null + } + } + + private val IMMUNITIES = hashSetOf>( + Grim::class.java, Terror::class.java, Corruption::class.java + ) + } +} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Yog.java b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Yog.java index a1870e59f..32c061b9c 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Yog.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/Yog.java @@ -29,6 +29,7 @@ import com.egoal.darkestpixeldungeon.actors.blobs.Fire; import com.egoal.darkestpixeldungeon.actors.blobs.ToxicGas; import com.egoal.darkestpixeldungeon.actors.buffs.Corruption; +import com.egoal.darkestpixeldungeon.actors.buffs.MagicalSleep; import com.egoal.darkestpixeldungeon.actors.buffs.ViewMark; import com.egoal.darkestpixeldungeon.effects.Pushing; import com.egoal.darkestpixeldungeon.effects.particles.ShadowParticle; @@ -198,6 +199,7 @@ public void notice() { IMMUNITIES.add(ToxicGas.class); IMMUNITIES.add(Vertigo.class); IMMUNITIES.add(Corruption.class); + IMMUNITIES.add(MagicalSleep.class); } @Override @@ -286,6 +288,7 @@ public int takeDamage(Damage dmg) { IMMUNITIES.add(Poison.class); IMMUNITIES.add(Vertigo.class); IMMUNITIES.add(Corruption.class); + IMMUNITIES.add(MagicalSleep.class); } @Override @@ -387,6 +390,7 @@ public int takeDamage(Damage dmg) { IMMUNITIES.add(Burning.class); IMMUNITIES.add(Vertigo.class); IMMUNITIES.add(Corruption.class); + IMMUNITIES.add(MagicalSleep.class); } @Override diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/Ghost.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/Ghost.kt index aa4d9b899..df6fc07d5 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/Ghost.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/Ghost.kt @@ -260,7 +260,7 @@ class Ghost : NPC.Unbreakable() { Sample.INSTANCE.play(Assets.SND_GHOST) processed = true // now the rose can spawn. - Generator.ARTIFACT.probMap[DriedRose::class.java] = 1f + Generator.ARTIFACT.probMap[DriedRose::class] = 1f } } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/MerchantImp.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/MerchantImp.kt index 961021599..f7a3044dc 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/MerchantImp.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/MerchantImp.kt @@ -24,15 +24,10 @@ class MerchantImp : Merchant() { override fun initSellItems() { // devil would be place by painter, here, add extra items - repeat(2) { - addItemToSell(Generator.POTION.generate()) - } - addItemToSell(ScrollOfRemoveCurse()) addItemToSell(ScrollOfMagicMapping()) - addItemToSell(Generator.SCROLL.generate()) - repeat(2) { + repeat(4) { addItemToSell(if (Random.Int(2) == 0) Generator.POTION.generate() else Generator.SCROLL.generate()) } @@ -45,7 +40,7 @@ class MerchantImp : Merchant() { addItemToSell(PlateArmor().identify()) - repeat(3) { addItemToSell(Torch()) } + addItemToSell(Torch().quantity(3)) } override fun flee() { diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/Monument.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/Monument.kt index c8c33d202..12d5d8520 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/Monument.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/Monument.kt @@ -27,9 +27,12 @@ class Monument : NPC.Unbreakable() { if (!activated && Dungeon.hero.lvl == 1) //todo: rework this GameScene.show(object : WndSelectChallenge() { override fun onChallengeWouldActivate(challenge: Challenge) { + val hero = Dungeon.hero + if (hero.challenge != null) return + activated = true - challenge.affect(Dungeon.hero) - Dungeon.hero.challenge = challenge + challenge.affect(hero) + hero.challenge = challenge hide() GLog.n(M.L(Monument::class.java, "activated", challenge.title())) } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/Seeker.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/Seeker.kt new file mode 100644 index 000000000..758daec1c --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/Seeker.kt @@ -0,0 +1,39 @@ +package com.egoal.darkestpixeldungeon.actors.mobs.npcs + +import android.content.Intent +import android.net.Uri +import com.egoal.darkestpixeldungeon.Assets +import com.egoal.darkestpixeldungeon.messages.M +import com.egoal.darkestpixeldungeon.sprites.SimpleMobSprite +import com.egoal.darkestpixeldungeon.windows.WndDialogue +import com.watabou.noosa.Game + +class Seeker : NPC.Unbreakable() { + init { + spriteClass = Sprite::class.java + } + + override fun interact(): Boolean { + WndDialogue.Show(this, M.L(this, "greetings"), M.L(this, "desc_yourself")) { + WndDialogue.Show(this, M.L(this, "dungeons"), M.L(this, "check_info")) { + WndDialogue.Show(this, M.L(this, "desc_state"), M.L(this, "info_dpd"), M.L(this, "info_all"), M.L(this, "maybe_nexttime")) { + if (it == 0) { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(WIKI_DPD)) + Game.instance.startActivity(intent) + } else if (it == 1) { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(WIKI_IDX)) + Game.instance.startActivity(intent) + } + } + } + } + return false + } + + class Sprite : SimpleMobSprite(Assets.SEEKER) + + companion object { + private const val WIKI_DPD = "https://pixeldungeon.fandom.com/wiki/Mod-Darkest_Pixel_Dungeon" + private const val WIKI_IDX = "https://pixeldungeon.fandom.com/wiki/Main_Page" + } +} \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/UndeadShopkeeper.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/UndeadShopkeeper.kt index a5dc6fb17..19ef97da0 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/UndeadShopkeeper.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/UndeadShopkeeper.kt @@ -1,15 +1,88 @@ package com.egoal.darkestpixeldungeon.actors.mobs.npcs import com.egoal.darkestpixeldungeon.Assets -import com.egoal.darkestpixeldungeon.sprites.MobSprite +import com.egoal.darkestpixeldungeon.Dungeon +import com.egoal.darkestpixeldungeon.actors.hero.perks.Discount +import com.egoal.darkestpixeldungeon.items.Generator +import com.egoal.darkestpixeldungeon.items.books.TomeOfPerk +import com.egoal.darkestpixeldungeon.messages.M import com.egoal.darkestpixeldungeon.sprites.SimpleMobSprite +import com.egoal.darkestpixeldungeon.windows.WndDialogue +import com.watabou.utils.Bundle +import com.watabou.utils.Random +import kotlin.math.round class UndeadShopkeeper : Merchant() { init { spriteClass = Sprite::class.java } - - - - class Sprite: SimpleMobSprite(Assets.UNDEAD_SHOPKEEPER) + + private var itemChecked = false + + override fun actions(): ArrayList> { + val acts = super.actions() + acts.add(AC_WHY_HERE to M.L(this, "ac_$AC_WHY_HERE")) + return acts + } + + override fun execute(action: String) { + if (action == AC_WHY_HERE) + WndDialogue.Show(this, M.L(this, "customer_filter")) {} + else if (action == "buy" && !itemChecked) { + WndDialogue.Show(this, M.L(this, "pay_to_see", infoPrice()), M.L(this, "unhappy"), M.L(this, "fine")) { + if (it == 0) WndDialogue.Show(this, M.L(this, "info_costs")) {} + else if (it == 1) { + val price = infoPrice() + if (Dungeon.gold < price) { + say(M.L(this, "no_money")) + } else { + Dungeon.gold -= price + itemChecked = true + spawnItems() + execute("buy") + } + } + } + } else + super.execute(action) + } + + override fun initSellItems() { + addItemToSell(Generator.SEED.generate()) // avoid empty initials + } + + private fun infoPrice() = round((100 + 10 * Dungeon.depth) * (Dungeon.hero.heroPerk.get(Discount::class.java)?.ratio() + ?: 1f)).toInt() + + private fun spawnItems() { + var arts = 0 + for (i in 0 until 2) { + val item = if (Random.Float() < 0.4f) { + ++arts + Generator.ARTIFACT.generate() + } else Generator.RING.generate() + addItemToSell(item) + } + if (arts < 1) addItemToSell(Generator.ARTIFACT.generate()) + + if (Random.Float() < 0.05) addItemToSell(TomeOfPerk()) + } + + class Sprite : SimpleMobSprite(Assets.UNDEAD_SHOPKEEPER) + + override fun storeInBundle(bundle: Bundle) { + super.storeInBundle(bundle) + bundle.put(ITEM_CHECKED, itemChecked) + } + + override fun restoreFromBundle(bundle: Bundle) { + super.restoreFromBundle(bundle) + itemChecked = bundle.getBoolean(ITEM_CHECKED) + } + + companion object { + private const val AC_WHY_HERE = "why_here" + + private const val ITEM_CHECKED = "checked" + } } \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/Yvette.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/Yvette.kt index 0e42a25f9..a31b508b3 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/Yvette.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/actors/mobs/npcs/Yvette.kt @@ -20,6 +20,7 @@ import com.egoal.darkestpixeldungeon.items.potions.Potion import com.egoal.darkestpixeldungeon.items.potions.PotionOfHealing import com.egoal.darkestpixeldungeon.items.scrolls.Scroll import com.egoal.darkestpixeldungeon.items.scrolls.ScrollOfTeleportation +import com.egoal.darkestpixeldungeon.items.weapon.melee.MagicBow import com.egoal.darkestpixeldungeon.messages.M import com.egoal.darkestpixeldungeon.messages.Messages import com.egoal.darkestpixeldungeon.scenes.GameScene @@ -46,13 +47,28 @@ class Yvette : NPC() { private var questGiven = false private var seenBefore = false // no store private var foodGotten = false + private var potionGotten = false override fun interact(): Boolean { sprite.turnTo(pos, Dungeon.hero.pos) if (Quest.Completed) { // safe on the land - tell(Messages.get(this, "see-again")) + //todo: + val bow = Dungeon.hero.belongings.getItem(MagicBow::class.java) + if (bow == null) { + tell(Messages.get(this, "see-again")) + } else { + WndDialogue.Show(this, M.L(this, "see-again"), M.L(this, "return-bow"), M.L(this, "bye")) { + if (it == 0) { + bow.cursed = false + if (bow.isEquipped(Dungeon.hero)) bow.doUnequip(Dungeon.hero, false) + else bow.detach(Dungeon.hero.belongings.backpack) + tell(M.L(this, "bow-got", Dungeon.hero.className())) + } + } + } + return false } @@ -80,7 +96,7 @@ class Yvette : NPC() { } GameScene.selectItem(selectorGiveItem, Messages.get(this, "give-item"), WndBag.Filter { - it is Food || it is Scroll + it is Food || it is Scroll || it is Potion }) } else { // kill her? you dirty adventurer! @@ -101,12 +117,19 @@ class Yvette : NPC() { private val selectorGiveItem = WndBag.Listener { it.let { item -> - if (item is Food) { - item.detach(Dungeon.hero.belongings.backpack) - onFoodGotten(item) - } else if (item is Scroll) { - item.detach(Dungeon.hero.belongings.backpack) - onScrollGotten(item) + when (item) { + is Food -> { + item.detach(Dungeon.hero.belongings.backpack) + onFoodGotten(item) + } + is Scroll -> { + item.detach(Dungeon.hero.belongings.backpack) + onScrollGotten(item) + } + is Potion -> { + item.detach(Dungeon.hero.belongings.backpack) + onPotionGotten(item) + } } } } @@ -123,8 +146,46 @@ class Yvette : NPC() { } private fun onScrollGotten(scroll: Scroll) { - if (scroll is ScrollOfTeleportation) { - val content = Messages.get(this, "thanks-for-scroll") + + if (scroll !is ScrollOfTeleportation) { + returnItem(scroll) + return + } + + //todo: clean this + if (potionGotten) { + val content = M.L(this, "thanks-for-scroll") + "\n\n" + M.L(this, "give-bow") + WndDialogue.Show(this, content, M.L(this, "decline_bow"), M.L(this, "bye")) { + if (it == 0) { + GameScene.show(object : WndQuest(this, M.L(this, "give_key")) { + override fun onBackPressed() { + super.onBackPressed() + Quest.Completed = true + Dungeon.hero.recoverSanity(Random.Float(10f, 25f)) // recover much more. + Dungeon.level.drop(IronKey(20), pos).sprite.drop() + + if (foodGotten) { + val perk = IntendedTransportation() + Dungeon.hero.heroPerk.add(perk) + + PerkGain.Show(Dungeon.hero, perk) + GLog.p(Messages.get(Yvette::class.java, "taught", name)) + } + + this@Yvette.destroy() + (sprite as Sprite).leave() + } + }) + } else { + Quest.Completed = true + Dungeon.hero.recoverSanity(Random.Float(4f, 10f)) + Dungeon.level.drop(MagicBow().identify(), pos).sprite.drop() + + this@Yvette.destroy() + (sprite as Sprite).leave() + } + } + } else { + val content = M.L(this, "thanks-for-scroll") + M.L(this, "give-items") + if (foodGotten) "\n\n" + Messages.get(this, "teach-teleportation") else "" GameScene.show(object : WndQuest(this, content) { @@ -133,13 +194,22 @@ class Yvette : NPC() { leave() } }) - } else { - tell(Messages.get(this, "not-teleportation")) - if (!scroll.collect()) - Dungeon.level.drop(scroll, Dungeon.hero.pos) } } + private fun onPotionGotten(potion: Potion) { + if (potion is PotionOfHealing) { + potionGotten = true + tell(M.L(this, "thanks-for-potion")) + sprite.emitter().start(Speck.factory(Speck.HEALING), 0.4f, 8) + } else returnItem(potion) + } + + private fun returnItem(item: Item) { + tell(M.L(this, "not-this")) + if (!item.collect()) Dungeon.level.drop(item, Dungeon.hero.pos) + } + private fun leave() { Quest.Completed = true @@ -194,6 +264,7 @@ class Yvette : NPC() { Dungeon.level.drop(RangerHat().identify(), pos) Dungeon.level.drop(Generator.WEAPON.generate(), pos) Dungeon.level.drop(YvettesDiary(), pos) + Dungeon.level.drop(MagicBow.Broken(), pos) Wound.hit(pos) Sample.INSTANCE.play(Assets.SND_CRITICAL) @@ -205,12 +276,14 @@ class Yvette : NPC() { super.storeInBundle(bundle) bundle.put(STR_QUEST_GIVEN, questGiven) bundle.put(STR_FOOD_GOTTEN, foodGotten) + bundle.put(STR_POTION_GOTTEN, potionGotten) } override fun restoreFromBundle(bundle: Bundle) { super.restoreFromBundle(bundle) questGiven = bundle.getBoolean(STR_QUEST_GIVEN) foodGotten = bundle.getBoolean(STR_FOOD_GOTTEN) + potionGotten = bundle.getBoolean(STR_POTION_GOTTEN) } // unbreakable @@ -225,6 +298,7 @@ class Yvette : NPC() { companion object { private const val STR_QUEST_GIVEN = "quest-given" private const val STR_FOOD_GOTTEN = "food-gotten" + private const val STR_POTION_GOTTEN = "potion-gotten" private const val STR_QUEST_NODE = "yvette" private const val STR_QUEST_COMPLETED = "completed" diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/Generator.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/Generator.kt index 385b99698..93a8ce65d 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/Generator.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/Generator.kt @@ -25,16 +25,38 @@ import com.watabou.utils.Bundlable import com.watabou.utils.Bundle import com.watabou.utils.GameMath import com.watabou.utils.Random +import kotlin.reflect.KClass object Generator { fun CurrentFloorSet(): Int = Dungeon.depth / 5 abstract class ItemGenerator { abstract fun generate(): Item + abstract fun reset() } - open class ClassMapGenerator(val probMap: HashMap, Float>) : ItemGenerator() { - override fun generate(): Item = (Random.chances(probMap).newInstance() as Item).random() + open class ClassMapGenerator(val probMap: HashMap, Float>) : ItemGenerator() { + override fun generate(): Item = (Random.chances(probMap).java.newInstance() as Item).random() + override fun reset() {} + } + + open class BalancedClassMapGenerator(val initialProbs: HashMap, Float>) : ItemGenerator() { + private val currentProbs = hashMapOf, Float>() + + init { + reset() + } + + override fun generate(): Item { + val it = Random.chances(currentProbs) + currentProbs[it] = currentProbs[it]!! / 2f // lower its prob, this is the "balanced" + return it.java.newInstance().random() + } + + override fun reset() { + currentProbs.clear() + for (pr in initialProbs) currentProbs[pr.key] = pr.value + } } object ARMOR : ItemGenerator() { @@ -52,6 +74,7 @@ object Generator { ) override fun generate(): Item = random(CurrentFloorSet()) + override fun reset() {} fun random(floorSet: Int): Armor { val fs = GameMath.clamp(floorSet, 0, floorSetProbs.size - 1) @@ -70,52 +93,55 @@ object Generator { ) object MELEE : ItemGenerator() { - object T1 : ClassMapGenerator(hashMapOf( - WornShortsword::class.java to 1f, - Knuckles::class.java to 1f, - Dagger::class.java to 1f, - MagesStaff::class.java to 0f, - SorceressWand::class.java to 0f, - BattleGloves::class.java to 1f + object T1 : BalancedClassMapGenerator(hashMapOf( + WornShortsword::class to 1f, + Knuckles::class to 1f, + Dagger::class to 1f, + MagesStaff::class to 0f, + SorceressWand::class to 0f, + BattleGloves::class to 1f, + RedHandleDagger::class to 0.1f )) - object T2 : ClassMapGenerator(hashMapOf( - Dirk::class.java to 5f, - ShortSword::class.java to 6f, - HandAxe::class.java to 5f, - Spear::class.java to 5f, - Quarterstaff::class.java to 4f, - Sickle::class.java to 5f, - DriedLeg::class.java to 5f + object T2 : BalancedClassMapGenerator(hashMapOf( + Dirk::class to 5f, + ShortSword::class to 6f, + HandAxe::class to 5f, + Spear::class to 5f, + Quarterstaff::class to 4f, + Sickle::class to 5f, + DriedLeg::class to 5f )) - object T3 : ClassMapGenerator(hashMapOf( - Sword::class.java to 6f, - Mace::class.java to 5f, - Scimitar::class.java to 5f, - RoundShield::class.java to 4f, - Sai::class.java to 4f, - Whip::class.java to 4f, - CrystalsSwords::class.java to 4f, - DaggerAxe::class.java to 5f + object T3 : BalancedClassMapGenerator(hashMapOf( + Sword::class to 6f, + Mace::class to 5f, + Scimitar::class to 5f, + RoundShield::class to 4f, + Sai::class to 4f, + Whip::class to 4f, + CrystalsSwords::class to 4f, + DaggerAxe::class to 5f, + InvisibleBlade::class to 5f )) - object T4 : ClassMapGenerator(hashMapOf( - Longsword::class.java to 6f, - BattleAxe::class.java to 5f, - Flail::class.java to 5f, - RunicBlade::class.java to 4f, - AssassinsBlade::class.java to 4f, - SpikeShield::class.java to 5f + object T4 : BalancedClassMapGenerator(hashMapOf( + Longsword::class to 6f, + BattleAxe::class to 5f, + Flail::class to 5f, + RunicBlade::class to 4f, + AssassinsBlade::class to 4f, + SpikeShield::class to 5f, + Pitchfork::class to 5f )) - object T5 : ClassMapGenerator(hashMapOf( - Claymore::class.java to 6f, - WarHammer::class.java to 5f, - Glaive::class.java to 5f, - Greataxe::class.java to 4f, - Greatshield::class.java to 4f, - Lance::class.java to 5f + object T5 : BalancedClassMapGenerator(hashMapOf( + Claymore::class to 6f, + WarHammer::class to 5f, + Glaive::class to 5f, + Greataxe::class to 4f, + Greatshield::class to 4f, + Lance::class to 5f )) private val Ts = arrayOf(T1, T2, T3, T4, T5) @@ -127,150 +153,162 @@ object Generator { return Ts[Random.chances(floorSetTierProbs[fs])].generate() as Weapon } - fun tier(t: Int): ClassMapGenerator = Ts[t - 1] + fun tier(t: Int): ItemGenerator = Ts[t - 1] + + override fun reset() { + for (t in Ts) t.reset() + } } - object MISSSILE : ClassMapGenerator(hashMapOf( + object MISSSILE : BalancedClassMapGenerator(hashMapOf( // 1 - Boomerang::class.java to 0f, - Dart::class.java to 12f, - SmokeSparks::class.java to 6f, + Boomerang::class to 0f, + Dart::class to 12f, + SmokeSparks::class to 6f, // 2 - Shuriken::class.java to 10f, - SwallowDart::class.java to 10f, - IncendiaryDart::class.java to 1f, - CurareDart::class.java to 1f, - CeremonialDagger::class.java to 1f, + Shuriken::class to 10f, + SwallowDart::class to 10f, + IncendiaryDart::class to 1f, + CurareDart::class to 1f, + CeremonialDagger::class to 1f, // 3 - FlyCutter::class.java to 8f, - SeventhDart::class.java to 8f, + FlyCutter::class to 8f, + SeventhDart::class to 8f, // 4 - Javelin::class.java to 6f, + Javelin::class to 6f, // 5 - Tamahawk::class.java to 4f + Tamahawk::class to 4f )) override fun generate(): Item = random(CurrentFloorSet()) + override fun reset() { + MELEE.reset() + MISSSILE.reset() + } + fun random(floorSet: Int): Weapon = (if (Random.Float() < 0.24f) MISSSILE.generate() else MELEE.random(floorSet)) as Weapon } - object POTION : ClassMapGenerator(hashMapOf( - PotionOfHealing::class.java to 20f, - PotionOfExperience::class.java to 4f, - PotionOfToxicGas::class.java to 15f, - PotionOfParalyticGas::class.java to 10f, - PotionOfLiquidFlame::class.java to 15f, - PotionOfLevitation::class.java to 10f, - PotionOfStrength::class.java to 0f, - PotionOfMindVision::class.java to 18f, - PotionOfPhysique::class.java to 4f, - PotionOfPurity::class.java to 12f, - PotionOfInvisibility::class.java to 10f, - PotionOfMight::class.java to 0f, - PotionOfFrost::class.java to 10f + object POTION : BalancedClassMapGenerator(hashMapOf( + PotionOfHealing::class to 20f, + PotionOfExperience::class to 4f, + PotionOfToxicGas::class to 15f, + PotionOfParalyticGas::class to 10f, + PotionOfLiquidFlame::class to 15f, + PotionOfLevitation::class to 10f, + PotionOfStrength::class to 0f, + PotionOfMindVision::class to 18f, + PotionOfPhysique::class to 4f, + PotionOfPurity::class to 12f, + PotionOfInvisibility::class to 10f, + PotionOfMight::class to 0f, + PotionOfFrost::class to 10f )) - object SCROLL : ClassMapGenerator(hashMapOf( - ScrollOfIdentify::class.java to 30f, - ScrollOfTeleportation::class.java to 10f, - ScrollOfRemoveCurse::class.java to 20f, - ScrollOfUpgrade::class.java to 0f, - ScrollOfRecharging::class.java to 15f, - ScrollOfMagicMapping::class.java to 15f, - ScrollOfRage::class.java to 12f, - ScrollOfTerror::class.java to 8f, - ScrollOfLullaby::class.java to 8f, - ScrollOfEnchanting::class.java to 6f, - ScrollOfPsionicBlast::class.java to 4f, - ScrollOfMirrorImage::class.java to 10f, - ScrollOfCurse::class.java to 4f, - ScrollOfLight::class.java to 6f + object SCROLL : BalancedClassMapGenerator(hashMapOf( + ScrollOfIdentify::class to 30f, + ScrollOfTeleportation::class to 10f, + ScrollOfRemoveCurse::class to 20f, + ScrollOfUpgrade::class to 0f, + ScrollOfRecharging::class to 15f, + ScrollOfMagicMapping::class to 15f, + ScrollOfRage::class to 12f, + ScrollOfTerror::class to 8f, + ScrollOfLullaby::class to 8f, + ScrollOfEnchanting::class to 6f, + ScrollOfPsionicBlast::class to 4f, + ScrollOfMirrorImage::class to 10f, + ScrollOfCurse::class to 4f, + ScrollOfLight::class to 6f )) - object WAND : ClassMapGenerator(hashMapOf( - WandOfMagicMissile::class.java to 5f, - WandOfLightning::class.java to 4f, - WandOfDisintegration::class.java to 4f, - WandOfFireblast::class.java to 4f, - WandOfVenom::class.java to 4f, - WandOfBlastWave::class.java to 3f, - WandOfFrost::class.java to 3f, - WandOfPrismaticLight::class.java to 3f, - // WandOfTransfusion::class.java to 3f, - WandOfAbel::class.java to 3f, - WandOfCorruption::class.java to 3f, - WandOfRegrowth::class.java to 3f + object WAND : BalancedClassMapGenerator(hashMapOf( + WandOfMagicMissile::class to 5f, + WandOfLightning::class to 4f, + WandOfDisintegration::class to 4f, + WandOfFireblast::class to 4f, + WandOfVenom::class to 4f, + WandOfBlastWave::class to 3f, + WandOfFrost::class to 3f, + WandOfPrismaticLight::class to 3f, + // WandOfTransfusion::class to 3f, + WandOfAbel::class to 3f, + WandOfCorruption::class to 3f, + WandOfRegrowth::class to 3f, + WandOfHypnosis::class to 3f )) - object RING : ClassMapGenerator(hashMapOf( - // RingOfAccuracy::class.java to 1f, - RingOfArcane::class.java to 1f, - RingOfEvasion::class.java to 1f, - RingOfResistance::class.java to 1f, - RingOfForce::class.java to 1f, - RingOfFuror::class.java to 1f, - RingOfHaste::class.java to 1f, - RingOfCritical::class.java to 1f, - RingOfMight::class.java to 1f, - RingOfSharpshooting::class.java to 1f, - RingOfHealth::class.java to 1f, - RingOfWealth::class.java to 1f + object RING : BalancedClassMapGenerator(hashMapOf( + // RingOfAccuracy::class to 1f, + RingOfArcane::class to 1f, + RingOfEvasion::class to 1f, + RingOfResistance::class to 1f, + RingOfForce::class to 1f, + RingOfFuror::class to 1f, + RingOfHaste::class to 1f, + RingOfCritical::class to 1f, + RingOfMight::class to 1f, + RingOfSharpshooting::class to 1f, + RingOfHealth::class to 1f, + RingOfWealth::class to 1f )) - object SEED : ClassMapGenerator(hashMapOf( - Firebloom.Seed::class.java to 12f, - Icecap.Seed::class.java to 12f, - Sorrowmoss.Seed::class.java to 12f, - Blindweed.Seed::class.java to 12f, - Sungrass.Seed::class.java to 12f, - Earthroot.Seed::class.java to 12f, - Fadeleaf.Seed::class.java to 12f, - Rotberry.Seed::class.java to 0f, - BlandfruitBush.Seed::class.java to 2f, - Dreamfoil.Seed::class.java to 12f, - Stormvine.Seed::class.java to 12f, - Starflower.Seed::class.java to 1f + object SEED : BalancedClassMapGenerator(hashMapOf( + Firebloom.Seed::class to 12f, + Icecap.Seed::class to 12f, + Sorrowmoss.Seed::class to 12f, + Blindweed.Seed::class to 12f, + Sungrass.Seed::class to 12f, + Earthroot.Seed::class to 12f, + Fadeleaf.Seed::class to 12f, + Rotberry.Seed::class to 0f, + BlandfruitBush.Seed::class to 2f, + Dreamfoil.Seed::class to 12f, + Stormvine.Seed::class to 12f, + Starflower.Seed::class to 1f )) - object FOOD : ClassMapGenerator(hashMapOf( - Food::class.java to 4f, - Pasty::class.java to 1.25f, - MysteryMeat::class.java to 0f + object FOOD : BalancedClassMapGenerator(hashMapOf( + Food::class to 4f, + Pasty::class to 1f, + MysteryMeat::class to 0f )) - object GOLD : ClassMapGenerator(hashMapOf( - Gold::class.java to 1f + object GOLD : ClassMapGenerator(hashMapOf( + Gold::class to 1f )) // artifact is uniquely dropping val INITIAL_ARTIFACT_PROBS = hashMapOf( - CapeOfThorns::class.java to 0f, // by DM300 - ChaliceOfBlood::class.java to 0f, // by statuary - CloakOfShadows::class.java to 0f, // for rouge - CrackedCoin::class.java to 1f, - HornOfPlenty::class.java to 1f, - MasterThievesArmband::class.java to 0f, // by thief - SandalsOfNature::class.java to 1f, - TalismanOfForesight::class.java to 1f, - TimekeepersHourglass::class.java to 1f, - UnstableSpellbook::class.java to 1f, - AlchemistsToolkit::class.java to 0f, // currently removed from drop tables, - DriedRose::class.java to 0f, // starts with no chance of spawning, chance is set directly after beating ghost quest. - LloydsBeacon::class.java to 0f, // by goo - EtherealChains::class.java to 1f, - RiemannianManifoldShield::class.java to 1f, - GoldPlatedStatue::class.java to 1f, - HandOfTheElder::class.java to 0f, // by undead - HandleOfAbyss::class.java to 1f, - HeartOfSatan::class.java to 1f, - CloakOfSheep::class.java to 1f, - EyeballOfTheElder.Right::class.java to 1f, - EyeballOfTheElder.Left::class.java to 1f + CapeOfThorns::class to 1f, + ChaliceOfBlood::class to 0f, // by statuary + CloakOfShadows::class to 0f, // for rouge + CrackedCoin::class to 1f, + HornOfPlenty::class to 1f, + MasterThievesArmband::class to 0f, // by thief + SandalsOfNature::class to 1f, + TalismanOfForesight::class to 1f, + TimekeepersHourglass::class to 1f, + UnstableSpellbook::class to 1f, + AlchemistsToolkit::class to 0f, // currently removed from drop tables, + DriedRose::class to 0f, // starts with no chance of spawning, chance is set directly after beating ghost quest. + LloydsBeacon::class to 0f, // by goo + EtherealChains::class to 1f, + RiemannianManifoldShield::class to 1f, + GoldPlatedStatue::class to 1f, + HandOfTheElder::class to 0f, // by undead + HandleOfAbyss::class to 1f, + HeartOfSatan::class to 1f, + CloakOfSheep::class to 1f, + EyeballOfTheElder.Right::class to 1f, + EyeballOfTheElder.Left::class to 1f, + // HomurasShield::class to 0.5f, + DragonsSquama::class to 1f ) - object ARTIFACT : ClassMapGenerator(HashMap()), Bundlable { + object ARTIFACT : ClassMapGenerator(HashMap()), Bundlable { private val spawned = ArrayList() init { @@ -283,11 +321,11 @@ object Generator { // be unique probMap[cls] = 0f - spawned.add(cls.simpleName) - return cls.newInstance().random() + spawned.add(cls.java.simpleName) + return cls.java.newInstance().random() } - private val lastProbMap = HashMap, Float>() + private val lastProbMap = HashMap, Float>() private val lastSpawned = ArrayList() fun push() { probMap.toMap(lastProbMap) @@ -301,7 +339,7 @@ object Generator { spawned.addAll(lastSpawned) } - fun reset() { + override fun reset() { spawned.clear() updateProbabilities() } @@ -320,15 +358,18 @@ object Generator { private fun updateProbabilities() { probMap.clear() for (pr in INITIAL_ARTIFACT_PROBS) - probMap[pr.key] = if (spawned.contains(pr.key.simpleName)) 0f else pr.value + probMap[pr.key] = if (spawned.contains(pr.key.java.simpleName)) 0f else pr.value } // save the probs private const val SPAWNED_ARTIFACTS = "spawned-artifacts" + override fun storeInBundle(bundle: Bundle) { + bundle.put(SPAWNED_ARTIFACTS, spawned.toTypedArray()) + } + override fun restoreFromBundle(bundle: Bundle) { - if (Ghost.Quest.completed()) - probMap[DriedRose::class.java] = 1f + if (Ghost.Quest.completed()) probMap[DriedRose::class] = 1f if (bundle.contains(SPAWNED_ARTIFACTS)) { spawned.addAll(bundle.getStringArray(SPAWNED_ARTIFACTS)) @@ -336,42 +377,39 @@ object Generator { updateProbabilities() } } - - override fun storeInBundle(bundle: Bundle) { - bundle.put(SPAWNED_ARTIFACTS, spawned.toTypedArray()) - } } - object HELMET : ClassMapGenerator(hashMapOf( - HelmetBarbarian::class.java to 1f, - HelmetCrusader::class.java to 1f, - HoodApprentice::class.java to 1f, - LittlePail::class.java to 1f, - CircletEmerald::class.java to 1f, - CrownOfDwarf::class.java to 0f, // by king - HeaddressRegeneration::class.java to 1f, - WizardHat::class.java to 1f, - MaskOfHorror::class.java to 1f, - MaskOfClown::class.java to 1f, - RangerHat::class.java to 0.2f, // very rare, so Yvette counts. - MaskOfMadness::class.java to 0f, // compose - TurtleScarf::class.java to 1f, - MaskOfLider::class.java to 0.2f + object HELMET : BalancedClassMapGenerator(hashMapOf( + HelmetBarbarian::class to 1f, + HelmetCrusader::class to 1f, + HoodApprentice::class to 1f, + LittlePail::class to 1f, + CircletEmerald::class to 1f, + CrownOfDwarf::class to 0f, // by king + HeaddressRegeneration::class to 1f, + WizardHat::class to 1f, + MaskOfHorror::class to 1f, + MaskOfClown::class to 1f, + RangerHat::class to 0.2f, // very rare, so Yvette counts. + MaskOfMadness::class to 0f, // compose + TurtleScarf::class to 1f, + MaskOfLider::class to 0.1f, + GuardHelmet::class to 0.2f )) - object BOOK : ClassMapGenerator(hashMapOf( - CallysDiary::class.java to 0f, - WardenSmithNotes::class.java to 0f + object BOOK : BalancedClassMapGenerator(hashMapOf( + CallysDiary::class to 0f, + WardenSmithNotes::class to 0f )) - object RUNE : ClassMapGenerator(hashMapOf( - RegenerationRune::class.java to 1f, - MendingRune::class.java to 1f, - CriticalRune::class.java to 0.5f, - BrightRune::class.java to 1f, - HasteRune::class.java to 1f, - TreasureRune::class.java to 1f, - BloodRune::class.java to 0f // from unholy blood + object RUNE : BalancedClassMapGenerator(hashMapOf( + RegenerationRune::class to 1f, + MendingRune::class to 1f, + CriticalRune::class to 0.5f, + BrightRune::class to 1f, + HasteRune::class to 1f, + TreasureRune::class to 1f, + BloodRune::class to 0f // from unholy blood )) // @@ -382,7 +420,7 @@ object Generator { SCROLL to 400f, WAND to 40f, RING to 15f, - ARTIFACT to 15f, + ARTIFACT to 10f, SEED to 50f, FOOD to 0f, GOLD to 500f, @@ -394,31 +432,61 @@ object Generator { private val categoryMap = HashMap() init { - ResetCategoryProbs() + resetCategoryProbs() } - fun ResetCategoryProbs() { + fun resetCategoryProbs() { categoryMap.clear() for (pr in InitCategoryMap) categoryMap[pr.key] = pr.value } fun generate(): Item { val cat = Random.chances(categoryMap) - categoryMap[cat] = categoryMap[cat]!! / 2f + categoryMap[cat] = categoryMap[cat]!! / 2f // simply lower its probs return cat.generate() } + // reset all prob: for start a new game fun reset() { + ARMOR.reset() + WEAPON.reset() + POTION.reset() + SCROLL.reset() + WAND.reset() + RING.reset() + SEED.reset() + FOOD.reset() + GOLD.reset() ARTIFACT.reset() + HELMET.reset() + BOOK.reset() + RUNE.reset() } fun stash() { ARTIFACT.push() + //todo: i may stash the balanced map, this keep the probmap consistent, until the player restart the game instead. } fun recover() { ARTIFACT.pop() + // currently, each time a new level is generated, the balanced prob map would be reset. + //fixme: see 'todo' in stash(), + + ARMOR.reset() + WEAPON.reset() + POTION.reset() + SCROLL.reset() + WAND.reset() + RING.reset() + SEED.reset() + FOOD.reset() + GOLD.reset() + // ARTIFACT.reset() + HELMET.reset() + BOOK.reset() + RUNE.reset() } fun restoreFromBundle(bundle: Bundle) { diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/Item.java b/core/src/main/java/com/egoal/darkestpixeldungeon/items/Item.java index 5a922e3dd..286ae278c 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/Item.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/Item.java @@ -412,7 +412,7 @@ public int price() { public int sellPrice() { //! the quantity affect the price() function - return price() * (Dungeon.depth + 4); + return price() * (Dungeon.depth/3*3 + 4); } public static Item virtual(Class cl) { diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/ClassArmor.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/ClassArmor.kt index 68f58baa0..c8034e601 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/ClassArmor.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/ClassArmor.kt @@ -29,6 +29,8 @@ import com.egoal.darkestpixeldungeon.utils.GLog import com.watabou.utils.Bundle import java.util.ArrayList +import kotlin.math.max +import kotlin.math.round abstract class ClassArmor : Armor(6) { private var armorTier: Int = 0 @@ -78,13 +80,15 @@ abstract class ClassArmor : Armor(6) { abstract fun doSpecial() override fun STRReq(lvl: Int): Int { - var lvl = Math.max(0, lvl) - var effectiveTier = armorTier.toFloat() + val level = max(0, lvl) + + var effectiveTier = if (armorTier == 0) -1.5f else armorTier.toFloat() //todo: this is just a hotfix to compatible with ragged armor. if (glyph != null) effectiveTier += glyph.tierSTRAdjust() - effectiveTier = Math.max(0f, effectiveTier) + effectiveTier = max(0f, effectiveTier) + return 8 + round(effectiveTier * 2f).toInt() - (level + 1) / 2 // +1, +3, +5, +7 //strength req decreases at +1,+3,+6,+10,etc. - return 8 + Math.round(effectiveTier * 2) - (Math.sqrt((8 * lvl + 1).toDouble()) - 1).toInt() / 2 +// return 8 + Math.round(effectiveTier * 2) - (Math.sqrt((8 * lvl + 1).toDouble()) - 1).toInt() / 2 } override fun DRMax(lvl: Int): Int { diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/RaggedArmor.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/RaggedArmor.kt new file mode 100644 index 000000000..e858a1812 --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/RaggedArmor.kt @@ -0,0 +1,24 @@ +package com.egoal.darkestpixeldungeon.items.armor + +import com.egoal.darkestpixeldungeon.sprites.ItemSpriteSheet +import kotlin.math.max + +//todo: do not use tier 0 +class RaggedArmor : Armor(0) { + init { + image = ItemSpriteSheet.ARMOR_RAGGED + + bones = false + } + + //todo: seal this + override fun DRMax(lvl: Int): Int { + var effectiveTier = 1 + if (glyph != null) effectiveTier += glyph.tierDRAdjust() + effectiveTier = max(0, effectiveTier) + + return max(DRMin(lvl), effectiveTier * (1 + lvl)) + } + + override fun STRReq(lvl: Int): Int = super.STRReq(lvl) - 3 +} \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/SorceressArmor.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/SorceressArmor.kt index 8bf94b7a0..398ef3116 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/SorceressArmor.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/SorceressArmor.kt @@ -15,7 +15,7 @@ import com.watabou.noosa.audio.Sample class SorceressArmor : ClassArmor() { init { - image = ItemSpriteSheet.DPD_ARMOR_SORCERESS + image = ItemSpriteSheet.ARMOR_SORCERESS } override fun doSpecial() { diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/curses/Multiplicity.java b/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/curses/Multiplicity.java deleted file mode 100644 index 034f7a766..000000000 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/curses/Multiplicity.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Pixel Dungeon - * Copyright (C) 2012-2015 Oleg Dolya - * - * Shattered Pixel Dungeon - * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.items.armor.curses; - -import com.egoal.darkestpixeldungeon.actors.Damage; -import com.egoal.darkestpixeldungeon.actors.hero.Hero; -import com.egoal.darkestpixeldungeon.Dungeon; -import com.egoal.darkestpixeldungeon.DarkestPixelDungeon; -import com.egoal.darkestpixeldungeon.actors.Actor; -import com.egoal.darkestpixeldungeon.actors.Char; -import com.egoal.darkestpixeldungeon.actors.mobs.Bestiary; -import com.egoal.darkestpixeldungeon.actors.mobs.Mob; -import com.egoal.darkestpixeldungeon.actors.mobs.npcs.MirrorImage; -import com.egoal.darkestpixeldungeon.items.armor.Armor; -import com.egoal.darkestpixeldungeon.items.scrolls.ScrollOfTeleportation; -import com.egoal.darkestpixeldungeon.levels.Level; -import com.egoal.darkestpixeldungeon.scenes.GameScene; -import com.egoal.darkestpixeldungeon.sprites.ItemSprite; -import com.watabou.utils.Bundle; -import com.watabou.utils.PathFinder; -import com.watabou.utils.Random; - -import java.util.ArrayList; - -public class Multiplicity extends Armor.Glyph { - - private static ItemSprite.Glowing BLACK = new ItemSprite.Glowing(0x000000); - - @Override - public Damage proc(Armor armor, Damage damage) { - Char attacker = (Char) damage.from; - Char defender = (Char) damage.to; - - if (Random.Int(20) == 0) { - ArrayList spawnPoints = new ArrayList<>(); - - for (int i = 0; i < PathFinder.NEIGHBOURS8.length; i++) { - int p = defender.pos + PathFinder.NEIGHBOURS8[i]; - if (Actor.findChar(p) == null && (Level.Companion.getPassable()[p] || Level.Companion.getAvoid()[p])) { - spawnPoints.add(p); - } - } - - if (spawnPoints.size() > 0) { - - Mob m = null; - if (Random.Int(2) == 0 && defender instanceof Hero) { - m = new MirrorImage(); - ((MirrorImage) m).duplicate((Hero) defender); - - } else { - if (attacker.properties().contains(Char.Property.BOSS) || attacker - .properties().contains(Char.Property.MINIBOSS)) { - m = Bestiary.INSTANCE.mutable(Dungeon.depth % 5 == 0 ? Dungeon.depth - 1 : - Dungeon.depth); - } else { - try { - m = (Mob) attacker.getClass().newInstance(); - Bundle store = new Bundle(); - attacker.storeInBundle(store); - m.restoreFromBundle(store); - m.HP = m.HT; - } catch (Exception e) { - DarkestPixelDungeon.reportException(e); - m = null; - } - } - - } - - if (m != null) { - GameScene.add(m); - ScrollOfTeleportation.Companion.appear(m, Random.element(spawnPoints)); - } - - } - } - - return damage; - } - - @Override - public ItemSprite.Glowing glowing() { - return BLACK; - } - - @Override - public boolean curse() { - return true; - } -} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/curses/Multiplicity.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/curses/Multiplicity.kt new file mode 100644 index 000000000..731e457e0 --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/curses/Multiplicity.kt @@ -0,0 +1,97 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.items.armor.curses + +import com.egoal.darkestpixeldungeon.actors.Damage +import com.egoal.darkestpixeldungeon.actors.hero.Hero +import com.egoal.darkestpixeldungeon.Dungeon +import com.egoal.darkestpixeldungeon.DarkestPixelDungeon +import com.egoal.darkestpixeldungeon.actors.Actor +import com.egoal.darkestpixeldungeon.actors.Char +import com.egoal.darkestpixeldungeon.actors.mobs.Bestiary +import com.egoal.darkestpixeldungeon.actors.mobs.Mob +import com.egoal.darkestpixeldungeon.actors.mobs.npcs.MirrorImage +import com.egoal.darkestpixeldungeon.items.armor.Armor +import com.egoal.darkestpixeldungeon.items.scrolls.ScrollOfTeleportation +import com.egoal.darkestpixeldungeon.levels.Level +import com.egoal.darkestpixeldungeon.scenes.GameScene +import com.egoal.darkestpixeldungeon.sprites.ItemSprite +import com.watabou.utils.Bundle +import com.watabou.utils.PathFinder +import com.watabou.utils.Random + +import java.util.ArrayList + +class Multiplicity : Armor.Glyph() { + + override fun proc(armor: Armor, damage: Damage): Damage { + val attacker = damage.from as Char + val defender = damage.to as Char + + if (Random.Int(20) == 0) { + val avalpts = PathFinder.NEIGHBOURS8.map { it + defender.pos }.filter { + Actor.findChar(it) == null && (Level.passable[it] || Level.avoid[it]) + } + + if (avalpts.isNotEmpty()) { + var m: Mob? = null + if (Random.Int(2) == 0 && defender is Hero) + m = MirrorImage().apply { duplicate(defender) } + else { + val props = attacker.properties() + if (props.contains(Char.Property.BOSS) || props.contains(Char.Property.MINIBOSS) || props.contains(Char.Property.PHANTOM)) { + m = Bestiary.mutable(if (Dungeon.bossLevel()) Dungeon.depth - 1 else Dungeon.depth) + } else { + try { + m = attacker.javaClass.newInstance() as Mob + // now we just make a new instance... + // copy +// val store = Bundle() +// attacker.storeInBundle(store) +// m.restoreFromBundle(store) +// m.HP = m.HT + m.properties().add(Char.Property.PHANTOM) + } catch (e: Exception) { + DarkestPixelDungeon.reportException(e) + m = null + } + } + + } + + if (m != null) { + GameScene.add(m) + ScrollOfTeleportation.appear(m, avalpts.random()) + } + } + } + + return damage + } + + override fun glowing(): ItemSprite.Glowing = BLACK + + override fun curse(): Boolean = true + + companion object { + private val BLACK = ItemSprite.Glowing(0x000000) + } +} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/glyphs/Swiftness.java b/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/glyphs/Swiftness.kt similarity index 55% rename from core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/glyphs/Swiftness.java rename to core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/glyphs/Swiftness.kt index e0085bdbd..708dda447 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/glyphs/Swiftness.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/armor/glyphs/Swiftness.kt @@ -18,36 +18,25 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see */ -package com.egoal.darkestpixeldungeon.items.armor.glyphs; +package com.egoal.darkestpixeldungeon.items.armor.glyphs -import com.egoal.darkestpixeldungeon.actors.Char; -import com.egoal.darkestpixeldungeon.actors.Damage; -import com.egoal.darkestpixeldungeon.items.armor.Armor; -import com.egoal.darkestpixeldungeon.sprites.ItemSprite; +import com.egoal.darkestpixeldungeon.actors.Damage +import com.egoal.darkestpixeldungeon.items.armor.Armor +import com.egoal.darkestpixeldungeon.sprites.ItemSprite -public class Swiftness extends Armor.Glyph { +class Swiftness : Armor.Glyph() { - private static ItemSprite.Glowing YELLOW = new ItemSprite.Glowing(0xFFFF00); - - @Override - public Damage proc(Armor armor, Damage damage) { //no proc effect, see hero.defenseskill and hero.speed for effect. - return damage; - } - - @Override - public int tierDRAdjust() { - return -2; - } - - @Override - public float tierSTRAdjust() { - return -1; - } - - @Override - public ItemSprite.Glowing glowing() { - return YELLOW; - } + override fun proc(armor: Armor, damage: Damage): Damage = damage + + override fun tierDRAdjust(): Int = -2 + + override fun tierSTRAdjust(): Float = -1f + + override fun glowing(): ItemSprite.Glowing = YELLOW + + companion object { + private val YELLOW = ItemSprite.Glowing(0xFFFF00) + } } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/artifacts/CapeOfThorns.java b/core/src/main/java/com/egoal/darkestpixeldungeon/items/artifacts/CapeOfThorns.java index fc4cd1cfb..080fedcd9 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/artifacts/CapeOfThorns.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/artifacts/CapeOfThorns.java @@ -84,6 +84,9 @@ public boolean act() { } public Damage proc(Damage dmg){ + Hero hero = (Hero)dmg.to; + if(hero.STR()<16) return dmg; + if(cooldown==0){ // getting charged charge += dmg.value*(.5+level()*.05); @@ -98,9 +101,7 @@ public Damage proc(Damage dmg){ int deflected = Random.NormalIntRange(0, dmg.value); dmg.value -= deflected; - if(dmg.from instanceof Mob && dmg.to instanceof Hero && - Dungeon.level.adjacent(((Mob) dmg.from).pos, - ((Hero) dmg.to).pos)) + if(dmg.from instanceof Mob && Dungeon.level.adjacent(((Mob) dmg.from).pos, hero.pos)) ((Mob) dmg.from).takeDamage(new Damage(deflected, dmg.to, dmg.from)); exp += deflected; diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/artifacts/DragonsSquama.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/artifacts/DragonsSquama.kt new file mode 100644 index 000000000..b33a714de --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/artifacts/DragonsSquama.kt @@ -0,0 +1,138 @@ +package com.egoal.darkestpixeldungeon.items.artifacts + +import com.egoal.darkestpixeldungeon.Dungeon +import com.egoal.darkestpixeldungeon.actors.Actor +import com.egoal.darkestpixeldungeon.actors.Char +import com.egoal.darkestpixeldungeon.actors.Damage +import com.egoal.darkestpixeldungeon.actors.blobs.Blob +import com.egoal.darkestpixeldungeon.actors.blobs.Fire +import com.egoal.darkestpixeldungeon.actors.buffs.Buff +import com.egoal.darkestpixeldungeon.actors.buffs.Shock +import com.egoal.darkestpixeldungeon.actors.hero.Hero +import com.egoal.darkestpixeldungeon.effects.MagicMissile +import com.egoal.darkestpixeldungeon.levels.Level +import com.egoal.darkestpixeldungeon.messages.M +import com.egoal.darkestpixeldungeon.scenes.GameScene +import com.egoal.darkestpixeldungeon.sprites.ItemSpriteSheet +import com.egoal.darkestpixeldungeon.utils.BArray +import com.egoal.darkestpixeldungeon.utils.GLog +import com.watabou.utils.PathFinder +import com.watabou.utils.Random +import java.util.ArrayList +import kotlin.math.min +import kotlin.math.round +import kotlin.math.sqrt + +class DragonsSquama : Artifact() { + init { + image = ItemSpriteSheet.DARGONS_SQUAMA + + levelCap = 10 + chargeCap = 100 + charge = chargeCap + + defaultAction = AC_TAP + } + + override fun actions(hero: Hero): ArrayList = super.actions(hero).apply { add(AC_TAP) } + + override fun execute(hero: Hero, action: String) { + super.execute(hero, action) + + if (action == AC_TAP) { + if (!isEquipped(hero)) GLog.w(M.L(Artifact::class.java, "need_to_equip")) + else if (cursed) GLog.w(M.L(this, "cursed")) + else if (charge < chargeCap) GLog.w(M.L(this, "no_charge")) + else superNova(hero) + } + } + + override fun doEquip(hero: Hero): Boolean { + val re = super.doEquip(hero) + if (re) hero.elementalResistance[0] += 0.6f //todo: 0-> fire, this is fragile + return re + } + + override fun doUnequip(hero: Hero, collect: Boolean, single: Boolean): Boolean { + val re = super.doUnequip(hero, collect, single) + if (re) hero.elementalResistance[0] -= 0.6f + return re + } + + override fun desc(): String { + var desc = super.desc() + if (isEquipped(Dungeon.hero)) + if (cursed) desc += "\n\n" + M.L(this, "desc_cursed") + else desc += "\n\n" + M.L(this, "desc_hint") + return desc + } + + private fun superNova(hero: Hero) { + charge = 0 + exp += 1 + val requireExp = (6f * sqrt(level().toFloat())).toInt() + 3 * level() + 1 + if (exp > requireExp && level() < levelCap) { + exp -= requireExp + upgrade() + GLog.p(M.L(this, "levelup")) + } + + hero.sprite.operate(hero.pos) + + val radius = 3 + level() / 3 + PathFinder.buildDistanceMap(hero.pos, BArray.not(Level.solid, null), radius) + + // (0 until PathFinder.distance) + val affectedCells = PathFinder.distance.indices.filter { + val dis = PathFinder.distance[it] + dis < Int.MAX_VALUE + } + + val last = affectedCells.maxBy { PathFinder.distance[it] } + + for (cell in affectedCells) { + if (cell != last) MagicMissile.fire(hero.sprite.parent, hero.pos, cell, null) + else + MagicMissile.fire(hero.sprite.parent, hero.pos, hero.pos) { + // burn the ground + for (i in affectedCells) + if (i != hero.pos) GameScene.add(Blob.seed(i, 1, Fire::class.java)) + + affectedCells.mapNotNull { Actor.findChar(it) }.forEach { burnChar(it) } + hero.spendAndNext(1f) + } + } + } + + private fun burnChar(char: Char) { + val value = Random.IntRange(2 + 2 * level(), 6 + 5 * level()) + val dmg = Damage(value, Dungeon.hero, char).type(Damage.Type.MAGICAL).addElement(Damage.Element.FIRE) + char.takeDamage(dmg) + if (char.isAlive && char !is Hero) { + Buff.prolong(char, Shock::class.java, 1.5f) + } + } + + override fun passiveBuff(): ArtifactBuff = Recharge() + + inner class Recharge : ArtifactBuff() { + fun procTakenDamage(damage: Damage) { + if (damage.type == Damage.Type.MENTAL) return + + val isCrit = damage.isFeatured(Damage.Feature.CRITICAL) + if (isCrit) { + val block = round(damage.value * (0.12f + 0.01f * level())).toInt() + damage.value += if (cursed) block else -block + } + + if (charge < chargeCap && damage.from is Char && damage.from !== Char.Nobody.INSTANCE) { + charge = min(chargeCap, charge + (4 - level() / 5) + if (isCrit) 1 else 0) + updateQuickslot() + } + } + } + + companion object { + private const val AC_TAP = "tap" + } +} \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/artifacts/HomurasShield.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/artifacts/HomurasShield.kt new file mode 100644 index 000000000..bc35f4f85 --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/artifacts/HomurasShield.kt @@ -0,0 +1,71 @@ +package com.egoal.darkestpixeldungeon.items.artifacts + +import com.egoal.darkestpixeldungeon.Dungeon +import com.egoal.darkestpixeldungeon.actors.hero.Hero +import com.egoal.darkestpixeldungeon.actors.mobs.npcs.GhostHero +import com.egoal.darkestpixeldungeon.messages.M +import com.egoal.darkestpixeldungeon.scenes.GameScene +import com.egoal.darkestpixeldungeon.scenes.InterlevelScene +import com.egoal.darkestpixeldungeon.sprites.ItemSprite +import com.egoal.darkestpixeldungeon.sprites.ItemSpriteSheet +import com.egoal.darkestpixeldungeon.utils.GLog +import com.egoal.darkestpixeldungeon.windows.WndOptions +import com.watabou.noosa.Game +import java.util.ArrayList + +class HomurasShield : Artifact() { + init { + image = ItemSpriteSheet.ARTIFACT_SHIELD + + levelCap = 1 + chargeCap = 100 + charge = 0 + } + + override fun actions(hero: Hero): ArrayList = super.actions(hero).apply { add(AC_REFLUX) } + + override fun execute(hero: Hero, action: String) { + super.execute(hero, action) + + if (action == AC_REFLUX) { + if (!isEquipped(hero)) GLog.w(M.L(Artifact::class.java, "need_to_equip")) + else if (cursed) GLog.w(M.L(this, "cursed")) + else if (charge < chargeCap) GLog.w(M.L(this, "no_charge")) + else { + GameScene.show(object : WndOptions(ItemSprite(this), M.L(this, "name"), + M.L(this, "return_warn"), M.L(this, "yes"), M.L(this, "no")) { + override fun onSelect(index: Int) { + if (index == 0) reflux() + } + }) + } + } + } + + private fun reflux() { + // remove it... + if (isEquipped(Dungeon.hero)) doUnequip(Dungeon.hero, false) + detachAll(Dungeon.hero.belongings.backpack) + + Dungeon.hero.buff(TimekeepersHourglass.TimeFreeze::class.java)?.detach() + + Dungeon.level.mobs.filterIsInstance().forEach { it.destroy() } + + InterlevelScene.mode = InterlevelScene.Mode.BACK_TO_PAST + Game.switchScene(InterlevelScene::class.java) + } + + override fun desc(): String { + var desc = super.desc() + if (isEquipped(Dungeon.hero)) desc += "\n\n" + M.L(this, "desc_hint") + return desc + } + + override fun passiveBuff(): ArtifactBuff = Recharge() + + inner class Recharge : ArtifactBuff() + + companion object { + private const val AC_REFLUX = "reflux" + } +} \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/artifacts/LloydsBeacon.java b/core/src/main/java/com/egoal/darkestpixeldungeon/items/artifacts/LloydsBeacon.java index 81317aae6..895571482 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/artifacts/LloydsBeacon.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/artifacts/LloydsBeacon.java @@ -169,9 +169,9 @@ public void execute(Hero hero, String action) { for (Mob mob : Dungeon.level.getMobs().toArray(new Mob[0])) if (mob instanceof GhostHero) mob.destroy(); - InterlevelScene.mode = InterlevelScene.Mode.RETURN; - InterlevelScene.returnDepth = returnDepth; - InterlevelScene.returnPos = returnPos; + InterlevelScene.Companion.setMode(InterlevelScene.Mode.RETURN); + InterlevelScene.Companion.setReturnDepth(returnDepth); + InterlevelScene.Companion.setReturnPos(returnPos); Game.switchScene(InterlevelScene.class); } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/artifacts/UnstableSpellbook.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/artifacts/UnstableSpellbook.kt index 627812164..710eac449 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/artifacts/UnstableSpellbook.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/artifacts/UnstableSpellbook.kt @@ -92,7 +92,7 @@ class UnstableSpellbook : Artifact() { // "sort" by prob val scrollprobs = HashMap, Float>() - scrollprobs.putAll(Generator.SCROLL.probMap) + for (pr in Generator.SCROLL.initialProbs) scrollprobs[pr.key.java as Class] = pr.value var cls = Random.chances(scrollprobs) while (cls != null) { diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/books/TomeOfPerk.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/books/TomeOfPerk.kt index b3d1d0932..bd29944e9 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/books/TomeOfPerk.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/books/TomeOfPerk.kt @@ -6,11 +6,13 @@ import com.egoal.darkestpixeldungeon.sprites.ItemSpriteSheet class TomeOfPerk : Book() { init { image = ItemSpriteSheet.MASTERY + + unique = true // consider: stolen/resurrect } override fun isIdentified(): Boolean = true - override fun price(): Int = 0 + override fun price(): Int = 100 override fun doRead(hero: Hero) { detach(hero.belongings.backpack) diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/books/TomeOfRetrain.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/books/TomeOfRetrain.kt new file mode 100644 index 000000000..1026c5860 --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/books/TomeOfRetrain.kt @@ -0,0 +1,40 @@ +package com.egoal.darkestpixeldungeon.items.books + +import com.egoal.darkestpixeldungeon.actors.hero.Hero +import com.egoal.darkestpixeldungeon.actors.hero.perks.Perk +import com.egoal.darkestpixeldungeon.actors.hero.perks.RavenousAppetite +import com.egoal.darkestpixeldungeon.messages.M +import com.egoal.darkestpixeldungeon.scenes.GameScene +import com.egoal.darkestpixeldungeon.sprites.ItemSpriteSheet +import com.egoal.darkestpixeldungeon.utils.GLog +import com.egoal.darkestpixeldungeon.windows.WndSelectPerk + +class TomeOfRetrain : Book() { + init { + image = ItemSpriteSheet.TOME_BLUE + + unique = true + } + + override fun isIdentified(): Boolean = true + + override fun price(): Int = 100 + + override fun doRead(hero: Hero) { + //todo: refactor + val perks = hero.heroPerk.perks.filter { it !is RavenousAppetite } + if (perks.isEmpty()) { + GLog.w(M.L(Book::class.java, "cannot_understand")) + return + } + + GameScene.show(object : WndSelectPerk(M.L(TomeOfRetrain::class.java, "select_perk"), perks) { + override fun onPerkSelected(perk: Perk) { + hero.heroPerk.downgrade(perk) + hero.reservedPerks += 1 + + detach(hero.belongings.backpack) + } + }) + } +} \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/books/TomeOfUpgrade.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/books/TomeOfUpgrade.kt new file mode 100644 index 000000000..72ed4c0da --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/books/TomeOfUpgrade.kt @@ -0,0 +1,41 @@ +package com.egoal.darkestpixeldungeon.items.books + +import com.egoal.darkestpixeldungeon.actors.hero.Hero +import com.egoal.darkestpixeldungeon.actors.hero.perks.Perk +import com.egoal.darkestpixeldungeon.effects.PerkGain +import com.egoal.darkestpixeldungeon.messages.M +import com.egoal.darkestpixeldungeon.scenes.GameScene +import com.egoal.darkestpixeldungeon.sprites.ItemSpriteSheet +import com.egoal.darkestpixeldungeon.utils.GLog +import com.egoal.darkestpixeldungeon.windows.WndSelectPerk + +class TomeOfUpgrade : Book() { + init { + image = ItemSpriteSheet.TOME_YELLOW + + unique = true + } + + override fun isIdentified(): Boolean = true + + override fun price(): Int = 100 + + override fun doRead(hero: Hero) { + //todo: refactor + val perks = hero.heroPerk.perks.filter { it.upgradable() } + if (perks.isEmpty()) { + GLog.w(M.L(Book::class.java, "cannot_understand")) + return + } + + GameScene.show(object : WndSelectPerk(M.L(TomeOfUpgrade::class.java, "select_perk"), perks) { + override fun onPerkSelected(perk: Perk) { + PerkGain.Show(hero, perk) + hero.heroPerk.add(perk) + hero.perkGained += 1 + + detach(hero.belongings.backpack) + } + }) + } +} \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/helmets/GuardHelmet.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/helmets/GuardHelmet.kt new file mode 100644 index 000000000..76a74b55c --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/helmets/GuardHelmet.kt @@ -0,0 +1,60 @@ +package com.egoal.darkestpixeldungeon.items.helmets + +import com.egoal.darkestpixeldungeon.Dungeon +import com.egoal.darkestpixeldungeon.actors.hero.Hero +import com.egoal.darkestpixeldungeon.messages.M +import com.egoal.darkestpixeldungeon.sprites.ItemSpriteSheet + +class GuardHelmet : Helmet() { + init { + image = ItemSpriteSheet.HELMET_GUARD + } + + override fun doEquip(hero: Hero): Boolean { + return if (super.doEquip(hero)) { + attach(hero) + true + } else false + } + + override fun doUnequip(hero: Hero, collect: Boolean, single: Boolean): Boolean { + return if (super.doUnequip(hero, collect, single)) { + detach(hero) + true + } else false + } + + override fun uncurse() { + super.uncurse() + if (!cursed) return + + // redo the modifications + //fixme: + detach(Dungeon.hero) + cursed = false + attach(Dungeon.hero) + } + + private fun detach(hero: Hero) { + val sign = if (cursed) -1f else 1f + hero.magicalResistance -= 0.09f * sign + for (i in 0 until hero.elementalResistance.size) hero.elementalResistance[i] -= 0.06f * sign + } + + private fun attach(hero: Hero) { + val sign = if (cursed) -1f else 1f + hero.magicalResistance += 0.09f * sign + for (i in 0 until hero.elementalResistance.size) hero.elementalResistance[i] += 0.06f * sign + } + + override fun desc(): String { + var desc = super.desc() + if (isIdentified) { + desc += "\n\n" + M.L(this, "effect-desc") + if (cursed) + desc += "\n\n" + M.L(this, "cursed-desc") + } + + return desc + } +} \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/helmets/Helmet.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/helmets/Helmet.kt index 7cea2108d..c071e7ab7 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/helmets/Helmet.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/helmets/Helmet.kt @@ -20,6 +20,9 @@ open class Helmet(private var ticksToKnow: Int = TICKS_TO_KNOW) : EquipableItem( private var inscription: Inscription? = null + //todo: + open fun uncurse() {} + override fun doEquip(hero: Hero): Boolean { detach(hero.belongings.backpack) @@ -64,7 +67,7 @@ open class Helmet(private var ticksToKnow: Int = TICKS_TO_KNOW) : EquipableItem( } // override fun isIdentified(): Boolean = false - + override fun isUpgradable(): Boolean = false override fun price(): Int = if (cursedKnown && cursed) 20 else 40 diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/scrolls/ScrollOfRemoveCurse.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/scrolls/ScrollOfRemoveCurse.kt index 39ec95f8a..72c5ebd39 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/scrolls/ScrollOfRemoveCurse.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/scrolls/ScrollOfRemoveCurse.kt @@ -31,6 +31,7 @@ import com.egoal.darkestpixeldungeon.windows.WndBag import com.egoal.darkestpixeldungeon.effects.Flare import com.egoal.darkestpixeldungeon.effects.particles.ShadowParticle import com.egoal.darkestpixeldungeon.items.Item +import com.egoal.darkestpixeldungeon.items.helmets.Helmet import com.egoal.darkestpixeldungeon.items.rings.Ring import com.egoal.darkestpixeldungeon.messages.Messages @@ -62,9 +63,6 @@ class ScrollOfRemoveCurse : InventoryScroll() { private fun uncurseOne(hero: Hero, item: Item): Boolean { var procced = item.cursed - item.cursed = false - item.cursedKnown = true - when (item) { is Weapon -> if (item.hasCurseEnchant()) { item.enchant(null) @@ -81,8 +79,12 @@ class ScrollOfRemoveCurse : InventoryScroll() { bagitem.cursed = false procced = true } + is Helmet -> item.uncurse() //todo: } + item.cursed = false + item.cursedKnown = true + return procced } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/scrolls/ScrollOfTeleportation.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/scrolls/ScrollOfTeleportation.kt index 5b8735d83..d20491f22 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/scrolls/ScrollOfTeleportation.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/scrolls/ScrollOfTeleportation.kt @@ -130,8 +130,11 @@ class ScrollOfTeleportation : Scroll() { ch.sprite.place(pos) if (ch.invisible == 0) { - ch.sprite.alpha(0f) - ch.sprite.parent.add(AlphaTweener(ch.sprite, 1f, 0.4f)) + if (ch.sprite.parent != null) { + // ^^^ null check: the char may be removed by a WarpingTrap or sth, in the ch.move call + ch.sprite.alpha(0f) + ch.sprite.parent.add(AlphaTweener(ch.sprite, 1f, 0.4f)) + } } ch.sprite.emitter().start(Speck.factory(Speck.LIGHT), 0.2f, 3) diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/scrolls/ScrollOfUpgrade.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/scrolls/ScrollOfUpgrade.kt index 6c4d3b8b1..bdb4df856 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/scrolls/ScrollOfUpgrade.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/scrolls/ScrollOfUpgrade.kt @@ -66,63 +66,47 @@ class ScrollOfUpgrade : InventoryScroll() { Item.curUser.recoverSanity(Random.Float(0.5f, 3.5f)) //logic for telling the user when item properties change from upgrades - //...yes this is rather messy - if (item is Weapon) { - val wasCursed = item.cursed - val hadCursedEnchant = item.hasCurseEnchant() - val hadGoodEnchant = item.hasGoodEnchant() - - item.upgrade() - - if (hadCursedEnchant && !item.hasCurseEnchant()) { - removeCurse(Dungeon.hero) - } else if (wasCursed && !item.cursed) { - weakenCurse(Dungeon.hero) + //...yes this is rather mess + when (item) { + is Weapon -> { + val enchanted = item.enchantment != null + item.upgrade() + if (enchanted && item.enchantment == null) + GLog.w(M.L(Weapon::class.java, "incompatible")) } - if (hadGoodEnchant && !item.hasGoodEnchant()) { - GLog.w(Messages.get(Weapon::class.java, "incompatible")) - } - - } else if (item is Armor) { - val wasCursed = item.cursed - val hadCursedGlyph = item.hasCurseGlyph() - val hadGoodGlyph = item.hasGoodGlyph() + is Armor -> { + val wasCursed = item.cursed + val hadCursedGlyph = item.hasCurseGlyph() + val hadGoodGlyph = item.hasGoodGlyph() - item.upgrade() + item.upgrade() - if (hadCursedGlyph && !item.hasCurseGlyph()) { - removeCurse(Dungeon.hero) - } else if (wasCursed && !item.cursed) { - weakenCurse(Dungeon.hero) + if (hadCursedGlyph && !item.hasCurseGlyph()) removeCurse(Dungeon.hero) + else if (wasCursed && !item.cursed) weakenCurse(Dungeon.hero) + if (hadGoodGlyph && !item.hasGoodGlyph()) + GLog.w(Messages.get(Armor::class.java, "incompatible")) } - if (hadGoodGlyph && !item.hasGoodGlyph()) { - GLog.w(Messages.get(Armor::class.java, "incompatible")) - } - - } else if (item is Wand) { - val wasCursed = item.cursed + is Wand -> { + val wasCursed = item.cursed - item.upgrade() + item.upgrade() - if (wasCursed && !item.cursed) { - removeCurse(Dungeon.hero) + if (wasCursed && !item.cursed) removeCurse(Dungeon.hero) } + is Ring -> { + val wasCursed = item.cursed - } else if (item is Ring) { - val wasCursed = item.cursed + item.upgrade() - item.upgrade() - - if (wasCursed && !item.cursed) { - if (item.level() < 1) { - weakenCurse(Dungeon.hero) - } else { - removeCurse(Dungeon.hero) + if (wasCursed && !item.cursed) { + if (item.level() < 1) { + weakenCurse(Dungeon.hero) + } else { + removeCurse(Dungeon.hero) + } } } - - } else { - item.upgrade() + else -> item.upgrade() } Badges.validateItemLevelAquired(item) diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/unclassified/Gold.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/unclassified/Gold.kt index 97d7dcf63..40c3acfb6 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/unclassified/Gold.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/unclassified/Gold.kt @@ -84,7 +84,7 @@ class Gold(value: Int = 1) : Item() { private fun upgradeItem(hero: Hero, item: Item) { val lvl = item.level() - val goldreq = 100 + lvl * 100 + (lvl / 3) * 60 * lvl + val goldreq = 100 + lvl * 120 + (lvl / 3) * 66 * lvl if (goldreq > Dungeon.gold) { hero.sayShort(HeroLines.NO_GOLD) return diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/unclassified/SpiderGland.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/unclassified/SpiderGland.kt new file mode 100644 index 000000000..80bfb33d1 --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/unclassified/SpiderGland.kt @@ -0,0 +1,31 @@ +package com.egoal.darkestpixeldungeon.items.unclassified + +import com.egoal.darkestpixeldungeon.Dungeon +import com.egoal.darkestpixeldungeon.actors.blobs.Blob +import com.egoal.darkestpixeldungeon.actors.blobs.ToxicGas +import com.egoal.darkestpixeldungeon.actors.blobs.Web +import com.egoal.darkestpixeldungeon.items.Item +import com.egoal.darkestpixeldungeon.levels.Level +import com.egoal.darkestpixeldungeon.scenes.GameScene +import com.egoal.darkestpixeldungeon.sprites.ItemSpriteSheet +import com.watabou.utils.Random + +class SpiderGland : Item() { + init { + image = ItemSpriteSheet.GLAND + + stackable = true + usesTargeting = true + + defaultAction = AC_THROW + } + + override fun onThrow(cell: Int) { + if (Level.pit[cell]) super.onThrow(cell) + else { + Dungeon.level.press(cell, null) + GameScene.add(Blob.seed(cell, Random.Int(12, 20), Web::class.java)) + GameScene.add(Blob.seed(cell, 30, ToxicGas::class.java)) + } + } +} \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/wands/CursedWand.java b/core/src/main/java/com/egoal/darkestpixeldungeon/items/wands/CursedWand.java index d328684f7..7aa85598e 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/wands/CursedWand.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/wands/CursedWand.java @@ -353,9 +353,9 @@ public void call() { for (Mob mob : Dungeon.level.getMobs().toArray(new Mob[0])) if (mob instanceof GhostHero) mob.destroy(); - InterlevelScene.mode = InterlevelScene.Mode.RETURN; - InterlevelScene.returnDepth = depth; - InterlevelScene.returnPos = -1; + InterlevelScene.Companion.setMode(InterlevelScene.Mode.RETURN); + InterlevelScene.Companion.setReturnDepth(depth); + InterlevelScene.Companion.setReturnPos(-1); Game.switchScene(InterlevelScene.class); } else { diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/wands/WandOfHypnosis.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/wands/WandOfHypnosis.kt new file mode 100644 index 000000000..267dc8efe --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/wands/WandOfHypnosis.kt @@ -0,0 +1,64 @@ +package com.egoal.darkestpixeldungeon.items.wands + +import com.egoal.darkestpixeldungeon.actors.Actor +import com.egoal.darkestpixeldungeon.actors.Char +import com.egoal.darkestpixeldungeon.actors.Damage +import com.egoal.darkestpixeldungeon.actors.blobs.Blob +import com.egoal.darkestpixeldungeon.actors.blobs.ConfusionGas +import com.egoal.darkestpixeldungeon.actors.buffs.Buff +import com.egoal.darkestpixeldungeon.actors.buffs.Drowsy +import com.egoal.darkestpixeldungeon.actors.buffs.MagicalSleep +import com.egoal.darkestpixeldungeon.actors.buffs.Vertigo +import com.egoal.darkestpixeldungeon.effects.Speck +import com.egoal.darkestpixeldungeon.items.weapon.melee.MagesStaff +import com.egoal.darkestpixeldungeon.mechanics.Ballistica +import com.egoal.darkestpixeldungeon.scenes.GameScene +import com.egoal.darkestpixeldungeon.sprites.ItemSpriteSheet +import com.watabou.utils.PointF +import com.watabou.utils.Random +import kotlin.math.max +import kotlin.math.min +import kotlin.math.pow +import kotlin.math.sqrt + +class WandOfHypnosis : Wand() { + init { + image = ItemSpriteSheet.WAND_HYPNOSIS + } + + override fun initialCharges(): Int = 1 + + override fun updateLevel() { + maxCharges = (1f + sqrt(8f * level() + 1f)).toInt() / 2 + curCharges = min(curCharges, maxCharges) + } + + override fun onZap(attack: Ballistica) { + val cell = attack.collisionPos + Actor.findChar(cell)?.let { + Buff.affect(it, MagicalSleep.Deep::class.java).ratio = 0.75f - 0.5f * 0.85f.pow(level()) + it.sprite.centerEmitter().start(Speck.factory(Speck.NOTE), 0.3f, 3 + level()) + } + + GameScene.add(Blob.seed(cell, 12, ConfusionGas::class.java)) + } + + override fun onHit(staff: MagesStaff, damage: Damage) { + val level = max(0, staff.level()) + if (Random.Int(level + 6) >= 4) { + val to = damage.to as Char + Buff.affect(to, Vertigo::class.java, Vertigo.duration(to)) + } + } + + override fun staffFx(particle: MagesStaff.StaffParticle) { + particle.color(0x1e0303.toInt()) + particle.am = 0.6f + particle.setLifespan(1f) + val angle = Random.Float(PointF.PI2) + particle.speed.polar(angle, 2f) + particle.acc.set(0f, -10f) + particle.setSize(1f, 2f) + particle.radiateXY(Random.Float(2f)) + } +} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/wands/WandOfRegrowth.java b/core/src/main/java/com/egoal/darkestpixeldungeon/items/wands/WandOfRegrowth.java deleted file mode 100644 index 964d2a866..000000000 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/wands/WandOfRegrowth.java +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Pixel Dungeon - * Copyright (C) 2012-2015 Oleg Dolya - * - * Shattered Pixel Dungeon - * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.items.wands; - -import com.egoal.darkestpixeldungeon.actors.Damage; -; -import com.egoal.darkestpixeldungeon.items.Generator; -import com.egoal.darkestpixeldungeon.items.potions.PotionOfHealing; -import com.egoal.darkestpixeldungeon.plants.Plant; -import com.egoal.darkestpixeldungeon.Assets; -import com.egoal.darkestpixeldungeon.Dungeon; -import com.egoal.darkestpixeldungeon.actors.Actor; -import com.egoal.darkestpixeldungeon.actors.Char; -import com.egoal.darkestpixeldungeon.actors.blobs.Blob; -import com.egoal.darkestpixeldungeon.actors.blobs.Regrowth; -import com.egoal.darkestpixeldungeon.actors.buffs.Buff; -import com.egoal.darkestpixeldungeon.effects.MagicMissile; -import com.egoal.darkestpixeldungeon.items.unclassified.Dewdrop; -import com.egoal.darkestpixeldungeon.items.weapon.melee.MagesStaff; -import com.egoal.darkestpixeldungeon.levels.Level; -import com.egoal.darkestpixeldungeon.levels.Terrain; -import com.egoal.darkestpixeldungeon.mechanics.Ballistica; -import com.egoal.darkestpixeldungeon.plants.BlandfruitBush; -import com.egoal.darkestpixeldungeon.plants.Starflower; -import com.egoal.darkestpixeldungeon.plants.Sungrass; -import com.egoal.darkestpixeldungeon.scenes.GameScene; -import com.egoal.darkestpixeldungeon.sprites.ItemSpriteSheet; -import com.watabou.noosa.audio.Sample; -import com.watabou.utils.Callback; -import com.watabou.utils.ColorMath; -import com.watabou.utils.PathFinder; -import com.watabou.utils.Random; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Iterator; - -public class WandOfRegrowth extends Wand { - - { - image = ItemSpriteSheet.WAND_REGROWTH; - - collisionProperties = Ballistica.STOP_TERRAIN; - } - - //the actual affected cells - private HashSet affectedCells; - //the cells to trace growth particles to, for visual effects. - private HashSet visualCells; - private int direction = 0; - - @Override - protected void onZap(Ballistica bolt) { - - //ignore tiles which can't have anything grow in them. - for (Iterator i = affectedCells.iterator(); i.hasNext(); ) { - int c = Dungeon.level.getMap()[i.next()]; - if (!(c == Terrain.EMPTY || - c == Terrain.EMBERS || - c == Terrain.EMPTY_DECO || - c == Terrain.GRASS || - c == Terrain.HIGH_GRASS)) { - i.remove(); - } - } - - float numPlants, numDews, numPods, numStars; - - int chrgUsed = chargesPerCast(); - //numbers greater than n*100% means n guaranteed plants, e.g. 210% = 2 - // plants w/10% chance for 3 plants. - numPlants = 0.2f + chrgUsed * chrgUsed * 0.020f; //scales from 22% to 220% - numDews = 0.05f + chrgUsed * chrgUsed * 0.016f; //scales from 6.6% to 165% - numPods = 0.02f + chrgUsed * chrgUsed * 0.013f; //scales from 3.3% to 135% - numStars = (chrgUsed * chrgUsed * chrgUsed / 5f) * 0.005f; //scales from - // 0.1% to 100% - placePlants(numPlants, numDews, numPods, numStars); - - for (int i : affectedCells) { - int c = Dungeon.level.getMap()[i]; - if (c == Terrain.EMPTY || - c == Terrain.EMBERS || - c == Terrain.EMPTY_DECO) { - Level.Companion.set(i, Terrain.GRASS); - } - - Char ch = Actor.findChar(i); - - GameScene.add(Blob.seed(i, 10, Regrowth.class)); - - } - } - - private void spreadRegrowth(int cell, float strength) { - if (strength >= 0 && Level.Companion.getPassable()[cell] && !Level.Companion.getLosBlocking()[cell]) { - affectedCells.add(cell); - if (strength >= 1.5f) { - spreadRegrowth(cell + PathFinder.CIRCLE[left(direction)], strength - - 1.5f); - spreadRegrowth(cell + PathFinder.CIRCLE[direction], strength - 1.5f); - spreadRegrowth(cell + PathFinder.CIRCLE[right(direction)], strength - - 1.5f); - } else { - visualCells.add(cell); - } - } else if (!Level.Companion.getPassable()[cell] || Level.Companion.getLosBlocking()[cell]) - visualCells.add(cell); - } - - private void placePlants(float numPlants, float numDews, float numPods, - float numStars) { - Iterator cells = affectedCells.iterator(); - Level floor = Dungeon.level; - - while (cells.hasNext() && Random.Float() <= numPlants) { - Plant.Seed seed = (Plant.Seed) Generator.SEED.INSTANCE.generate(); - - if (seed instanceof BlandfruitBush.Seed) { - if (Random.Int(15) - Dungeon.limitedDrops.blandfruitSeed.count >= 0) { - floor.plant(seed, cells.next()); - Dungeon.limitedDrops.blandfruitSeed.count++; - } - } else - floor.plant(seed, cells.next()); - - numPlants--; - } - - while (cells.hasNext() && Random.Float() <= numDews) { - floor.plant(new Dewcatcher.Seed(), cells.next()); - numDews--; - } - - while (cells.hasNext() && Random.Float() <= numPods) { - floor.plant(new Seedpod.Seed(), cells.next()); - numPods--; - } - - while (cells.hasNext() && Random.Float() <= numStars) { - floor.plant(new Starflower.Seed(), cells.next()); - numStars--; - } - - } - - private int left(int direction) { - return direction == 0 ? 7 : direction - 1; - } - - private int right(int direction) { - return direction == 7 ? 0 : direction + 1; - } - - @Override - public void onHit(MagesStaff staff, Damage damage) { - //like pre-nerf vampiric enchantment, except with herbal healing buff - - int level = Math.max(0, staff.level()); - - // lvl 0 - 33% - // lvl 1 - 43% - // lvl 2 - 50% - int maxValue = damage.value * (level + 2) / (level + 6); - - Char attacker = (Char) damage.from; - int effValue = Math.min(Random.IntRange(0, maxValue), - attacker.HT - attacker.HP); - - Buff.affect(attacker, Sungrass.Health.class).boost(effValue); - - } - - public void fx(Ballistica bolt, Callback callback) { - - affectedCells = new HashSet<>(); - visualCells = new HashSet<>(); - - int maxDist = Math.round(1.2f + chargesPerCast() * .8f); - int dist = Math.min(bolt.dist, maxDist); - - for (int i = 0; i < PathFinder.CIRCLE.length; i++) { - if (bolt.sourcePos + PathFinder.CIRCLE[i] == bolt.path.get(1)) { - direction = i; - break; - } - } - - float strength = maxDist; - for (int c : bolt.subPath(1, dist)) { - strength--; //as we start at dist 1, not 0. - if (!Level.Companion.getLosBlocking()[c]) { - affectedCells.add(c); - spreadRegrowth(c + PathFinder.CIRCLE[left(direction)], strength - 1); - spreadRegrowth(c + PathFinder.CIRCLE[direction], strength - 1); - spreadRegrowth(c + PathFinder.CIRCLE[right(direction)], strength - 1); - } else { - visualCells.add(c); - } - } - - //going to call this one manually - visualCells.remove(bolt.path.get(dist)); - - for (int cell : visualCells) { - //this way we only get the cells at the tip, much better performance. - MagicMissile.foliage(curUser.sprite.parent, bolt.sourcePos, cell, null); - } - MagicMissile.foliage(curUser.sprite.parent, bolt.sourcePos, bolt.path.get - (dist), callback); - - Sample.INSTANCE.play(Assets.SND_ZAP); - } - - @Override - protected int initialCharges() { - return 1; - } - - @Override - //consumes all available charges, needs at least one. - protected int chargesPerCast() { - return Math.max(1, curCharges); - } - - @Override - public void staffFx(MagesStaff.StaffParticle particle) { - particle.color(ColorMath.random(0x004400, 0x88CC44)); - particle.am = 1f; - particle.setLifespan(1.2f); - particle.setSize(1f, 2f); - particle.shuffleXY(1f); - float dst = Random.Float(11f); - particle.x -= dst; - particle.y += dst; - } - - public static class Dewcatcher extends Plant { - public Dewcatcher() { - super(12); - } - - @Override - public void activate() { - - int nDrops = Random.NormalIntRange(2, 8); - - ArrayList candidates = new ArrayList(); - for (int i : PathFinder.NEIGHBOURS8) { - if (Level.Companion.getPassable()[getPos() + i]) { - candidates.add(getPos() + i); - } - } - - for (int i = 0; i < nDrops && !candidates.isEmpty(); i++) { - Integer c = Random.element(candidates); - Dungeon.level.drop(new Dewdrop(), c).getSprite().drop(getPos()); - candidates.remove(c); - } - - } - - //seed is never dropped, only care about plant class - public static class Seed extends Plant.Seed { - public Seed() { - super(Dewcatcher.class, PotionOfHealing.class); - } - } - } - - public static class Seedpod extends Plant { - - public Seedpod() { - super(13); - } - - @Override - public void activate() { - - int nSeeds = Random.NormalIntRange(1, 5); - - ArrayList candidates = new ArrayList(); - for (int i : PathFinder.NEIGHBOURS8) { - if (Level.Companion.getPassable()[getPos() + i]) { - candidates.add(getPos() + i); - } - } - - for (int i = 0; i < nSeeds && !candidates.isEmpty(); i++) { - Integer c = Random.element(candidates); - Dungeon.level.drop(Generator.SEED.INSTANCE.generate(), c).getSprite().drop(getPos()); - candidates.remove(c); - } - - } - - //seed is never dropped, only care about plant class - public static class Seed extends Plant.Seed { - public Seed() { - super(Seedpod.class, PotionOfHealing.class); - } - } - - } - -} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/wands/WandOfRegrowth.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/wands/WandOfRegrowth.kt new file mode 100644 index 000000000..0b3eb4737 --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/wands/WandOfRegrowth.kt @@ -0,0 +1,288 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.items.wands + +import com.egoal.darkestpixeldungeon.actors.Damage +import com.egoal.darkestpixeldungeon.items.Generator +import com.egoal.darkestpixeldungeon.items.potions.PotionOfHealing +import com.egoal.darkestpixeldungeon.plants.Plant +import com.egoal.darkestpixeldungeon.Assets +import com.egoal.darkestpixeldungeon.Dungeon +import com.egoal.darkestpixeldungeon.actors.Actor +import com.egoal.darkestpixeldungeon.actors.Char +import com.egoal.darkestpixeldungeon.actors.blobs.Blob +import com.egoal.darkestpixeldungeon.actors.blobs.Regrowth +import com.egoal.darkestpixeldungeon.actors.buffs.Buff +import com.egoal.darkestpixeldungeon.effects.MagicMissile +import com.egoal.darkestpixeldungeon.items.Item +import com.egoal.darkestpixeldungeon.items.unclassified.Dewdrop +import com.egoal.darkestpixeldungeon.items.weapon.melee.MagesStaff +import com.egoal.darkestpixeldungeon.levels.Level +import com.egoal.darkestpixeldungeon.levels.Terrain +import com.egoal.darkestpixeldungeon.mechanics.Ballistica +import com.egoal.darkestpixeldungeon.plants.BlandfruitBush +import com.egoal.darkestpixeldungeon.plants.Starflower +import com.egoal.darkestpixeldungeon.plants.Sungrass +import com.egoal.darkestpixeldungeon.scenes.GameScene +import com.egoal.darkestpixeldungeon.sprites.ItemSpriteSheet +import com.watabou.noosa.audio.Sample +import com.watabou.utils.Callback +import com.watabou.utils.ColorMath +import com.watabou.utils.PathFinder +import com.watabou.utils.Random + +import java.util.ArrayList +import java.util.HashSet +import kotlin.math.max + +class WandOfRegrowth : Wand() { + //the actual affected cells + private var affectedCells: HashSet? = null + //the cells to trace growth particles to, for visual effects. + private var visualCells: HashSet? = null + private var direction = 0 + + init { + image = ItemSpriteSheet.WAND_REGROWTH + + collisionProperties = Ballistica.STOP_TERRAIN + } + + override fun onZap(bolt: Ballistica) { + + //ignore tiles which can't have anything grow in them. + val i = affectedCells!!.iterator() + while (i.hasNext()) { + val c = Dungeon.level.map[i.next()] + if (!(c == Terrain.EMPTY || + c == Terrain.EMBERS || + c == Terrain.EMPTY_DECO || + c == Terrain.GRASS || + c == Terrain.HIGH_GRASS)) { + i.remove() + } + } + + val numPlants: Float + val numDews: Float + val numPods: Float + val numStars: Float + + val chrgUsed = chargesPerCast() + //numbers greater than n*100% means n guaranteed plants, e.g. 210% = 2 + // plants w/10% chance for 3 plants. + numPlants = 0.2f + chrgUsed.toFloat() * chrgUsed.toFloat() * 0.020f //scales from 22% to 220% + numDews = 0.05f + chrgUsed.toFloat() * chrgUsed.toFloat() * 0.016f //scales from 6.6% to 165% + numPods = 0.02f + chrgUsed.toFloat() * chrgUsed.toFloat() * 0.013f //scales from 3.3% to 135% + numStars = chrgUsed * chrgUsed * chrgUsed / 5f * 0.005f //scales from + // 0.1% to 100% + placePlants(numPlants, numDews, numPods, numStars) + + for (i in affectedCells!!) { + val c = Dungeon.level.map[i] + if (c == Terrain.EMPTY || + c == Terrain.EMBERS || + c == Terrain.EMPTY_DECO) { + Level[i] = Terrain.GRASS + } + + val ch = Actor.findChar(i) + + GameScene.add(Blob.seed(i, 10, Regrowth::class.java)) + + } + } + + private fun spreadRegrowth(cell: Int, strength: Float) { + if (strength >= 0 && Level.passable[cell] && !Level.losBlocking[cell]) { + affectedCells!!.add(cell) + if (strength >= 1.5f) { + spreadRegrowth(cell + PathFinder.CIRCLE[left(direction)], strength - 1.5f) + spreadRegrowth(cell + PathFinder.CIRCLE[direction], strength - 1.5f) + spreadRegrowth(cell + PathFinder.CIRCLE[right(direction)], strength - 1.5f) + } else { + visualCells!!.add(cell) + } + } else if (!Level.passable[cell] || Level.losBlocking[cell]) + visualCells!!.add(cell) + } + + private fun placePlants(numPlants: Float, numDews: Float, numPods: Float, + numStars: Float) { + var numPlants = numPlants + var numDews = numDews + var numPods = numPods + var numStars = numStars + val cells = affectedCells!!.iterator() + val floor = Dungeon.level + + while (cells.hasNext() && Random.Float() <= numPlants) { + val seed = Generator.SEED.generate() as Plant.Seed + + if (seed is BlandfruitBush.Seed) { + if (Random.Int(15) - Dungeon.limitedDrops.blandfruitSeed.count >= 0) { + floor.plant(seed, cells.next()) + Dungeon.limitedDrops.blandfruitSeed.count++ + } + } else + floor.plant(seed, cells.next()) + + numPlants-- + } + + while (cells.hasNext() && Random.Float() <= numDews) { + floor.plant(Dewcatcher.Seed(), cells.next()) + numDews-- + } + + while (cells.hasNext() && Random.Float() <= numPods) { + floor.plant(Seedpod.Seed(), cells.next()) + numPods-- + } + + while (cells.hasNext() && Random.Float() <= numStars) { + floor.plant(Starflower.Seed(), cells.next()) + numStars-- + } + + } + + private fun left(direction: Int): Int { + return if (direction == 0) 7 else direction - 1 + } + + private fun right(direction: Int): Int { + return if (direction == 7) 0 else direction + 1 + } + + override fun onHit(staff: MagesStaff, damage: Damage) { + //like pre-nerf vampiric enchantment, except with herbal healing buff + + val level = Math.max(0, staff.level()) + + // lvl 0 - 33% + // lvl 1 - 43% + // lvl 2 - 50% + val maxValue = damage.value * (level + 2) / (level + 6) + + val attacker = damage.from as Char + val effValue = Math.min(Random.IntRange(0, maxValue), + attacker.HT - attacker.HP) + + Buff.affect(attacker, Sungrass.Health::class.java).boost(effValue) + + } + + override fun fx(bolt: Ballistica, callback: Callback) { + + affectedCells = HashSet() + visualCells = HashSet() + + val maxDist = Math.round(1.2f + chargesPerCast() * .8f) + val dist = Math.min(bolt.dist, maxDist) + + for (i in PathFinder.CIRCLE.indices) { + if (bolt.sourcePos + PathFinder.CIRCLE[i] == bolt.path[1]) { + direction = i + break + } + } + + var strength = maxDist.toFloat() + for (c in bolt.subPath(1, dist)) { + strength-- //as we start at dist 1, not 0. + if (!Level.losBlocking[c]) { + affectedCells!!.add(c) + spreadRegrowth(c + PathFinder.CIRCLE[left(direction)], strength - 1) + spreadRegrowth(c + PathFinder.CIRCLE[direction], strength - 1) + spreadRegrowth(c + PathFinder.CIRCLE[right(direction)], strength - 1) + } else { + visualCells!!.add(c) + } + } + + //going to call this one manually + visualCells!!.remove(bolt.path[dist]) + + for (cell in visualCells!!) { + //this way we only get the cells at the tip, much better performance. + MagicMissile.foliage(Item.curUser.sprite.parent, bolt.sourcePos, cell, null) + } + MagicMissile.foliage(Item.curUser.sprite.parent, bolt.sourcePos, bolt.path[dist], callback) + + Sample.INSTANCE.play(Assets.SND_ZAP) + } + + override fun initialCharges(): Int = 1 + + //consumes all available charges, needs at least one. + override fun chargesPerCast(): Int = max(1, curCharges) + + override fun staffFx(particle: MagesStaff.StaffParticle) { + particle.color(ColorMath.random(0x004400, 0x88CC44)) + particle.am = 1f + particle.setLifespan(1.2f) + particle.setSize(1f, 2f) + particle.shuffleXY(1f) + val dst = Random.Float(11f) + particle.x -= dst + particle.y += dst + } + + class Dewcatcher : Plant(12) { + + override fun activate() { + + var nDrops = Random.NormalIntRange(2, 8) + + val candidates = PathFinder.NEIGHBOURS8.map { pos + it }.filter { Level.passable[it] }.shuffled() + + for (c in candidates) { + Dungeon.level.drop(Dewdrop(), c).sprite.drop(pos) + --nDrops + if (nDrops == 0) break + } + } + + //seed is never dropped, only care about plant class + class Seed : Plant.Seed(Dewcatcher::class.java, PotionOfHealing::class.java) + } + + class Seedpod : Plant(13) { + + override fun activate() { + + var nSeeds = Random.NormalIntRange(1, 5) + + val candidates = PathFinder.NEIGHBOURS8.map { pos + it }.filter { Level.passable[it] }.shuffled() + + for (c in candidates) { + Dungeon.level.drop(Generator.SEED.generate(), c).sprite.drop(pos) + --nSeeds + if (nSeeds == 0) break + } + } + + //seed is never dropped, only care about plant class + class Seed : Plant.Seed(Seedpod::class.java, PotionOfHealing::class.java) + } + +} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/Weapon.java b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/Weapon.java index 78bdcb1b4..ae0f81ccb 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/Weapon.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/Weapon.java @@ -24,6 +24,8 @@ import com.egoal.darkestpixeldungeon.actors.hero.Hero; import com.egoal.darkestpixeldungeon.actors.hero.perks.ExtraStrengthPower; import com.egoal.darkestpixeldungeon.items.weapon.curses.Arrogant; +import com.egoal.darkestpixeldungeon.items.weapon.curses.Bloodthirsty; +import com.egoal.darkestpixeldungeon.items.weapon.curses.Provocation; import com.egoal.darkestpixeldungeon.items.weapon.enchantments.Dazzling; import com.egoal.darkestpixeldungeon.items.weapon.enchantments.Holy; import com.egoal.darkestpixeldungeon.items.weapon.enchantments.Projecting; @@ -47,6 +49,7 @@ import com.egoal.darkestpixeldungeon.items.weapon.enchantments.Grim; import com.egoal.darkestpixeldungeon.items.weapon.enchantments.Lucky; import com.egoal.darkestpixeldungeon.items.weapon.enchantments.Shocking; +import com.egoal.darkestpixeldungeon.items.weapon.enchantments.Storming; import com.egoal.darkestpixeldungeon.items.weapon.enchantments.Stunning; import com.egoal.darkestpixeldungeon.items.weapon.enchantments.Suppress; import com.egoal.darkestpixeldungeon.items.weapon.enchantments.Unstable; @@ -284,17 +287,16 @@ public static abstract class Enchantment implements Bundlable { private static final Class[] enchants = new Class[]{ Blazing.class, Venomous.class, Vorpal.class, Shocking.class, - Chilling.class, Eldritch.class, Lucky.class, Projecting.class, - Unstable.class, Dazzling.class, Suppress.class, + Chilling.class, Eldritch.class, Lucky.class, Projecting.class, Unstable.class, Dazzling.class, Suppress.class, Storming.class, Grim.class, Stunning.class, Vampiric.class,}; private static final float[] chances = new float[]{ 10, 10, 10, 10, - 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2}; private static final Class[] curses = new Class[]{ Annoying.class, Displacing.class, Exhausting.class, Fragile - .class, Sacrificial.class, Wayward.class, Arrogant.class, + .class, Sacrificial.class, Wayward.class, Arrogant.class, Provocation.class, Bloodthirsty.class, }; public abstract Damage proc(Weapon weapon, Damage damage); diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/curses/Annoying.java b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/curses/Annoying.java index f83ec0dce..f362a3740 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/curses/Annoying.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/curses/Annoying.java @@ -47,8 +47,7 @@ public Damage proc(Weapon weapon, Damage damage) { for (Mob mob : Dungeon.level.getMobs().toArray(new Mob[0])) { mob.beckon(attacker.pos); } - attacker.sprite.centerEmitter().start(Speck.factory(Speck.SCREAM), - 0.3f, 3); + attacker.sprite.centerEmitter().start(Speck.factory(Speck.SCREAM), 0.3f, 3); Sample.INSTANCE.play(Assets.SND_MIMIC); Invisibility.dispel(); GLog.w(Messages.get(this, "msg_" + (Random.Int(5) + 1))); diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/curses/Arrogant.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/curses/Arrogant.kt index 61ef26928..e9a523b37 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/curses/Arrogant.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/curses/Arrogant.kt @@ -17,8 +17,8 @@ class Arrogant : Weapon.Enchantment() { override fun proc(weapon: Weapon, damage: Damage): Damage { if (Random.Int(10) == 0) - (damage.from as Char).buff(Pressure::class.java)?.upPressure(Random.Int(1, 3).toFloat()) - + (damage.from as Char).takeDamage(Damage(Random.Int(1, 3), damage.from, damage.from).type(Damage.Type.MENTAL)) + return damage } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/curses/Bloodthirsty.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/curses/Bloodthirsty.kt new file mode 100644 index 000000000..635820d18 --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/curses/Bloodthirsty.kt @@ -0,0 +1,39 @@ +package com.egoal.darkestpixeldungeon.items.weapon.curses + +import com.egoal.darkestpixeldungeon.Dungeon +import com.egoal.darkestpixeldungeon.actors.Char +import com.egoal.darkestpixeldungeon.actors.Damage +import com.egoal.darkestpixeldungeon.actors.hero.Hero +import com.egoal.darkestpixeldungeon.items.weapon.Weapon +import com.egoal.darkestpixeldungeon.sprites.ItemSprite +import com.watabou.utils.Random + +class Bloodthirsty : Weapon.Enchantment(), Hero.Doom { + private var thirsty = 0 + + override fun proc(weapon: Weapon, damage: Damage): Damage { + val extra = Random.Int(1, damage.value / 2) + damage.value += extra // directly add. + thirsty -= extra + if (thirsty > 0) { + val attacker = damage.from as Char + val dmg = Damage(thirsty, this, attacker) // .addFeature(Damage.Feature.PURE) + attacker.takeDamage(dmg) + attacker.sprite.bloodBurstB((damage.to as Char).sprite.center(), dmg.value) + } else thirsty = extra + + return damage + } + + override fun curse(): Boolean = true + + override fun glowing(): ItemSprite.Glowing = DARK_RED + + override fun onDeath() { + Dungeon.fail(javaClass) + } + + companion object { + private val DARK_RED = ItemSprite.Glowing(0x902626) + } +} \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/curses/Provocation.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/curses/Provocation.kt new file mode 100644 index 000000000..ef7b85732 --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/curses/Provocation.kt @@ -0,0 +1,36 @@ +package com.egoal.darkestpixeldungeon.items.weapon.curses + +import com.egoal.darkestpixeldungeon.Assets +import com.egoal.darkestpixeldungeon.actors.Char +import com.egoal.darkestpixeldungeon.actors.Damage +import com.egoal.darkestpixeldungeon.actors.buffs.Buff +import com.egoal.darkestpixeldungeon.actors.buffs.Rage +import com.egoal.darkestpixeldungeon.effects.Speck +import com.egoal.darkestpixeldungeon.items.weapon.Weapon +import com.egoal.darkestpixeldungeon.messages.M +import com.egoal.darkestpixeldungeon.sprites.ItemSprite +import com.egoal.darkestpixeldungeon.utils.GLog +import com.watabou.noosa.audio.Sample +import com.watabou.utils.Random + +class Provocation : Weapon.Enchantment() { + override fun proc(weapon: Weapon, damage: Damage): Damage { + if (Random.Int(10) == 0 && damage.to is Char) { + (damage.from as Char).sprite.centerEmitter().start(Speck.factory(Speck.SCREAM), 0.3f, 3) + Sample.INSTANCE.play(Assets.SND_MIMIC) + + GLog.w(M.L(this, "msg_" + (Random.Int(4)))) + Buff.prolong(damage.to as Char, Rage::class.java, Random.Float(2f, 5f)) + } + + return damage + } + + override fun curse(): Boolean = true + + override fun glowing(): ItemSprite.Glowing = DARK_RED + + companion object { + private val DARK_RED = ItemSprite.Glowing(0x902626) + } +} \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/enchantments/Eldritch.java b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/enchantments/Eldritch.java index 06e019061..23a7c9b34 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/enchantments/Eldritch.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/enchantments/Eldritch.java @@ -45,7 +45,7 @@ public Damage proc(Weapon weapon, Damage damage) { if (Random.Int(level + 5) >= 4) { if (defender == Dungeon.hero) { - Buff.affect(defender, Vertigo.class, Vertigo.duration(defender)); + Buff.affect(defender, Vertigo.class, Vertigo.Companion.duration(defender)); } else { Buff.affect(defender, Terror.class, Terror.DURATION).object = ((Char) damage.from).id(); diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/enchantments/Storming.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/enchantments/Storming.kt new file mode 100644 index 000000000..5a3958ff6 --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/enchantments/Storming.kt @@ -0,0 +1,50 @@ +package com.egoal.darkestpixeldungeon.items.weapon.enchantments + +import com.egoal.darkestpixeldungeon.actors.Char +import com.egoal.darkestpixeldungeon.actors.Damage +import com.egoal.darkestpixeldungeon.items.weapon.Weapon +import com.egoal.darkestpixeldungeon.sprites.ItemSprite +import com.watabou.utils.Bundle +import kotlin.math.max + +class Storming : Weapon.Enchantment() { + + private var id = -1 + private var acc = 0 + + override fun proc(weapon: Weapon, damage: Damage): Damage { + val defender = damage.to as Char + + if (defender.id() == id) { + // this enchant may usually apply on fast weapon, so this fix should be powerful enough. + acc += max(1, weapon.level()) + damage.value += acc + } else { + id = defender.id() + acc = 0 + } + + return damage + } + + override fun glowing(): ItemSprite.Glowing = GREY + + override fun storeInBundle(bundle: Bundle) { + super.storeInBundle(bundle) + bundle.put(ID, id) + bundle.put(ACC, acc) + } + + override fun restoreFromBundle(bundle: Bundle) { + super.restoreFromBundle(bundle) + id = bundle.getInt(ID) + acc = bundle.getInt(ACC) + } + + companion object { + private const val ID = "id" + private const val ACC = "acc" + + private val GREY = ItemSprite.Glowing(0x404040) + } +} \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/melee/InvisibleBlade.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/melee/InvisibleBlade.kt new file mode 100644 index 000000000..e6ac31b5d --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/melee/InvisibleBlade.kt @@ -0,0 +1,23 @@ +package com.egoal.darkestpixeldungeon.items.weapon.melee + +import com.egoal.darkestpixeldungeon.actors.Damage +import com.egoal.darkestpixeldungeon.sprites.ItemSpriteSheet +import com.watabou.utils.Random + +class InvisibleBlade : MeleeWeapon() { + init { + image = ItemSpriteSheet.INVISIBLE_BLADE + + tier = 3 + + ACC = 1.25f + } + + override fun max(lvl: Int): Int = 5 * tier + lvl * tier // 20+ 4x lvl -> 15+ 3x lvl + + override fun proc(dmg: Damage): Damage { + if (Random.Float() < 0.2f + 0.04f * level()) dmg.addFeature(Damage.Feature.PURE) + + return super.proc(dmg) + } +} \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/melee/MagicBow.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/melee/MagicBow.kt new file mode 100644 index 000000000..a2409b60a --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/melee/MagicBow.kt @@ -0,0 +1,135 @@ +package com.egoal.darkestpixeldungeon.items.weapon.melee + +import com.egoal.darkestpixeldungeon.Assets +import com.egoal.darkestpixeldungeon.Dungeon +import com.egoal.darkestpixeldungeon.Statistics +import com.egoal.darkestpixeldungeon.actors.Actor +import com.egoal.darkestpixeldungeon.actors.Char +import com.egoal.darkestpixeldungeon.actors.Damage +import com.egoal.darkestpixeldungeon.actors.buffs.Buff +import com.egoal.darkestpixeldungeon.actors.buffs.Invisibility +import com.egoal.darkestpixeldungeon.actors.buffs.Unbalance +import com.egoal.darkestpixeldungeon.actors.hero.Hero +import com.egoal.darkestpixeldungeon.actors.hero.HeroClass +import com.egoal.darkestpixeldungeon.items.Item +import com.egoal.darkestpixeldungeon.mechanics.Ballistica +import com.egoal.darkestpixeldungeon.messages.M +import com.egoal.darkestpixeldungeon.scenes.CellSelector +import com.egoal.darkestpixeldungeon.scenes.GameScene +import com.egoal.darkestpixeldungeon.sprites.CharSprite +import com.egoal.darkestpixeldungeon.sprites.ItemSpriteSheet +import com.egoal.darkestpixeldungeon.sprites.MissileSprite +import com.egoal.darkestpixeldungeon.utils.GLog +import com.watabou.noosa.audio.Sample +import com.watabou.utils.Callback +import com.watabou.utils.Random +import java.util.ArrayList +import kotlin.math.max + +class MagicBow : MeleeWeapon() { + + init { + image = ItemSpriteSheet.RANGER_BOW + + tier = 2 + defaultAction = AC_SHOOT + usesTargeting = true + DLY = 1.2f + } + + override fun min(lvl: Int): Int = lvl + 1 + override fun max(lvl: Int): Int = 4 * (tier + 1) + lvl * (tier + 1) + + override fun actions(hero: Hero?): ArrayList = super.actions(hero).apply { add(AC_SHOOT) } + + override fun execute(hero: Hero, action: String) { + super.execute(hero, action) + if (action == AC_SHOOT) { + if (!isEquipped(hero)) GLog.w(M.L(this, "need_equipped")) + else { + Item.curUser = hero + Item.curItem = this + GameScene.selectCell(shooter) + } + } + } + + //todo: handle the proc things. + private fun giveShootDamage(hero: Hero, enemy: Char) = + hero.giveDamage(enemy).type(Damage.Type.MAGICAL).addFeature(Damage.Feature.RANGED) + + private fun onShot(enemy: Char) { + val hero = Item.curUser + if (Dungeon.level.adjacent(hero.pos, enemy.pos)) { + val dur = if (hero.heroClass == HeroClass.HUNTRESS) 1.5f else 2.5f + Buff.prolong(hero, Unbalance::class.java, dur) + } + + val dmg = giveShootDamage(hero, enemy) + // still need a hit check + if (enemy.checkHit(dmg)) { + //todo: may proc enchantment here. +// hero.attackProc(dmg) +// if (!enemy.isAlive) return + + enemy.defendDamage(dmg) + enemy.defenseProc(dmg) + enemy.takeDamage(dmg) + enemy.sprite.burst(0x57e14e, level() / 2 + 2) + + Statistics.HighestDamage = max(Statistics.HighestDamage, dmg.value) + if (!enemy.isAlive) hero.onKillChar(enemy) + + Sample.INSTANCE.play(Assets.SND_HIT, 1f, 1f, Random.Float(0.8f, 1.25f)) + } else { + enemy.sprite.showStatus(CharSprite.NEUTRAL, enemy.defenseVerb()) + } + Invisibility.dispel() + } + + private val shooter = object : CellSelector.Listener { + override fun onSelect(cell: Int?) { + if (cell == null) return + + val hero = Item.curUser + val shot = Ballistica(hero.pos, cell, Ballistica.PROJECTILE) + val shotpos = shot.collisionPos + + if (cell == hero.pos || shotpos == hero.pos) { + GLog.i(M.L(MagicBow::class.java, "not_yourself")) + return + } + + hero.sprite.zap(shotpos) + hero.busy() + + Sample.INSTANCE.play(Assets.SND_MISS, 0.6f, 0.6f, 1.5f) + val enemy = Actor.findChar(shotpos) + val delay = hero.attackDelay() + + (hero.sprite.parent.recycle(MissileSprite::class.java) as MissileSprite).reset( + hero.pos, shotpos, ItemSpriteSheet.MAGIC_DART, null, Callback { + if (enemy != null) onShot(enemy) + + hero.spendAndNext(delay) + }) + } + + override fun prompt(): String = M.L(MagicBow::class.java, "prompt") + } + + companion object { + private const val AC_SHOOT = "shoot" + } + + class Broken : Item() { + init { + image = ItemSpriteSheet.RANGER_BOW + } + + override fun price(): Int = 10 + + override fun isIdentified(): Boolean = true + override fun isUpgradable(): Boolean = false + } +} \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/melee/Pitchfork.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/melee/Pitchfork.kt new file mode 100644 index 000000000..1cda007a8 --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/melee/Pitchfork.kt @@ -0,0 +1,29 @@ +package com.egoal.darkestpixeldungeon.items.weapon.melee + +import com.egoal.darkestpixeldungeon.actors.Char +import com.egoal.darkestpixeldungeon.actors.Damage +import com.egoal.darkestpixeldungeon.actors.buffs.Bleeding +import com.egoal.darkestpixeldungeon.actors.buffs.Buff +import com.egoal.darkestpixeldungeon.sprites.ItemSpriteSheet +import com.watabou.utils.Random +import kotlin.math.min + +class Pitchfork : MeleeWeapon() { + init { + image = ItemSpriteSheet.PITCHFORK + + tier = 4 + DLY = 1.5f + RCH = 2 + } + + // x1.33 + override fun max(lvl: Int): Int = (tier + 1) * 20 / 3 + lvl * (tier + 1) * 4 / 3 + + override fun proc(dmg: Damage): Damage { + if (Random.Int(5) == 0) + Buff.affect(dmg.to as Char, Bleeding::class.java).set(min(10, dmg.value / 4)) + + return super.proc(dmg) + } +} \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/melee/RedHandleDagger.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/melee/RedHandleDagger.kt new file mode 100644 index 000000000..63136f979 --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/items/weapon/melee/RedHandleDagger.kt @@ -0,0 +1,28 @@ +package com.egoal.darkestpixeldungeon.items.weapon.melee + +import com.egoal.darkestpixeldungeon.Dungeon +import com.egoal.darkestpixeldungeon.actors.Damage +import com.egoal.darkestpixeldungeon.actors.buffs.Buff +import com.egoal.darkestpixeldungeon.actors.buffs.Cripple +import com.egoal.darkestpixeldungeon.actors.mobs.Mob +import com.egoal.darkestpixeldungeon.sprites.ItemSpriteSheet +import com.watabou.utils.Random + +class RedHandleDagger : MeleeWeapon() { + init { + image = ItemSpriteSheet.RED_HANDLE_DAGGER + + tier = 1 + } + + override fun proc(dmg: Damage): Damage { + if (dmg.to is Mob) { + val defender = dmg.to as Mob + if (defender.surprisedBy(Dungeon.hero) && Random.Float() < 0.3f) { + Buff.prolong(defender, Cripple::class.java, 2f + level()) + } + } + + return super.proc(dmg) + } +} \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/CavesBossLevel.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/CavesBossLevel.kt index ad183db50..9f7210b1b 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/CavesBossLevel.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/CavesBossLevel.kt @@ -68,7 +68,18 @@ class CavesBossLevel : Level() { override fun build(iterations: Int): Boolean { loadMapDataFromFile(MAP_FILE) - val patch = Patch.Generate(this, 0.45f, 6) + repeat(3) { + // 7, 14-> 24, 31 + var x: Int + var y: Int + do { + x = Random.Int(7, 24) + y = Random.Int(14, 31) + } while (map[xy2cell(x, y)] != Terrain.EMPTY || ROOM_ENTRANCE.inside(x, y)) + map[xy2cell(x, y)] = Terrain.WALL + } + + val patch = Patch.Generate(this, 0.45f, 4) for (i in 0 until length()) { if (map[i] == Terrain.EMPTY && patch[i]) { map[i] = Terrain.WATER diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/Level.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/Level.kt index a617803bf..b29bc3364 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/Level.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/Level.kt @@ -66,7 +66,6 @@ import com.egoal.darkestpixeldungeon.levels.traps.Trap import com.egoal.darkestpixeldungeon.mechanics.ShadowCaster import com.egoal.darkestpixeldungeon.messages.Messages import com.egoal.darkestpixeldungeon.scenes.GameScene -import com.egoal.darkestpixeldungeon.sprites.ItemSprite import com.egoal.darkestpixeldungeon.utils.BArray import com.egoal.darkestpixeldungeon.utils.GLog import com.watabou.noosa.Game @@ -188,7 +187,7 @@ abstract class Level : Bundlable { customTiles.clear() luminaries.clear() - Generator.ResetCategoryProbs() + Generator.resetCategoryProbs() if (build(i)) { Log.d("dpd", "level build okay after $i trails.") break diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/RegularLevel.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/RegularLevel.kt index 34125447c..5e2802b66 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/RegularLevel.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/RegularLevel.kt @@ -515,7 +515,8 @@ abstract class RegularLevel : Level() { SecretLibraryDigger::class.java to 1f, SecretSummoningDigger::class.java to 1f, SecretTreasuryDigger::class.java to 1f, - SecretGardenDigger::class.java to 1f + SecretGardenDigger::class.java to 1f, + SecretMerchantDigger::class.java to 0.5f ) val NormalDiggers: HashMap, Float> = hashMapOf( diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/VillageLevel.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/VillageLevel.kt index 28aff118c..fd3e9a22f 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/VillageLevel.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/VillageLevel.kt @@ -121,6 +121,9 @@ class VillageLevel : RegularLevel() { putMobAt(Monument::class.java, 21, 2) + // seeker + putMobAt(Seeker::class.java, 12, 18) + // Buff.affect(putMobAt(Rat::class.java, 16, 29), Dementage::class.java) // (putMobAt(Merchant::class.java, 16, 27) as Merchant).apply { // for (i in 1..10) addItemToSell(Generator.generate()) @@ -130,6 +133,8 @@ class VillageLevel : RegularLevel() { // addItemToSell(BattleGloves()) // addItemToSell(TomeOfPerk()) // } +// (putMobAt(UndeadShopkeeper::class.java, 15, 27) as UndeadShopkeeper).initSellItems() +// putMobAt(Yvette::class.java, 15, 27) } override fun onSwitchedIn() { diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/diggers/Rect.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/diggers/Rect.kt index 1208d216c..f499e9f4e 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/diggers/Rect.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/diggers/Rect.kt @@ -17,7 +17,8 @@ open class Rect(var x1: Int = 0, var x2: Int = 0, var y1: Int = 0, var y2: Int = fun shrink(inner: Int) = Rect(x1 + inner, x2 - inner, y1 + inner, y2 - inner) - fun inside(pt: Point) = pt.x in x1..x2 && pt.y in y1..y2 + fun inside(pt: Point) = inside(pt.x, pt.y) + fun inside(x: Int, y: Int) = x in x1..x2 && y in y1..y2 fun getAllPoints(): HashSet { val points = HashSet() diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/diggers/secret/SecretMerchantDigger.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/diggers/secret/SecretMerchantDigger.kt new file mode 100644 index 000000000..e7c2de8bc --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/diggers/secret/SecretMerchantDigger.kt @@ -0,0 +1,36 @@ +package com.egoal.darkestpixeldungeon.levels.diggers.secret + +import com.egoal.darkestpixeldungeon.actors.mobs.npcs.UndeadShopkeeper +import com.egoal.darkestpixeldungeon.levels.Level +import com.egoal.darkestpixeldungeon.levels.Terrain +import com.egoal.darkestpixeldungeon.levels.diggers.DigResult +import com.egoal.darkestpixeldungeon.levels.diggers.Rect +import com.egoal.darkestpixeldungeon.levels.diggers.Wall +import com.egoal.darkestpixeldungeon.levels.diggers.normal.RectDigger +import com.watabou.utils.PathFinder +import com.watabou.utils.Point +import com.watabou.utils.Random + +class SecretMerchantDigger : RectDigger() { + private lateinit var shopkeeper: UndeadShopkeeper + + override fun chooseRoomSize(wall: Wall): Point = Point(Random.Int(3, 6), Random.Int(3, 6)) + + override fun dig(level: Level, wall: Wall, rect: Rect): DigResult { + Fill(level, rect, Terrain.GRASS) + val door = level.pointToCell(overlappedWall(wall, rect).random()) + Set(level, door, Terrain.SECRET_DOOR) + + if(!::shopkeeper.isInitialized){ + shopkeeper = UndeadShopkeeper() + shopkeeper.initSellItems() + } + + shopkeeper.pos = level.pointToCell(rect.center) + for (i in PathFinder.NEIGHBOURS8) + if (Random.Int(2) == 0) Set(level, shopkeeper.pos, Terrain.WATER) + level.mobs.add(shopkeeper) + + return DigResult(rect, DigResult.Type.Secret) + } +} \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/features/Chasm.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/features/Chasm.kt index 3f027d93c..0008d1465 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/features/Chasm.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/features/Chasm.kt @@ -15,6 +15,7 @@ import com.egoal.darkestpixeldungeon.actors.mobs.npcs.GhostHero import com.egoal.darkestpixeldungeon.items.artifacts.TimekeepersHourglass import com.egoal.darkestpixeldungeon.levels.RegularLevel import com.egoal.darkestpixeldungeon.levels.diggers.DigResult +import com.egoal.darkestpixeldungeon.messages.M import com.egoal.darkestpixeldungeon.messages.Messages import com.egoal.darkestpixeldungeon.scenes.GameScene import com.egoal.darkestpixeldungeon.scenes.InterlevelScene @@ -68,14 +69,18 @@ object Chasm { fun HeroLand() { Dungeon.hero.apply { sprite.burst(sprite.blood(), 10) - takeDamage(Damage(Random.NormalIntRange(HP / 3, HT / 3), { - Badges.validateDeathFromFalling() - Dungeon.fail(javaClass) - GLog.n(Messages.get(Chasm::class.java, "ondeath")) + takeDamage(Damage(Random.NormalIntRange(HP / 3, HT / 3), object : Hero.Doom { + override fun onDeath() { + Badges.validateDeathFromFalling() + Dungeon.fail(Chasm::class.java) + GLog.n(M.L(Chasm::class.java, "ondeath")) + } }, this)) - Buff.prolong(this, Cripple::class.java, Cripple.DURATION) - Buff.affect(this, Bleeding::class.java).set(HT / 8) + if (isAlive) { + Buff.prolong(this, Cripple::class.java, Cripple.DURATION) + Buff.affect(this, Bleeding::class.java).set(HT / 8) + } } Camera.main.shake(4f, 0.2f) diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/features/HighGrass.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/features/HighGrass.kt index ed7e331d4..9ca932c96 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/features/HighGrass.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/features/HighGrass.kt @@ -29,7 +29,7 @@ object HighGrass { val prize = Harvest(level, pos, ch) if (prize != null) level.drop(prize, pos).sprite.drop() - if (prize is Plant.Seed) Level.set(pos, Terrain.GRASS) + if (prize is Plant.Seed || Dungeon.depth == 0) Level.set(pos, Terrain.GRASS) GameScene.updateMap(pos) } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/traps/LightningTrap.java b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/traps/LightningTrap.java deleted file mode 100644 index 9c845c18f..000000000 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/traps/LightningTrap.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Pixel Dungeon - * Copyright (C) 2012-2015 Oleg Dolya - * - * Shattered Pixel Dungeon - * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.levels.traps; - -import com.egoal.darkestpixeldungeon.actors.Damage; -import com.egoal.darkestpixeldungeon.effects.CellEmitter; -import com.egoal.darkestpixeldungeon.Dungeon; -import com.egoal.darkestpixeldungeon.actors.Actor; -import com.egoal.darkestpixeldungeon.actors.Char; -import com.egoal.darkestpixeldungeon.effects.Lightning; -import com.egoal.darkestpixeldungeon.effects.particles.SparkParticle; -import com.egoal.darkestpixeldungeon.items.Heap; -import com.egoal.darkestpixeldungeon.items.Item; -import com.egoal.darkestpixeldungeon.items.wands.Wand; -import com.egoal.darkestpixeldungeon.messages.Messages; -import com.egoal.darkestpixeldungeon.sprites.TrapSprite; -import com.egoal.darkestpixeldungeon.utils.GLog; -import com.watabou.noosa.Camera; -import com.watabou.utils.Random; - -import java.util.ArrayList; - -public class LightningTrap extends Trap { - - { - color = TrapSprite.TEAL; - shape = TrapSprite.CROSSHAIR; - } - - @Override - public void activate() { - - Char ch = Actor.findChar(pos); - - if (ch != null) { - ch.takeDamage(new Damage(Math.max(1, Random.Int(ch.HP / 3, 2 * ch.HP / - 3)), this, ch).type(Damage.Type.MAGICAL).addElement(Damage.Element.LIGHT)); - - if (ch == Dungeon.hero) { - - Camera.main.shake(2, 0.3f); - - if (!ch.isAlive()) { - Dungeon.fail(getClass()); - GLog.n(Messages.get(this, "ondeath")); - } - } - - ArrayList arcs = new ArrayList<>(); - arcs.add(new Lightning.Arc(pos - Dungeon.level.width(), pos + Dungeon - .level.width())); - arcs.add(new Lightning.Arc(pos - 1, pos + 1)); - - ch.sprite.parent.add(new Lightning(arcs, null)); - } - - Heap heap = Dungeon.level.getHeaps().get(pos); - if (heap != null) { - //TODO: this should probably charge staffs too - Item item = heap.getItems().peek(); - if (item instanceof Wand) { - Wand wand = (Wand) item; - ((Wand) item).curCharges += (int) Math.ceil((wand.maxCharges - wand - .curCharges) / 2f); - } - } - - CellEmitter.center(pos).burst(SparkParticle.FACTORY, Random.IntRange(3, 4)); - } -} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/traps/LightningTrap.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/traps/LightningTrap.kt new file mode 100644 index 000000000..0e137787b --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/traps/LightningTrap.kt @@ -0,0 +1,74 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.levels.traps + +import com.egoal.darkestpixeldungeon.actors.Damage +import com.egoal.darkestpixeldungeon.effects.CellEmitter +import com.egoal.darkestpixeldungeon.Dungeon +import com.egoal.darkestpixeldungeon.actors.Actor +import com.egoal.darkestpixeldungeon.effects.Lightning +import com.egoal.darkestpixeldungeon.effects.particles.SparkParticle +import com.egoal.darkestpixeldungeon.items.wands.Wand +import com.egoal.darkestpixeldungeon.messages.M +import com.egoal.darkestpixeldungeon.messages.Messages +import com.egoal.darkestpixeldungeon.sprites.TrapSprite +import com.egoal.darkestpixeldungeon.utils.GLog +import com.watabou.noosa.Camera +import com.watabou.utils.Random + +import java.util.ArrayList +import kotlin.math.ceil +import kotlin.math.max + +class LightningTrap : Trap() { + + init { + color = TrapSprite.TEAL + shape = TrapSprite.CROSSHAIR + } + + override fun activate() { + Actor.findChar(pos)?.let { + it.takeDamage(Damage(max(1, Random.Int(it.HP / 3, it.HP * 2 / 3)), this, it).type(Damage.Type.MAGICAL).addElement(Damage.Element.LIGHT)) + + if (it === Dungeon.hero) { + Camera.main.shake(2f, 0.3f) + if (!it.isAlive) { + Dungeon.fail(javaClass) + GLog.n(M.L(this, "ondeath")) + } + } + + val arcs = ArrayList() + arcs.add(Lightning.Arc(pos - Dungeon.level.width(), pos + Dungeon.level.width())) + arcs.add(Lightning.Arc(pos - 1, pos + 1)) + + it.sprite.parent.add(Lightning(arcs, null)) + } + + Dungeon.level.heaps.get(pos)?.let { + val item = it.items.peek() + if (item is Wand) item.curCharges += ceil((item.maxCharges - item.curCharges) / 2f).toInt() + } + + CellEmitter.center(pos).burst(SparkParticle.FACTORY, Random.IntRange(3, 4)) + } +} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/traps/WarpingTrap.java b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/traps/WarpingTrap.java deleted file mode 100644 index b48d74abd..000000000 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/traps/WarpingTrap.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Pixel Dungeon - * Copyright (C) 2012-2015 Oleg Dolya - * - * Shattered Pixel Dungeon - * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.levels.traps; - -import com.egoal.darkestpixeldungeon.Assets; -import com.egoal.darkestpixeldungeon.Dungeon; -import com.egoal.darkestpixeldungeon.actors.Actor; -import com.egoal.darkestpixeldungeon.actors.Char; -import com.egoal.darkestpixeldungeon.actors.buffs.Buff; -import com.egoal.darkestpixeldungeon.actors.mobs.Mob; -import com.egoal.darkestpixeldungeon.actors.mobs.npcs.GhostHero; -import com.egoal.darkestpixeldungeon.effects.CellEmitter; -import com.egoal.darkestpixeldungeon.effects.Speck; -import com.egoal.darkestpixeldungeon.items.Heap; -import com.egoal.darkestpixeldungeon.items.artifacts.DriedRose; -import com.egoal.darkestpixeldungeon.items.artifacts.TimekeepersHourglass; -import com.egoal.darkestpixeldungeon.items.Item; -import com.egoal.darkestpixeldungeon.scenes.InterlevelScene; -import com.egoal.darkestpixeldungeon.sprites.TrapSprite; -import com.watabou.noosa.Game; -import com.watabou.noosa.audio.Sample; -import com.watabou.utils.Random; - -import java.util.ArrayList; - -public class WarpingTrap extends Trap { - - { - color = TrapSprite.TEAL; - shape = TrapSprite.STARS; - } - - @Override - public void activate() { - CellEmitter.get(pos).start(Speck.factory(Speck.LIGHT), 0.2f, 3); - Sample.INSTANCE.play(Assets.SND_TELEPORT); - - if (Dungeon.depth > 1 && !Dungeon.bossLevel()) { - - //each depth has 1 more weight than the previous depth. - float[] depths = new float[Dungeon.depth - 1]; - for (int i = 1; i < Dungeon.depth; i++) depths[i - 1] = i; - int depth = 1 + Math.max(Random.chances(depths), Random.chances(depths)); - - Heap heap = Dungeon.level.getHeaps().get(pos); - if (heap != null) { - ArrayList dropped = Dungeon.droppedItems.get(depth); - if (dropped == null) { - Dungeon.droppedItems.put(depth, dropped = new ArrayList()); - } - for (Item item : heap.getItems()) { - dropped.add(item); - } - heap.destroy(); - } - - Char ch = Actor.findChar(pos); - if (ch == Dungeon.hero) { - Buff buff = Dungeon.hero.buff(TimekeepersHourglass.TimeFreeze.class); - if (buff != null) buff.detach(); - - for (Mob mob : Dungeon.level.getMobs().toArray(new Mob[0])) - if (mob instanceof GhostHero) mob.destroy(); - - InterlevelScene.mode = InterlevelScene.Mode.RETURN; - InterlevelScene.returnDepth = depth; - InterlevelScene.returnPos = -1; - Game.switchScene(InterlevelScene.class); - } else if (ch != null) { - ch.destroy(); - ch.sprite.killAndErase(); - Dungeon.level.getMobs().remove(ch); - } - - } - - } -} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/levels/traps/WarpingTrap.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/traps/WarpingTrap.kt new file mode 100644 index 000000000..7d9307be8 --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/levels/traps/WarpingTrap.kt @@ -0,0 +1,88 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.levels.traps + +import com.egoal.darkestpixeldungeon.Assets +import com.egoal.darkestpixeldungeon.Dungeon +import com.egoal.darkestpixeldungeon.actors.Actor +import com.egoal.darkestpixeldungeon.actors.Char +import com.egoal.darkestpixeldungeon.actors.buffs.Buff +import com.egoal.darkestpixeldungeon.actors.mobs.Mob +import com.egoal.darkestpixeldungeon.actors.mobs.npcs.GhostHero +import com.egoal.darkestpixeldungeon.effects.CellEmitter +import com.egoal.darkestpixeldungeon.effects.Speck +import com.egoal.darkestpixeldungeon.items.Heap +import com.egoal.darkestpixeldungeon.items.artifacts.DriedRose +import com.egoal.darkestpixeldungeon.items.artifacts.TimekeepersHourglass +import com.egoal.darkestpixeldungeon.items.Item +import com.egoal.darkestpixeldungeon.scenes.InterlevelScene +import com.egoal.darkestpixeldungeon.sprites.TrapSprite +import com.watabou.noosa.Game +import com.watabou.noosa.audio.Sample +import com.watabou.utils.Random + +import java.util.ArrayList + +class WarpingTrap : Trap() { + + init { + color = TrapSprite.TEAL + shape = TrapSprite.STARS + } + + override fun activate() { + CellEmitter.get(pos).start(Speck.factory(Speck.LIGHT), 0.2f, 3) + Sample.INSTANCE.play(Assets.SND_TELEPORT) + + if (Dungeon.depth <= 1 || Dungeon.bossLevel()) return + + //each depth has 1 more weight than the previous depth. + val depths = (1 until Dungeon.depth).map { it.toFloat() }.toFloatArray() + val depth = 1 + Math.max(Random.chances(depths), Random.chances(depths)) + + Dungeon.level.heaps.get(pos)?.let { heap -> + var dropped = Dungeon.droppedItems.get(depth) + if (dropped == null) { + dropped = ArrayList() + Dungeon.droppedItems.put(depth, dropped) + } + dropped.addAll(heap.items) + heap.destroy() + } + + Actor.findChar(pos)?.let { ch -> + if (ch === Dungeon.hero) { + Dungeon.hero.buff(TimekeepersHourglass.TimeFreeze::class.java)?.detach() + for (gh in Dungeon.level.mobs.filterIsInstance()) gh.destroy() + + InterlevelScene.mode = InterlevelScene.Mode.RETURN + InterlevelScene.returnDepth = depth + InterlevelScene.returnPos = -1 + Game.switchScene(InterlevelScene::class.java) + } else { + // just destroy the char + ch.destroy() + ch.sprite.killAndErase() + Dungeon.level.mobs.remove(ch) + } + } + } +} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/messages/Languages.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/messages/Languages.kt index 718ae7aaf..efff9ac87 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/messages/Languages.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/messages/Languages.kt @@ -46,9 +46,9 @@ enum class Languages(val nativeName: String, val code: String get() = locale.toString() companion object { - fun matchLocale(locale: Locale): Languages = values().find { it.locale == locale } ?: ENGLISH + fun matchLocale(locale: Locale): Languages = values().find { it.locale == locale } ?: CHINESE - fun matchCode(code: String): Languages = values().find { it.code == code } ?: ENGLISH + fun matchCode(code: String): Languages = values().find { it.code == code } ?: CHINESE } } \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/AmuletScene.java b/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/AmuletScene.java index 8205bec51..eb01612a2 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/AmuletScene.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/AmuletScene.java @@ -115,7 +115,7 @@ protected void onClick() { @Override protected void onBackPressed() { - InterlevelScene.mode = InterlevelScene.Mode.CONTINUE; + InterlevelScene.Companion.setMode(InterlevelScene.Mode.CONTINUE); Game.switchScene(InterlevelScene.class); } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/BadgesScene.java b/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/BadgesScene.java deleted file mode 100644 index 5223ef6d8..000000000 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/BadgesScene.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Pixel Dungeon - * Copyright (C) 2012-2015 Oleg Dolya - * - * Shattered Pixel Dungeon - * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.scenes; - -import com.egoal.darkestpixeldungeon.Assets; -import com.egoal.darkestpixeldungeon.Badges; -import com.egoal.darkestpixeldungeon.DarkestPixelDungeon; -import com.egoal.darkestpixeldungeon.effects.BadgeBanner; -import com.egoal.darkestpixeldungeon.messages.Messages; -import com.egoal.darkestpixeldungeon.ui.Archs; -import com.egoal.darkestpixeldungeon.ui.ExitButton; -import com.egoal.darkestpixeldungeon.windows.WndBadge; -import com.egoal.darkestpixeldungeon.ui.Window; -import com.watabou.noosa.Camera; -import com.watabou.noosa.Game; -import com.watabou.noosa.Image; -import com.watabou.noosa.RenderedText; -import com.watabou.noosa.audio.Music; -import com.watabou.noosa.audio.Sample; -import com.watabou.noosa.ui.Button; -import com.watabou.utils.Callback; -import com.watabou.utils.Random; - -import java.util.List; - -public class BadgesScene extends PixelScene { - - @Override - public void create() { - - super.create(); - - Music.INSTANCE.play(Assets.TRACK_MAIN_THEME, true); - Music.INSTANCE.volume(DarkestPixelDungeon.musicVol() / 10f); - - uiCamera.visible = false; - - int w = Camera.main.width; - int h = Camera.main.height; - - Archs archs = new Archs(); - archs.setSize(w, h); - add(archs); - - float pw = Math.min(w, (DarkestPixelDungeon.landscape() ? MIN_WIDTH_L : - MIN_WIDTH_P) * 3) - 16; - float ph = Math.min(h, (DarkestPixelDungeon.landscape() ? MIN_HEIGHT_L : - MIN_HEIGHT_P) * 3) - 32; - - float size = (float) Math.sqrt(pw * ph / 27f); - int nCols = (int) Math.ceil(pw / size); - int nRows = (int) Math.ceil(ph / size); - size = Math.min(pw / nCols, ph / nRows); - - float left = (w - size * nCols) / 2; - float top = (h - size * nRows) / 2; - - RenderedText title = renderText(Messages.get(this, "title"), 9); - title.hardlight(Window.TITLE_COLOR); - title.x = (w - title.width()) / 2; - title.y = (top - title.baseLine()) / 2; - align(title); - add(title); - - Badges.INSTANCE.loadGlobal(); - - List badges = Badges.INSTANCE.filtered(true); - for (int i = 0; i < nRows; i++) { - for (int j = 0; j < nCols; j++) { - int index = i * nCols + j; - Badges.Badge b = index < badges.size() ? badges.get(index) : null; - BadgeButton button = new BadgeButton(b); - button.setPos( - left + j * size + (size - button.width()) / 2, - top + i * size + (size - button.height()) / 2); - align(button); - add(button); - } - } - - ExitButton btnExit = new ExitButton(); - btnExit.setPos(Camera.main.width - btnExit.width(), 0); - add(btnExit); - - fadeIn(); - - Badges.INSTANCE.setLoadingListener(new Callback() { - @Override - public void call() { - if (Game.scene() == BadgesScene.this) { - DarkestPixelDungeon.switchNoFade(BadgesScene.class); - } - } - }); - } - - @Override - public void destroy() { - - Badges.INSTANCE.saveGlobal(); - Badges.INSTANCE.setLoadingListener(null); - - super.destroy(); - } - - @Override - protected void onBackPressed() { - DarkestPixelDungeon.switchNoFade(TitleScene.class); - } - - private static class BadgeButton extends Button { - - private Badges.Badge badge; - - private Image icon; - - public BadgeButton(Badges.Badge badge) { - super(); - - this.badge = badge; - active = (badge != null); - - icon = active ? BadgeBanner.image(badge.getImage()) : new Image(Assets.LOCKED); - add(icon); - - setSize(icon.width(), icon.height()); - } - - @Override - protected void layout() { - super.layout(); - - icon.x = x + (width - icon.width()) / 2; - icon.y = y + (height - icon.height()) / 2; - } - - @Override - public void update() { - super.update(); - - if (Random.Float() < Game.elapsed * 0.1) { - BadgeBanner.highlight(icon, badge.getImage()); - } - } - - @Override - protected void onClick() { - Sample.INSTANCE.play(Assets.SND_CLICK, 0.7f, 0.7f, 1.2f); - Game.scene().add(new WndBadge(badge)); - } - } -} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/KBadgesScene.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/BadgesScene.kt similarity index 97% rename from core/src/main/java/com/egoal/darkestpixeldungeon/scenes/KBadgesScene.kt rename to core/src/main/java/com/egoal/darkestpixeldungeon/scenes/BadgesScene.kt index 839545e7d..fb096f754 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/KBadgesScene.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/BadgesScene.kt @@ -10,12 +10,11 @@ import com.watabou.noosa.Camera import com.watabou.noosa.Game import com.watabou.noosa.Image import com.watabou.noosa.audio.Music -import com.watabou.noosa.ui.Button import com.watabou.noosa.ui.Component import com.watabou.utils.Callback import com.watabou.utils.Random -class KBadgesScene : PixelScene() { +class BadgesScene : PixelScene() { private val archs: Archs by lazy { Archs() } override fun create() { super.create() @@ -69,7 +68,7 @@ class KBadgesScene : PixelScene() { fadeIn() Badges.loadingListener = Callback { - if (Game.scene() === this) DarkestPixelDungeon.switchNoFade(KBadgesScene::class.java) + if (Game.scene() === this) DarkestPixelDungeon.switchNoFade(BadgesScene::class.java) } } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/ChangesScene.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/ChangesScene.kt index f2d87452a..e0c60740b 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/ChangesScene.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/ChangesScene.kt @@ -95,7 +95,7 @@ class ChangesScene : PixelScene() { // add versions' button val HSPLIT = "---" val oldVersions = arrayOf( - "0.4.1", "0.4.0", HSPLIT, + "0.4.2a", "0.4.2", "0.4.1", "0.4.0", HSPLIT, "0.3.2a", "0.3.2", "0.3.1a", "0.3.1", "0.3.0", HSPLIT, "0.2.4c", "0.2.4b", "0.2.4a", "0.2.4", "0.2.3", "0.2.2b", "0.2.2a", "0.2.2", "0.2.1a", "0.2.1", "0.2.0", HSPLIT, "0.1.3", "0.1.2", "0.1.1", "0.1.0") diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/GameScene.java index 2a98f1547..e911bce2f 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/GameScene.java @@ -322,7 +322,7 @@ public void draw() { busy.y = pane.bottom() + 1; add(busy); - switch (InterlevelScene.mode) { + switch (InterlevelScene.Companion.getMode()) { case RESURRECT: ScrollOfTeleportation.Companion.appear(Dungeon.hero, Dungeon.level .getEntrance()); @@ -380,7 +380,7 @@ public void draw() { Camera.main.target = hero; - if (InterlevelScene.mode != InterlevelScene.Mode.NONE) { + if (InterlevelScene.Companion.getMode() != InterlevelScene.Mode.NONE) { if (Dungeon.depth < Statistics.INSTANCE.getDeepestFloor()) { GLog.h(Messages.get(this, "welcome_back"), Dungeon.depth); } else { @@ -409,7 +409,7 @@ public void draw() { ((RegularLevel) Dungeon.level).secretDoors() > 0) GLog.n(Messages.get(this, "secrets")); - InterlevelScene.mode = InterlevelScene.Mode.NONE; + InterlevelScene.Companion.setMode(InterlevelScene.Mode.NONE); fadeIn(); } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/InterlevelScene.java b/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/InterlevelScene.java deleted file mode 100644 index 371061033..000000000 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/InterlevelScene.java +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Pixel Dungeon - * Copyright (C) 2012-2015 Oleg Dolya - * - * Shattered Pixel Dungeon - * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.scenes; - -import com.egoal.darkestpixeldungeon.Assets; -import com.egoal.darkestpixeldungeon.Dungeon; -import com.egoal.darkestpixeldungeon.DarkestPixelDungeon; -import com.egoal.darkestpixeldungeon.Statistics; -import com.egoal.darkestpixeldungeon.actors.Actor; -; -import com.egoal.darkestpixeldungeon.levels.Level; -import com.egoal.darkestpixeldungeon.messages.Messages; -import com.egoal.darkestpixeldungeon.ui.GameLog; -import com.egoal.darkestpixeldungeon.windows.WndError; -import com.egoal.darkestpixeldungeon.windows.WndStory; -import com.watabou.noosa.Camera; -import com.watabou.noosa.Game; -import com.watabou.noosa.RenderedText; -import com.watabou.noosa.audio.Music; -import com.watabou.noosa.audio.Sample; - -import java.io.FileNotFoundException; -import java.io.IOException; - -public class InterlevelScene extends PixelScene { - - private static final float TIME_TO_FADE = 0.3f; - - public enum Mode { - DESCEND, ASCEND, CONTINUE, RESURRECT, RETURN, FALL, RESET, NONE, REFLUX, - } - - public static Mode mode; - - public static int returnDepth; - public static int returnPos; - - public static boolean noStory = false; - - public static boolean fallIntoPit; - - private enum Phase { - FADE_IN, STATIC, FADE_OUT - } - - private Phase phase; - private float timeLeft; - - private RenderedText message; - - private Thread thread; - private Exception error = null; - - @Override - public void create() { - super.create(); - - String text = Messages.get(Mode.class, mode.name()); - - message = renderText(text, 9); - message.x = (Camera.main.width - message.width()) / 2; - message.y = (Camera.main.height - message.height()) / 2; - align(message); - add(message); - - phase = Phase.FADE_IN; - timeLeft = TIME_TO_FADE; - - thread = new Thread() { - @Override - public void run() { - - try { - switch (mode) { - case DESCEND: - descend(); - break; - case ASCEND: - ascend(); - break; - case CONTINUE: - restore(); - break; - case REFLUX: - reflux(); - break; - case RESURRECT: - resurrect(); - break; - case RETURN: - returnTo(); - break; - case FALL: - fall(); - break; - case RESET: - reset(); - break; - } - - if (Dungeon.bossLevel()) - Sample.INSTANCE.load(Assets.SND_BOSS); - - } catch (Exception e) { - - error = e; - - } - - if (phase == Phase.STATIC && error == null) { - phase = Phase.FADE_OUT; - timeLeft = TIME_TO_FADE; - } - } - }; - thread.start(); - } - - @Override - public void update() { - super.update(); - - float p = timeLeft / TIME_TO_FADE; - - switch (phase) { - - case FADE_IN: - message.alpha(1 - p); - if ((timeLeft -= Game.elapsed) <= 0) { - if (!thread.isAlive() && error == null) { - phase = Phase.FADE_OUT; - timeLeft = TIME_TO_FADE; - } else { - phase = Phase.STATIC; - } - } - break; - - case FADE_OUT: - message.alpha(p); - - if (mode == Mode.CONTINUE || (mode == Mode.DESCEND && Dungeon.depth - == 1)) { - Music.INSTANCE.volume(p * (DarkestPixelDungeon.musicVol() / 10f)); - } - if ((timeLeft -= Game.elapsed) <= 0) { - Game.switchScene(GameScene.class); - } - break; - - case STATIC: - if (error != null) { - String errorMsg; - if (error instanceof FileNotFoundException) - errorMsg = Messages.get(this, "file_not_found"); - else if (error instanceof IOException) - errorMsg = Messages.get(this, "io_error"); - else - throw new RuntimeException(error); - - if (InterlevelScene.mode == Mode.REFLUX) - errorMsg = "no backup file found, return."; - - add(new WndError(errorMsg) { - public void onBackPressed() { - super.onBackPressed(); - if (InterlevelScene.mode == Mode.REFLUX) - Game.switchScene(StartScene.class); - else { - InterlevelScene.mode = Mode.REFLUX; - Game.switchScene(InterlevelScene.class); - } - } - }); - error = null; - } - break; - } - } - - private void descend() throws IOException { - - Actor.fixTime(); - if (Dungeon.hero == null) { - Dungeon.init(); - if (noStory) { - Dungeon.chapters.add(WndStory.ID_SEWERS); - noStory = false; - } - GameLog.wipe(); - } else { - Dungeon.hero.holdFollowers(Dungeon.level); - Dungeon.saveAll(true); - } - - Level level; - if (Dungeon.depth >= Statistics.INSTANCE.getDeepestFloor()) { - level = Dungeon.newLevel(); - } else { - Dungeon.depth++; - level = Dungeon.loadLevel(Dungeon.hero.getHeroClass()); - } - Dungeon.switchLevel(level, level.getEntrance()); - } - - private void fall() throws IOException { - - Actor.fixTime(); - Dungeon.hero.holdFollowers(Dungeon.level); - Dungeon.saveAll(true); - - Level level; - if (Dungeon.depth >= Statistics.INSTANCE.getDeepestFloor()) { - level = Dungeon.newLevel(); - } else { - Dungeon.depth++; - level = Dungeon.loadLevel(Dungeon.hero.getHeroClass()); - } - Dungeon.switchLevel(level, fallIntoPit ? level.pitCell() : level - .randomRespawnCell()); - } - - private void ascend() throws IOException { - Actor.fixTime(); - Dungeon.hero.holdFollowers(Dungeon.level); - - Dungeon.saveAll(); - Dungeon.depth--; - Level level = Dungeon.loadLevel(Dungeon.hero.getHeroClass()); - Dungeon.switchLevel(level, level.getExit()); - } - - private void returnTo() throws IOException { - - Actor.fixTime(); - Dungeon.hero.holdFollowers(Dungeon.level); - - Dungeon.saveAll(); - Dungeon.depth = returnDepth; - Level level = Dungeon.loadLevel(Dungeon.hero.getHeroClass()); - Dungeon.switchLevel(level, returnPos); - } - - private void restore() throws IOException { - Actor.fixTime(); - - GameLog.wipe(); - - // init level - Dungeon.loadGame(StartScene.Companion.getCurrentClass()); - - if (Dungeon.depth == -1) { - Dungeon.depth = Statistics.INSTANCE.getDeepestFloor(); - Dungeon.switchLevel(Dungeon.loadLevel(StartScene.Companion.getCurrentClass()), -1); - } else { - Dungeon.switchLevel(Dungeon.loadLevel(StartScene.Companion.getCurrentClass()), Dungeon - .hero.pos); - } - } - - private void reflux() throws IOException { - Actor.fixTime(); - - GameLog.wipe(); - - Dungeon.loadBackupGame(StartScene.Companion.getCurrentClass()); - Level level = Dungeon.loadBackupLevel(StartScene.Companion.getCurrentClass()); - Dungeon.switchLevel(level, Dungeon.hero.pos); - } - - private void resurrect() throws IOException { - - Actor.fixTime(); - Dungeon.hero.holdFollowers(Dungeon.level); - - if (Dungeon.level.getLocked()) { - Dungeon.hero.resurrect(Dungeon.depth); - Dungeon.depth--; - Level level = Dungeon.newLevel(); - Dungeon.switchLevel(level, level.getEntrance()); - } else { - Dungeon.hero.resurrect(-1); - Dungeon.resetLevel(); - } - } - - private void reset() throws IOException { - - Actor.fixTime(); - Dungeon.hero.holdFollowers(Dungeon.level); - - Dungeon.depth--; - Level level = Dungeon.newLevel(); - //FIXME this only partially addresses issues regarding weak floors. - Level.Companion.setWeakFloorCreated(false); - Dungeon.switchLevel(level, level.getEntrance()); - } - - @Override - protected void onBackPressed() { - //Do nothing - } -} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/InterlevelScene.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/InterlevelScene.kt new file mode 100644 index 000000000..b2384d243 --- /dev/null +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/InterlevelScene.kt @@ -0,0 +1,309 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2016 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.egoal.darkestpixeldungeon.scenes + +import com.egoal.darkestpixeldungeon.Assets +import com.egoal.darkestpixeldungeon.Dungeon +import com.egoal.darkestpixeldungeon.DarkestPixelDungeon +import com.egoal.darkestpixeldungeon.Statistics +import com.egoal.darkestpixeldungeon.actors.Actor +import com.egoal.darkestpixeldungeon.items.artifacts.HomurasShield +import com.egoal.darkestpixeldungeon.levels.Level +import com.egoal.darkestpixeldungeon.messages.M +import com.egoal.darkestpixeldungeon.messages.Messages +import com.egoal.darkestpixeldungeon.ui.GameLog +import com.egoal.darkestpixeldungeon.windows.WndError +import com.egoal.darkestpixeldungeon.windows.WndStory +import com.watabou.noosa.Camera +import com.watabou.noosa.Game +import com.watabou.noosa.RenderedText +import com.watabou.noosa.audio.Music +import com.watabou.noosa.audio.Sample + +import java.io.FileNotFoundException +import java.io.IOException + +class InterlevelScene : PixelScene() { + enum class Mode { + DESCEND, ASCEND, CONTINUE, RESURRECT, RETURN, FALL, RESET, NONE, REFLUX, BACK_TO_PAST + } + + private enum class Phase { + FADE_IN, STATIC, FADE_OUT + } + + private var phase: Phase = Phase.FADE_IN + private var timeLeft: Float = 0f + + private lateinit var message: RenderedText + + private lateinit var thread: Thread + private var error: Exception? = null + + override fun create() { + super.create() + + val text = Messages.get(Mode::class.java, mode.name) + + message = renderText(text, 9) + message.x = (Camera.main.width - message.width()) / 2 + message.y = (Camera.main.height - message.height()) / 2 + align(message) + add(message) + + phase = Phase.FADE_IN + timeLeft = TIME_TO_FADE + + thread = object : Thread() { + override fun run() { + try { + when (mode) { + Mode.DESCEND -> descend() + Mode.ASCEND -> ascend() + Mode.CONTINUE -> restore() + Mode.REFLUX -> reflux() + Mode.RESURRECT -> resurrect() + Mode.RETURN -> returnTo() + Mode.FALL -> fall() + Mode.RESET -> reset() + Mode.BACK_TO_PAST -> backToPast() + Mode.NONE -> { + } + } + + if (Dungeon.bossLevel()) + Sample.INSTANCE.load(Assets.SND_BOSS) + + } catch (e: Exception) { + error = e + } + + if (phase == Phase.STATIC && error == null) { + phase = Phase.FADE_OUT + timeLeft = TIME_TO_FADE + } + } + } + thread.start() + } + + override fun update() { + super.update() + + val p = timeLeft / TIME_TO_FADE + + when (phase) { + Phase.FADE_IN -> { + message.alpha(1 - p) + timeLeft -= Game.elapsed + if (timeLeft <= 0f) { + if (!thread.isAlive && error == null) { + phase = Phase.FADE_OUT + timeLeft = TIME_TO_FADE + } else phase = Phase.STATIC + } + } + + Phase.FADE_OUT -> { + message.alpha(p) + + if (mode == Mode.CONTINUE || mode == Mode.DESCEND && Dungeon.depth == 0) { + Music.INSTANCE.volume(p * (DarkestPixelDungeon.musicVol() / 10f)) + } + timeLeft -= Game.elapsed + if (timeLeft <= 0f) Game.switchScene(GameScene::class.java) + } + + Phase.STATIC -> if (error != null) { + var errorMsg: String = when (error) { + is FileNotFoundException -> M.L(this, "file_not_found") + is IOException -> M.L(this, "io_error") + else -> throw RuntimeException(error) + } + + if (mode == Mode.REFLUX) errorMsg = "备存存档不存在,返回。" + + add(object : WndError(errorMsg) { + override fun onBackPressed() { + super.onBackPressed() + if (mode == Mode.REFLUX) Game.switchScene(StartScene::class.java) + else { + mode = Mode.REFLUX + Game.switchScene(InterlevelScene::class.java) + } + } + }) + error = null + } + } + } + + @Throws(IOException::class) + private fun descend() { + Actor.fixTime() + if (Dungeon.hero == null) { + Dungeon.init() + if (noStory) { + Dungeon.chapters.add(WndStory.ID_SEWERS) + noStory = false + } + GameLog.wipe() + } else { + Dungeon.hero.holdFollowers(Dungeon.level) + Dungeon.saveAll(true) + } + + val level: Level + if (Dungeon.depth >= Statistics.DeepestFloor) { + level = Dungeon.newLevel() + } else { + Dungeon.depth++ + level = Dungeon.loadLevel(Dungeon.hero.heroClass) + } + Dungeon.switchLevel(level, level.entrance) + } + + @Throws(IOException::class) + private fun fall() { + Actor.fixTime() + Dungeon.hero.holdFollowers(Dungeon.level) + Dungeon.saveAll(true) + + val level: Level + if (Dungeon.depth >= Statistics.DeepestFloor) { + level = Dungeon.newLevel() + } else { + Dungeon.depth++ + level = Dungeon.loadLevel(Dungeon.hero.heroClass) + } + Dungeon.switchLevel(level, if (fallIntoPit) + level.pitCell() + else + level + .randomRespawnCell()) + } + + @Throws(IOException::class) + private fun ascend() { + Actor.fixTime() + Dungeon.hero.holdFollowers(Dungeon.level) + + Dungeon.saveAll() + Dungeon.depth-- + val level = Dungeon.loadLevel(Dungeon.hero.heroClass) + Dungeon.switchLevel(level, level.exit) + } + + @Throws(IOException::class) + private fun returnTo() { + + Actor.fixTime() + Dungeon.hero.holdFollowers(Dungeon.level) + + Dungeon.saveAll() + Dungeon.depth = returnDepth + val level = Dungeon.loadLevel(Dungeon.hero.heroClass) + Dungeon.switchLevel(level, returnPos) + } + + @Throws(IOException::class) + private fun restore() { + Actor.fixTime() + + GameLog.wipe() + + // init level + Dungeon.loadGame(StartScene.CurrentClass) + + if (Dungeon.depth == -1) { + Dungeon.depth = Statistics.DeepestFloor + Dungeon.switchLevel(Dungeon.loadLevel(StartScene.CurrentClass), -1) + } else { + Dungeon.switchLevel(Dungeon.loadLevel(StartScene.CurrentClass), Dungeon + .hero.pos) + } + } + + @Throws(IOException::class) + private fun reflux() { + Actor.fixTime() + + GameLog.wipe() + + Dungeon.loadBackupGame(StartScene.CurrentClass) + val level = Dungeon.loadBackupLevel(StartScene.CurrentClass) + //todo: remove shield only if reflux with shield + val shield = Dungeon.hero.belongings.getItem(HomurasShield::class.java) + if (shield != null) { + shield.cursed = false + if (shield.isEquipped(Dungeon.hero)) shield.doUnequip(Dungeon.hero, false) + shield.detach(Dungeon.hero.belongings.backpack) + } + Dungeon.switchLevel(level, Dungeon.hero.pos) + } + + @Throws(IOException::class) + private fun resurrect() { + Actor.fixTime() + Dungeon.hero.holdFollowers(Dungeon.level) + + if (Dungeon.level.locked) { + Dungeon.hero.resurrect(Dungeon.depth) + Dungeon.depth-- + val level = Dungeon.newLevel() + Dungeon.switchLevel(level, level.entrance) + } else { + Dungeon.hero.resurrect(-1) + Dungeon.resetLevel() + } + } + + @Throws(IOException::class) + private fun reset() { + Actor.fixTime() + Dungeon.hero.holdFollowers(Dungeon.level) + + Dungeon.depth-- + val level = Dungeon.newLevel() + //FIXME this only partially addresses issues regarding weak floors. + Level.weakFloorCreated = false + Dungeon.switchLevel(level, level.entrance) + } + + private fun backToPast() {} + + override fun onBackPressed() { + //Do nothing + } + + companion object { + private const val TIME_TO_FADE = 0.3f + + var mode: Mode = Mode.NONE + + var returnDepth: Int = 0 + var returnPos: Int = 0 + + var noStory = false + + var fallIntoPit: Boolean = false + } +} diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/SurfaceScene.java b/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/SurfaceScene.java index e3a39985b..f8b1e0eec 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/SurfaceScene.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/SurfaceScene.java @@ -183,6 +183,7 @@ protected void onClick() { add(gameOver); Badges.INSTANCE.validateHappyEnd(); + Badges.INSTANCE.validateNeverGainPerk(); Badges.INSTANCE.validateNoPerk(); fadeIn(); diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/TitleScene.java b/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/TitleScene.java index 5273ae365..de656c149 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/TitleScene.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/scenes/TitleScene.java @@ -24,6 +24,7 @@ import com.egoal.darkestpixeldungeon.Assets; import com.egoal.darkestpixeldungeon.DarkestPixelDungeon; +import com.egoal.darkestpixeldungeon.Dungeon; import com.egoal.darkestpixeldungeon.TopExceptionHandler; import com.egoal.darkestpixeldungeon.effects.BannerSprites; import com.egoal.darkestpixeldungeon.effects.Fireball; @@ -117,7 +118,7 @@ protected void onClick() { new DashboardItem(Messages.get(this, "badges"), 3) { @Override protected void onClick() { - DarkestPixelDungeon.switchNoFade(KBadgesScene.class); + DarkestPixelDungeon.switchNoFade(BadgesScene.class); } }, new DashboardItem(Messages.get(this, "about"), 1) { @@ -181,8 +182,8 @@ protected void onClick() { add(sdpVersion); // dpd version - BitmapText version = new BitmapText("version " + Game.version + "", - pixelFont); + String versionstr = Dungeon.VERSION_STRING==""? Game.version: Dungeon.VERSION_STRING; + BitmapText version = new BitmapText("version " + versionstr + "", pixelFont); version.measure(); version.hardlight(0xCCCCCC); version.x = w - version.width(); diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/sprites/ItemSpriteSheet.java b/core/src/main/java/com/egoal/darkestpixeldungeon/sprites/ItemSpriteSheet.java index eae5e9413..b0d7f6d74 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/sprites/ItemSpriteSheet.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/sprites/ItemSpriteSheet.java @@ -82,13 +82,14 @@ private static int xy(int x, int y) { public static final int EVIL_GOLDEN_CLAW = GOLDEN_CLAW + 1; public static final int HEAL_REAGENT = SINGLE_USE + 21; public static final int FISH_BONE = SINGLE_USE + 22; - + public static final int TOME_BLUE = SINGLE_USE + 23; + public static final int TOME_YELLOW = SINGLE_USE + 24; private static final int WEP_TIER1 = xy(1, 5); //16 slots public static final int WORN_SHORTSWORD = WEP_TIER1 + 0; public static final int DPD_BATTLE_GLOVES = WEP_TIER1 + 1; public static final int KNUCKLEDUSTER = WEP_TIER1 + 2; - public static final int RAPIER = WEP_TIER1 + 3; + public static final int RED_HANDLE_DAGGER = WEP_TIER1 + 3; public static final int DAGGER = WEP_TIER1 + 4; public static final int MAGES_STAFF = WEP_TIER1 + 5; public static final int DPD_SORCERESS_WAND = WEP_TIER1 + 6; @@ -102,6 +103,8 @@ private static int xy(int x, int y) { public static final int DRIED_LEG = WEP_TIER2 + 5; public static final int SICKLE = WEP_TIER2 + 6; + public static final int RANGER_BOW = WEP_TIER2 + 8; + private static final int WEP_TIER3 = xy(1, 7); //16 slots public static final int SWORD = WEP_TIER3 + 0; public static final int MACE = WEP_TIER3 + 1; @@ -111,6 +114,8 @@ private static int xy(int x, int y) { public static final int WHIP = WEP_TIER3 + 5; public static final int DPD_CRYSTALS_SWORDS = WEP_TIER3 + 6; public static final int DAGGER_AXE = WEP_TIER3 + 7; + public static final int CANDLESTICK = WEP_TIER3 + 8; + public static final int INVISIBLE_BLADE = WEP_TIER3 + 9; private static final int WEP_TIER4 = xy(1, 8); //16 slots public static final int LONGSWORD = WEP_TIER4 + 0; @@ -119,6 +124,7 @@ private static int xy(int x, int y) { public static final int RUNIC_BLADE = WEP_TIER4 + 3; public static final int ASSASSINS_BLADE = WEP_TIER4 + 4; public static final int SPIKE_SHIELD = WEP_TIER4 + 5; + public static final int PITCHFORK = WEP_TIER4 + 6; private static final int WEP_TIER5 = xy(1, 9); //16 slots public static final int Claymore = WEP_TIER5 + 0; @@ -143,6 +149,7 @@ private static int xy(int x, int y) { public static final int ENHANCED_BOOMERANG = MISSILE_WEP + 10; public static final int DART_SEVENTH = MISSILE_WEP + 11; public static final int CEREMONIAL_DAGGER = MISSILE_WEP + 12; + public static final int MAGIC_DART = MISSILE_WEP + 13; private static final int ARMOR = xy(1, 11); //16 slots public static final int ARMOR_CLOTH = ARMOR + 0; @@ -154,8 +161,9 @@ private static int xy(int x, int y) { public static final int ARMOR_MAGE = ARMOR + 6; public static final int ARMOR_ROGUE = ARMOR + 7; public static final int ARMOR_HUNTRESS = ARMOR + 8; - public static final int DPD_ARMOR_SORCERESS = ARMOR + 9; + public static final int ARMOR_SORCERESS = ARMOR + 9; public static final int ARMOR_MAGE_ENHANCED = ARMOR + 10; + public static final int ARMOR_RAGGED = ARMOR + 11; private static final int HELMET = xy(1, 12); public static final int HELMET_CRUSADER = HELMET + 0; @@ -172,6 +180,7 @@ private static int xy(int x, int y) { // 3 scarf here. public static final int LITTLE_PAIL = HELMET + 14; public static final int RIDER_MASK = HELMET + 15; + public static final int HELMET_GUARD = HELMET + 16; //16 free slots @@ -183,7 +192,7 @@ private static int xy(int x, int y) { public static final int WAND_DISINTEGRATION = WANDS + 4; public static final int WAND_PRISMATIC_LIGHT = WANDS + 5; public static final int WAND_VENOM = WANDS + 6; - public static final int WAND_LIVING_EARTH = WANDS + 7; + public static final int WAND_HYPNOSIS = WANDS + 7; public static final int WAND_BLAST_WAVE = WANDS + 8; public static final int WAND_CORRUPTION = WANDS + 9; public static final int WAND_WARDING = WANDS + 10; @@ -249,6 +258,7 @@ private static int xy(int x, int y) { public static final int ARTIFACT_CLOAK_ENHANCED = ARTIFACTS + 40; public static final int CRACKED_COIN = ARTIFACTS + 41; public static final int ARTIFACT_SHIELD = ARTIFACTS + 42; + public static final int DARGONS_SQUAMA = ARTIFACTS + 43; //32 free slots @@ -317,7 +327,8 @@ private static int xy(int x, int y) { public static final int BROWN_ALE = FOOD + 10; public static final int MOON_STONE = FOOD + 11; public static final int STEWED = FOOD + 12; - public static final int SKEWER = FOOD+13; + public static final int SKEWER = FOOD + 13; + public static final int GLAND = FOOD + 14; private static final int QUEST = xy(1, 26); //32 slots public static final int SKULL = QUEST + 0; @@ -327,7 +338,6 @@ private static int xy(int x, int y) { public static final int PICKAXE = QUEST + 4; public static final int ORE = QUEST + 5; public static final int TOKEN = QUEST + 6; - public static final int RANGER_BOW = QUEST + 7; private static final int BAGS = xy(1, 28); //16 slots public static final int POUCH = BAGS + 0; diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/sprites/MissileSprite.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/sprites/MissileSprite.kt index 6cdfbeca8..7189375f1 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/sprites/MissileSprite.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/sprites/MissileSprite.kt @@ -54,7 +54,7 @@ class MissileSprite : ItemSprite(), Tweener.Listener { private val FIXED_ROTATION_IMAGES = arrayOf( ItemSpriteSheet.DART, ItemSpriteSheet.INCENDIARY_DART, ItemSpriteSheet.CURARE_DART, ItemSpriteSheet.JAVELIN, - ItemSpriteSheet.SWALLOW_DART, ItemSpriteSheet.CEREMONIAL_DAGGER + ItemSpriteSheet.SWALLOW_DART, ItemSpriteSheet.CEREMONIAL_DAGGER, ItemSpriteSheet.MAGIC_DART ) } } \ No newline at end of file diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/ui/BuffIndicator.java b/core/src/main/java/com/egoal/darkestpixeldungeon/ui/BuffIndicator.java index b7d7e0179..105fbc6fe 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/ui/BuffIndicator.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/ui/BuffIndicator.java @@ -39,7 +39,7 @@ public class BuffIndicator extends Component { public static final int NONE = -1; - //TODO consider creating an enum to store both index, and tint. Saves + //TODO consider creating an enum to store both index, and tint. Saves // making separate images for color differences. public static final int MIND_VISION = 0; public static final int LEVITATION = 1; @@ -199,7 +199,7 @@ protected void layout() { @Override protected void onClick() { - GameScene.show(new WndInfoBuff(buff)); + if(buff.icon()!= NONE) GameScene.show(new WndInfoBuff(buff)); } } diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/windows/WndDialogue.kt b/core/src/main/java/com/egoal/darkestpixeldungeon/windows/WndDialogue.kt index f346321f1..5377ac233 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/windows/WndDialogue.kt +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/windows/WndDialogue.kt @@ -44,10 +44,11 @@ abstract class WndDialogue(image: Image?, text: String, what: String, vararg opt setPos(MARGIN, top) } add(rtm) + top = rtm.bottom() + MARGIN // options if (options.isNotEmpty()) { - top = rtm.bottom() + MARGIN + 10f + top += 10f for (pr in options.withIndex()) { val btn = object : OptionButton(pr.value) { override fun onClick() { diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/windows/WndGame.java b/core/src/main/java/com/egoal/darkestpixeldungeon/windows/WndGame.java index 1fb8aa464..6f5767371 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/windows/WndGame.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/windows/WndGame.java @@ -62,8 +62,8 @@ protected void onClick() { @Override protected void onClick() { Dungeon.hero = null; - InterlevelScene.mode = InterlevelScene.Mode.DESCEND; - InterlevelScene.noStory = true; + InterlevelScene.Companion.setMode(InterlevelScene.Mode.DESCEND); + InterlevelScene.Companion.setNoStory(true); Game.switchScene(InterlevelScene.class); } }); @@ -72,7 +72,7 @@ protected void onClick() { addButton(new RedButton(Messages.get(this, "rankings")) { @Override protected void onClick() { - InterlevelScene.mode = InterlevelScene.Mode.DESCEND; + InterlevelScene.Companion.setMode(InterlevelScene.Mode.DESCEND); Game.switchScene(RankingsScene.class); } }); diff --git a/core/src/main/java/com/egoal/darkestpixeldungeon/windows/WndResurrect.java b/core/src/main/java/com/egoal/darkestpixeldungeon/windows/WndResurrect.java index 1f347ee2e..5a4f932a8 100644 --- a/core/src/main/java/com/egoal/darkestpixeldungeon/windows/WndResurrect.java +++ b/core/src/main/java/com/egoal/darkestpixeldungeon/windows/WndResurrect.java @@ -68,7 +68,7 @@ protected void onClick() { Statistics.INSTANCE.setAnkhsUsed(Statistics.INSTANCE.getAnkhsUsed()+1); - InterlevelScene.mode = InterlevelScene.Mode.RESURRECT; + InterlevelScene.Companion.setMode(InterlevelScene.Mode.RESURRECT); Game.switchScene(InterlevelScene.class); } }; diff --git a/core/src/main/resources/com/egoal/darkestpixeldungeon/messages/actors/actors_zh.properties b/core/src/main/resources/com/egoal/darkestpixeldungeon/messages/actors/actors_zh.properties index 536073539..0b6006876 100644 --- a/core/src/main/resources/com/egoal/darkestpixeldungeon/messages/actors/actors_zh.properties +++ b/core/src/main/resources/com/egoal/darkestpixeldungeon/messages/actors/actors_zh.properties @@ -48,7 +48,7 @@ actors.buffs.berserk.angered=愤怒 actors.buffs.berserk.berserk=狂暴 actors.buffs.berserk.exhausted=力竭 actors.buffs.berserk.recovering=恢复 -actors.buffs.berserk.angered_desc=狂战士的伤势程度会增强他的攻击力。狂战士的生命值越少,造成的额外伤害就越高。这个效果在他濒临死亡时尤为显著。\n\n当装备纹章的狂战士的生命值降至0时,他会进入_狂暴_并在短时间内无法死亡。\n\n当前伤害加成:%.2f%% +actors.buffs.berserk.angered_desc=狂战士的伤势程度会增强他的攻击力。狂战士的生命值越少,造成的额外伤害就越高。这个效果在他濒临死亡时尤为显著。\n\n当装备纹章的狂战士的生命值降至0时,他会进入_狂暴_并在短时间内无法死亡。\n\n当前等级%d,伤害加成:%.2f%% actors.buffs.berserk.berserk_desc=在弥留之际,恐惧和怀疑已经烟消云散,留存下来的只剩怒火。这种濒死情况下的狂战士会变的无比强大,造成双倍的伤害,获得额外的护盾值,并且无法死亡。\n\n这种额外的护盾值比狂战士的护甲强大许多,而且会随着时间的推移消失殆尽。当这个护盾值降至0后,狂战士会彻底消亡。\n\n任何形式的治疗都会让狂战士恢复稳定,不过他会变的精疲力竭。在力竭时狂战士在短时间内造成的伤害会大幅下降,并且需要得到足够经验才可以再次狂化。 actors.buffs.berserk.exhausted_desc=精神上的力量也有用尽的时候。狂战士现在精疲力竭了,这让他十分虚弱而且令他不能再次狂暴起来。\n\n在这种状态下狂战士造成的伤害将会显著降低,并且在生命值至0时立即死亡。\n\n力竭剩余回合:%d\n当前伤害修正\:%.2f%% actors.buffs.berserk.recovering_desc=精神上的力量也有用尽的时候。狂战士必须在他下次狂暴之前休息。\n\n当正在恢复时狂战士仍然造成额外的伤害,但是在生命值至0时会立即死去。\n\n恢复所需等级:%.2f\n当前伤害修正:%.2f%%. @@ -163,6 +163,7 @@ actors.buffs.magicalsleep.toohealthy=你十分健康,因此抵抗住了强烈 actors.buffs.magicalsleep.fallasleep=你深深地陷入了魔法睡眠。 actors.buffs.magicalsleep.wakeup=你醒来后,感觉浑身清爽并且十分健康。 actors.buffs.magicalsleep.desc=目标已深深陷入了魔法睡眠,不会自然醒来。\n\n魔法睡眠与一般的睡眠基本一样,但只有受伤会致使目标醒来。\n\n对于英雄,魔法睡眠有一些恢复性的效果,使他们能够在睡眠中迅速愈合伤口。 +actors.buffs.magicalsleep$deep.name=沉睡 actors.buffs.mindvision.name=灵视 actors.buffs.mindvision.desc=你可以在脑海中以某种方式看到这一层的所有生物。这种感觉非常奇异。\n\n只要灵视效果依然存在,这层的所有生物都会在你的视野当中。通过灵视看到的生物同样算作视野中的目标,可以被很多魔法效果影响。\n\n剩余的灵视效果时长:%s回合 @@ -324,7 +325,7 @@ actors.hero.heroclass.sorceress_perk5=女巫的初始武器为一根附魔的手 actors.hero.herosubclass.gladiator=角斗士 actors.hero.herosubclass.gladiator_desc=_角斗士_获得_战斗专注_特质,成功的近战攻击可以让_角斗士_开启连击。累积连击数能够使他释放特殊的处决技能。 actors.hero.herosubclass.berserker=狂战士 -actors.hero.herosubclass.berserker_desc=_狂战士_能根据自身受创程度造成额外伤害。当生命值被扣减为0时,他将在短时间内_坚韧不屈_,但作为代价随后会陷入力竭之中。 +actors.hero.herosubclass.berserker_desc=_狂战士_能根据自身受创程度造成额外伤害。当生命值被扣减为0时,他将在短时间内_坚韧不屈_,但作为代价随后会陷入力竭之中。_每当狂战士因为坚韧不屈从濒临死亡恢复时,这份天赋都能变得更强_。 actors.hero.herosubclass.warlock=术士 # actors.hero.herosubclass.warlock_desc=每当用法杖击中敌人,_术士_都有几率标记敌人的灵魂。被标记的敌人受近战攻击时都会治愈他的伤口并回复饥饿。 actors.hero.herosubclass.warlock_desc=每次击杀敌人,_术士_将禁锢对方的灵魂,这些可怜的灵魂将作为_术士_施法的祭品。 @@ -368,6 +369,7 @@ actors.hero.perks.lowhealthdexterous.desc=血量低于30%时将获得额外的 actors.hero.perks.lowhealthregeneration.desc=低血量时获得额外的生命回复。 actors.hero.perks.extradexterous.desc=额外提升灵巧值。 actors.hero.perks.extraevasion.desc=提供%d%%闪避几率。 +actors.hero.perks.lowweightdexterous.desc=力量高于所装备护甲时更易闪避。 actors.hero.perks.extraperkchoice.desc=升级时获得特质的选项增加到5。 actors.hero.perks.brewenhancedpotion.desc=炼药有一定几率获得强化药剂。 actors.hero.perks.knowledgeable.desc=拾起装备时有几率知晓其属性。 @@ -398,6 +400,7 @@ actors.hero.perks.baredswiftness.desc=未装备护甲时你的移动速度和闪 actors.hero.perks.quicklearner.desc=经验获取速度提高%02d%%。 actors.hero.perks.extramagicalresistance.desc=提供%02d%%的魔法抗性。 actors.hero.perks.levelperception.desc=楼层感知,进入新的一层的时候,你总能觉察到隐藏房的存在。 +actors.hero.perks.maniac.desc=视野范围内位敌人数量越多,攻击速度越快。 actors.hero.perks.ravenousappetite.desc=胃口好也未必时间好事,会加速消耗你的饱食度。 @@ -587,6 +590,17 @@ actors.mobs.npcs.robotren.ac_wherefrom=你从哪里来 actors.mobs.npcs.robotren.introduction=哦吼……仁恩,赛……高!什么?泽智莲华又是谁?唔…\n……\n……\n咕,没有搜索到相关记忆——啊,大概是只羊吧,咩……咩……反刍行为,失败…… actors.mobs.npcs.robotren.wherefrom=不不不,仁恩最美,汪,叽…… +actors.mobs.npcs.seeker.name=探求者科斯迪斯 +actors.mobs.npcs.seeker.desc=探求者是一类神秘的职业,他们不辞劳苦走遍世界,声称只为将自己在某一方面的见识拓宽到极致。人们对探求者们的看法不一,不同地区对待他们的方式也不同,甚至截然相反。 +actors.mobs.npcs.seeker.greetings=来了位冒险家啊,你好。 +actors.mobs.npcs.seeker.desc_yourself=问她在这里做什么 +actors.mobs.npcs.seeker.dungeons=和你一样,我也是被这里的地牢吸引而来。与你不同,我只是为收录这个地牢知识而来。\n你知道吗,这个世界的地牢远不止你眼前的这一座,种类繁多且各具特色,我和几位同仁也是因此而周游世界。 +actors.mobs.npcs.seeker.check_info=问她的事业进展如何 +actors.mobs.npcs.seeker.desc_state=哦,你有感兴趣吗?嗯,基本上来说,我们应该已经收录了绝大部分地牢。可是……啊,怎么说呢。地牢,其实是在成长的!这一点或许很难接受,但这是我们长久以来的观察所得出结论。\n这十多年来,我们一直在发现新的地牢,然而重要的是,很多地牢在形成之后会不断的产生变化,尤其是那些新产生的地牢,而也有很多地牢在成长到一定时间之后会停止发生变化。\n我们还不清楚推动这些变化背后的力量,但抛开这一点,不断地有新的领域和知识等待着我们去发现,这一点倒十分令人兴奋。\n\n话说,如果你有兴趣地话,我很乐意分享我们的资料。 +actors.mobs.npcs.seeker.info_dpd=说你想先看一下关于这个地牢的资料(将跳转网页) +actors.mobs.npcs.seeker.info_all=请求看一下她的全部资料(将跳转网页) +actors.mobs.npcs.seeker.maybe_nexttime=下次吧 + actors.mobs.npcs.sheep.name=绵羊 actors.mobs.npcs.sheep.baa!=咩! actors.mobs.npcs.sheep.baa?=咩? @@ -626,7 +640,7 @@ actors.mobs.npcs.wandmaker.desc=这位老先生的表情看起来十分困扰。 actors.mobs.npcs.yvette.name=伊薇特 actors.mobs.npcs.yvette.desc=看这位女性的打扮是个冒险家,更具体一点的话,她用长弓拄在地上,应该是游侠,射手之类的。 actors.mobs.npcs.yvette.hey=嘿,%s!劳驾! -actors.mobs.npcs.yvette.task=啊,你也是冒险者对吗?帮帮我,如你所见我的腿……我被困在这里了。我已经放弃我的冒险了,现在我只想离开这个鬼地方!你能帮助我吗?我需要一张_传送卷轴_……\n\n那个,如果你还有一些食物能分给我的话……我已经被困在这里三天了。。 +actors.mobs.npcs.yvette.task=啊,你也是冒险者对吗?帮帮我,如你所见我的腿……我被困在这里了。我已经放弃我的冒险了,现在我只想离开这个鬼地方!你能帮助我吗?我需要一张_传送卷轴_……\n\n那个,如果你还能腾出一点补给给我的话……我受的伤有点重,已经被困在这里三天了。。 actors.mobs.npcs.yvette.opt-onit=叫她先放下心来,你会帮助她离开这里。 actors.mobs.npcs.yvette.opt-betray=趁她受伤之时,背叛她。 actors.mobs.npcs.yvette.reminder=我需要一张传送卷轴,就能逃脱这里了。 @@ -635,17 +649,22 @@ actors.mobs.npcs.yvette.scroll-identified=%s告诉了你如何识别传送卷轴 actors.mobs.npcs.yvette.give-item=选择要给予的物品 actors.mobs.npcs.yvette.full=哦,谢谢,我刚才已经吃过一点了。非常感谢你,但你的冒险还没结束对吧?我不能接受这个。 actors.mobs.npcs.yvette.thanks-for-food=谢谢!我……我先不客气了。 -actors.mobs.npcs.yvette.thanks-for-scroll=啊,太感谢了!你是我的救命恩人!\n我要离开啦,作为一个失败的冒险者。总之,再次感谢你,我身上有些东西也许能帮上你的忙,希望我们还能再见! +actors.mobs.npcs.yvette.thanks-for-potion=啊!你真是救了我一命!(伊薇特一饮而尽,终于恢复了一些气色) +actors.mobs.npcs.yvette.thanks-for-scroll=啊,太感谢了!你是我的救命恩人!\n我要离开啦,作为一个失败的冒险者。 +actors.mobs.npcs.yvette.give-items=总之,再次感谢你,我身上有些东西也许能帮上你的忙,希望我们还能再见! actors.mobs.npcs.yvette.teach-teleportation=哦对了,走之前我还有一个小诀窍教给你,也希望能帮上你的忙。:) +actors.mobs.npcs.yvette.give-bow=你还要继续冒险吧?我手上也没有什么东西好给你的,拿着这把弓吧,她已经陪我很长一段时间了,相信也能给你带来好运! +actors.mobs.npcs.yvette.decline_bow=这件物品似乎对她很重要,说你其实不善射术,婉言拒绝。 +actors.mobs.npcs.yvette.give_key=哈哈哈,你还真是个,可靠的家伙啊!倒是我……(她浅浅地笑,眼睛却没有看着你)来,这个给你,这把钥匙我偶然发现的,但还没能找到匹配的那把锁。我相信它一定对应着某些特别的财富。 actors.mobs.npcs.yvette.taught=%s将_定点传送_的秘诀告诉了你。你现在可以使用传送卷轴进行定点传送了。 actors.mobs.npcs.yvette.disappear=你看着%s在你眼前消失了。 -actors.mobs.npcs.yvette.not-teleportation=哦,不对,不是这个卷轴。请收好它,对你的冒险有用的。 +actors.mobs.npcs.yvette.not-this=哦,不对,不是这个。你还要继续前进,请收好它,它对你比对我更有用。 actors.mobs.npcs.yvette.you-bastard=可恶……你…混蛋…… actors.mobs.npcs.yvette.killed=就在%s满怀期待之时你趁其不备直接了结了她,但你的内心多少还是有点不快。 actors.mobs.npcs.yvette.see-again=哇!你成功了!由衷为你感到高兴。\n\n我啊?炼金术士老先生帮我看过了,没关系,不过我想我还要在这里休息一段时间才能离开。\n\n真地很佩服你,你做到了! - -actors.mobs.npcs.yvette$bow.name=伊薇特的长弓 -actors.mobs.npcs.yvette$bow.desc=没有受过专业训练的话是用不起来的,不过看起来蛮精致,可以卖个好价钱。 +actors.mobs.npcs.yvette.return-bow=归还魔法长弓。 +actors.mobs.npcs.yvette.bow-got=哦,她有帮到你对吧!我相信她(她小心打量着失而复得的心爱之物)\n你总是能给我莫大的希望。真希望以后的日子里,我们能有机会并肩作战啊!一个游侠,加上一个%s,嗯~(伊薇特抬头畅想,开心的眼眸发出光芒,如同孩童一般。但随即发现自己言有不妥,轻轻捂嘴)\n总之,再次感谢你! +actors.mobs.npcs.yvette.bye=向她告别,说你很高兴能帮到她。 ###mobs actors.mobs.acidic.name=酸液蝎子 @@ -687,6 +706,7 @@ actors.mobs.dm300.overload_warning=DM300处于超负荷状态下! actors.mobs.dm300.rankings_desc=被DM-300碾压致死 actors.mobs.dm300.desc=数个世纪前矮人们制造了这个机器。但此后,矮人们开始使用魔像、元素生物甚至是恶魔来替换机器,最终导致其文明的衰败。DM-300及类似的机器通常用于建设和挖掘,某些情况下,也可以用于城防。 actors.mobs.dm300.overloaded_desc=DM-300正处在超负荷状态下,攻速与攻击力得到了提升,但不再具有额外的物理抗性。 +actors.mobs.dm300.bump=目标锁定。冲击准备。 actors.mobs.elemental.name=火元素 actors.mobs.elemental.desc=这些游荡的火元素是在召唤某种更强大存在时产生的副产品。其特性太过紊乱,以至于最强大的恶魔学者都没有办法驱使。 @@ -948,12 +968,12 @@ actors.mobs.npcs.minstrel.name=吟游诗人泰勒 actors.mobs.npcs.minstrel.desc=看打扮似乎是时常可见的游走在世界各地,通过演奏诗歌传述英雄史诗与乡野传奇的浪子,不过这位诗人有着不那么寻常的肤色,也看起来有点神经质。 actors.mobs.npcs.minstrel.hello=哈!一位冒险家吗?叫我泰勒,Teller,not,Tylor。你知道,别人经常混淆,不过也没关系。名字不过是个代号而已,不是吗? actors.mobs.npcs.minstrel.ac_sing=我能点一首曲子吗 - actors.mobs.npcs.minstrel.select_poetry=乐意为您效劳!有缘人,你想听哪一首呢? - actors.mobs.npcs.minstrel.poetry_away=热血在你胸中奔腾,我知道你的万夫不当;\n希望在你身边耳语,我理解你的凌霄之志;\n\n走吧,走吧,怀揣满腔激昂,不要让你的理想,在此处枯萎;\n啊,出发吧,握紧手中的剑,向最高的山峰攀登;\n我看到远方的她们在向你招手;\n\n走吧,走吧,是时候启程了,愿你的前途,与我的女神一样光明;\n啊,出发吧,带上你的权杖,向无尽的知海扬帆;\n我将会在这里将你的故事唱传; +actors.mobs.npcs.minstrel.select_poetry=乐意为您效劳!有缘人,你想听哪一首呢? +actors.mobs.npcs.minstrel.poetry_away=热血在你胸中奔腾,我知道你的万夫不当;\n希望在你身边耳语,我理解你的凌霄之志;\n\n走吧,走吧,怀揣满腔激昂,不要让你的理想,在此处枯萎;\n啊,出发吧,握紧手中的剑,向最高的山峰攀登;\n我看到远方的她们在向你招手;\n\n走吧,走吧,是时候启程了,愿你的前途,与我的女神一样光明;\n啊,出发吧,带上你的权杖,向无尽的知海扬帆;\n我将会在这里将你的故事唱传; actors.mobs.npcs.minstrel.ac_yourself=跟我说说你自己 - actors.mobs.npcs.minstrel.introduction=哦?是因为我的肤色很奇怪吗?没关系,哈哈!我是从北方来的,漂泊在外,旅途的所见所闻,一切的经历都让我感到自由,这果然是我生命最重要的东西。\n唯有一点,我时常想念家乡的罐头,对,没错,就是牛肉罐头。 +actors.mobs.npcs.minstrel.introduction=哦?是因为我的肤色很奇怪吗?没关系,哈哈!我是从北方来的,漂泊在外,旅途的所见所闻,一切的经历都让我感到自由,这果然是我生命最重要的东西。\n唯有一点,我时常想念家乡的罐头,对,没错,就是牛肉罐头。 actors.mobs.npcs.minstrel.ac_leave=再会 - actors.mobs.npcs.minstrel.farewell=祝你好运啊,伙计! +actors.mobs.npcs.minstrel.farewell=祝你好运啊,伙计! actors.mobs.npcs.spdbattlemage.name=霜寒战斗法师 actors.mobs.npcs.spdbattlemage.desc=这位战斗法师腰间挂着一块四分五裂但没有散架的护符,手里握着的一把法杖镶嵌着夺目的蓝色冰晶。他身体周围散发着一股不同寻常的强大能量,给人彻骨的寒意。 @@ -1060,8 +1080,16 @@ actors.mobs.npcs.scrollseller.not_cleansed=一次徒劳。 actors.mobs.npcs.undeadshopkeeper.name=不死商人 actors.mobs.npcs.undeadshopkeeper.desc=即使戴着面罩,披着斗篷也掩饰不了他的亡灵身份——空洞的眼窝总是让你感到不适。 +actors.mobs.npcs.undeadshopkeeper.nothing_more=桀桀,很高兴,和你做生意~亡灵山河对你表达敬意,桀桀。 actors.mobs.npcs.undeadshopkeeper.thief=绝了!你在想什么! -actors.mobs.npcs.undeadshopkeeper.greeting=啊,桀桀, +actors.mobs.npcs.undeadshopkeeper.greeting=啊,桀桀。 +actors.mobs.npcs.undeadshopkeeper.ac_why_here=好奇问他既然是要做生意,为什么还要躲在这种地方呢。 +actors.mobs.npcs.undeadshopkeeper.customer_filter=桀桀,你觉得,对于那些找不到我的蠢蛋,有必要和他们做生意吗? +actors.mobs.npcs.undeadshopkeeper.pay_to_see=可以,但你需要先支付我……(稍作思考)嗯,大概%d金币。 +actors.mobs.npcs.undeadshopkeeper.unhappy=表达你的不满,就算看一眼也要付钱,没有人这么做生意的。 +actors.mobs.npcs.undeadshopkeeper.info_costs=不不不,一切都是有代价的,关于我卖什么东西,这个信息也是一样。桀桀! +actors.mobs.npcs.undeadshopkeeper.no_money=你的钱不够哦。 +actors.mobs.npcs.undeadshopkeeper.fine=这骨头确实刻薄了一点但现在不是计较这个的时候。(付钱) actors.mobs.npcs.questioner.name=发问者 actors.mobs.npcs.questioner.desc=看起来是一堵有着脸的墙,没有人知道它到底算不算是生物。 @@ -1097,6 +1125,9 @@ actors.mobs.skeletonknight.desc=恐怖的无头战士,它的身上还穿着曾 actors.mobs.skeletonknight.combo=连击 actors.mobs.skeletonknight.counter=反击 +actors.mobs.slug.name=下水道蠕虫 +actors.mobs.slug.desc=换句话说,也就是鼻涕虫。这种粘稠装的生物攻击十分缓慢,对物理攻击具有较高的抗性,普通的挥砍很难对其造成大量伤害,但在魔法攻击面前却十分脆弱。 + actors.mobs.madman.name=疯子 actors.mobs.madman.def_verb=躲避 actors.mobs.madman.desc=多少冒险者在地牢中绝望、崩溃而彻底丧失自我意识,如今只能被称为衣衫褴褛的“人形生物”。难以想象他如何在这里存活至今。\n尽管没有什么战斗力,但同为冒险者,它的处境,它口中的绝望之语难免让人开始担忧自己的结局,徒增压力。 diff --git a/core/src/main/resources/com/egoal/darkestpixeldungeon/messages/items/items_zh.properties b/core/src/main/resources/com/egoal/darkestpixeldungeon/messages/items/items_zh.properties index 659a892d6..67eb10eb4 100644 --- a/core/src/main/resources/com/egoal/darkestpixeldungeon/messages/items/items_zh.properties +++ b/core/src/main/resources/com/egoal/darkestpixeldungeon/messages/items/items_zh.properties @@ -119,6 +119,9 @@ items.armor.mailarmor.desc=由金属链环环相扣制成的一套结实又不 items.armor.platearmor.name=板甲 items.armor.platearmor.desc=厚重的金属板拼接到一起,为能承受其骇人重量的冒险者提供无与伦比的防御。 +items.armor.raggedarmor.name=破旧衣裳 +items.armor.raggedarmor.desc=碎成花的布衣十分轻便——如果还能称为衣裳的话。这件衣服几乎提供不了有效的防御,但据说某位专家偏好这种衣服。 + items.armor.roguearmor.name=盗贼风衣 items.armor.roguearmor.ac_special=烟幕爆炸 items.armor.roguearmor.fov=你只能跳到视野范围内的空格子里 @@ -144,7 +147,7 @@ items.artifacts.artifact.curse_known=你能感觉到在遗物上潜伏着一股 items.artifacts.artifact.need_to_equip=你需要装备遗物才能进行该操作。 items.artifacts.capeofthorns.name=荆棘斗篷 -items.artifacts.capeofthorns.desc=这些从DM-300上掉落的金属片构成了一件坚硬的斗篷。它似乎能储存很多能量,也许它还残留有少量DM-300的能力? +items.artifacts.capeofthorns.desc=坚硬的斗篷由纯金属打造,十分沉重,需要一定力量才能穿戴(_装备时,需要16点力量才能发挥其力量_)。精细的金属雕纹与链环,金属片之间巧妙的配合,都令人赞叹这份铠甲背后先进的冶炼锻造技术,也难怪有人猜想是出自矮人之手。 items.artifacts.capeofthorns.desc_inactive=斗篷压在你的肩上的感觉非常沉重,它似乎能从你受的伤里获得能量。 items.artifacts.capeofthorns.desc_active=斗篷似乎在释放其存储的能量,并将其辐射出一种防护力场。 items.artifacts.capeofthorns$thorns.inert=你的斗篷再次失效了。 @@ -201,6 +204,15 @@ items.artifacts.crackedcoin.self_target=不能以自己作为目标! items.artifacts.crackedcoin$shield.name=带裂纹的银币 items.artifacts.crackedcoin$shield.desc=以金币的代价,护盾为你吸收50%%伤害,同时为银币储能(若其已储满能量则无效)。每点金币吸收%.1f点伤害。 +items.artifacts.dragonssquama.name=红龙之鳞 +items.artifacts.dragonssquama.desc=这枚鳞片似乎始终能保持自己的温度,拿在手上让你感觉到温暖。\n据说是古代巨龙亚历山大的鳞片,在她晚年与一位人类结下友谊,并以此为信物约定由其见证巨龙的飞升之仪。如今这块鳞片仍流离于世,流传已久的古老故事看来也并没有美好的结局。事实上,伴随着魔法和铸造术的崛起,古代巨兽早已淡出历史,如今很多人已经不愿意相信曾有龙存在的时代了。 +items.artifacts.dragonssquama.desc_hint=装备龙鳞能提高你对暴击伤害的减免,并极大的提高你对火焰元素的抗性。储能完毕时,轻叩龙鳞便能释能量,释放超新星,造成大量火焰属性魔法伤害,_打击所有单位_。 +items.artifacts.dragonssquama.desc_cursed=被诅咒的龙鳞使得你所有者在暴击伤害面前更为脆弱。 +items.artifacts.dragonssquama.ac_tap=轻叩 +items.artifacts.dragonssquama.cursed=鳞片已被诅咒,无法使用! +items.artifacts.dragonssquama.no_charge=红龙之鳞尚未具有足够的能量。 +items.artifacts.dragonssquama.levelup=红龙之鳞变得更加强大! + items.artifacts.driedrose.name=干枯玫瑰 items.artifacts.driedrose.ac_summon=召唤 items.artifacts.driedrose.spawned=你已经召唤出幽灵了。 @@ -277,6 +289,16 @@ items.artifacts.heartofsatan.desc=脱离了组织的硕大心脏仍然在微微 items.artifacts.heartofsatan.desc_cursed=被诅咒的心脏紧紧地贴在你身上,抑制了你回复生命的能力,甚至在微微吮吸! items.artifacts.heartofsatan.desc_hint=心脏似乎在逐渐恢复活力,你可以隐约感受到它在为你送来生命能量,你还想继续割伤自己,即便你知道那很疼。 +items.artifacts.homurasshield.name=时间旅行者的盾牌 +items.artifacts.homurasshield.desc=所有能操控时间的法器都是强大到令人畏惧的,这面盾牌也不例外——时之盾牌有着_倒转时间_的威力。有人认为这是时空术士曾经存在的又一正面论据,当然反对者们不以为然,认为自古以来只有神才有拨动时间轮盘的资格与可能。\n在已知最早的记载中,据说这个强大的法器曾由某位心存执念之人所获得——为了再次见到自己心爱之人。人们愿意相信她确实回到了过去,但没有人知道她最终的结局,或是达成了半生的心愿,还是就此迷失在时间裂缝之中。 +items.artifacts.homurasshield.desc_hint=使用时之盾牌能让你重新回到时间线的某一点,但从没有人能真正驾驭这份遗物,_这份撕裂时空的力量也可能会对当前的世界造成影响_。 +items.artifacts.homurasshield.cursed=无法使用被诅咒的盾牌。 +items.artifacts.homurasshield.no_charge=时之盾牌尚未具有足够能量。 +items.artifacts.homurasshield.ac_reflux=时间回溯 +items.artifacts.homurasshield.return_warn=时之盾牌将要将你送回之前的时间点,这意味着你将失去它,是否继续操作? +items.artifacts.homurasshield.yes=是的,我知道自己在干什么。 +items.artifacts.homurasshield.no=不,我放弃了 + items.artifacts.hornofplenty.name=丰饶之角 items.artifacts.hornofplenty.ac_eat=食用 items.artifacts.hornofplenty.ac_store=贮存 @@ -480,6 +502,11 @@ items.helmets.circletemerald.cursed-desc=被诅咒的头环会起到相反的作 items.helmets.crownofdwarf.name=矮人王冠 items.helmets.crownofdwarf.desc=矮人国王的尸骸褪去后留下的稀有物品,十分精致的金色王冠上镶满了宝石。任何人在面对这样一件工艺品时都会变得小心翼翼——它曾是至高无上权力的象征,而如今更是印证着矮人王国曾经的盛世辉煌。\n\n华而不实的物具一向是商人们狂热的追求。 +items.helmets.guardhelmet.name=守卫头盔 +items.helmets.guardhelmet.desc=监狱守卫的铁质头盔,造型平平无奇。 +items.helmets.guardhelmet.effect-desc=这个头盔十分厚实,能稍微提升抗性。 +items.helmets.guardhelmet.cursed-desc=被诅咒的头环会起到相反的作用。 + items.helmets.helmetbarbarian.name=野蛮人头盔 items.helmets.helmetbarbarian.desc=这是一个野蛮人头盔,如果它的两只角还不足以说明的话。 items.helmets.helmetbarbarian.effect-desc=当你的受伤较重时,愤怒将使你的每一击都格外强力。 @@ -527,7 +554,7 @@ items.helmets.rangerhat.cursed-desc=被诅咒的系带只为起相反的作用 items.helmets.turtlescarf.name=乌龟头巾 items.helmets.turtlescarf.desc=据说这种头巾一共有四种颜色,但谁能告诉我这和乌龟有什么关系? -items.helmets.turtlescarf.effect-desc=系上头巾能提高你对魔法伤害的抗性。 +items.helmets.turtlescarf.effect-desc=头巾对魔法伤害有着额外的抵抗作用。 items.helmets.turtlescarf.cursed-desc=被诅咒的系带只为起相反的作用。 items.helmets.wizardhat.name=巫师之帽 @@ -876,6 +903,11 @@ items.wands.wandoffrost.staff_name=霜冻之杖 items.wands.wandoffrost.desc=这根法杖似乎由某种魔法冰块制成。它的圆顶闪着亮光。握起来很冰,但不知为何你的手仍保持着温暖。 items.wands.wandoffrost.stats_desc=该法杖能向你的敌人射击冰霜能量,造成_附带冰属性的%1$d~%2$d点伤害_并冷冻目标,降低其行动速度。在水中的作用似乎更强。正被冻伤和冻结的敌人将受到更少该法杖的伤害,因为他们已经足够冷了。 +items.wands.wandofhypnosis.name=昏睡权杖 +items.wands.wandofhypnosis.staff_name=沉眠之杖 +items.wands.wandofhypnosis.desc=这根法杖由一种黑金打造,前端的红色宝石发出诡异的光晕。当盯着这块宝石看时总会感到一阵精神恍惚,令你刻意避开对其直视。这根法杖的充能十分少。 +items.wands.wandofhypnosis.stats_desc=该法杖能在目标地点射出法球,释放眩晕气体。若击中目标,则会令其陷入沉睡,当其从沉睡中惊醒时会承受额外伤害,并被短暂地恐惧,这个效果将随等级提高而增强。 + items.wands.wandoflightning.name=雷霆法杖 items.wands.wandoflightning.staff_name=雷霆之杖 items.wands.wandoflightning.ondeath=你用雷霆法杖杀死了自己… @@ -922,6 +954,10 @@ items.weapon.curses.annoying.msg_4=现在是打BOSS的时间吗!? items.weapon.curses.annoying.msg_5=我去,别这么用力! items.weapon.curses.annoying.desc=喧闹诅咒的武器真的是想帮你,只不过它的吵闹无比的“帮助”总是会吸引大量敌人。 +items.weapon.curses.bloodthirsty.name=嗜血%s +items.weapon.curses.bloodthirsty.desc=魔域巫师焚风的作品,拥有嗜血附魔的武器更加强力,在攻击中会索取受击方的生命,然而,如果这还不能满足它,则会索取持有者的生命。 +items.weapon.curses.bloodthirsty.rankings_desc=被嗜血侵蚀。 + items.weapon.curses.displacing.name=转移%s items.weapon.curses.displacing.desc=转移诅咒的武器被灌注了混乱的传送魔法,会将敌人传送到当前层的随机位置。 @@ -931,6 +967,13 @@ items.weapon.curses.exhausting.desc=虚耗诅咒的武器需要费大量精力 items.weapon.curses.fragile.name=晶化%s items.weapon.curses.fragile.desc=晶化诅咒的武器和其他的武器几乎一样强大,但是在使用过程中会效能会快速降低。 +items.weapon.curses.provocation.name=挑衅%s +items.weapon.curses.provocation.desc=挑衅诅咒不会改变武器本身的属性,只是有可能让攻击目标变得狂暴。 +items.weapon.curses.provocation.msg_0=不像个样子! +items.weapon.curses.provocation.msg_1=你就是这样战斗的? +items.weapon.curses.provocation.msg_2=懦夫,别跑! +items.weapon.curses.provocation.msg_3=让你打我一轮怎么样? + items.weapon.curses.sacrificial.name=血祭%s items.weapon.curses.sacrificial.desc=血祭诅咒会向使用者索求血液作为攻击的回报,你的状态越健康,诅咒索取的也就越多。 @@ -965,6 +1008,9 @@ items.weapon.enchantments.projecting.desc=这个附魔会使肉搏武器获得 items.weapon.enchantments.shocking.name=电击%s items.weapon.enchantments.shocking.desc=电弧在这个武器上不断地闪烁震荡,能够对邻近所有敌人造成额外伤害。被附魔武器带有_电_属性。 +items.weapon.enchantments.storming.name=强攻%s +items.weapon.enchantments.storming.desc=Press-the-Attack!拥有强攻附魔的武器在攻击同一个单位时会不断累积额外伤害,因此常被应用在快速武器上,十分强力。 + items.weapon.enchantments.stunning.name=重击%s items.weapon.enchantments.stunning.desc=重击附魔的武器可以击晕敌人,使其无法反抗。 @@ -1038,6 +1084,10 @@ items.weapon.melee.handaxe.name=手斧 items.weapon.melee.handaxe.stats_desc=这是一把比较精准的武器。 items.weapon.melee.handaxe.desc=一把轻斧头,通常用来砍树。当然,它的宽刃对敌人来说同样有效。 +items.weapon.melee.invisibleblade.name=隐形之刃 +items.weapon.melee.invisibleblade.stats_desc=这是一把十分精准的武器,并且有一定几率造成纯粹伤害。 +items.weapon.melee.invisibleblade.desc=有着半透明刀刃的细剑,在战斗中挥舞起来能让对手难以分辨。 + items.weapon.melee.knuckles.name=指虎 items.weapon.melee.knuckles.stats_desc=这是一个非常快的武器。 items.weapon.melee.knuckles.desc=一块专门塑成契合指节形状的铁片。不占用双手空间,揍起人时又比空手要强些。 @@ -1068,11 +1118,25 @@ items.weapon.melee.magesstaff.desc=这支法杖是件独一无二的魔法武器 items.weapon.melee.magesstaff.no_wand=这支法杖并没有任何魔力, 它必须先被_注入进另一支法杖的魔力_才能用于施放法术。 items.weapon.melee.magesstaff.has_wand=魔杖目前被灌注了_%s_的力量。 +items.weapon.melee.magicbow.name=伊薇特的魔法长弓 +items.weapon.melee.magicbow.desc=游侠伊薇特最心爱的魔法长弓,能看出主人很注意对她的保养。\n这把弓十分强大,_远程射击会造成魔法伤害_,若射击近身敌人则难以发挥这份威力,同时会带来较大幅度的失衡。好在她本身具有一定的近战性能。 +items.weapon.melee.magicbow.ac_shoot=射击 +items.weapon.melee.magicbow.need_equipped=魔法长弓尚未装备。 +items.weapon.melee.magicbow.prompt=选择射击目标 +items.weapon.melee.magicbow.not_yourself=无法以自身作为目标。 + +items.weapon.melee.magicbow$broken.name=魔法长弓(已损坏) +items.weapon.melee.magicbow$broken.desc=这把弓已经损坏了,看起来也确实有些年头了。 + items.weapon.melee.meleeweapon.stats_known=这件_%1$d阶_近战武器可以造成_%2$d~%3$d点伤害_,并且需要_%4$d点力量_来正常使用。 items.weapon.melee.meleeweapon.stats_unknown=一般情况下这件_%1$d阶_近战武器可以造成_%2$d~%3$d点伤害_,并且需要_%4$d点力量_来正常使用。 items.weapon.melee.meleeweapon.probably_too_heavy=这件武器对你来说或许太重了。 items.weapon.melee.meleeweapon.stats_desc= +items.weapon.melee.pitchfork.name=强化草叉 +items.weapon.melee.pitchfork.desc=“斩木为兵,揭竿为旗”。草叉作为农具,本不适合作战,但经过加固和打磨,强化草叉能轻易刺穿护甲。 +items.weapon.melee.pitchfork.stats_desc=这是一件相当缓慢的武器。\n这把武器有额外的攻击距离。 + items.weapon.melee.shortsword.name=短剑 items.weapon.melee.shortsword.desc=它确实相当短,只比一把匕首长出几厘米。 @@ -1085,6 +1149,10 @@ items.weapon.melee.quarterstaff.name=铁头棍 items.weapon.melee.quarterstaff.stats_desc=这件武器可以抵挡部分伤害。 items.weapon.melee.quarterstaff.desc=这是两端以铁包覆的硬木棍。 +items.weapon.melee.redhandledagger.name=红柄短刀 +items.weapon.melee.redhandledagger.desc=轻便耐用的单手武器,在小偷或盗贼之中十分流行。 +items.weapon.melee.redhandledagger.stats_desc=发动偷袭攻击时,有几率使目标残废。 + items.weapon.melee.roundshield.name=圆盾 items.weapon.melee.roundshield.stats_desc=这件武器可以抵挡大量的伤害,通过升级可以使抵挡量增长。 items.weapon.melee.roundshield.desc=这个大盾可以有效格挡攻击,在危机时刻也可以作为不错的武器使用。 @@ -1195,7 +1263,7 @@ items.weapon.weapon.cursed_worn=由于这件武器被诅咒,你无法将其放 items.weapon.weapon.cursed=你能感觉到这件武器里潜伏着一股充满恶意的魔力。 items.weapon.weapon.lighter=它被打磨得_更轻_了。 items.weapon.weapon.heavier=它被打磨得_更重_了。 -items.weapon.weapon.enchanted=这个拥有_%s._ +items.weapon.weapon.enchanted=这个拥有_%s_。 items.weapon.weapon$enchantment.enchant=附魔 ## unclassified @@ -1344,6 +1412,9 @@ items.unclassified.rune.name=神符 items.unclassified.rune.no-vial=你需要一个露水瓶来盛装这枚神符。 items.unclassified.rune.already-has-rune=露水瓶中已经盛装有神符了。 +items.unclassified.spidergland.name=蜘蛛腺体 +items.unclassified.spidergland.desc=巨大蜘蛛的某种怪异腺体,看起来可能十分有营养,然而还没有被人们开发为食材。\n滑溜溜的触感十分恶心,砸碎时能困住附近的单位。 + items.unclassified.regenerationrune.name=恢复神符 items.unclassified.regenerationrune.desc=恢复神符能永久加强使用者的生命恢复速度。 @@ -1530,6 +1601,7 @@ items.books.book.name=书籍 items.books.book.desc=看似平淡无奇的老旧书籍,无聊时倒是可以用来打发时间。 items.books.book.ac_read=阅读 items.books.book.blinded=你看不到! +items.books.book.cannot_understand=你还读不懂这本书。 items.books.textbook.bookname=文本书籍 items.books.textbook.bookdesc=普通的纯文本书籍,没什么意思。 @@ -1539,6 +1611,14 @@ items.books.textbook.page0=说了没什么意思了。 items.books.tomeofperk.bookname=天赋之书 items.books.tomeofperk.bookdesc=阅读天赋之书将直接获得一个额外的特质。 +items.books.tomeofretrain.bookname=重修之书 +items.books.tomeofretrain.bookdesc=重修之书允许你重新选择一个正面天赋。 +items.books.tomeofretrain.select_perk=选择想要重修的天赋。 + +items.books.tomeofupgrade.bookname=精进之书 +items.books.tomeofupgrade.bookdesc=阅读精进之书能提升阅读者一个正面天赋等级。 +items.books.tomeofupgrade.select_perk=选择想要精进的天赋。 + items.books.textbook.callysdiary.bookname=柯利的日记 items.books.textbook.callysdiary.bookdesc=冒险者柯利最后的懊悔,令人可惜。\n\n也许这算是给杰西卡的一个交代。 items.books.textbook.callysdiary.pagesize=3 diff --git a/core/src/main/resources/com/egoal/darkestpixeldungeon/messages/misc/misc_zh.properties b/core/src/main/resources/com/egoal/darkestpixeldungeon/messages/misc/misc_zh.properties index 9a0ee779f..701302755 100644 --- a/core/src/main/resources/com/egoal/darkestpixeldungeon/messages/misc/misc_zh.properties +++ b/core/src/main/resources/com/egoal/darkestpixeldungeon/messages/misc/misc_zh.properties @@ -63,6 +63,7 @@ badges$badge.perk_gain_1=获得3个天赋 badges$badge.perk_gain_2=获得6个天赋 badges$badge.perk_gain_3=获得9个天赋 badges$badge.perk_none=在不获得天赋的情况下通关 +badges$badge.perk_empty=谁会需要天赋? badges$badge.suicide=你不可能杀得了我!(自杀) badges$badge.games_played_1=进行10场游戏 badges$badge.games_played_2=进行100场游戏 diff --git a/core/src/main/resources/com/egoal/darkestpixeldungeon/messages/scenes/scenes_zh.properties b/core/src/main/resources/com/egoal/darkestpixeldungeon/messages/scenes/scenes_zh.properties index 4af0dfdca..3b288db63 100644 --- a/core/src/main/resources/com/egoal/darkestpixeldungeon/messages/scenes/scenes_zh.properties +++ b/core/src/main/resources/com/egoal/darkestpixeldungeon/messages/scenes/scenes_zh.properties @@ -96,7 +96,7 @@ scenes.guidescene.body_9=探险活动会影响你的心理,同时压力会在 scenes.guidescene.title_10=把握光照 scenes.guidescene.body_10=毫无疑问地牢是阴暗的,黑暗中的敌人十分致命,而某些时候你的视野甚至会更小。\n\n所幸的是,除了地牢中少量的场景光源之外,你总能在地牢中找到火把,有计划地使用这些重要的资源是地牢冒险的制胜之策。\n\n注意,随着地牢者深入,火把的配额会逐渐减少。 scenes.guidescene.title_11=辨别伤害 -scenes.guidescene.body_11=暗黑像素地牢中的伤害抵抗与结算方式稍有不同,了解一些处理机制对你的冒险大有脾益。\n\n伤害被分为普通、魔法、精神三种类型。普通攻击是最为常见的攻击类型;魔法攻击能直接穿透护盾且极难闪避;精神攻击同样无视护盾,通常表现为增加你的压力;\n\n某些伤害带有元素:火、毒、冰、电、暗、光。对于冒险家来说,武器附魔是最常见的给出带有元素伤害的方式。不同的单位具有不同的元素抗性,注意,元素抗性与魔法抗性是分别结算的。\n\n最后,伤害可以带有属性:精准、暴击等。\n\n(战斗机制:闪避判定->护甲抵挡->攻方修正->守方修正->抗性结算->类型判定->结算。) +scenes.guidescene.body_11=暗黑像素地牢中的伤害抵抗与结算方式稍有不同,了解一些处理机制对你的冒险大有脾益。\n\n伤害被分为普通、魔法、精神三种类型,在游戏中可以通过战斗中数值的颜色来进行分辨。普通攻击是最为常见的攻击类型,对应灰色数值;魔法攻击能直接穿透护盾且极难闪避,则以蓝色数值;精神攻击同样无视护盾,以黑色数值显示,会直接增加你的压力;\n\n某些伤害带有元素:火、毒、冰、电、暗、光。对于冒险家来说,武器附魔是最常见的给出带有元素伤害的方式。不同的单位具有不同的元素抗性,注意,元素抗性与魔法抗性是分别结算的。\n\n最后,伤害可以带有属性:精准、暴击等。\n\n(战斗机制:闪避判定->护甲抵挡->攻方修正->守方修正->抗性结算->类型判定->结算。) # report scenes.errorreportscene.title=反馈日志 @@ -136,5 +136,6 @@ scenes.changesscene.info0.4.0=[191005]全新特质系统,新的敌人与物品 scenes.changesscene.info0.4.1=[191228]新的特质,新物品与平衡性改动;\n\n【更新】:\n-新增10种特质;现在升级获得特质时总是具有一次随机机会;\n-现在英雄在12级获得进阶机会,精通之书从地牢中移除,天狗现在掉落一本天赋之书;\n-调整了装备的力量需求与等级的关系,现在力量下降分别在+1、+3、+5、+7...\n-提高了投掷武器的掉落,新增阿贝尔神杖替换注魂法杖,提高了几乎所有法杖的伤害;\n-新增压力回复道具仪式匕首;点金手,镰刀,带裂纹的银币等加入地牢;\n-实验功能自言自语的英雄与可控制的盟友;\n-宝藏与惊惧陷阱加入到地牢;\n【调整】:\n-压力调整,现在压力在游戏种的浮动将更为明显;命中添加一项闪避几率判定;\n-剧毒法杖现在具有命中伤害;巨斧现在具有50%溅射;磨刀石现在影响武器的力量需求;\n-灰烬头骨不再具有夜视能力;\n【其他】:\n-更详细的属性显示,人物对话界面改动;\n日志滚动等问题修正; scenes.changesscene.info0.4.2=[200426]新单位,新物品,全新地牢挑战;\n\n【更新】:\n-红恶魔加入到地牢,在地牢较深处出现;新的稀有怪速射炮加入到地牢;新村民路人加入到第0层;\n-元素、韧性、精准之戒从地牢中移除,新增三枚戒指;新的头饰来打面具加入地牢;\n-移除旧有挑战选项,新增地牢石碑,提供全新的挑战内容,包括一项新手选项;\n【调整】:\n-地牢生成算法微调;\n-为矮人国王添加了怒气技能;\n-十字军头盔现在总是能减免远程伤害;恢复药水总量增加,闪避之戒现在提供闪避几率而非潜行点;硬币、尖刺大盾等物品数值调整;\n【其他】:\n-现在可以和商人交换位置;全新单位面板,血条数值,物品排序,天赋延迟选择等细节;排行榜现在容纳至多30个记录;\n-无限炼金、暴击商人等问题修正; scenes.changesscene.info0.4.2a=[200521]繁体中文加入,修复与几个新物品;\n\n【调整】\n-急救试剂,干枯羊腿等物品;\n-萃取瓶现在可置于快捷栏;现在治愈神符的回复效果以独立buff给出;酿造强化现在使用伪随机,不再可以升级;天赋异禀、体质药剂、撒旦之心等微调;\n\n【其他】\n-繁体中文现在可用;大部分徽章条件现在可见;\n-一些修复; +scenes.changesscene.info0.4.3=[200801]新的NPC,众多新物品,平衡性调整;\n\n【更新】\n-亡灵商人以隐藏形式加入地牢;探求者加入到村庄;伊薇特任务扩展及相关物品;\n-红龙之鳞,强化草叉,隐形之刃,昏睡权杖等物品添加;\n-新增怪物下水道蠕虫;怪物属性调整,现在部分怪物具有一定的暴击几率;某些怪物会有唯一掉落物;\n-DM300现在具有冲撞技能;新增天赋书由boss单位掉落;几种新的天赋;\n-新增挑衅,嗜血,强攻附魔;升级卷轴不会主动移除武器诅咒;\n【调整】\n-重要修复:修正了元素抗性结算的bug(@阿莱克丝塔萨);\n-饥饿上限重新提高到500;现在英雄攻速不可超过0.25;\n-调整了生成器以更均衡的掉落各物品;\n【其他】\n-修正了错误的天赋移除触发等问题;\n-伤害数值颜色随类型变化;新徽章与徽章贴图; -scenes.welcomescene.update_msg=-繁体中文加入;\n-可见徽章与几个新物品; +scenes.welcomescene.update_msg=-新的NPC;\n-众多新物品;\n-大量平衡性调整; diff --git a/dev/dev-notes b/dev/dev-notes index 514cf7792..0c53877a2 100644 --- a/dev/dev-notes +++ b/dev/dev-notes @@ -33,24 +33,42 @@ backlog: 感谢 敌人额外的麻痹抗性 - 山河、红龙 新英雄 - 背包不够大 法杖命中事件 附魔,法杖 新堆桶 命运之轮 武器刀光 新的强化道具 - 部分旧挑战改为徽章 - + 梦魇权杖,时之盾牌, + 0.5 - 楼层扩充; - - 0.4 - 法术学习系统? release: +0.4.3 + 赛亚人狂战士,狂暴恢复速度加快 + 昏睡权杖 + 隐藏亡灵商人 + 挑衅,嗜血,强攻,升级卷轴不再主动移除武器诅咒 + 怪物掉落:小偷短刀,狱卒头盔,疯子衣服,蜘蛛腺体,重修之书,精进之书, + boss单位免疫睡眠 + 盗贼低甲天赋,暴力狂天赋,好战天赋 + 成就:无天赋通关 + DM现在能冲撞 + 红龙之鳞 + 暴击几率现在是怪物基础属性之一,少量怪物具有了十分低的暴击几率与暴击倍数,通常来说对这些怪物进行了攻击削弱。 + 极限攻速0.25 + 强化草叉,隐形之刃 + wiki kostis + + 降低小恶魔卖东西的数量 + 元素抗性结算bug + 掉落 + 天赋移除触发 + 伤害类型颜色 + 饥饿削弱 + 新徽章的贴图 + 0.4.2a 干枯羊腿,急救试剂,鱼骨,肉串 萃取瓶,天赋异禀,体质药剂,强化药剂天赋 diff --git a/dev/tmx/CavesBossLevel.tmx b/dev/tmx/CavesBossLevel.tmx index aab0acdcb..0948d1273 100644 --- a/dev/tmx/CavesBossLevel.tmx +++ b/dev/tmx/CavesBossLevel.tmx @@ -1,9 +1,9 @@ - + - + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, @@ -17,28 +17,28 @@ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,2,2,2,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,2,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,2,2,2,5,5,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,2,2,26,5,5,5,5,2,2,5,5,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,2,2,2,2,2,5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,2,2,2,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,2,2,2,5,5,5,5,2,2,2,2,2,2,2,2,5,5,5,2,2,2,5,2,26,5,5,5,5,5,5, -5,5,5,5,5,5,2,2,2,5,5,5,5,2,2,2,2,2,2,2,2,2,5,5,2,2,2,5,2,2,5,5,5,5,5,5, -5,5,5,5,5,5,2,2,5,5,5,5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5, +5,5,5,5,5,5,2,2,2,5,5,5,5,2,2,2,2,2,2,2,2,26,5,5,2,2,2,5,2,2,5,5,5,5,5,5, +5,5,5,5,5,5,2,2,26,5,5,5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5, 5,5,5,5,5,5,2,2,2,5,5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5, 5,5,5,5,5,5,2,2,2,2,2,2,2,2,5,5,5,5,5,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5, 5,5,5,5,5,5,2,2,2,2,2,2,2,2,5,2,2,2,5,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5, -5,5,5,5,5,2,2,2,2,2,2,2,2,2,5,2,8,2,5,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,2,2,2,2,2,2,2,2,2,5,2,8,2,5,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,2,2,2,2,2,2,2,2,2,5,2,2,2,5,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,2,2,2,2,2,2,2,2,5,5,6,5,5,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,26,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,2,2,2,5,5,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,2,2,2,5,5,5,5,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,2,2,2,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,2,2,2,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,2,2,2,5,5,5,2,2,2,2,2,2,2,2,2,26,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5