From 52aa38780f817b6516b541d31ebef25e6a30c5f7 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Fri, 14 Jun 2024 16:30:48 -0400 Subject: [PATCH] v2.5.0: expanded catalogs to include bestiary and lore sections --- .../assets/messages/actors/actors.properties | 9 +- .../assets/messages/items/items.properties | 8 +- .../assets/messages/levels/levels.properties | 3 +- .../messages/windows/windows.properties | 10 + core/src/main/assets/sprites/items.png | Bin 23616 -> 23682 bytes .../hero/abilities/huntress/SpiritHawk.java | 7 +- .../hero/abilities/rogue/ShadowClone.java | 3 +- .../actors/mobs/ArmoredStatue.java | 12 +- .../actors/mobs/Mob.java | 2 +- .../actors/mobs/Statue.java | 6 +- .../actors/mobs/npcs/MirrorImage.java | 2 + .../actors/mobs/npcs/PrismaticImage.java | 2 + .../items/wands/WandOfLivingEarth.java | 14 +- .../items/wands/WandOfRegrowth.java | 9 +- .../items/wands/WandOfWarding.java | 19 +- .../journal/Bestiary.java | 4 +- .../journal/Catalog.java | 15 +- .../sprites/ItemSpriteSheet.java | 8 +- .../sprites/PrismaticSprite.java | 9 + .../tiles/TerrainFeaturesTilemap.java | 18 ++ .../ui/ScrollingGridPane.java | 30 +- .../windows/WndJournal.java | 279 ++++++++++++++++-- .../windows/WndJournalItem.java | 45 +++ 23 files changed, 446 insertions(+), 68 deletions(-) create mode 100644 core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndJournalItem.java diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties index 4d3056a8c..00491b505 100644 --- a/core/src/main/assets/messages/actors/actors.properties +++ b/core/src/main/assets/messages/actors/actors.properties @@ -492,7 +492,8 @@ actors.hero.abilities.huntress.spirithawk$hawkally.name=spirit hawk actors.hero.abilities.huntress.spirithawk$hawkally.direct_defend=Your hawk moves to that position. actors.hero.abilities.huntress.spirithawk$hawkally.direct_follow=Your hawk moves to follow you. actors.hero.abilities.huntress.spirithawk$hawkally.direct_attack=Your hawk moves to attack! -actors.hero.abilities.huntress.spirithawk$hawkally.desc=A magical hawk, summoned by the Huntress. It glows a bright ethereal blue, its head constantly shifts around as it surveys the area.\n\nWhile it isn't much of a fighter its speed and vision make it excellent for scouting and distracting enemies.\n\nTurns remaining: %d. +actors.hero.abilities.huntress.spirithawk$hawkally.desc=A magical hawk, summoned by the Huntress. It glows a bright ethereal blue, its head constantly shifts around as it surveys the area.\n\nWhile it isn't much of a fighter its speed and vision make it excellent for scouting and distracting enemies. +actors.hero.abilities.huntress.spirithawk$hawkally.desc_remaining=Turns remaining: %d. actors.hero.abilities.huntress.spirithawk$hawkally.desc_dodges=Guaranteed dodges remaining: %d. actors.hero.abilities.duelist.challenge.name=challenge @@ -1107,7 +1108,8 @@ actors.mobs.albino.name=albino rat actors.mobs.albino.desc=This is a rare breed of marsupial rat, with pure white fur and jagged teeth. actors.mobs.armoredstatue.name=armored statue -actors.mobs.armoredstatue.desc=You would think that it's just another one of this dungeon's inanimate statues, but its red glowing eyes give it away.\n\nIt seems to be in great condition because of the armor it's wearing, it might be very hard to kill.\n\nWhile the statue itself is made of stone, the _%1$s_ and _%2$s_ it's wielding look real. +actors.mobs.armoredstatue.desc=You would think that it's just another one of this dungeon's inanimate statues, but its red glowing eyes give it away.\n\nIt seems to be in great condition because of the armor it's wearing, it might be very hard to kill. +actors.mobs.armoredstatue.desc_arm_wep=While the statue itself is made of stone, the _%1$s_ and _%2$s_ it's wielding look real. actors.mobs.bandit.name=crazy bandit @@ -1370,7 +1372,8 @@ actors.mobs.spinner.desc=These greenish furry cave spiders try to avoid direct c actors.mobs.statue.name=animated statue actors.mobs.statue.def_verb=blocked -actors.mobs.statue.desc=You would think that it's just another one of this dungeon's inanimate statues, but its red glowing eyes give it away.\n\nWhile the statue itself is made of stone, the _%s_ it's wielding looks real. +actors.mobs.statue.desc=You would think that it's just another one of this dungeon's inanimate statues, but its red glowing eyes give it away. +actors.mobs.statue.desc_weapon=While the statue itself is made of stone, the _%s_ it's wielding looks real. actors.mobs.succubus.name=succubus actors.mobs.succubus.desc=Succubi are shapeshifting demons that manipulate the minds of their prey. This one has taken the form of a pale gothic humanoid, perhaps to attract dwarven warlocks?\n\nSuccubi may temporarily charm their enemy when they attack, making their enemy unable to directly attack them. When succubi attack a charmed enemy, they will steal some of their life essence. diff --git a/core/src/main/assets/messages/items/items.properties b/core/src/main/assets/messages/items/items.properties index df487bb9e..01da39d64 100644 --- a/core/src/main/assets/messages/items/items.properties +++ b/core/src/main/assets/messages/items/items.properties @@ -1418,7 +1418,8 @@ items.wands.wandoflivingearth.eleblast_desc=An elemental blast with a staff of l items.wands.wandoflivingearth$rockarmor.name=rock armor items.wands.wandoflivingearth$rockarmor.desc=Magical rocks are surrounding your body, when you are attacked they will attempt to block for you, and will reduce the damage you take by 50%%. Each damage blocked scrapes away some of the rock however.\n\nRemaining Armor: %1$d.\n\nIf enough rock is built around you, the next zap from your wand of living earth will cause the rocks to form up into a guardian which will fight with you.\n\nArmor needed for Guardian: %2$d. items.wands.wandoflivingearth$earthguardian.name=earthen guardian -items.wands.wandoflivingearth$earthguardian.desc=The rocks from your wand of living earth have formed into a protective earthen guardian! This rocky protector will attack nearby enemies, which will force them to attack the guardian instead of you. When all nearby threats are gone, the guardian will re-form around you, and will return when you next use your wand.\n\nThe guardian's defensive power is tied to the level of your wand. It currently blocks _%1$d-%2$d damage._ +items.wands.wandoflivingearth$earthguardian.desc=The rocks from your wand of living earth have formed into a protective earthen guardian! This rocky protector will attack nearby enemies, which will force them to attack the guardian instead of you. When all nearby threats are gone, the guardian will re-form around you, and will return when you next use your wand. +items.wands.wandoflivingearth$earthguardian.wand_info=The guardian's defensive power is tied to the level of your wand. It currently blocks _%1$d-%2$d damage._ items.wands.wandofmagicmissile.name=wand of magic missile items.wands.wandofmagicmissile.staff_name=staff of magic missile @@ -1448,7 +1449,8 @@ items.wands.wandofregrowth$dewcatcher.desc=Dewcatchers are wondrous plants that items.wands.wandofregrowth$seedpod.name=Seed Pod items.wands.wandofregrowth$seedpod.desc=Seed Pods are magical plants that produce seeds from other plant types, rather than any seeds of their own. They somehow manage to spread despite having no seed of their own. items.wands.wandofregrowth$lotus.name=Golden Lotus -items.wands.wandofregrowth$lotus.desc=The golden lotus is a mystical plant that can only be conjured by a powerful wand of regrowth. Its aura enhances all plants and plant effects, but it burns through its energy and dies after a short time.\n\nThis lotus was produced by a _+%1$d_ wand of regrowth. All plants in its effect will _instantly trigger_ if they are planted on a character. Plants will also have a _%2$d%% chance_ to drop their seed, and tipped darts will use _%3$d%% less durability_. +items.wands.wandofregrowth$lotus.desc=The golden lotus is a mystical plant that can only be conjured by a powerful wand of regrowth. Its aura enhances all plants and plant effects, but it burns through its energy and dies after a short time. +items.wands.wandofregrowth$lotus.wand_info=This lotus was produced by a _+%1$d_ wand of regrowth. All plants in its effect will _instantly trigger_ if they are planted on a character. Plants will also have a _%2$d%% chance_ to drop their seed, and tipped darts will use _%3$d%% less durability_. items.wands.wandoftransfusion.name=wand of transfusion items.wands.wandoftransfusion.staff_name=staff of transfusion @@ -1467,6 +1469,8 @@ items.wands.wandofwarding.desc=This short metal wand has a bright purple gem flo items.wands.wandofwarding.stats_desc=Rather than directly damaging an enemy, this wand will summon stationary wards and sentries. Wards can be summoned anywhere, even through walls if you have vision. This wand can sustain _%d energy_ worth of wards at a time. items.wands.wandofwarding.bmage_desc=When _the Battlemage_ strikes an enemy with a staff of warding, all active sentries have a chance to be healed. items.wands.wandofwarding.eleblast_desc=An elemental blast with a staff of warding heals all sentries in the blast area. +items.wands.wandofwarding$ward.desc_generic_ward=This ward will automatically zap any enemy which comes into its range of vision.\n\nZapping this ward with your wand of warding will upgrade it.\n\nWards have a limited number of zaps before dissipating. +items.wands.wandofwarding$ward.desc_generic_sentry=This sentry has the same firepower as a ward, but has health instead of a set number of charges. It resembles the gem at the tip of your wand of warding.\n\nZapping this sentry with your wand of warding will upgrade and heal it.\n\nThis sentry will spend some health each time it zaps an enemy, but can be healed by using your wand of warding on it. items.wands.wandofwarding$ward.name_1=lesser ward items.wands.wandofwarding$ward.desc_1=This basic ward will automatically zap any enemy which comes into its range of vision, dealing _%1$d-%2$d damage._\n\nZapping this ward with your wand of warding will upgrade it.\n\nThis ward will only zap a single time before dissipating.\n\nYour wand of warding is using _%3$d energy_ to sustain this ward. items.wands.wandofwarding$ward.name_2=ward diff --git a/core/src/main/assets/messages/levels/levels.properties b/core/src/main/assets/messages/levels/levels.properties index 3391af2e3..5109be740 100644 --- a/core/src/main/assets/messages/levels/levels.properties +++ b/core/src/main/assets/messages/levels/levels.properties @@ -98,7 +98,8 @@ levels.traps.guardiantrap.name=guardian trap levels.traps.guardiantrap.alarm=The trap emits a piercing sound that echoes throughout the dungeon! levels.traps.guardiantrap.desc=This trap is tied to a strange magical mechanism, which will summon guardians and alert all enemies on the floor. levels.traps.guardiantrap$guardian.name=summoned guardian -levels.traps.guardiantrap$guardian.desc=This blue apparition seems to be a summoned echo of one of the dungeon's stone guardians.\n\nWhile the statue itself is almost incorporeal, the _%s_ it's wielding looks real. +levels.traps.guardiantrap$guardian.desc=This blue apparition seems to be a summoned echo of one of the dungeon's stone guardians. +levels.traps.guardiantrap$guardian.desc_weapon=While the statue itself is almost incorporeal, the _%s_ it's wielding looks real. levels.traps.oozetrap.name=ooze trap levels.traps.oozetrap.desc=This trap will splash out caustic ooze when activated, which will burn until it is washed away. diff --git a/core/src/main/assets/messages/windows/windows.properties b/core/src/main/assets/messages/windows/windows.properties index b18ff79d1..e161ce815 100644 --- a/core/src/main/assets/messages/windows/windows.properties +++ b/core/src/main/assets/messages/windows/windows.properties @@ -122,9 +122,19 @@ windows.wndjournal$notestab.landmarks=Landmarks windows.wndjournal$catalogtab.title=Catalogs windows.wndjournal$catalogtab.title_equipment=Equipment windows.wndjournal$catalogtab.title_consumables=Consumables +windows.wndjournal$catalogtab.title_bestiary=Bestiary +windows.wndjournal$catalogtab.title_lore=Lore windows.wndjournal$catalogtab.not_seen_item=You haven't found and identified that item in any of your runs yet. windows.wndjournal$catalogtab.not_seen_enchantment=You haven't found and identified a weapon with that enchantmet in any of your runs yet. windows.wndjournal$catalogtab.not_seen_glyph=You haven't found and identified an armor with that glyph in any of your runs yet. +windows.wndjournal$catalogtab.not_seen_enemy=This enemy hasn't been defeated in any of your runs yet. +windows.wndjournal$catalogtab.not_seen_ally=You haven't encountered this character in any of your runs yet. +windows.wndjournal$catalogtab.not_seen_trap=You haven't triggered this trap in any of your runs yet. +windows.wndjournal$catalogtab.not_seen_plant=You haven't trampled this plant in any of your runs yet. +windows.wndjournal$catalogtab.enemy_count=You have defeated this enemy _%d_ times. +windows.wndjournal$catalogtab.trap_count=You have triggered this trap _%d_ times. +windows.wndjournal$catalogtab.plant_count=You have trampled this plant _%d_ times. +windows.wndjournal$catalogtab.not_seen_lore=You haven't found this lore text in any of your runs yet. windows.wndjournal$loretab.title=Documents windows.wndkeybindings.controller_info=The left stick moves your character\nThe right stick controls an on-screen pointer diff --git a/core/src/main/assets/sprites/items.png b/core/src/main/assets/sprites/items.png index 5752637074f7527791635a70dfb67ccfadc61b5c..a7c6d1d0fd61ebd6b58a36becb188b0127c41b4d 100644 GIT binary patch literal 23682 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 diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/huntress/SpiritHawk.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/huntress/SpiritHawk.java index 32022c72a..56522cb09 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/huntress/SpiritHawk.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/huntress/SpiritHawk.java @@ -254,8 +254,11 @@ public class SpiritHawk extends ArmorAbility { @Override public String description() { String message = Messages.get(this, "desc", (int)timeRemaining); - if (dodgesUsed < 2*Dungeon.hero.pointsInTalent(Talent.SWIFT_SPIRIT)){ - message += "\n" + Messages.get(this, "desc_dodges", (2*Dungeon.hero.pointsInTalent(Talent.SWIFT_SPIRIT) - dodgesUsed)); + if (Actor.chars().contains(this)){ + message += "\n\n" + Messages.get(this, "desc_remaining", (int)timeRemaining); + if (dodgesUsed < 2*Dungeon.hero.pointsInTalent(Talent.SWIFT_SPIRIT)){ + message += "\n" + Messages.get(this, "desc_dodges", (2*Dungeon.hero.pointsInTalent(Talent.SWIFT_SPIRIT) - dodgesUsed)); + } } return message; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/rogue/ShadowClone.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/rogue/ShadowClone.java index 54d98d411..fbb40d9ac 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/rogue/ShadowClone.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/rogue/ShadowClone.java @@ -29,6 +29,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.AllyBuff; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Burning; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Invisibility; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.ArmorAbility; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.huntress.SpiritHawk; @@ -367,7 +368,7 @@ public class ShadowClone extends ArmorAbility { public ShadowSprite() { super(); - texture( Dungeon.hero.heroClass.spritesheet() ); + texture( HeroClass.ROGUE.spritesheet() ); TextureFilm film = new TextureFilm( HeroSprite.tiers(), 6, 12, 15 ); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/ArmoredStatue.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/ArmoredStatue.java index c138684fc..5258d9e12 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/ArmoredStatue.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/ArmoredStatue.java @@ -116,7 +116,11 @@ public class ArmoredStatue extends Statue { @Override public CharSprite sprite() { CharSprite sprite = super.sprite(); - ((StatueSprite)sprite).setArmor(armor.tier); + if (armor != null) { + ((StatueSprite) sprite).setArmor(armor.tier); + } else { + ((StatueSprite) sprite).setArmor(3); + } return sprite; } @@ -144,7 +148,11 @@ public class ArmoredStatue extends Statue { @Override public String description() { - return Messages.get(this, "desc", weapon.name(), armor.name()); + String desc = Messages.get(this, "desc"); + if (weapon != null && armor != null){ + desc += "\n\n" + Messages.get(this, "desc_arm_wep", weapon.name(), armor.name()); + } + return desc; } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java index dbc4b57b9..de9819a42 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java @@ -782,7 +782,7 @@ public abstract class Mob extends Char { Statistics.enemiesSlain++; Badges.validateMonstersSlain(); Statistics.qualifiedForNoKilling = false; - Bestiary.trackKill(getClass()); + Bestiary.trackEncounter(getClass()); AscensionChallenge.processEnemyKill(this); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Statue.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Statue.java index 20f59f26f..2fcaca14c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Statue.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Statue.java @@ -182,7 +182,11 @@ public class Statue extends Mob { @Override public String description() { - return Messages.get(this, "desc", weapon.name()); + String desc = Messages.get(this, "desc"); + if (weapon != null){ + desc += "\n\n" + Messages.get(this, "desc_weapon", weapon.name()); + } + return desc; } { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/MirrorImage.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/MirrorImage.java index 617b83b64..ee84b2a1a 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/MirrorImage.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/MirrorImage.java @@ -187,6 +187,8 @@ public class MirrorImage extends NPC { hero = (Hero)Actor.findById(heroID); if (hero != null) { armTier = hero.tier(); + } else { + armTier = 1; } ((MirrorSprite)s).updateArmor( armTier ); return s; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/PrismaticImage.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/PrismaticImage.java index 695179dac..614212b22 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/PrismaticImage.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/PrismaticImage.java @@ -240,6 +240,8 @@ public class PrismaticImage extends NPC { hero = (Hero)Actor.findById(heroID); if (hero != null) { armTier = hero.tier(); + } else { + armTier = 1; } ((PrismaticSprite)s).updateArmor( armTier ); return s; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfLivingEarth.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfLivingEarth.java index 642f37796..c7d5270b8 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfLivingEarth.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfLivingEarth.java @@ -368,11 +368,17 @@ public class WandOfLivingEarth extends DamageWand { @Override public String description() { - if (Dungeon.isChallenged(Challenges.NO_ARMOR)){ - return Messages.get(this, "desc", wandLevel, 2 + wandLevel); - } else { - return Messages.get(this, "desc", wandLevel, 3 + 3*wandLevel); + String desc = Messages.get(this, "desc"); + + if (Actor.chars().contains(this)) { + if (Dungeon.isChallenged(Challenges.NO_ARMOR)) { + desc += "\n\n" + Messages.get(this, "wand_info", wandLevel, 2 + wandLevel); + } else { + desc += "\n\n" + Messages.get(this, "wand_info", wandLevel, 3 + 3 * wandLevel); + } } + + return desc; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java index 05e2a76fb..50a16dfce 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java @@ -26,7 +26,6 @@ import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.Statistics; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; -import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.AllyBuff; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Doom; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Roots; @@ -469,8 +468,12 @@ public class WandOfRegrowth extends Wand { @Override public String description() { - int preservation = Math.round(seedPreservation()*100); - return Messages.get(this, "desc", wandLvl, preservation, preservation); + String desc = Messages.get(this, "desc"); + if (Actor.chars().contains(this)) { + int preservation = Math.round(seedPreservation()*100); + desc += "\n\n" + Messages.get(this, "wand_info", wandLvl, preservation, preservation); + } + return desc; } private static final String WAND_LVL = "wand_lvl"; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfWarding.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfWarding.java index b0dbfb194..33c83859f 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfWarding.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfWarding.java @@ -37,6 +37,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.NPC; import com.shatteredpixel.shatteredpixeldungeon.effects.FloatingText; import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.MagesStaff; +import com.shatteredpixel.shatteredpixeldungeon.journal.Bestiary; import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; @@ -251,6 +252,10 @@ public class WandOfWarding extends Wand { break; } + if (tier >= 4){ + Bestiary.setSeen(WardSentry.class); + } + if (tier < 6){ tier++; viewDistance++; @@ -263,6 +268,9 @@ public class WandOfWarding extends Wand { } + //this class is used so that wards and sentries can have two entries in the Bestiary + public static class WardSentry extends Ward{}; + public void wandHeal( int wandLevel ){ wandHeal( wandLevel, 1f ); } @@ -431,7 +439,16 @@ public class WandOfWarding extends Wand { @Override public String description() { - return Messages.get(this, "desc_" + tier, 2+wandLevel, 8 + 4*wandLevel, tier ); + if (!Actor.chars().contains(this)){ + //for viewing in the journal + if (tier < 4){ + return Messages.get(this, "desc_generic_ward"); + } else { + return Messages.get(this, "desc_generic_sentry"); + } + } else { + return Messages.get(this, "desc_" + tier, 2 + wandLevel, 8 + 4 * wandLevel, tier); + } } { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/journal/Bestiary.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/journal/Bestiary.java index f8b788ff2..b93a89670 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/journal/Bestiary.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/journal/Bestiary.java @@ -230,7 +230,7 @@ public enum Bestiary { ALLY.addEntities(MirrorImage.class, PrismaticImage.class, DriedRose.GhostHero.class, - WandOfWarding.Ward.class, WandOfLivingEarth.EarthGuardian.class, + WandOfWarding.Ward.class, WandOfWarding.Ward.WardSentry.class, WandOfLivingEarth.EarthGuardian.class, ShadowClone.ShadowAlly.class, SmokeBomb.NinjaLog.class, SpiritHawk.HawkAlly.class); TRAP.addEntities(WornDartTrap.class, PoisonDartTrap.class, DisintegrationTrap.class, GatewayTrap.class, @@ -340,7 +340,7 @@ public enum Bestiary { public static void restore( Bundle bundle ){ - if (bundle.contains(BESTIARY_CLASSES)){ + if (bundle.contains(BESTIARY_CLASSES) && bundle.contains(BESTIARY_ENCOUNTERS)){ Class[] classes = bundle.getClassArray(BESTIARY_CLASSES); int[] kills = bundle.getIntArray(BESTIARY_ENCOUNTERS); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/journal/Catalog.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/journal/Catalog.java index adef72281..bdd8198ee 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/journal/Catalog.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/journal/Catalog.java @@ -345,19 +345,8 @@ public enum Catalog { public static void restore( Bundle bundle ){ Badges.loadGlobal(); - - //logic for if we have all badges - //FIXME skip this for now as it's outdated - /*if (Badges.isUnlocked(Badges.Badge.ALL_ITEMS_IDENTIFIED)){ - for ( Catalog cat : values()){ - for (Class item : cat.items()){ - cat.seen.put(item, true); - } - } - return; - }*/ - - //catalog-specific badge logic + + //old logic for pre-v2.5 catalog-specific badges for (Catalog cat : values()){ if (Badges.isUnlocked(catalogBadges.get(cat))){ for (Class item : cat.items()){ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java index 1553090fd..dc7730448 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java @@ -42,7 +42,7 @@ public class ItemSpriteSheet { film.add( item, x, y, x+width, y+height); } - private static final int PLACEHOLDERS = xy(1, 1); //16 slots + private static final int PLACEHOLDERS = xy(1, 1); //18 slots //SOMETHING is the default item sprite at position 0. May show up ingame if there are bugs. public static final int SOMETHING = PLACEHOLDERS+0; public static final int WEAPON_HOLDER = PLACEHOLDERS+1; @@ -60,6 +60,8 @@ public class ItemSpriteSheet { public static final int STONE_HOLDER = PLACEHOLDERS+13; public static final int ELIXIR_HOLDER = PLACEHOLDERS+14; public static final int SPELL_HOLDER = PLACEHOLDERS+15; + public static final int MOB_HOLDER = PLACEHOLDERS+16; + public static final int DOCUMENT_HOLDER = PLACEHOLDERS+17; static{ assignItemRect(SOMETHING, 8, 13); assignItemRect(WEAPON_HOLDER, 14, 14); @@ -77,9 +79,11 @@ public class ItemSpriteSheet { assignItemRect(STONE_HOLDER, 14, 12); assignItemRect(ELIXIR_HOLDER, 12, 14); assignItemRect(SPELL_HOLDER, 8, 16); + assignItemRect(MOB_HOLDER, 15, 14); + assignItemRect(DOCUMENT_HOLDER, 10, 11); } - private static final int UNCOLLECTIBLE = xy(1, 2); //16 slots + private static final int UNCOLLECTIBLE = xy(3, 2); //14 slots public static final int GOLD = UNCOLLECTIBLE+0; public static final int ENERGY = UNCOLLECTIBLE+1; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/PrismaticSprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/PrismaticSprite.java index 8c91ee8fc..7832a9dfe 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/PrismaticSprite.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/PrismaticSprite.java @@ -26,6 +26,15 @@ import com.watabou.noosa.Game; public class PrismaticSprite extends MirrorSprite { + public PrismaticSprite(){ + super(); + + float interval = (Game.timeTotal % 9 ) /3f; + tint(interval > 2 ? interval - 2 : Math.max(0, 1 - interval), + interval > 1 ? Math.max(0, 2-interval): interval, + interval > 2 ? Math.max(0, 3-interval): interval-1, 0.5f); + } + @Override public void updateArmor() { updateArmor( ((PrismaticImage)ch).armTier ); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/TerrainFeaturesTilemap.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/TerrainFeaturesTilemap.java index 5c023af46..5400024b1 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/TerrainFeaturesTilemap.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/TerrainFeaturesTilemap.java @@ -80,6 +80,24 @@ public class TerrainFeaturesTilemap extends DungeonTilemap { return -1; } + public static Image getTrapVisual( Trap trap ){ + RectF uv = instance.tileset.get((trap.active ? trap.color : Trap.BLACK) + (trap.shape * 16)); + if (uv == null) return null; + + Image img = new Image( instance.texture ); + img.frame(uv); + return img; + } + + public static Image getPlantVisual( Plant plant ){ + RectF uv = instance.tileset.get(plant.image + 7*16); + if (uv == null) return null; + + Image img = new Image( instance.texture ); + img.frame(uv); + return img; + } + public static Image tile(int pos, int tile ) { RectF uv = instance.tileset.get( instance.getTileVisual( pos, tile, true ) ); if (uv == null) return null; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/ScrollingGridPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/ScrollingGridPane.java index 6d60c86af..34b227032 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/ScrollingGridPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/ScrollingGridPane.java @@ -25,6 +25,7 @@ import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite; import com.watabou.noosa.ColorBlock; import com.watabou.noosa.Image; +import com.watabou.noosa.Visual; import com.watabou.noosa.ui.Component; import java.util.ArrayList; @@ -76,12 +77,30 @@ public class ScrollingGridPane extends ScrollPane { super.layout(); float left = 0; + boolean freshRow = true; float top = 0; - for (Component item : items){ + for (int i = 0; i < items.size(); i++){ + Component item = items.get(i); if (item instanceof GridHeader){ if (left > 0){ - left = 0; - top += ITEM_SIZE+2; + //this bit of logic here exists so that multiple headers can be on one row in landscape + // if both of their groups have a small number of items (e.g. 6) + float spaceLeft = width() - left; + int spaceReq = 0; + for (int j = i+1; j < items.size(); j++){ + if (items.get(j) instanceof GridItem){ + spaceReq += ITEM_SIZE+1; + } else { + break; + } + } + if (freshRow && spaceLeft >= spaceReq){ + top -= item.height()+1; + } else { + left = 0; + top += ITEM_SIZE + 2; + freshRow = true; + } } item.setRect(left, top, width(), item.height()); top += item.height()+1; @@ -89,6 +108,7 @@ public class ScrollingGridPane extends ScrollPane { if (left + ITEM_SIZE > width()) { left = 0; top += ITEM_SIZE+1; + freshRow = false; } item.setRect(left, top, ITEM_SIZE, ITEM_SIZE); left += ITEM_SIZE+1; @@ -106,7 +126,7 @@ public class ScrollingGridPane extends ScrollPane { protected Image icon; - protected Image secondIcon; + protected Visual secondIcon; protected ColorBlock bg; @@ -122,7 +142,7 @@ public class ScrollingGridPane extends ScrollPane { add(this.icon); } - public void addSecondIcon( Image icon ){ + public void addSecondIcon( Visual icon ){ secondIcon = icon; add(secondIcon); layout(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndJournal.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndJournal.java index cee386150..80caca28a 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndJournal.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndJournal.java @@ -24,21 +24,31 @@ package com.shatteredpixel.shatteredpixeldungeon.windows; import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; +import com.shatteredpixel.shatteredpixeldungeon.actors.Char; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mimic; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Pylon; import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.armor.Armor; import com.shatteredpixel.shatteredpixeldungeon.items.armor.ClassArmor; import com.shatteredpixel.shatteredpixeldungeon.items.potions.Potion; import com.shatteredpixel.shatteredpixeldungeon.items.rings.Ring; import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.Scroll; +import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfWarding; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.Weapon; +import com.shatteredpixel.shatteredpixeldungeon.journal.Bestiary; import com.shatteredpixel.shatteredpixeldungeon.journal.Catalog; import com.shatteredpixel.shatteredpixeldungeon.journal.Document; import com.shatteredpixel.shatteredpixeldungeon.journal.Notes; +import com.shatteredpixel.shatteredpixeldungeon.levels.traps.Trap; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.plants.Plant; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene; +import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; +import com.shatteredpixel.shatteredpixeldungeon.tiles.TerrainFeaturesTilemap; import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; import com.shatteredpixel.shatteredpixeldungeon.ui.QuickRecipe; import com.shatteredpixel.shatteredpixeldungeon.ui.RedButton; @@ -46,9 +56,11 @@ import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; import com.shatteredpixel.shatteredpixeldungeon.ui.ScrollPane; import com.shatteredpixel.shatteredpixeldungeon.ui.ScrollingGridPane; import com.shatteredpixel.shatteredpixeldungeon.ui.ScrollingListPane; +import com.watabou.noosa.BitmapText; import com.watabou.noosa.ColorBlock; import com.watabou.noosa.Image; import com.watabou.noosa.ui.Component; +import com.watabou.utils.RectF; import com.watabou.utils.Reflection; import java.util.ArrayList; @@ -98,10 +110,10 @@ public class WndJournal extends WndTabbed { catalogTab.setRect(0, 0, width, height); catalogTab.updateList(); - loreTab = new LoreTab(); + /*loreTab = new LoreTab(); add(loreTab); loreTab.setRect(0, 0, width, height); - loreTab.updateList(); + loreTab.updateList();*/ Tab[] tabs = { new IconTab( new ItemSprite(ItemSpriteSheet.MASTERY, null) ) { @@ -125,20 +137,20 @@ public class WndJournal extends WndTabbed { if (value) last_index = 2; } }, - new IconTab( new ItemSprite(ItemSpriteSheet.WEAPON_HOLDER, null) ) { + new IconTab( Icons.RENAME_ON.get() ) { //TODO dedicated icon here? protected void select( boolean value ) { super.select( value ); catalogTab.active = catalogTab.visible = value; if (value) last_index = 3; } }, - new IconTab( new ItemSprite(ItemSpriteSheet.GUIDE_PAGE, null) ) { + /*new IconTab( new ItemSprite(ItemSpriteSheet.GUIDE_PAGE, null) ) { protected void select( boolean value ) { super.select( value ); loreTab.active = loreTab.visible = value; if (value) last_index = 4; } - } + }*/ }; for (Tab tab : tabs) { @@ -453,17 +465,15 @@ public class WndJournal extends WndTabbed { private static class CatalogTab extends Component{ private RedButton[] itemButtons; - private static final int NUM_BUTTONS = 2; + private static final int NUM_BUTTONS = 4; private static int currentItemIdx = 0; //sprite locations private static final int EQUIP_IDX = 0; private static final int CONSUM_IDX = 1; - - private static final int spriteIndexes[] = - {ItemSpriteSheet.WEAPON_HOLDER, - ItemSpriteSheet.POTION_HOLDER}; + private static final int BESTIARY_IDX = 2; + private static final int LORE_IDX = 3; private ScrollingGridPane grid; @@ -479,9 +489,12 @@ public class WndJournal extends WndTabbed { updateList(); } }; - itemButtons[i].icon(new ItemSprite(spriteIndexes[i], null)); add( itemButtons[i] ); } + itemButtons[EQUIP_IDX].icon(new ItemSprite(ItemSpriteSheet.WEAPON_HOLDER)); + itemButtons[CONSUM_IDX].icon(new ItemSprite(ItemSpriteSheet.POTION_HOLDER)); + itemButtons[BESTIARY_IDX].icon(new ItemSprite(ItemSpriteSheet.MOB_HOLDER)); + itemButtons[LORE_IDX].icon(new ItemSprite(ItemSpriteSheet.DOCUMENT_HOLDER)); grid = new ScrollingGridPane(); add( grid ); @@ -528,8 +541,6 @@ public class WndJournal extends WndTabbed { grid.addHeader("_" + Messages.get(this, "title_equipment") + "_ (" + totalSeen + "/" + totalItems + ")", 9, true); for (Catalog catalog : Catalog.equipmentCatalogs){ - totalItems += catalog.totalItems(); - totalSeen += catalog.totalSeen(); grid.addHeader("_" + Messages.titleCase(catalog.title()) + "_ (" + catalog.totalSeen() + "/" + catalog.totalItems() + "):"); addGridItems(grid, catalog.items()); } @@ -544,12 +555,70 @@ public class WndJournal extends WndTabbed { grid.addHeader("_" + Messages.get(this, "title_consumables") + "_ (" + totalSeen + "/" + totalItems + ")", 9, true); for (Catalog catalog : Catalog.consumableCatalogs){ - totalItems += catalog.totalItems(); - totalSeen += catalog.totalSeen(); grid.addHeader("_" + Messages.titleCase(catalog.title()) + "_ (" + catalog.totalSeen() + "/" + catalog.totalItems() + "):"); addGridItems(grid, catalog.items()); } + } else if (currentItemIdx == BESTIARY_IDX){ + int totalItems = 0; + int totalSeen = 0; + for (Bestiary bestiary : Bestiary.values()){ + totalItems += bestiary.totalEntities(); + totalSeen += bestiary.totalSeen(); + } + grid.addHeader("_" + Messages.get(this, "title_bestiary") + "_ (" + totalSeen + "/" + totalItems + ")", 9, true); + + for (Bestiary bestiary : Bestiary.values()){ + grid.addHeader("_" + Messages.titleCase(bestiary.title()) + "_ (" + bestiary.totalSeen() + "/" + bestiary.totalEntities() + "):"); + addGridEntities(grid, bestiary.entities()); + } + + } else { + int totalItems = 0; + int totalSeen = 0; + for (Document doc : Document.values()){ + if (!doc.isLoreDoc()){ + continue; + } + for (String page : doc.pageNames()){ + totalItems++; + if (doc.isPageFound(page)){ + totalSeen++; + } + } + } + grid.addHeader("_" + Messages.get(this, "title_lore") + "_ (" + totalSeen + "/" + totalItems + ")", 9, true); + + for (Document doc : Document.values()){ + if (!doc.isLoreDoc()){ + continue; + } + + for (String page : doc.pageNames()){ + totalItems++; + if (doc.isPageFound(page)){ + totalSeen++; + } + } + } + for (Document doc : Document.values()){ + if (!doc.isLoreDoc()){ + continue; + } + totalItems = totalSeen = 0; + for (String page : doc.pageNames()){ + totalItems++; + if (doc.isPageFound(page)){ + totalSeen++; + } + } + if (!doc.anyPagesFound()){ + grid.addHeader("_???_ (" + totalSeen + "/" + totalItems + "):"); + } else { + grid.addHeader("_" + Messages.titleCase(doc.title()) + "_ (" + totalSeen + "/" + totalItems + "):"); + } + addGridDocuments(grid, doc); + } } grid.setRect(x, itemButtons[NUM_BUTTONS-1].bottom() + 1, width, @@ -558,11 +627,12 @@ public class WndJournal extends WndTabbed { } + //also includes item-like things such as enchantments, glyphs, curses. private static void addGridItems( ScrollingGridPane grid, Collection> classes) { for (Class itemClass : classes) { boolean seen = Catalog.isSeen(itemClass);; - Image sprite = null; + ItemSprite sprite = null; Image secondIcon = null; String title = ""; String desc = ""; @@ -634,15 +704,9 @@ public class WndJournal extends WndTabbed { @Override public boolean onClick(float x, float y) { if (inside(x, y)) { - //TODO need to dupe! - Image sprite; - if (icon instanceof ItemSprite){ - sprite = new ItemSprite(); - sprite.copy(icon); - } else { - sprite = new Image(icon); - } - GameScene.show(new WndTitledMessage(sprite, finalTitle, finalDesc)); + Image sprite = new ItemSprite(); + sprite.copy(icon); + GameScene.show(new WndJournalItem(sprite, finalTitle, finalDesc)); return true; } else { return false; @@ -659,6 +723,171 @@ public class WndJournal extends WndTabbed { } } + private static void addGridEntities(ScrollingGridPane grid, Collection> classes) { + for (Class entityCls : classes){ + + boolean seen = Bestiary.isSeen(entityCls); + Mob mob = null; + Image icon = null; + String title = null; + String desc = null; + + if (Mob.class.isAssignableFrom(entityCls)) { + + mob = (Mob) Reflection.newInstance(entityCls); + + if (mob instanceof Mimic || mob instanceof Pylon) { + mob.alignment = Char.Alignment.ENEMY; + } + if (mob instanceof WandOfWarding.Ward){ + if (mob instanceof WandOfWarding.Ward.WardSentry){ + ((WandOfWarding.Ward) mob).upgrade(3); + ((WandOfWarding.Ward) mob).upgrade(3); + ((WandOfWarding.Ward) mob).upgrade(3); + ((WandOfWarding.Ward) mob).upgrade(3); + } else { + ((WandOfWarding.Ward) mob).upgrade(0); + } + } + + CharSprite sprite = mob.sprite(); + sprite.idle(); + + icon = new Image(sprite); + if (seen) { + title = Messages.titleCase(mob.name()); + desc = mob.description(); + if (Bestiary.encounterCount(entityCls) > 1){ + desc += "\n\n" + Messages.get(CatalogTab.class, "enemy_count", Bestiary.encounterCount(entityCls)); + } + } else { + icon.lightness(0f); + title = "???"; + desc = mob.alignment == Char.Alignment.ENEMY ? Messages.get(CatalogTab.class, "not_seen_enemy") : Messages.get(CatalogTab.class, "not_seen_ally"); + } + + //we have to clip the bounds of the sprite if it's too large + if (icon.width() >= 17 || icon.height() >= 17) { + RectF frame = icon.frame(); + + float wShrink = frame.width() * (1f - 17f / icon.width()); + if (wShrink > 0) { + frame.left += wShrink / 2f; + frame.right -= wShrink / 2f; + } + float hShrink = frame.height() * (1f - 17f / icon.height()); + if (hShrink > 0) { + frame.top += hShrink / 2f; + frame.bottom -= hShrink / 2f; + } + icon.frame(frame); + } + } else if (Trap.class.isAssignableFrom(entityCls)){ + + Trap trap = (Trap) Reflection.newInstance(entityCls); + icon = TerrainFeaturesTilemap.getTrapVisual(trap); + + if (seen) { + title = Messages.titleCase(trap.name()); + desc = trap.desc(); + if (Bestiary.encounterCount(entityCls) > 1){ + desc += "\n\n" + Messages.get(CatalogTab.class, "trap_count", Bestiary.encounterCount(entityCls)); + } + } else { + icon.lightness(0f); + title = "???"; + desc = Messages.get(CatalogTab.class, "not_seen_trap"); + } + + } else if (Plant.class.isAssignableFrom(entityCls)){ + + Plant plant = (Plant) Reflection.newInstance(entityCls); + icon = TerrainFeaturesTilemap.getPlantVisual(plant); + + if (seen) { + title = Messages.titleCase(plant.name()); + desc = plant.desc(); + if (Bestiary.encounterCount(entityCls) > 1){ + desc += "\n\n" + Messages.get(CatalogTab.class, "plant_count", Bestiary.encounterCount(entityCls)); + } + } else { + icon.lightness(0f); + title = "???"; + desc = Messages.get(CatalogTab.class, "not_seen_trap"); + } + + } + + Mob finalMob = mob; + String finalTitle = title; + String finalDesc = desc; + ScrollingGridPane.GridItem gridItem = new ScrollingGridPane.GridItem(icon) { + @Override + public boolean onClick(float x, float y) { + if (inside(x, y)) { + if (seen && finalMob != null){ + GameScene.show(new WndJournalItem(finalMob.sprite(), finalTitle, finalDesc)); + } else { + GameScene.show(new WndJournalItem(new Image(icon), finalTitle, finalDesc)); + } + + return true; + } else { + return false; + } + } + }; + if (!seen) { + gridItem.hardLightBG(2f, 1f, 2f); + } + grid.addItem(gridItem); + } + }; + + private static void addGridDocuments( ScrollingGridPane grid, Document doc ){ + for (String page : doc.pageNames()){ + + Image sprite = doc.pageSprite(page); + + boolean seen = doc.isPageFound(page); + boolean read = doc.isPageRead(page); + + if (!seen){ + sprite.lightness(0f); + } + + ScrollingGridPane.GridItem gridItem = new ScrollingGridPane.GridItem(sprite) { + @Override + public boolean onClick(float x, float y) { + if (inside(x, y)) { + Image sprite = new Image(icon); + if (seen) { + GameScene.show(new WndStory(sprite, doc.pageTitle(page), doc.pageBody(page))); + hardLightBG(1, 1, 1); + } else { + GameScene.show(new WndJournalItem(sprite, "???", Messages.get(CatalogTab.class, "not_seen_lore"))); + } + return true; + } else { + return false; + } + } + }; + + if (seen){ + BitmapText text = new BitmapText(Integer.toString(doc.pageIdx(page)+1), PixelScene.pixelFont); + text.measure(); + gridItem.addSecondIcon( text ); + if (!read) { + gridItem.hardLightBG(1f, 1f, 2f); + } + } else { + gridItem.hardLightBG(2f, 1f, 2f); + } + grid.addItem(gridItem); + } + } + public static class LoreTab extends Component{ private ScrollingListPane list; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndJournalItem.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndJournalItem.java new file mode 100644 index 000000000..5614ea899 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndJournalItem.java @@ -0,0 +1,45 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2024 Evan Debenham + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package com.shatteredpixel.shatteredpixeldungeon.windows; + +import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene; +import com.watabou.input.PointerEvent; +import com.watabou.noosa.Image; +import com.watabou.noosa.PointerArea; + +public class WndJournalItem extends WndTitledMessage { + + public WndJournalItem(Image icon, String title, String message ) { + super( icon, title, message); + + PointerArea blocker = new PointerArea( 0, 0, PixelScene.uiCamera.width, PixelScene.uiCamera.height ) { + @Override + protected void onClick( PointerEvent event ) { + onBackPressed(); + } + }; + blocker.camera = PixelScene.uiCamera; + add(blocker); + + } + +}