diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 130aa023..1cbbf35a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -13,7 +13,7 @@
android:glEsVersion="0x00020000"/>
@@ -22,14 +22,17 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
- android:allowBackup="false">
+ android:allowBackup="false"
+ android:largeHeap="true"
+ >
+
diff --git a/assets/buffs.png b/assets/buffs.png
index d4006417..4c8e79a5 100644
Binary files a/assets/buffs.png and b/assets/buffs.png differ
diff --git a/assets/firerabbit.png b/assets/firerabbit.png
index 39d03f62..277b7063 100644
Binary files a/assets/firerabbit.png and b/assets/firerabbit.png differ
diff --git a/assets/items.png b/assets/items.png
index 3bae5985..77507b85 100644
Binary files a/assets/items.png and b/assets/items.png differ
diff --git a/assets/large_buffs.png b/assets/large_buffs.png
index 800a36ae..02e283bc 100644
Binary files a/assets/large_buffs.png and b/assets/large_buffs.png differ
diff --git a/assets/painter.png b/assets/painter.png
index 9d96421e..498ff441 100644
Binary files a/assets/painter.png and b/assets/painter.png differ
diff --git a/assets/ranger.png b/assets/ranger.png
index 625c3817..3be4b636 100644
Binary files a/assets/ranger.png and b/assets/ranger.png differ
diff --git a/assets/status_pane.png b/assets/status_pane.png
index c6d7ce8e..9e464875 100644
Binary files a/assets/status_pane.png and b/assets/status_pane.png differ
diff --git a/java/com/hmdzl/spspd/Assets.java b/java/com/hmdzl/spspd/Assets.java
new file mode 100644
index 00000000..b3fe49a2
--- /dev/null
+++ b/java/com/hmdzl/spspd/Assets.java
@@ -0,0 +1,347 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd;
+
+public class Assets {
+
+ public static final String ARCS_BG = "arcs1.png";
+ public static final String ARCS_FG = "arcs2.png";
+ public static final String DASHBOARD = "dashboard.png";
+
+ public static final String BANNERS = "banners.png";
+ public static final String BADGES = "badges.png";
+ public static final String AMULET = "amulet.png";
+ public static final String PUDDING_CUP = "pudding_cup.png";
+
+ public static final String CHROME = "chrome.png";
+ public static final String ICONS = "icons.png";
+ public static final String STATUS = "status_pane.png";
+ public static final String HP_BAR = "hp_bar.png";
+ public static final String XP_BAR = "exp_bar.png";
+ public static final String TOOLBAR = "toolbar.png";
+ public static final String SHADOW = "shadow.png";
+
+ public static final String PIXELFONT = "pixel_font.png";
+ public static final String FONT1X = "font1x(2).png";
+ public static final String FONT2X = "font2x(2).png";
+
+ public static final String WARRIOR = "warrior.png";
+ public static final String MAGE = "mage.png";
+ public static final String ROGUE = "rogue.png";
+ public static final String HUNTRESS = "ranger.png";
+ public static final String PERFORMER = "performer.png";
+ public static final String SOLDIER = "soldier.png";
+ public static final String FOLLOWER = "follower.png";
+ public static final String AVATARS = "avatars.png";
+ public static final String PET = "pet.png";
+
+ public static final String SURFACE = "surface.png";
+
+ public static final String FIREBALL = "fireball.png";
+ public static final String SPECKS = "specks.png";
+ public static final String EFFECTS = "effects.png";
+
+ public static final String RAT = "rat.png";
+ public static final String GNOLL = "gnoll.png";
+ public static final String GNOLLARCHER = "gnollarcher.png";
+ public static final String CRAB = "crab.png";
+ public static final String GOO = "goo.png";
+ public static final String POISONGOO = "poisongoo.png";
+ public static final String SWARM = "swarm.png";
+ public static final String SKELETON = "skeleton.png";
+ public static final String MOSSYSKELETON = "mossyskeleton.png";
+ public static final String SHAMAN = "shaman.png";
+ public static final String THIEF = "thief.png";
+ public static final String TENGU = "tengu.png";
+ public static final String SHEEP = "sheep.png";
+ public static final String SOKOBANSHEEP = "sokobansheep.png";
+ public static final String KEEPER = "shopkeeper.png";
+ public static final String BAT = "bat.png";
+ public static final String BRUTE = "brute.png";
+ public static final String SPINNER = "spinner.png";
+ public static final String DM300 = "dm300.png";
+ public static final String WRAITH = "wraith.png";
+ public static final String BLUEWRAITH = "bluewraith.png";
+ public static final String ELEMENTAL = "elemental.png";
+ public static final String MONK = "monk.png";
+ public static final String WARLOCK = "warlock.png";
+ public static final String GOLEM = "golem.png";
+ public static final String UNDEAD = "undead.png";
+ public static final String KING = "king.png";
+ public static final String STATUE = "statue.png";
+ public static final String PIRANHA = "piranha.png";
+ public static final String ALBINOPIRANHA = "albinopiranha.png";
+ public static final String EYE = "eye.png";
+ public static final String SUCCUBUS = "succubus.png";
+ public static final String SCORPIO = "scorpio.png";
+ public static final String ROTTING = "rotting_fist.png";
+ public static final String BURNING = "burning_fist.png";
+ public static final String PINNING = "pinning_fist.png";
+ public static final String INFECTING = "infecting_fist.png";
+ public static final String YOG = "yog.png";
+ public static final String LARVA = "larva.png";
+ public static final String GHOST = "ghost.png";
+ public static final String MAKER = "wandmaker.png";
+ public static final String TROLL = "blacksmith.png";
+ public static final String IMP = "demon.png";
+ public static final String RATKING = "ratking.png";
+ public static final String BEE = "bee.png";
+ public static final String MIMIC = "mimic.png";
+ public static final String RATBOSS = "ratboss.png";
+ public static final String ASSASSIN = "assassin.png";
+ public static final String MONSTERBOX = "monsterbox.png";
+ public static final String BROKENROBOT = "robot.png";
+ public static final String TOWER = "tower.png";
+ public static final String DWARFLICH = "dwarflich.png";
+ public static final String DEMONGOO = "demongoo.png";
+ public static final String BANDITKING = "banditking.png";
+ public static final String DWARFKINGTOMB = "dwarfkingtomb.png";
+ public static final String FLYINGPROTECTOR = "flyingprotector.png";
+ public static final String SENTINEL = "sentinel.png";
+ public static final String ONI = "oni.png";
+ public static final String SHADOWYOG = "shadowyog.png";
+ public static final String SPECTRALRAT = "shadowghost.png";
+ public static final String REDWRAITH = "redwraith.png";
+ public static final String GOLDTHIEF = "goldthief.png";
+ public static final String MRDESTRUCTO = "mrdestructo.png";
+ public static final String MRDESTRUCTO2 = "mrdestructo2.png";
+ public static final String GREYONI = "greyoni.png";
+ public static final String TINKERER1 = "tinkerer.png";
+ public static final String DEWPROTECTOR = "dewprotector.png";
+ public static final String ORBOFZOT = "orbofzot.png";
+ public static final String SEEKINGBOMB = "seekingbomb.png";
+ public static final String CRABKING = "crabking.png";
+ public static final String HERMITCRAB = "hermitcrab.png";
+ public static final String SHELL = "shell.png";
+ public static final String GUARD = "guard.png";
+ public static final String THIEFKING = "thiefking.png";
+ public static final String SKELETONKING = "skeletonkingskull.png";
+ public static final String SKELETONHAND1 = "skeletonhand1.png";
+ public static final String SKELETONHAND2 = "skeletonhand2.png";
+ public static final String PETDRAGON = "petreddragon.png";
+ public static final String VELOCIROOSTER = "velocirooster.png";
+ public static final String FAIRY = "fairy.png";
+ public static final String BUNNY = "rabbit.png";
+ public static final String OTILUKESTONE = "otilukestone.png";
+ public static final String OTILUKE = "otiluke.png";
+ public static final String ZOT = "zot.png";
+ public static final String ZOTPHASE = "zotphase.png";
+ public static final String MAGICEYE = "magiceye.png";
+ public static final String DRAGON = "adultdragon.png";
+
+ public static final String ITEMS = "items.png";
+ public static final String PLANTS = "plants.png";
+ public static final String TRAPS = "traps.png";
+
+ public static final String TILES_SEWERS = "tiles0.png";
+ public static final String TILES_PRISON = "tiles1.png";
+ public static final String TILES_CAVES = "tiles2.png";
+ public static final String TILES_CITY = "tiles3.png";
+ public static final String TILES_HALLS = "tiles4.png";
+ public static final String TILES_PUZZLE = "tiles5.png";
+ public static final String TILES_SEAL = "tiles_magic_cave.png";
+ public static final String TILES_BEACH = "tiles_beach.png";
+ public static final String TILES_SKELETON = "tiles_skeleton.png";
+ public static final String TILES_VAULT = "tiles_vault.png";
+ public static final String TILES_FOREST = "tiles_forest.png";
+ public static final String TILES_TOWN = "tiles_town.png";
+ public static final String TILES_SP = "tiles_sp.png";
+
+ public static final String WATER_SEWERS = "water0.png";
+ public static final String WATER_PRISON = "water1.png";
+ public static final String WATER_CAVES = "water2.png";
+ public static final String WATER_CITY = "water3.png";
+ public static final String WATER_HALLS = "water4.png";
+
+ public static final String WEAK_FLOOR = "custom_tiles/weak_floor.png";
+
+ public static final String BUFFS_SMALL = "buffs.png";
+ public static final String BUFFS_LARGE = "large_buffs.png";
+ public static final String SPELL_ICONS = "spell_icons.png";
+ public static final String CONS_ICONS = "consumable_icons.png";
+ public static final String CONS_ICONS2 = "consumable_icons2.png";
+
+ public static final String FONTS1X = "font1x.png";
+ public static final String FONTS15X = "font15x.png";
+ public static final String FONTS2X = "font2x.png";
+ public static final String FONTS25X = "font25x.png";
+ public static final String FONTS3X = "font3x.png";
+
+ public static final String THEME = "theme.mp3";
+ public static final String TUNE = "game.mp3";
+ public static final String HAPPY = "surface.mp3";
+
+ public static final String SND_CLICK = "snd_click.mp3";
+ public static final String SND_BADGE = "snd_badge.mp3";
+ public static final String SND_GOLD = "snd_gold.mp3";
+
+ public static final String SND_OPEN = "snd_door_open.mp3";
+ public static final String SND_UNLOCK = "snd_unlock.mp3";
+ public static final String SND_ITEM = "snd_item.mp3";
+ public static final String SND_DEWDROP = "snd_dewdrop.mp3";
+ public static final String SND_HIT = "snd_hit.mp3";
+ public static final String SND_MISS = "snd_miss.mp3";
+ public static final String SND_STEP = "snd_step.mp3";
+ public static final String SND_WATER = "snd_water.mp3";
+ public static final String SND_DESCEND = "snd_descend.mp3";
+ public static final String SND_EAT = "snd_eat.mp3";
+ public static final String SND_READ = "snd_read.mp3";
+ public static final String SND_LULLABY = "snd_lullaby.mp3";
+ public static final String SND_DRINK = "snd_drink.mp3";
+ public static final String SND_SHATTER = "snd_shatter.mp3";
+ public static final String SND_ZAP = "snd_zap.mp3";
+ public static final String SND_LIGHTNING = "snd_lightning.mp3";
+ public static final String SND_LEVELUP = "snd_levelup.mp3";
+ public static final String SND_DEATH = "snd_death.mp3";
+ public static final String SND_CHALLENGE = "snd_challenge.mp3";
+ public static final String SND_CURSED = "snd_cursed.mp3";
+ public static final String SND_TRAP = "snd_trap.mp3";
+ public static final String SND_EVOKE = "snd_evoke.mp3";
+ public static final String SND_TOMB = "snd_tomb.mp3";
+ public static final String SND_ALERT = "snd_alert.mp3";
+ public static final String SND_MELD = "snd_meld.mp3";
+ public static final String SND_BOSS = "snd_boss.mp3";
+ public static final String SND_BLAST = "snd_blast.mp3";
+ public static final String SND_PLANT = "snd_plant.mp3";
+ public static final String SND_RAY = "snd_ray.mp3";
+ public static final String SND_BEACON = "snd_beacon.mp3";
+ public static final String SND_TELEPORT = "snd_teleport.mp3";
+ public static final String SND_CHARMS = "snd_charms.mp3";
+ public static final String SND_MASTERY = "snd_mastery.mp3";
+ public static final String SND_PUFF = "snd_puff.mp3";
+ public static final String SND_ROCKS = "snd_rocks.mp3";
+ public static final String SND_BURNING = "snd_burning.mp3";
+ public static final String SND_FALLING = "snd_falling.mp3";
+ public static final String SND_GHOST = "snd_ghost.mp3";
+ public static final String SND_SECRET = "snd_secret.mp3";
+ public static final String SND_BONES = "snd_bones.mp3";
+ public static final String SND_BEE = "snd_bee.mp3";
+ public static final String SND_DEGRADE = "snd_degrade.mp3";
+ public static final String SND_MIMIC = "snd_mimic.mp3";
+
+ public static final String GNOLLKING = "gnollking.png";
+ public static final String DRAGONKING = "dragonking.png";
+ public static final String UDAWOS = "udawos.png";
+ public static final String TYPEDSCROLL = "typedscroll.png";
+ public static final String G2159687 = "g2159687.png";
+ public static final String CONSIDEREDHAMSTER = "consideredhamster.png";
+ public static final String EVAN = "evan.png";
+ public static final String NYRDS = "NYRDS.png";
+ public static final String BILBOLDEV = "bilboldev.png";
+ public static final String WATABOU = "watabou.png";
+ public static final String HBB = "HBB.png";
+ public static final String SFB = "SFB.png";
+ public static final String HEXA = "HeXA.png";
+ public static final String RUSTYBLADE = "rustyblade.png";
+ public static final String JINKELOID = "jinkeloid.png";
+ public static final String SP931 = "SP931.png";
+ public static final String LYN = "Lyn.png";
+ public static final String COCONUT = "coconut.png";
+ public static final String LOCASTAN = "locastan.png";
+ public static final String DACHHACK = "dachhack.png";
+ public static final String TEMPEST102 = "tempest102.png";
+ public static final String ERROR = "error.png";
+ public static final String SAR = "stormandrain.png";
+ public static final String MOS = "memoryofsand.png";
+ public static final String HS = "hatesokoban.png";
+ public static final String FRUITCAT = "fruitcat.png";
+ public static final String LAJI = "laji.png";
+ public static final String RAIN = "rain.png";
+ public static final String LYNN = "lynn.png";
+ public static final String JUH9870 = "juh9870.png";
+ public static final String SADSALTAN ="sadsaltan.png";
+ public static final String OLDNEWSTWIST = "oldnewstwist.png";
+
+ public static final String KLIKS = "kliks.png";
+ public static final String SNAKE = "snakes.png";
+ public static final String MUSKETEER ="musketeer.png";
+ public static final String THIEFIMP = "thiefimp.png";
+ public static final String LIVEMOSS = "livemoss.png";
+ public static final String TROLLWARRIOR = "trollwarrior.png";
+
+ public static final String SCARECROW = "scarecrow.png";
+
+ public static final String UGOO = "ugoo.png";
+ public static final String GENTLECRAB = "gentlecrab.png";
+
+ public static final String XAVIER = "xavier251998.png";
+ public static final String REN = "ren.png";
+
+ public static final String SEWER_HEART = "sewer_heart.png";
+ public static final String SEWER_LASHER = "sewer_lasher.png";
+
+ public static final String T_CLOUD = "tcloud.png";
+
+ public static final String PLAGUEDOCTOR = "plaguedoctor.png";
+
+ public static final String PRISONWANDER = "prisonwander.png";
+
+ public static final String SANDMOB = "sandmob.png";
+ public static final String SPIDERBOT = "spiderbot.png";
+ public static final String ZOMBIE = "zombie.png";
+ public static final String TANK = "tank.png";
+ public static final String SUFFERER = "sufferer.png";
+ public static final String DEMONFLOWER = "demonflower.png";
+ public static final String SPIDERQUEEN = "spider_queen.png";
+ public static final String SPIDERWORKER = "spider_worker.png";
+ public static final String SPIDERMIND = "spider_mind.png";
+ public static final String SPIDEREGG = "spider_egg.png";
+
+ public static final String KOSTIS = "kostis12345.png";
+ public static final String NOODLEMIRE = "noodlemire.png";
+ public static final String RAVEBWOLF = "ravenwolf.png";
+ public static final String HMDZL = "hmdzl001.png";
+ public static final String NEW_PLAYER = "newplayer.png";
+ public static final String THANK_LIST = "thanklist.png";
+
+ public static final String CELL_MOB = "cellmob.png";
+ public static final String MOBILE = "mobile.png";
+ public static final String HYBRID = "hybrid.png";
+
+ public static final String OBELISK = "obelisk.png";
+ public static final String ELDER_AVATAR = "elderavatar.png";
+
+ public static final String M_AMD_W = "mandw.png";
+ public static final String UNCLE_S = "sibaoluodeti.png";
+
+ public static final String GOBLIN_PLAYER = "goblinplayer.png";
+ public static final String SAID_BY_SUN = "saidbysun.png";
+ public static final String MILLILITRE = "millilitre.png";
+ public static final String APOSTLE = "apostle.png";
+ public static final String SHOWER = "shower.png";
+ public static final String HONEY_POOOOT = "honeypoooot.png";
+ public static final String XIXIZERO = "cat_lix.png";
+ public static final String A_FLY = "npcalfred.png";
+ public static final String PAINTER= "painter.png";
+ public static final String DREAMPLAYER = "dreamplayer.png";
+ public static final String PLANT_KING = "plantking.png";
+ public static final String OMICRONRG9 = "omicronrg9.png";
+
+
+ public static final String LICH_DANCER = "boss_lich.png";
+ public static final String BATTERYTOMB = "batterytomb.png";
+
+ public static final String PATROLUAV = "patroluav.png";
+ public static final String ICE13 = "ice13.png";
+
+ public static final String FIRERABBIT = "firerabbit.png";
+ public static final String MANY_SKELETON = "manyskeleton.png";
+ public static final String BEAST_YEAR = "beastyear.png";
+
+}
+
diff --git a/java/com/hmdzl/spspd/Badges.java b/java/com/hmdzl/spspd/Badges.java
new file mode 100644
index 00000000..31a02b62
--- /dev/null
+++ b/java/com/hmdzl/spspd/Badges.java
@@ -0,0 +1,1079 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import com.hmdzl.spspd.actors.mobs.Acidic;
+import com.hmdzl.spspd.actors.mobs.Albino;
+import com.hmdzl.spspd.actors.mobs.Bandit;
+import com.hmdzl.spspd.actors.mobs.Mob;
+import com.hmdzl.spspd.actors.mobs.Senior;
+import com.hmdzl.spspd.actors.mobs.Shielded;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.items.artifacts.Artifact;
+import com.hmdzl.spspd.items.bags.PotionBandolier;
+import com.hmdzl.spspd.items.bags.ScrollHolder;
+import com.hmdzl.spspd.items.bags.SeedPouch;
+import com.hmdzl.spspd.items.bags.WandHolster;
+import com.hmdzl.spspd.items.potions.Potion;
+import com.hmdzl.spspd.items.rings.Ring;
+import com.hmdzl.spspd.items.scrolls.Scroll;
+import com.hmdzl.spspd.scenes.PixelScene;
+import com.hmdzl.spspd.utils.GLog;
+import com.watabou.noosa.Game;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Callback;
+import com.hmdzl.spspd.messages.Messages;
+
+public class Badges {
+
+ public /*static*/ enum Badge {
+ MONSTERS_SLAIN_1(0),
+ MONSTERS_SLAIN_2(1),
+ MONSTERS_SLAIN_3(2),
+ MONSTERS_SLAIN_4(3),
+ GOLD_COLLECTED_1(4),
+ GOLD_COLLECTED_2(5),
+ GOLD_COLLECTED_3(6),
+ GOLD_COLLECTED_4(7),
+ LEVEL_REACHED_1(8),
+ LEVEL_REACHED_2(9),
+ LEVEL_REACHED_3(10),
+ LEVEL_REACHED_4(11),
+ ALL_POTIONS_IDENTIFIED(16),
+ ALL_SCROLLS_IDENTIFIED(17),
+ ALL_RINGS_IDENTIFIED(18),
+ ALL_WANDS_IDENTIFIED(19),
+ ALL_ITEMS_IDENTIFIED(35, true),
+ BAG_BOUGHT_SEED_POUCH, BAG_BOUGHT_SCROLL_HOLDER, BAG_BOUGHT_POTION_BANDOLIER, BAG_BOUGHT_WAND_HOLSTER, ALL_BAGS_BOUGHT(23),
+ DEATH_FROM_FIRE(24),
+ DEATH_FROM_POISON(25),
+ DEATH_FROM_GAS(26),
+ DEATH_FROM_HUNGER(27),
+ DEATH_FROM_GLYPH(57),
+ DEATH_FROM_FALLING(59),
+ YASD(34, true),
+ BOSS_SLAIN_1_WARRIOR, BOSS_SLAIN_1_MAGE, BOSS_SLAIN_1_ROGUE, BOSS_SLAIN_1_HUNTRESS, BOSS_SLAIN_1_PERFORMER,BOSS_SLAIN_1_SOLDIER,BOSS_SLAIN_1_FOLLOWER, BOSS_SLAIN_1(12),
+ BOSS_SLAIN_2(13),
+ BOSS_SLAIN_3(14),
+ BOSS_SLAIN_4(15),
+ BOSS_SLAIN_1_ALL_CLASSES(32, true),
+ BOSS_SLAIN_3_GLADIATOR, BOSS_SLAIN_3_BERSERKER, BOSS_SLAIN_3_WARLOCK, BOSS_SLAIN_3_BATTLEMAGE, BOSS_SLAIN_3_FREERUNNER, BOSS_SLAIN_3_ASSASSIN, BOSS_SLAIN_3_SNIPER, BOSS_SLAIN_3_WARDEN,BOSS_SLAIN_3_SUPERSTAR,BOSS_SLAIN_3_JOKER, BOSS_SLAIN_3_ALL_SUBCLASSES(33, true),
+ RING_OF_HAGGLER(20),
+ RING_OF_THORNS(21),
+ STRENGTH_ATTAINED_1(40),
+ STRENGTH_ATTAINED_2(41),
+ STRENGTH_ATTAINED_3(42),
+ STRENGTH_ATTAINED_4(43),
+ FOOD_EATEN_1(44),
+ FOOD_EATEN_2(45),
+ FOOD_EATEN_3(46),
+ FOOD_EATEN_4(47),
+ MASTERY_WARRIOR, MASTERY_MAGE, MASTERY_ROGUE, MASTERY_HUNTRESS, MASTERY_PERFORMER, MASTERY_SOLDIER,MASTERY_FOLLOWER,
+ ITEM_LEVEL_1(48),
+ ITEM_LEVEL_2(49),
+ ITEM_LEVEL_3(50),
+ ITEM_LEVEL_4(51),
+ RARE_ALBINO, RARE_BANDIT, RARE_SHIELDED, RARE_SENIOR, RARE_ACIDIC, RARE(37, true),
+ VICTORY_WARRIOR, VICTORY_MAGE, VICTORY_ROGUE, VICTORY_HUNTRESS, VICTORY_PERFORMER, VICTORY_SOLDIER,VICTORY_FOLLOWER,VICTORY(22),
+ VICTORY_ALL_CLASSES(36, true),
+ MASTERY_COMBO(56),
+ POTIONS_COOKED_1(52),
+ POTIONS_COOKED_2(53),
+ POTIONS_COOKED_3(54),
+ POTIONS_COOKED_4(55),
+ NO_MONSTERS_SLAIN(28),
+ GRIM_WEAPON(29),
+ PIRANHAS(30),
+ NIGHT_HUNTER(58),
+ GAMES_PLAYED_1(60, true),
+ GAMES_PLAYED_2(61, true),
+ GAMES_PLAYED_3(62, true),
+ GAMES_PLAYED_4(63, true),
+ HAPPY_END(38),
+ CHAMPION(39, true),
+ SUPPORTER(31, true),
+ ORB(68),
+ OTILUKE(65),
+ TRI(66),
+ EGG_BREAK_1(69),
+ EGG_BREAK_2(70),
+ EGG_BREAK_3(71);
+
+ public boolean meta;
+
+ public int image;
+
+ private Badge(int image) {
+ this(image, false);
+ }
+
+ Badge( int image, boolean meta ) {
+ this.image = image;
+ this.meta = meta;
+ }
+
+ public String desc(){
+ return Messages.get(this, name());
+ }
+
+ Badge() {
+ this( -1 );
+ }
+
+ }
+
+ private static HashSet global;
+ private static HashSet local = new HashSet();
+
+ private static boolean saveNeeded = false;
+
+ public static Callback loadingListener = null;
+
+ public static void reset() {
+ local.clear();
+ loadGlobal();
+ }
+
+ private static final String BADGES_FILE = "badges.dat";
+ private static final String BADGES = "badges";
+
+ private static HashSet restore(Bundle bundle) {
+ HashSet badges = new HashSet();
+
+ String[] names = bundle.getStringArray(BADGES);
+ for (int i = 0; i < names.length; i++) {
+ try {
+ badges.add(Badge.valueOf(names[i]));
+ } catch (Exception e) {
+ }
+ }
+
+ return badges;
+ }
+
+ private static void store(Bundle bundle, HashSet badges) {
+ int count = 0;
+ String names[] = new String[badges.size()];
+
+ for (Badge badge : badges) {
+ names[count++] = badge.toString();
+ }
+ bundle.put(BADGES, names);
+ }
+
+ public static void loadLocal(Bundle bundle) {
+ local = restore(bundle);
+ }
+
+ public static void saveLocal(Bundle bundle) {
+ store(bundle, local);
+ }
+
+ public static void loadGlobal() {
+ if (global == null) {
+ try {
+ InputStream input = Game.instance.openFileInput(BADGES_FILE);
+ Bundle bundle = Bundle.read(input);
+ input.close();
+
+ global = restore(bundle);
+
+ } catch (Exception e) {
+ global = new HashSet();
+ }
+ }
+ }
+
+ public static void saveGlobal() {
+ if (saveNeeded) {
+
+ Bundle bundle = new Bundle();
+ store(bundle, global);
+
+ try {
+ OutputStream output = Game.instance.openFileOutput(BADGES_FILE,
+ Game.MODE_PRIVATE);
+ Bundle.write(bundle, output);
+ output.close();
+ saveNeeded = false;
+ } catch (IOException e) {
+
+ }
+ }
+ }
+
+ public static void validateMonstersSlain() {
+ Badge badge = null;
+
+ if (!local.contains(Badge.MONSTERS_SLAIN_1)
+ && Statistics.enemiesSlain >= 10) {
+ badge = Badge.MONSTERS_SLAIN_1;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.MONSTERS_SLAIN_2)
+ && Statistics.enemiesSlain >= 50) {
+ badge = Badge.MONSTERS_SLAIN_2;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.MONSTERS_SLAIN_3)
+ && Statistics.enemiesSlain >= 150) {
+ badge = Badge.MONSTERS_SLAIN_3;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.MONSTERS_SLAIN_4)
+ && Statistics.enemiesSlain >= 250) {
+ badge = Badge.MONSTERS_SLAIN_4;
+ local.add(badge);
+ }
+
+ displayBadge(badge);
+ }
+
+ public static void validateGoldCollected() {
+ Badge badge = null;
+
+ if (!local.contains(Badge.GOLD_COLLECTED_1)
+ && Statistics.goldCollected >= 100) {
+ badge = Badge.GOLD_COLLECTED_1;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.GOLD_COLLECTED_2)
+ && Statistics.goldCollected >= 500) {
+ badge = Badge.GOLD_COLLECTED_2;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.GOLD_COLLECTED_3)
+ && Statistics.goldCollected >= 2500) {
+ badge = Badge.GOLD_COLLECTED_3;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.GOLD_COLLECTED_4)
+ && Statistics.goldCollected >= 7500) {
+ badge = Badge.GOLD_COLLECTED_4;
+ local.add(badge);
+ }
+
+ displayBadge(badge);
+ }
+
+ public static void validateLevelReached() {
+ Badge badge = null;
+
+ if (!local.contains(Badge.LEVEL_REACHED_1) && Dungeon.hero.lvl >= 10) {
+ badge = Badge.LEVEL_REACHED_1;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.LEVEL_REACHED_2) && Dungeon.hero.lvl >= 20) {
+ badge = Badge.LEVEL_REACHED_2;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.LEVEL_REACHED_3) && Dungeon.hero.lvl >= 30) {
+ badge = Badge.LEVEL_REACHED_3;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.LEVEL_REACHED_4) && Dungeon.hero.lvl >= 40) {
+ badge = Badge.LEVEL_REACHED_4;
+ local.add(badge);
+ }
+
+ displayBadge(badge);
+ }
+
+ public static void validateStrengthAttained() {
+ Badge badge = null;
+
+ if (!local.contains(Badge.STRENGTH_ATTAINED_1)
+ && Dungeon.hero.STR >= 13) {
+ badge = Badge.STRENGTH_ATTAINED_1;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.STRENGTH_ATTAINED_2)
+ && Dungeon.hero.STR >= 15) {
+ badge = Badge.STRENGTH_ATTAINED_2;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.STRENGTH_ATTAINED_3)
+ && Dungeon.hero.STR >= 17) {
+ badge = Badge.STRENGTH_ATTAINED_3;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.STRENGTH_ATTAINED_4)
+ && Dungeon.hero.STR >= 19) {
+ badge = Badge.STRENGTH_ATTAINED_4;
+ local.add(badge);
+ }
+
+ displayBadge(badge);
+ }
+
+ public static void validateFoodEaten() {
+ Badge badge = null;
+
+ if (!local.contains(Badge.FOOD_EATEN_1) && Statistics.foodEaten >= 10) {
+ badge = Badge.FOOD_EATEN_1;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.FOOD_EATEN_2) && Statistics.foodEaten >= 20) {
+ badge = Badge.FOOD_EATEN_2;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.FOOD_EATEN_3) && Statistics.foodEaten >= 30) {
+ badge = Badge.FOOD_EATEN_3;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.FOOD_EATEN_4) && Statistics.foodEaten >= 40) {
+ badge = Badge.FOOD_EATEN_4;
+ local.add(badge);
+ }
+
+ displayBadge(badge);
+ }
+
+ public static void validateEggBreak() {
+ Badge badge = null;
+
+ if (!local.contains(Badge.EGG_BREAK_1) && Statistics.eggBreak >= 1) {
+ badge = Badge.EGG_BREAK_1;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.EGG_BREAK_2) && Statistics.eggBreak >= 2) {
+ badge = Badge.EGG_BREAK_2;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.EGG_BREAK_3) && Statistics.eggBreak >= 5) {
+ badge = Badge.EGG_BREAK_3;
+ local.add(badge);
+ }
+
+ displayBadge(badge);
+
+ }
+
+ public static void validatePotionsCooked() {
+ Badge badge = null;
+
+ if (!local.contains(Badge.POTIONS_COOKED_1)
+ && Statistics.potionsCooked >= 3) {
+ badge = Badge.POTIONS_COOKED_1;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.POTIONS_COOKED_2)
+ && Statistics.potionsCooked >= 6) {
+ badge = Badge.POTIONS_COOKED_2;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.POTIONS_COOKED_3)
+ && Statistics.potionsCooked >= 9) {
+ badge = Badge.POTIONS_COOKED_3;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.POTIONS_COOKED_4)
+ && Statistics.potionsCooked >= 12) {
+ badge = Badge.POTIONS_COOKED_4;
+ local.add(badge);
+ }
+
+ displayBadge(badge);
+ }
+
+ public static void validatePiranhasKilled() {
+ Badge badge = null;
+
+ if (!local.contains(Badge.PIRANHAS) && Statistics.piranhasKilled >= 6) {
+ badge = Badge.PIRANHAS;
+ local.add(badge);
+ }
+
+ displayBadge(badge);
+ }
+
+ public static void validateItemLevelAquired(Item item) {
+
+ // This method should be called:
+ // 1) When an item is obtained (Item.collect)
+ // 2) When an item is upgraded (ScrollOfUpgrade, ScrollOfWeaponUpgrade,
+ // ShortSword, WandOfMagicMissile)
+ // 3) When an item is identified
+
+ // Note that artifacts should never trigger this badge as they are
+ // alternatively upgraded
+ if (!item.levelKnown || item instanceof Artifact) {
+ return;
+ }
+
+ Badge badge = null;
+ if (!local.contains(Badge.ITEM_LEVEL_1) && item.level >= 3) {
+ badge = Badge.ITEM_LEVEL_1;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.ITEM_LEVEL_2) && item.level >= 6) {
+ badge = Badge.ITEM_LEVEL_2;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.ITEM_LEVEL_3) && item.level >= 9) {
+ badge = Badge.ITEM_LEVEL_3;
+ local.add(badge);
+ }
+ if (!local.contains(Badge.ITEM_LEVEL_4) && item.level >= 12) {
+ badge = Badge.ITEM_LEVEL_4;
+ local.add(badge);
+ }
+
+ displayBadge(badge);
+ }
+
+ public static void validateAllPotionsIdentified() {
+ if (Dungeon.hero != null && Dungeon.hero.isAlive()
+ && !local.contains(Badge.ALL_POTIONS_IDENTIFIED)
+ && Potion.allKnown()) {
+
+ Badge badge = Badge.ALL_POTIONS_IDENTIFIED;
+ local.add(badge);
+ displayBadge(badge);
+
+ validateAllItemsIdentified();
+ }
+ }
+
+ public static void validateAllScrollsIdentified() {
+ if (Dungeon.hero != null && Dungeon.hero.isAlive()
+ && !local.contains(Badge.ALL_SCROLLS_IDENTIFIED)
+ && Scroll.allKnown()) {
+
+ Badge badge = Badge.ALL_SCROLLS_IDENTIFIED;
+ local.add(badge);
+ displayBadge(badge);
+
+ validateAllItemsIdentified();
+ }
+ }
+
+ public static void validateAllRingsIdentified() {
+ if (Dungeon.hero != null && Dungeon.hero.isAlive()
+ && !local.contains(Badge.ALL_RINGS_IDENTIFIED)
+ && Ring.allKnown()) {
+
+ Badge badge = Badge.ALL_RINGS_IDENTIFIED;
+ local.add(badge);
+ displayBadge(badge);
+
+ validateAllItemsIdentified();
+ }
+ }
+
+ public static void validateAllWandsIdentified() {
+ if (Dungeon.hero != null && Dungeon.hero.isAlive()
+ && !local.contains(Badge.ALL_WANDS_IDENTIFIED)
+ ) {
+
+ Badge badge = Badge.ALL_WANDS_IDENTIFIED;
+ local.add(badge);
+ displayBadge(badge);
+
+ validateAllItemsIdentified();
+ }
+ }
+
+ public static void validateAllBagsBought(Item bag) {
+
+ Badge badge = null;
+ if (bag instanceof SeedPouch) {
+ badge = Badge.BAG_BOUGHT_SEED_POUCH;
+ } else if (bag instanceof ScrollHolder) {
+ badge = Badge.BAG_BOUGHT_SCROLL_HOLDER;
+ } else if (bag instanceof PotionBandolier) {
+ badge = Badge.BAG_BOUGHT_POTION_BANDOLIER;
+ } else if (bag instanceof WandHolster) {
+ badge = Badge.BAG_BOUGHT_WAND_HOLSTER;
+ }
+
+ if (badge != null) {
+
+ local.add(badge);
+
+ if (!local.contains(Badge.ALL_BAGS_BOUGHT)
+ && local.contains(Badge.BAG_BOUGHT_SEED_POUCH)
+ && local.contains(Badge.BAG_BOUGHT_SCROLL_HOLDER)
+ && local.contains(Badge.BAG_BOUGHT_POTION_BANDOLIER)
+ && local.contains(Badge.BAG_BOUGHT_WAND_HOLSTER)) {
+
+ badge = Badge.ALL_BAGS_BOUGHT;
+ local.add(badge);
+ displayBadge(badge);
+ }
+ }
+ }
+
+ public static void validateAllItemsIdentified() {
+ if (!global.contains(Badge.ALL_ITEMS_IDENTIFIED)
+ && global.contains(Badge.ALL_POTIONS_IDENTIFIED)
+ && global.contains(Badge.ALL_SCROLLS_IDENTIFIED)
+ && global.contains(Badge.ALL_RINGS_IDENTIFIED)
+ && global.contains(Badge.ALL_WANDS_IDENTIFIED)) {
+
+ Badge badge = Badge.ALL_ITEMS_IDENTIFIED;
+ displayBadge(badge);
+ }
+ }
+
+ public static void validateDeathFromFire() {
+ Badge badge = Badge.DEATH_FROM_FIRE;
+ local.add(badge);
+ displayBadge(badge);
+
+ validateYASD();
+ }
+
+ public static void validateDeathFromPoison() {
+ Badge badge = Badge.DEATH_FROM_POISON;
+ local.add(badge);
+ displayBadge(badge);
+
+ validateYASD();
+ }
+
+ public static void validateDeathFromGas() {
+ Badge badge = Badge.DEATH_FROM_GAS;
+ local.add(badge);
+ displayBadge(badge);
+
+ validateYASD();
+ }
+
+ public static void validateDeathFromHunger() {
+ Badge badge = Badge.DEATH_FROM_HUNGER;
+ local.add(badge);
+ displayBadge(badge);
+
+ validateYASD();
+ }
+
+ public static void validateDeathFromGlyph() {
+ Badge badge = Badge.DEATH_FROM_GLYPH;
+ local.add(badge);
+ displayBadge(badge);
+ }
+
+ public static void validateDeathFromFalling() {
+ Badge badge = Badge.DEATH_FROM_FALLING;
+ local.add(badge);
+ displayBadge(badge);
+ }
+
+ private static void validateYASD() {
+ if (global.contains(Badge.DEATH_FROM_FIRE)
+ && global.contains(Badge.DEATH_FROM_POISON)
+ && global.contains(Badge.DEATH_FROM_GAS)
+ && global.contains(Badge.DEATH_FROM_HUNGER)) {
+
+ Badge badge = Badge.YASD;
+ local.add(badge);
+ displayBadge(badge);
+ }
+ }
+
+ public static void validateBossSlain() {
+ Badge badge = null;
+ switch (Dungeon.depth) {
+ case 5:
+ badge = Badge.BOSS_SLAIN_1;
+ break;
+ case 10:
+ badge = Badge.BOSS_SLAIN_2;
+ break;
+ case 15:
+ badge = Badge.BOSS_SLAIN_3;
+ break;
+ case 20:
+ badge = Badge.BOSS_SLAIN_4;
+ break;
+ }
+
+ if (badge != null) {
+ local.add(badge);
+ displayBadge(badge);
+
+ if (badge == Badge.BOSS_SLAIN_1) {
+ switch (Dungeon.hero.heroClass) {
+ case WARRIOR:
+ badge = Badge.BOSS_SLAIN_1_WARRIOR;
+ break;
+ case MAGE:
+ badge = Badge.BOSS_SLAIN_1_MAGE;
+ break;
+ case ROGUE:
+ badge = Badge.BOSS_SLAIN_1_ROGUE;
+ break;
+ case HUNTRESS:
+ badge = Badge.BOSS_SLAIN_1_HUNTRESS;
+ break;
+ case PERFORMER:
+ badge = Badge.BOSS_SLAIN_1_PERFORMER;
+ break;
+ case SOLDIER:
+ badge = Badge.BOSS_SLAIN_1_SOLDIER;
+ break;
+ case FOLLOWER:
+ badge = Badge.BOSS_SLAIN_1_FOLLOWER;
+ break;
+ }
+ local.add(badge);
+ if (!global.contains(badge)) {
+ global.add(badge);
+ saveNeeded = true;
+ }
+
+ if (global.contains(Badge.BOSS_SLAIN_1_WARRIOR)
+ && global.contains(Badge.BOSS_SLAIN_1_MAGE)
+ && global.contains(Badge.BOSS_SLAIN_1_ROGUE)
+ && global.contains(Badge.BOSS_SLAIN_1_HUNTRESS)) {
+
+ badge = Badge.BOSS_SLAIN_1_ALL_CLASSES;
+ if (!global.contains(badge)) {
+ displayBadge(badge);
+ global.add(badge);
+ saveNeeded = true;
+ }
+ }
+ } else if (badge == Badge.BOSS_SLAIN_3) {
+ switch (Dungeon.hero.subClass) {
+ case GLADIATOR:
+ badge = Badge.BOSS_SLAIN_3_GLADIATOR;
+ break;
+ case BERSERKER:
+ badge = Badge.BOSS_SLAIN_3_BERSERKER;
+ break;
+ case WARLOCK:
+ badge = Badge.BOSS_SLAIN_3_WARLOCK;
+ break;
+ case BATTLEMAGE:
+ badge = Badge.BOSS_SLAIN_3_BATTLEMAGE;
+ break;
+ case FREERUNNER:
+ badge = Badge.BOSS_SLAIN_3_FREERUNNER;
+ break;
+ case ASSASSIN:
+ badge = Badge.BOSS_SLAIN_3_ASSASSIN;
+ break;
+ case SNIPER:
+ badge = Badge.BOSS_SLAIN_3_SNIPER;
+ break;
+ case WARDEN:
+ badge = Badge.BOSS_SLAIN_3_WARDEN;
+ break;
+ case SUPERSTAR:
+ badge = Badge.BOSS_SLAIN_3_SUPERSTAR;
+ break;
+ case JOKER:
+ badge = Badge.BOSS_SLAIN_3_JOKER;
+ break;
+ default:
+ return;
+ }
+ local.add(badge);
+ if (!global.contains(badge)) {
+ global.add(badge);
+ saveNeeded = true;
+ }
+
+ if (global.contains(Badge.BOSS_SLAIN_3_GLADIATOR)
+ && global.contains(Badge.BOSS_SLAIN_3_BERSERKER)
+ && global.contains(Badge.BOSS_SLAIN_3_WARLOCK)
+ && global.contains(Badge.BOSS_SLAIN_3_BATTLEMAGE)
+ && global.contains(Badge.BOSS_SLAIN_3_FREERUNNER)
+ && global.contains(Badge.BOSS_SLAIN_3_ASSASSIN)
+ && global.contains(Badge.BOSS_SLAIN_3_SNIPER)
+ && global.contains(Badge.BOSS_SLAIN_3_WARDEN)
+ && global.contains(Badge.BOSS_SLAIN_3_SUPERSTAR)
+ && global.contains(Badge.BOSS_SLAIN_3_JOKER)) {
+
+ badge = Badge.BOSS_SLAIN_3_ALL_SUBCLASSES;
+ if (!global.contains(badge)) {
+ displayBadge(badge);
+ global.add(badge);
+ saveNeeded = true;
+ }
+ }
+ }
+ }
+ }
+
+ public static void validateOrbObtained() {
+ Badge badge = Badge.ORB;
+ local.add(badge);
+ displayBadge(badge);
+ if (!global.contains(Badge.ORB)) {
+ global.add(badge);
+ }
+ }
+
+ public static boolean checkOrbObtained() {
+ return global.contains(Badge.ORB);
+ }
+
+
+
+ public static boolean checkOtilukeRescued() {
+ return local.contains(Badge.OTILUKE);
+ }
+
+ public static boolean checkCoconutRescued() {
+ return local.contains(Badge.MONSTERS_SLAIN_4);
+ }
+
+ public static boolean checkSARRescued() {
+ return local.contains(Badge.ALL_RINGS_IDENTIFIED);
+ }
+
+ public static boolean checkMOSRescued() {
+ return local.contains(Badge.FOOD_EATEN_4);
+ }
+
+ public static boolean checkItemRescued() {
+ return local.contains(Badge.ITEM_LEVEL_4);
+ }
+
+ public static boolean checkFishRescued() {
+ return local.contains(Badge.BOSS_SLAIN_3);
+ }
+
+ public static boolean checkEggRescued() {
+ return local.contains(Badge.EGG_BREAK_3);
+ }
+
+ public static boolean checkTombRescued() {
+ return local.contains(Badge.BOSS_SLAIN_4);
+ }
+
+ public static boolean checkRainRescued() {
+ return local.contains(Badge.LEVEL_REACHED_4);
+ }
+
+ public static boolean checkUncleRescued() {
+ return local.contains(Badge.POTIONS_COOKED_1);
+ }
+
+ public static void validateMastery() {
+
+ Badge badge = null;
+ switch (Dungeon.hero.heroClass) {
+ case WARRIOR:
+ badge = Badge.MASTERY_WARRIOR;
+ break;
+ case MAGE:
+ badge = Badge.MASTERY_MAGE;
+ break;
+ case ROGUE:
+ badge = Badge.MASTERY_ROGUE;
+ break;
+ case HUNTRESS:
+ badge = Badge.MASTERY_HUNTRESS;
+ break;
+ case PERFORMER:
+ badge = Badge.MASTERY_PERFORMER;
+ break;
+ case SOLDIER:
+ badge = Badge.MASTERY_SOLDIER;
+ break;
+ case FOLLOWER:
+ badge = Badge.MASTERY_FOLLOWER;
+ break;
+ }
+
+ if (!global.contains(badge)) {
+ global.add(badge);
+ saveNeeded = true;
+ }
+ }
+
+ public static void validateMasteryCombo(int n) {
+ if (!local.contains(Badge.MASTERY_COMBO) && n == 7) {
+ Badge badge = Badge.MASTERY_COMBO;
+ local.add(badge);
+ displayBadge(badge);
+ }
+ }
+
+ // TODO: Replace this badge, delayed until an eventual badge rework
+ public static void validateRingOfHaggler() {
+ if (!local.contains(Badge.RING_OF_HAGGLER)/*
+ * && new
+ * RingOfThorns().isKnown()
+ */) {
+ Badge badge = Badge.RING_OF_HAGGLER;
+ local.add(badge);
+ displayBadge(badge);
+ }
+ }
+
+ // TODO: Replace this badge, delayed until an eventual badge rework
+ public static void validateRingOfThorns() {
+ if (!local.contains(Badge.RING_OF_THORNS)/*
+ * && new
+ * RingOfThorns().isKnown()
+ */) {
+ Badge badge = Badge.RING_OF_THORNS;
+ local.add(badge);
+ displayBadge(badge);
+ }
+ }
+
+ public static void validateRare(Mob mob) {
+
+ Badge badge = null;
+ if (mob instanceof Albino) {
+ badge = Badge.RARE_ALBINO;
+ } else if (mob instanceof Bandit) {
+ badge = Badge.RARE_BANDIT;
+ } else if (mob instanceof Shielded) {
+ badge = Badge.RARE_SHIELDED;
+ } else if (mob instanceof Senior) {
+ badge = Badge.RARE_SENIOR;
+ } else if (mob instanceof Acidic) {
+ badge = Badge.RARE_ACIDIC;
+ }
+ if (!global.contains(badge)) {
+ global.add(badge);
+ saveNeeded = true;
+ }
+
+ if (global.contains(Badge.RARE_ALBINO)
+ && global.contains(Badge.RARE_BANDIT)
+ && global.contains(Badge.RARE_SHIELDED)
+ && global.contains(Badge.RARE_SENIOR)
+ && global.contains(Badge.RARE_ACIDIC)) {
+
+ badge = Badge.RARE;
+ displayBadge(badge);
+ }
+ }
+
+ public static void validateVictory() {
+
+ Badge badge = Badge.VICTORY;
+ displayBadge(badge);
+
+ switch (Dungeon.hero.heroClass) {
+ case WARRIOR:
+ badge = Badge.VICTORY_WARRIOR;
+ break;
+ case MAGE:
+ badge = Badge.VICTORY_MAGE;
+ break;
+ case ROGUE:
+ badge = Badge.VICTORY_ROGUE;
+ break;
+ case HUNTRESS:
+ badge = Badge.VICTORY_HUNTRESS;
+ break;
+ case PERFORMER:
+ badge = Badge.VICTORY_PERFORMER;
+ break;
+ }
+ local.add(badge);
+ if (!global.contains(badge)) {
+ global.add(badge);
+ saveNeeded = true;
+ }
+
+ if (global.contains(Badge.VICTORY_WARRIOR)
+ && global.contains(Badge.VICTORY_MAGE)
+ && global.contains(Badge.VICTORY_ROGUE)
+ && global.contains(Badge.VICTORY_HUNTRESS)
+ && global.contains(Badge.VICTORY_PERFORMER)
+ && global.contains(Badge.VICTORY_SOLDIER)
+ && global.contains(Badge.VICTORY_FOLLOWER)) {
+
+ badge = Badge.VICTORY_ALL_CLASSES;
+ displayBadge(badge);
+ }
+ }
+
+ public static void validateNoKilling() {
+ if (!local.contains(Badge.NO_MONSTERS_SLAIN)
+ && Statistics.completedWithNoKilling) {
+ Badge badge = Badge.NO_MONSTERS_SLAIN;
+ local.add(badge);
+ displayBadge(badge);
+ }
+ }
+
+ public static void validateGrimWeapon() {
+ if (!local.contains(Badge.GRIM_WEAPON)) {
+ Badge badge = Badge.GRIM_WEAPON;
+ local.add(badge);
+ displayBadge(badge);
+ }
+ }
+
+ public static void validateOtilukeRescued() {
+ if (!local.contains(Badge.OTILUKE)) {
+ Badge badge = Badge.OTILUKE;
+ local.add(badge);
+ displayBadge(badge);
+ }
+ }
+
+ public static void validateNightHunter() {
+ if (!local.contains(Badge.NIGHT_HUNTER) && Statistics.nightHunt >= 15) {
+ Badge badge = Badge.NIGHT_HUNTER;
+ local.add(badge);
+ displayBadge(badge);
+ }
+ }
+
+ public static void validateSupporter() {
+
+ global.add(Badge.SUPPORTER);
+ saveNeeded = true;
+
+ PixelScene.showBadge(Badge.SUPPORTER);
+ }
+
+ public static void validateGamesPlayed() {
+ Badge badge = null;
+ if (Rankings.INSTANCE.totalNumber >= 10) {
+ badge = Badge.GAMES_PLAYED_1;
+ }
+ if (Rankings.INSTANCE.totalNumber >= 100) {
+ badge = Badge.GAMES_PLAYED_2;
+ }
+ if (Rankings.INSTANCE.totalNumber >= 500) {
+ badge = Badge.GAMES_PLAYED_3;
+ }
+ if (Rankings.INSTANCE.totalNumber >= 2000) {
+ badge = Badge.GAMES_PLAYED_4;
+ }
+
+ displayBadge(badge);
+ }
+
+ public static void validateHappyEnd() {
+ displayBadge(Badge.HAPPY_END);
+ }
+
+ public static void validateChampion() {
+ displayBadge(Badge.CHAMPION);
+ }
+
+ private static void displayBadge(Badge badge) {
+
+ if (badge == null) {
+ return;
+ }
+
+ if (global.contains(badge)) {
+
+ if (!badge.meta) {
+ GLog.h(Messages.get(Badges.class, "endorsed", badge.desc()));
+ }
+
+ } else {
+
+ global.add(badge);
+ saveNeeded = true;
+
+ if (badge.meta) {
+ GLog.h( Messages.get(Badges.class, "new_super", badge.desc()) );
+ } else {
+ GLog.h( Messages.get(Badges.class, "new", badge.desc()) );
+ }
+ PixelScene.showBadge( badge );
+ }
+ }
+
+ public static boolean isUnlocked(Badge badge) {
+ return global.contains(badge);
+ }
+
+ public static void disown(Badge badge) {
+ loadGlobal();
+ global.remove(badge);
+ saveNeeded = true;
+ }
+
+ public static List filtered(boolean global) {
+
+ HashSet filtered = new HashSet(global ? Badges.global
+ : Badges.local);
+
+ if (!global) {
+ Iterator iterator = filtered.iterator();
+ while (iterator.hasNext()) {
+ Badge badge = iterator.next();
+ if (badge.meta) {
+ iterator.remove();
+ }
+ }
+ }
+
+ leaveBest(filtered, Badge.MONSTERS_SLAIN_1, Badge.MONSTERS_SLAIN_2,
+ Badge.MONSTERS_SLAIN_3, Badge.MONSTERS_SLAIN_4);
+ leaveBest(filtered, Badge.GOLD_COLLECTED_1, Badge.GOLD_COLLECTED_2,
+ Badge.GOLD_COLLECTED_3, Badge.GOLD_COLLECTED_4);
+ leaveBest(filtered, Badge.BOSS_SLAIN_1, Badge.BOSS_SLAIN_2,
+ Badge.BOSS_SLAIN_3, Badge.BOSS_SLAIN_4);
+ leaveBest(filtered, Badge.LEVEL_REACHED_1, Badge.LEVEL_REACHED_2,
+ Badge.LEVEL_REACHED_3, Badge.LEVEL_REACHED_4);
+ leaveBest(filtered, Badge.STRENGTH_ATTAINED_1,
+ Badge.STRENGTH_ATTAINED_2, Badge.STRENGTH_ATTAINED_3,
+ Badge.STRENGTH_ATTAINED_4);
+ leaveBest(filtered, Badge.FOOD_EATEN_1, Badge.FOOD_EATEN_2,
+ Badge.FOOD_EATEN_3, Badge.FOOD_EATEN_4);
+ leaveBest(filtered, Badge.EGG_BREAK_1, Badge.EGG_BREAK_2,
+ Badge.EGG_BREAK_3);
+ leaveBest(filtered, Badge.ITEM_LEVEL_1, Badge.ITEM_LEVEL_2,
+ Badge.ITEM_LEVEL_3, Badge.ITEM_LEVEL_4);
+ leaveBest(filtered, Badge.POTIONS_COOKED_1, Badge.POTIONS_COOKED_2,
+ Badge.POTIONS_COOKED_3, Badge.POTIONS_COOKED_4);
+ leaveBest(filtered, Badge.BOSS_SLAIN_1_ALL_CLASSES,
+ Badge.BOSS_SLAIN_3_ALL_SUBCLASSES);
+ leaveBest(filtered, Badge.DEATH_FROM_FIRE, Badge.YASD);
+ leaveBest(filtered, Badge.DEATH_FROM_GAS, Badge.YASD);
+ leaveBest(filtered, Badge.DEATH_FROM_HUNGER, Badge.YASD);
+ leaveBest(filtered, Badge.DEATH_FROM_POISON, Badge.YASD);
+ leaveBest(filtered, Badge.VICTORY, Badge.VICTORY_ALL_CLASSES);
+ leaveBest(filtered, Badge.GAMES_PLAYED_1, Badge.GAMES_PLAYED_2,
+ Badge.GAMES_PLAYED_3, Badge.GAMES_PLAYED_4);
+
+ ArrayList list = new ArrayList(filtered);
+ Collections.sort(list);
+
+ return list;
+ }
+
+ private static void leaveBest(HashSet list, Badge... badges) {
+ for (int i = badges.length - 1; i > 0; i--) {
+ if (list.contains(badges[i])) {
+ for (int j = 0; j < i; j++) {
+ list.remove(badges[j]);
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/java/com/hmdzl/spspd/Challenges.java b/java/com/hmdzl/spspd/Challenges.java
new file mode 100644
index 00000000..917b109c
--- /dev/null
+++ b/java/com/hmdzl/spspd/Challenges.java
@@ -0,0 +1,46 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd;
+
+public class Challenges {
+
+ public static final int ITEM_PHOBIA = 1;
+ public static final int LISTLESS = 2;
+ public static final int NIGHTMARE_VIRUS = 4;
+ public static final int ENERGY_LOST = 8;
+ public static final int DEW_REJECTION = 16;
+ public static final int DARKNESS = 32;
+ public static final int ABRASION = 64;
+ public static final int TEST_TIME = 128;
+
+ public static final String[] NAME_IDS = {
+ "item_phobia",
+ "listless",
+ "nightmare_virus",
+ "energy_lost",
+ "dew_rejection",
+ "darkness",
+ "abrasion",
+ "test_time"
+ };
+
+ public static final int[] MASKS = {
+ ITEM_PHOBIA, LISTLESS, NIGHTMARE_VIRUS,
+ ENERGY_LOST, DEW_REJECTION, DARKNESS, ABRASION, TEST_TIME};
+
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/Chrome.java b/java/com/hmdzl/spspd/Chrome.java
new file mode 100644
index 00000000..4099c50b
--- /dev/null
+++ b/java/com/hmdzl/spspd/Chrome.java
@@ -0,0 +1,55 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd;
+
+import com.watabou.noosa.NinePatch;
+
+public class Chrome {
+
+ public enum Type {
+ TOAST, TOAST_TR, WINDOW, BUTTON, TAG, GEM, SCROLL, TAB_SET, TAB_SELECTED, TAB_UNSELECTED
+ };
+
+ public static NinePatch get(Type type) {
+ String Asset = Assets.CHROME;
+ switch (type) {
+ case WINDOW:
+ return new NinePatch(Asset, 0, 0, 20, 20, 6);
+ case TOAST:
+ return new NinePatch(Asset, 22, 0, 18, 18, 5);
+ case TOAST_TR:
+ return new NinePatch(Asset, 40, 0, 18, 18, 5);
+ case BUTTON:
+ return new NinePatch(Asset, 58, 0, 4, 4, 1);
+ case TAG:
+ return new NinePatch(Asset, 22, 18, 16, 14, 3);
+ case GEM:
+ return new NinePatch(Asset, 0, 32, 32, 32, 13);
+ case SCROLL:
+ return new NinePatch(Asset, 32, 32, 32, 32, 5, 11, 5, 11);
+ case TAB_SET:
+ return new NinePatch(Asset, 64, 0, 20, 20, 6);
+ case TAB_SELECTED:
+ return new NinePatch(Asset, 65, 22, 8, 13, 3, 7, 3, 5);
+ case TAB_UNSELECTED:
+ return new NinePatch(Asset, 75, 22, 8, 13, 3, 7, 3, 5);
+ default:
+ return null;
+ }
+ }
+}
diff --git a/java/com/hmdzl/spspd/Dungeon.java b/java/com/hmdzl/spspd/Dungeon.java
new file mode 100644
index 00000000..2d1317bd
--- /dev/null
+++ b/java/com/hmdzl/spspd/Dungeon.java
@@ -0,0 +1,1572 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.HashSet;
+
+import com.hmdzl.spspd.items.artifacts.DriedRose;
+import com.hmdzl.spspd.levels.ChaosLevel;
+import com.hmdzl.spspd.levels.PotLevel;
+import com.hmdzl.spspd.levels.ShadowEaterLevel;
+import com.hmdzl.spspd.levels.SokobanSPLevel;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Amok;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Dewcharge;
+import com.hmdzl.spspd.actors.buffs.Light;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.actors.hero.HeroClass;
+import com.hmdzl.spspd.actors.mobs.npcs.Blacksmith;
+import com.hmdzl.spspd.actors.mobs.npcs.Ghost;
+import com.hmdzl.spspd.actors.mobs.npcs.Imp;
+import com.hmdzl.spspd.actors.mobs.npcs.Wandmaker;
+import com.hmdzl.spspd.items.Ankh;
+import com.hmdzl.spspd.items.Generator;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.items.potions.Potion;
+import com.hmdzl.spspd.items.rings.Ring;
+import com.hmdzl.spspd.items.scrolls.Scroll;
+import com.hmdzl.spspd.levels.BattleLevel;
+import com.hmdzl.spspd.levels.CatacombLevel;
+import com.hmdzl.spspd.levels.CavesBossLevel;
+import com.hmdzl.spspd.levels.CavesLevel;
+import com.hmdzl.spspd.levels.ChasmLevel;
+import com.hmdzl.spspd.levels.CityBossLevel;
+import com.hmdzl.spspd.levels.CityLevel;
+import com.hmdzl.spspd.levels.CrabBossLevel;
+import com.hmdzl.spspd.levels.DeadEndLevel;
+import com.hmdzl.spspd.levels.FieldLevel;
+import com.hmdzl.spspd.levels.FieldBossLevel;
+import com.hmdzl.spspd.levels.FishingLevel;
+import com.hmdzl.spspd.levels.FortressLevel;
+import com.hmdzl.spspd.levels.HallsBossLevel;
+import com.hmdzl.spspd.levels.HallsLevel;
+import com.hmdzl.spspd.levels.InfestBossLevel;
+import com.hmdzl.spspd.levels.LastLevel;
+import com.hmdzl.spspd.levels.LastShopLevel;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.levels.MinesBossLevel;
+import com.hmdzl.spspd.levels.PrisonBossLevel;
+import com.hmdzl.spspd.levels.PrisonLevel;
+import com.hmdzl.spspd.levels.Room;
+import com.hmdzl.spspd.levels.SafeLevel;
+import com.hmdzl.spspd.levels.SewerBossLevel;
+import com.hmdzl.spspd.levels.SewerLevel;
+import com.hmdzl.spspd.levels.SkeletonBossLevel;
+import com.hmdzl.spspd.levels.SokobanCastle;
+import com.hmdzl.spspd.levels.SokobanIntroLevel;
+import com.hmdzl.spspd.levels.SokobanPuzzlesLevel;
+import com.hmdzl.spspd.levels.SokobanTeleportLevel;
+import com.hmdzl.spspd.levels.TenguDenLevel;
+import com.hmdzl.spspd.levels.ThiefBossLevel;
+import com.hmdzl.spspd.levels.ThiefCatchLevel;
+import com.hmdzl.spspd.levels.BossRushLevel;
+import com.hmdzl.spspd.levels.TownLevel;
+import com.hmdzl.spspd.levels.VaultLevel;
+import com.hmdzl.spspd.levels.ZotBossLevel;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.scenes.StartScene;
+import com.hmdzl.spspd.ui.QuickSlotButton;
+import com.hmdzl.spspd.utils.BArray;
+import com.hmdzl.spspd.utils.GLog;
+
+import com.hmdzl.spspd.windows.WndResurrect;
+import com.watabou.noosa.Game;
+import com.watabou.utils.Bundlable;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.PathFinder;
+import com.watabou.utils.Random;
+import com.watabou.utils.SparseArray;
+
+public class Dungeon {
+
+ // enum of items which have limited spawns, records how many have spawned
+ // could all be their own separate numbers, but this allows iterating, much
+ // nicer for bundling/initializing.
+ public static enum limitedDrops {
+ // limited world drops
+ strengthPotions, upgradeScrolls,
+
+ //Norn Stones
+ nornstones,
+
+ // doesn't use Generator, so we have to enforce one armband drop here
+ spork, sewerkey, prisonkey, caveskey, citykey, potkey, ringofwealth, vaultpage, town,
+ conchshell, ancientcoin, tengukey, bone, journal, safespotpage, dragoncave, treasuremap, goei,
+
+ // containers
+ dewVial, seedBag, scrollBag, potionBag, wandBag, shopcart, heartScarecrow, challengebook;
+
+ public int count = 0;
+
+ // for items which can only be dropped once, should directly access
+ // count otherwise.
+ public boolean dropped() {
+ return count != 0;
+ }
+
+ public void drop() {
+ count = 1;
+ }
+ }
+
+ public static int[] pars;
+
+ public static boolean earlygrass = false;
+ public static boolean gnollspawned = false;
+ public static boolean skeletonspawned = false;
+ public static boolean goldthiefspawned = false;
+ public static boolean triforce = false;
+ public static boolean triforceofcourage = false;
+ public static boolean triforceofpower = false;
+ public static boolean triforceofwisdom = false;
+ public static boolean shadowyogkilled = false;
+ public static boolean crabkingkilled = false;
+ public static boolean banditkingkilled = false;
+ public static boolean skeletonkingkilled = false;
+ public static boolean gnollkingkilled = false;
+ public static boolean tengudenkilled = false;
+ public static boolean zotkilled = false;
+ public static boolean dewDraw = false;
+ public static boolean dewWater = false;
+ public static boolean wings = false;
+ public static boolean dewNorn = false;
+ public static boolean canSave = false;
+ public static boolean gnollmission = false;
+ public static boolean oneDay = false;
+ public static boolean error = false;
+ //public static boolean secondQuest = false;
+
+ public static int challenges;
+ public static int skins;
+
+ public static int ratChests = 0;
+ public static int sacrifice = 0;
+ public static boolean sporkAvail = false;
+ public static boolean challengebookdrop = false;
+ public static boolean goeidrop = false;
+
+ public static Hero hero;
+ public static Level level;
+
+ public static QuickSlot quickslot = new QuickSlot();
+
+ public static int depth = 1;
+ public static int gold = 0;
+
+ public static String resultDescription;
+
+ public static HashSet chapters;
+
+ // Hero's field of view
+ public static boolean[] visible = new boolean[Level.getLength()];
+
+ public static SparseArray> droppedItems;
+
+ public static int version;
+
+ public static void init() {
+
+ version = Game.versionCode;
+ challenges = ShatteredPixelDungeon.challenges();
+
+ //Generator.initArtifacts();
+
+ Actor.clear();
+ Actor.resetNextID();
+
+ PathFinder.setMapSize(Level.getWidth(), Level.HEIGHT);
+
+ Scroll.initLabels();
+ Potion.initColors();
+ Ring.initGems();
+
+ Statistics.reset();
+ Journal.reset();
+
+ quickslot.reset();
+ QuickSlotButton.reset();
+
+ depth = 0;
+ gold = 0;
+
+ droppedItems = new SparseArray>();
+
+ for (limitedDrops a : limitedDrops.values())
+ a.count = 0;
+
+ chapters = new HashSet();
+
+ Ghost.Quest.reset();
+ Wandmaker.Quest.reset();
+ Blacksmith.Quest.reset();
+ Imp.Quest.reset();
+
+ Room.shuffleTypes();
+
+ //Generator.initArtifacts();
+ hero = new Hero();
+ hero.live();
+
+ Badges.reset();
+
+ StartScene.curClass.initHero(hero);
+
+ earlygrass = false;
+ gnollspawned = false;
+ skeletonspawned = false;
+ goldthiefspawned = false;
+ triforce = false;
+ triforceofcourage = false;
+ triforceofpower = false;
+ triforceofwisdom = false;
+ shadowyogkilled = false;
+ crabkingkilled = false;
+ banditkingkilled = false;
+ gnollkingkilled = false;
+ tengudenkilled = false;
+ skeletonkingkilled = false;
+ zotkilled = false;
+ ratChests = 0;
+ sacrifice = 0 ;
+ sporkAvail = false;
+ challengebookdrop = false;
+ goeidrop = false;
+ dewDraw = false;
+ dewWater = false;
+ wings = false;
+ dewNorn = false;
+ canSave = false;
+ gnollmission = false;
+ oneDay =false;
+ error = false;
+
+ pars = new int[100];
+
+ }
+
+ public static boolean isChallenged(int mask) {
+ return (challenges & mask) != 0;
+ }
+
+ public static Level newFieldLevel(){
+
+ Dungeon.level = null;
+ Actor.clear();
+ depth = 27;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ level = new FieldLevel();
+
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+
+ return level;
+ }
+ public static Level newBattleLevel(){
+
+ Dungeon.level = null;
+ Actor.clear();
+ depth = 28;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ level = new BattleLevel();
+
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+
+ return level;
+ }
+ public static Level newFishLevel(){
+
+ Dungeon.level = null;
+ Actor.clear();
+ depth = 29;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ level = new FishingLevel();
+
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+
+ return level;
+ }
+ public static Level newVaultLevel(){
+
+ Dungeon.level = null;
+ Actor.clear();
+ depth = 30;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ level = new VaultLevel();
+
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+
+ return level;
+ }
+
+ public static Level newCatacombLevel(){
+
+
+ Dungeon.level = null;
+ Actor.clear();
+ depth = 31;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ level = new CatacombLevel();
+
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+
+ return level;
+ }
+
+public static Level newFortressLevel(){
+
+ Dungeon.level = null;
+ Actor.clear();
+ depth = 32;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ level = new FortressLevel();
+
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+
+ return level;
+ }
+
+public static Level newChasmLevel(){
+
+ Dungeon.level = null;
+ Actor.clear();
+ depth = 33;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ level = new ChasmLevel();
+
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+
+ return level;
+}
+
+public static Level newInfestLevel(){
+
+ Dungeon.level = null;
+ Actor.clear();
+ depth = 35;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ level = new InfestBossLevel();
+
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+ if (Statistics.deepestFloor>24){Statistics.deepestFloor = depth;}
+
+ return level;
+}
+
+
+
+public static Level newTenguHideoutLevel(){
+
+ Dungeon.level = null;
+ Actor.clear();
+ depth = 36;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ level = new TenguDenLevel();
+
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+
+ return level;
+}
+
+public static Level newSkeletonBossLevel(){
+
+ Dungeon.level = null;
+ Actor.clear();
+ depth = 37;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ level = new SkeletonBossLevel();
+
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+
+ return level;
+}
+
+public static Level newCrabBossLevel(){
+
+ Dungeon.level = null;
+ Actor.clear();
+ depth = 38;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ level = new CrabBossLevel();
+
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+
+ return level;
+}
+
+public static Level newThiefBossLevel(){
+
+ Dungeon.level = null;
+ Actor.clear();
+ depth = 40;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ level = new ThiefBossLevel();
+
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+
+ return level;
+}
+
+public static Level newFieldBossLevel(){
+
+ Dungeon.level = null;
+ Actor.clear();
+ depth = 43;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ level = new FieldBossLevel();
+
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+
+ return level;
+}
+
+public static Level newPotLevel(){
+
+ Dungeon.level = null;
+ Actor.clear();
+ depth = 45;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ level = new PotLevel();
+
+ level.create();
+
+ return level;
+}
+
+public static Level newShadowEaterLevel(){
+
+ Dungeon.level = null;
+ Actor.clear();
+ depth = 47;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ level = new ShadowEaterLevel();
+
+ level.create();
+
+ return level;
+}
+
+public static Level newMineBossLevel(){
+
+ Dungeon.level = null;
+ Actor.clear();
+ //depth = 67;
+ depth++;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ level = new MinesBossLevel();
+
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+
+ return level;
+}
+
+public static Level newBossRushLevel(){
+
+
+ Dungeon.level = null;
+ Actor.clear();
+ depth = 71;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ level = new BossRushLevel();
+
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+
+ return level;
+ }
+
+ public static Level newChaosLevel(){
+
+ Dungeon.level = null;
+ Actor.clear();
+ depth = 85;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ level = new ChaosLevel();
+
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+
+ return level;
+ }
+
+public static Level newZotBossLevel(){
+
+ Dungeon.level = null;
+ Actor.clear();
+ depth = 99;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ level = new ZotBossLevel();
+
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+
+ return level;
+}
+
+public static Level newJournalLevel(int page, Boolean first){
+
+ Dungeon.level = null;
+ Actor.clear();
+
+ depth = 50+page;
+
+ if (page==6){
+ depth = 66;
+ }
+
+ if (page==7){
+ depth = 67;
+ }
+
+ if (depth > Statistics.realdeepestFloor && depth < 68) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ switch(page){
+ case 0:
+ level = new SafeLevel();
+ break;
+ case 1:
+ level = new SokobanIntroLevel();
+ break;
+ case 2:
+ level = new SokobanCastle();
+ break;
+ case 3:
+ level = new SokobanTeleportLevel();
+ break;
+ case 4:
+ level = new SokobanPuzzlesLevel();
+ break;
+ case 5:
+ level = new TownLevel();
+ break;
+ case 6:
+ level = new SokobanSPLevel();
+ break;
+ case 7:
+ level = new MinesBossLevel();
+ break;
+ default:
+ level = Dungeon.newLevel();
+ }
+
+ level.first = first;
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+
+ return level;
+}
+
+public static Level newChallengeLevel(int list, Boolean first){
+
+ Dungeon.level = null;
+ Actor.clear();
+
+ depth = 26+list;
+ if (list==0){
+ depth = 26;
+ }
+ if (list==1 ){
+ depth = 27;
+ }
+ if (list==2){
+ depth = 28;
+ }
+ if (list==3){
+ depth = 29;
+ }
+ if (list==4){
+ depth = 30;
+ }
+ if (list==5){
+ depth = 31;
+ }
+ if (list==6){
+ depth = 32;
+ }
+ if (list==7){
+ depth = 33;
+ }
+
+ if (depth > Statistics.realdeepestFloor && depth < 34) {
+ Statistics.realdeepestFloor = depth;}
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ switch(list){
+ case 0:
+ level = Dungeon.newLevel();
+ break;
+ case 1:
+ level = new FieldLevel();
+ break;
+ case 2:
+ level = new BattleLevel();
+ break;
+ case 3:
+ level = new FishingLevel();
+ break;
+ case 4:
+ level = new VaultLevel();
+ break;
+ case 5:
+ level = new CatacombLevel();
+ break;
+ case 6:
+ level = new FortressLevel();
+ break;
+ case 7:
+ level = new ChasmLevel();
+ break;
+ default:
+ level = Dungeon.newLevel();
+ }
+
+ level.first = first;
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+
+ return level;
+}
+
+
+ public static Level newLevel() {
+
+ Dungeon.level = null;
+ Actor.clear();
+
+ depth++;
+ if (depth > Statistics.realdeepestFloor) {
+ Statistics.realdeepestFloor = depth;}
+
+ if (depth > Statistics.deepestFloor && depth < 27) {
+ Statistics.deepestFloor = depth;
+
+ if (Statistics.qualifiedForNoKilling) {
+ Statistics.completedWithNoKilling = true;
+ } else {
+ Statistics.completedWithNoKilling = false;
+ }
+ }
+
+ if (depth==6){
+ Statistics.sewerKills=Statistics.enemiesSlain;
+ }
+ if (depth==10){
+ Statistics.prisonKills=Statistics.enemiesSlain-Statistics.sewerKills;
+ }
+
+ Arrays.fill(visible, false);
+
+ Level level;
+ switch (depth) {
+ case 1:
+ //level = new PrisonBossLevel();
+ //level = new SewerLevel();
+ //hero.HT=999;
+ //hero.HP=hero.HT;
+ //break;
+ case 2:
+ //level = new HallsLevel();
+ //hero.HT=999;
+ //hero.HP=hero.HT;
+ //break;
+ case 3:
+ case 4:
+ //level = new CavesLevel();
+ level = new SewerLevel();
+ //hero.HT=999;
+ //hero.HP=hero.HT;
+ break;
+ case 5:
+ level = new SewerBossLevel();
+ break;
+ case 6:
+ //level = new HallsLevel();
+ //hero.HT=999;
+ //hero.HP=hero.HT;
+ //break;
+ case 7:
+ case 8:
+ case 9:
+ level = new PrisonLevel();
+ break;
+ case 10:
+ level = new PrisonBossLevel();
+ break;
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ level = new CavesLevel();
+ break;
+ case 15:
+ level = new CavesBossLevel();
+ break;
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ level = new CityLevel();
+ break;
+ case 20:
+ level = new CityBossLevel();
+ break;
+ case 21:
+ level = new LastShopLevel();
+ break;
+ case 22:
+ case 23:
+ case 24:
+ level = new HallsLevel();
+ break;
+ case 25:
+ level = new HallsBossLevel();
+ break;
+ case 26:
+ level = new LastLevel();
+ break;
+ case 41:
+ level = new ThiefCatchLevel();
+ break;
+ case 67:
+ level = new MinesBossLevel();
+ break;
+ case 71:
+ level = new BossRushLevel();
+ break;
+ case 85:
+ level = new ChaosLevel();
+ default:
+ level = new DeadEndLevel();
+ if (depth<27){Statistics.deepestFloor--;}
+ }
+
+ level.create();
+
+ Statistics.qualifiedForNoKilling = !bossLevel();
+ if (depth<26 && depth!=21 && !Dungeon.bossLevel(depth) && (Dungeon.dewDraw || Dungeon.dewWater)){
+ Buff.prolong(Dungeon.hero, Dewcharge.class, Dewcharge.DURATION+(Math.max(Statistics.prevfloormoves,1)));
+ //GLog.p("You feel the dungeon charge with dew!");
+ }
+ /*if(Dungeon.hero.heroClass == HeroClass.PERFORMER){
+ //Buff.prolong(Dungeon.hero,Rhythm.class,50);
+ Buff.affect(Dungeon.hero,GlassShield.class).turns(3);
+ }
+ if(Dungeon.hero.heroClass == HeroClass.PERFORMER && Dungeon.hero.subClass == HeroSubClass.SUPERSTAR){
+ Buff.affect(Dungeon.hero,Rhythm.class,50);
+ Buff.prolong(Dungeon.hero,Rhythm2.class,50);
+ }*/
+
+ return level;
+ }
+
+ public static void resetLevel() {
+
+ Actor.clear();
+
+ Arrays.fill(visible, false);
+
+ level.reset();
+ switchLevel(level, level.entrance);
+ }
+
+ public static boolean shopOnLevel() {
+ return depth==1 || depth == 6 || depth == 11 || depth == 16;
+ }
+
+ public static boolean bossLevel() {
+ return bossLevel(depth);
+ }
+
+ public static boolean bossLevel(int depth) {
+ return depth == 5 || depth == 10 || depth == 15 || depth == 20
+ || depth == 25 || depth == 36 || depth == 41 || depth == 71 ;
+ }
+
+ public static boolean notClearableLevel(int depth) {
+ return depth == 1 || depth ==2 ||depth == 5 || depth == 10 || depth == 15 || depth == 20 || depth == 21
+ || depth == 25 || depth>25;
+ }
+
+ public static boolean townCheck(int depth) {
+ return depth > 54 && depth < 66;
+ }
+
+ public static boolean growLevel(int depth) {
+ return depth == 27 || depth == 28 || depth == 32 || depth == 30 || depth == 55;
+ }
+
+ public static boolean waterLevel(int depth) {
+ return depth == 29;
+ }
+
+ public static boolean sokobanLevel(int depth) {
+ return depth == 51 || depth == 52 || depth == 53 || depth == 54;
+ }
+
+ //public static boolean dropLevel(int depth) {
+ //return depth == 40;
+ //}
+
+
+ @SuppressWarnings("deprecation")
+ public static void switchLevel(final Level level, int pos) {
+
+ Dungeon.level = level;
+ DriedRose.restoreGhostHero( level, pos );
+ Actor.init();
+
+ Actor respawner = level.respawner();
+ if (respawner != null) {
+ Actor.add(level.respawner());
+ }
+
+ Actor regrower = level.regrower();
+ if (regrower != null && growLevel(depth)) {
+ Actor.add(level.regrower());
+ }
+
+ Actor waterer = level.waterer();
+ if (waterer != null && waterLevel(depth)) {
+ Actor.add(level.waterer());
+ }
+
+ /*Actor floordropper = level.floordropper();
+ if (floordropper != null && dropLevel(depth)) {
+ Actor.add(level.floordropper());
+ }*/
+
+ hero.pos = pos != -1 ? pos : level.exit;
+
+ Light light = hero.buff(Light.class);
+ hero.viewDistance = light == null ? level.viewDistance : Math.max(
+ Light.DISTANCE, level.viewDistance);
+
+ Actor respawnerPet = level.respawnerPet();
+ if (respawnerPet != null) {
+ Actor.add(level.respawnerPet());
+ }
+
+ observe();
+ try {
+ saveAll();
+ } catch (IOException e) {
+ /*
+ * This only catches IO errors. Yes, this means things can go wrong,
+ * and they can go wrong catastrophically. But when they do the user
+ * will get a nice 'report this issue' dialogue, and I can fix the
+ * bug.
+ */
+ }
+ }
+
+ public static void dropToChasm(Item item) {
+ int depth = Dungeon.depth + 1;
+ ArrayList- dropped = Dungeon.droppedItems
+ .get(depth);
+ if (dropped == null) {
+ Dungeon.droppedItems.put(depth, dropped = new ArrayList
- ());
+ }
+ dropped.add(item);
+ }
+
+ public static boolean posNeeded() {
+ int[] quota = { 4, 2, 9, 4, 14, 6, 19, 8, 24, 10 };
+ return chance(quota, limitedDrops.strengthPotions.count);
+ }
+
+ public static boolean souNeeded() {
+ int[] quota = { 5, 4, 10, 8, 15, 12, 20, 16, 25, 20 };
+ return chance(quota, limitedDrops.upgradeScrolls.count);
+ }
+
+ private static boolean chance(int[] quota, int number) {
+
+ for (int i = 0; i < quota.length; i += 2) {
+ int qDepth = quota[i];
+ if (depth <= qDepth) {
+ int qNumber = quota[i + 1];
+ return Random.Float() < (float) (qNumber - number)
+ / (qDepth - depth + 1);
+ }
+ }
+
+ return false;
+ }
+
+ private static final String RG_GAME_FILE = "rogue.dat";
+ private static final String RG_DEPTH_FILE = "rogue%d.dat";
+
+ private static final String WR_GAME_FILE = "warrior.dat";
+ private static final String WR_DEPTH_FILE = "warrior%d.dat";
+
+ private static final String MG_GAME_FILE = "mage.dat";
+ private static final String MG_DEPTH_FILE = "mage%d.dat";
+
+ private static final String RN_GAME_FILE = "huntress.dat";
+ private static final String RN_DEPTH_FILE = "huntress%d.dat";
+
+ private static final String PE_GAME_FILE = "performer.dat";
+ private static final String PE_DEPTH_FILE = "performer%d.dat";
+
+ private static final String SO_GAME_FILE = "soldier.dat";
+ private static final String SO_DEPTH_FILE = "soldier%d.dat";
+
+ private static final String FO_GAME_FILE = "follower.dat";
+ private static final String FO_DEPTH_FILE = "follower%d.dat";
+
+ private static final String VERSION = "version";
+ private static final String SKINS = "skins";
+ private static final String CHALLENGES = "challenges";
+ private static final String HERO = "hero";
+ private static final String GOLD = "gold";
+ private static final String DEPTH = "depth";
+ private static final String DROPPED = "dropped%d";
+ private static final String LEVEL = "level";
+ private static final String LIMDROPS = "limiteddrops";
+ private static final String DV = "dewVial";
+ private static final String CHAPTERS = "chapters";
+ private static final String QUESTS = "quests";
+ private static final String BADGES = "badges";
+
+ private static final String SACRIFICE = "sacrifice";
+ private static final String RATCHESTS = "ratChests";
+ private static final String EARLYGRASS = "earlygrass";
+ private static final String GNOLLSPAWN = "gnollspawned";
+ private static final String SKELETONSPAWN = "skeletonspawned";
+ private static final String THIEFSPAWN = "goldthiefspawned";
+ private static final String STRI = "triforce";
+ private static final String STRID = "triforceofcourage";
+ private static final String STRIL = "triforceofpower";
+ private static final String STRIT = "triforceofwisdom";
+ private static final String SYOGKILL = "shadowyogkilled";
+ private static final String CRABKILL = "crabkingkilled";
+ private static final String TENGUDENKILL = "tengudenkilled";
+ private static final String SKELETONKILL = "skeletonkingkilled";
+ private static final String GNOLLKILL = "gnollkingkilled";
+ private static final String BANDITKILL = "banditkingkilled";
+ private static final String ZOTKILL = "zotkilled";
+ private static final String SPORK = "sporkAvail";
+ private static final String CBDROP = "challengebookdrop";
+ private static final String GOEIDROP = "goeidrop";
+ private static final String DEWDRAW = "dewDraw";
+ private static final String DEWWATER = "dewWater";
+ private static final String DEWNORN = "dewNorn";
+ private static final String CANSAVE = "canSave";
+ private static final String GNOLLMISSION = "gnollmission";
+ private static final String ONEDAY = "oneDay";
+ private static final String ERROR = "error";
+ private static final String WINGS = "wings";
+ private static final String PARS = "pars";
+
+ //private static final String SECONDQUEST = "secondQuest";
+
+ public static String gameFile(HeroClass cl) {
+ switch (cl) {
+ case WARRIOR:
+ return WR_GAME_FILE;
+ case MAGE:
+ return MG_GAME_FILE;
+ case ROGUE:
+ return RG_GAME_FILE;
+ case HUNTRESS:
+ return RN_GAME_FILE;
+ case PERFORMER:
+ return PE_GAME_FILE;
+ case SOLDIER:
+ return SO_GAME_FILE;
+ case FOLLOWER:
+ return FO_GAME_FILE;
+ default:
+ return RG_GAME_FILE;
+ }
+ }
+
+ private static String depthFile(HeroClass cl) {
+ switch (cl) {
+ case WARRIOR:
+ return WR_DEPTH_FILE;
+ case MAGE:
+ return MG_DEPTH_FILE;
+ case ROGUE:
+ return RG_DEPTH_FILE;
+ case HUNTRESS:
+ return RN_DEPTH_FILE;
+ case PERFORMER:
+ return PE_DEPTH_FILE;
+ case SOLDIER:
+ return SO_DEPTH_FILE;
+ case FOLLOWER:
+ return FO_DEPTH_FILE;
+ default:
+ return RG_DEPTH_FILE;
+ }
+ }
+
+ public static void saveGame(String fileName) throws IOException {
+ try {
+ Bundle bundle = new Bundle();
+
+ version = Game.versionCode;
+ bundle.put(VERSION, Game.versionCode);
+ bundle.put( SKINS, skins );
+ bundle.put(CHALLENGES, challenges);
+ bundle.put(HERO, hero);
+ bundle.put(GOLD, gold);
+ bundle.put(DEPTH, depth);
+
+ //bundle.put(SECONDQUEST, secondQuest);
+ bundle.put(SACRIFICE, sacrifice);
+ bundle.put(RATCHESTS, ratChests);
+ bundle.put(EARLYGRASS, earlygrass);
+ bundle.put(GNOLLSPAWN, gnollspawned);
+ bundle.put(SKELETONSPAWN, skeletonspawned);
+ bundle.put(THIEFSPAWN, goldthiefspawned);
+ bundle.put(STRI, triforce);
+ bundle.put(STRID, triforceofcourage);
+ bundle.put(STRIL, triforceofpower);
+ bundle.put(STRIT, triforceofwisdom);
+ bundle.put(SYOGKILL, shadowyogkilled);
+ bundle.put(CRABKILL, crabkingkilled);
+ bundle.put(TENGUDENKILL, tengudenkilled);
+ bundle.put(BANDITKILL, banditkingkilled);
+ bundle.put(SKELETONKILL, skeletonkingkilled);
+ bundle.put(GNOLLKILL, gnollkingkilled);
+ bundle.put(ZOTKILL, zotkilled);
+ bundle.put(SPORK, sporkAvail);
+ bundle.put(CBDROP, challengebookdrop);
+ bundle.put(GOEIDROP, goeidrop);
+ bundle.put(DEWDRAW, dewDraw);
+ bundle.put(DEWWATER, dewWater);
+ bundle.put(WINGS, wings);
+ bundle.put(DEWNORN, dewNorn);
+ bundle.put(CANSAVE, canSave);
+ bundle.put(GNOLLMISSION, gnollmission);
+ bundle.put(ONEDAY, oneDay);
+ bundle.put(ERROR, error);
+ bundle.put(PARS, pars);
+
+ for (int d : droppedItems.keyArray()) {
+ bundle.put(String.format(DROPPED, d), droppedItems.get(d));
+ }
+
+ quickslot.storePlaceholders(bundle);
+
+ int[] dropValues = new int[limitedDrops.values().length];
+ for (limitedDrops value : limitedDrops.values())
+ dropValues[value.ordinal()] = value.count;
+ bundle.put(LIMDROPS, dropValues);
+
+ int count = 0;
+ int ids[] = new int[chapters.size()];
+ for (Integer id : chapters) {
+ ids[count++] = id;
+ }
+ bundle.put(CHAPTERS, ids);
+
+ Bundle quests = new Bundle();
+ Ghost.Quest.storeInBundle(quests);
+ Wandmaker.Quest.storeInBundle(quests);
+ Blacksmith.Quest.storeInBundle(quests);
+ Imp.Quest.storeInBundle(quests);
+ bundle.put(QUESTS, quests);
+
+ Room.storeRoomsInBundle(bundle);
+
+ Statistics.storeInBundle(bundle);
+ Journal.storeInBundle(bundle);
+ //Generator.storeInBundle(bundle);
+
+ Scroll.save(bundle);
+ Potion.save(bundle);
+ Ring.save(bundle);
+
+ Actor.storeNextID(bundle);
+
+ Bundle badges = new Bundle();
+ Badges.saveLocal(badges);
+ bundle.put(BADGES, badges);
+
+ OutputStream output = Game.instance.openFileOutput(fileName,
+ Game.MODE_PRIVATE);
+ Bundle.write(bundle, output);
+ output.close();
+
+ } catch (IOException e) {
+
+ GamesInProgress.setUnknown(hero.heroClass);
+ }
+ }
+
+ public static void saveLevel() throws IOException {
+ Bundle bundle = new Bundle();
+ bundle.put(LEVEL, level);
+
+ OutputStream output = Game.instance.openFileOutput(
+ Messages.format(depthFile(hero.heroClass), depth),
+ Game.MODE_PRIVATE);
+ Bundle.write(bundle, output);
+ output.close();
+ }
+
+ public static void saveAll() throws IOException {
+ if (hero.isAlive()) {
+
+ Actor.fixTime();
+ saveGame(gameFile(hero.heroClass));
+ saveLevel();
+
+ GamesInProgress.set(hero.heroClass, depth, hero.lvl,skins,
+ challenges != 0);
+
+ } else if (WndResurrect.instance != null) {
+
+ WndResurrect.instance.hide();
+ Hero.reallyDie(WndResurrect.causeOfDeath);
+
+ }
+ }
+
+ public static void loadGame(HeroClass cl) throws IOException {
+ loadGame(gameFile(cl), true);
+ }
+
+ public static void loadGame(String fileName) throws IOException {
+ loadGame(fileName, false);
+ }
+
+ public static void loadGame(String fileName, boolean fullLoad)
+ throws IOException {
+ try{
+ Bundle bundle = gameBundle(fileName);
+
+ version = bundle.getInt(VERSION);
+
+ Generator.reset();
+
+ Actor.restoreNextID(bundle);
+
+ quickslot.reset();
+ QuickSlotButton.reset();
+
+ Dungeon.challenges = bundle.getInt(CHALLENGES);
+ Dungeon.skins = bundle.getInt(SKINS);
+
+ Dungeon.level = null;
+ Dungeon.depth = -1;
+
+ if (fullLoad) {
+ PathFinder.setMapSize(Level.getWidth(), Level.HEIGHT);
+ }
+
+ Scroll.restore(bundle);
+ Potion.restore(bundle);
+ Ring.restore(bundle);
+
+ quickslot.restorePlaceholders(bundle);
+ // TODO: adjust this when dropping support for pre-0.2.3 saves
+ if (bundle.contains(LIMDROPS)) {
+ int[] dropValues = bundle.getIntArray(LIMDROPS);
+ for (limitedDrops value : limitedDrops.values())
+ value.count = value.ordinal() < dropValues.length ? dropValues[value
+ .ordinal()] : 0;
+
+ // for pre-0.2.4 saves
+ if (bundle.getBoolean(DV))
+ limitedDrops.dewVial.drop();
+
+ chapters = new HashSet();
+ int ids[] = bundle.getIntArray(CHAPTERS);
+ if (ids != null) {
+ for (int id : ids) {
+ chapters.add(id);
+ }
+ }
+
+ Bundle quests = bundle.getBundle(QUESTS);
+ if (!quests.isNull()) {
+ Ghost.Quest.restoreFromBundle(quests);
+ Wandmaker.Quest.restoreFromBundle(quests);
+ Blacksmith.Quest.restoreFromBundle(quests);
+ Imp.Quest.restoreFromBundle(quests);
+ } else {
+ Ghost.Quest.reset();
+ Wandmaker.Quest.reset();
+ Blacksmith.Quest.reset();
+ Imp.Quest.reset();
+ }
+
+ Room.restoreRoomsFromBundle(bundle);
+ }
+
+ Bundle badges = bundle.getBundle(BADGES);
+ if (!badges.isNull()) {
+ Badges.loadLocal(badges);
+ } else {
+ Badges.reset();
+ }
+
+ hero = null;
+ hero = (Hero) bundle.get(HERO);
+
+ gold = bundle.getInt(GOLD);
+ depth = bundle.getInt(DEPTH);
+
+ sacrifice = bundle.getInt(SACRIFICE);
+ ratChests = bundle.getInt(RATCHESTS);
+ earlygrass = bundle.getBoolean(EARLYGRASS);
+ gnollspawned = bundle.getBoolean(GNOLLSPAWN);
+ skeletonspawned = bundle.getBoolean(SKELETONSPAWN);
+ goldthiefspawned = bundle.getBoolean(THIEFSPAWN);
+ triforce = bundle.getBoolean(STRI);
+ triforceofcourage = bundle.getBoolean(STRID);
+ triforceofpower = bundle.getBoolean(STRIL);
+ triforceofwisdom = bundle.getBoolean(STRIT);
+ shadowyogkilled = bundle.getBoolean(SYOGKILL);
+ crabkingkilled = bundle.getBoolean(CRABKILL);
+ tengudenkilled = bundle.getBoolean(TENGUDENKILL);
+ banditkingkilled = bundle.getBoolean(BANDITKILL);
+ skeletonkingkilled = bundle.getBoolean(SKELETONKILL);
+ gnollkingkilled = bundle.getBoolean(GNOLLKILL);
+ zotkilled = bundle.getBoolean(ZOTKILL);
+ sporkAvail = bundle.getBoolean(SPORK);
+ challengebookdrop = bundle.getBoolean(CBDROP);
+ goeidrop = bundle.getBoolean(GOEIDROP);
+ dewDraw = bundle.getBoolean(DEWDRAW);
+ dewWater = bundle.getBoolean(DEWWATER);
+ wings = bundle.getBoolean(WINGS);
+ dewNorn = bundle.getBoolean(DEWNORN);
+ canSave = bundle.getBoolean(CANSAVE);
+ gnollmission = bundle.getBoolean(GNOLLMISSION);
+ oneDay = bundle.getBoolean(ONEDAY);
+ error = bundle.getBoolean(ERROR);
+ pars = bundle.getIntArray(PARS);
+
+ Statistics.restoreFromBundle(bundle);
+ Journal.restoreFromBundle(bundle);
+ //Generator.restoreFromBundle(bundle);
+
+ droppedItems = new SparseArray>();
+ for (int i = 2; i <= Statistics.realdeepestFloor + 1; i++) {
+ ArrayList
- dropped = new ArrayList
- ();
+ for (Bundlable b : bundle.getCollection(String.format(DROPPED, i))) {
+ dropped.add((Item) b);
+ }
+ if (!dropped.isEmpty()) {
+ droppedItems.put(i, dropped);
+ }
+ }
+ }
+ catch (IOException ex) {
+ GLog.i("Save File corrupt...\n\nthe gremlins have won this round!");
+ }
+ }
+
+ public static Level loadLevel(HeroClass cl) throws IOException {
+
+ Dungeon.level = null;
+ Actor.clear();
+
+ InputStream input = Game.instance.openFileInput(Messages.format(
+ depthFile(cl), depth));
+ Bundle bundle = Bundle.read(input);
+ input.close();
+
+ return (Level) bundle.get("level");
+ }
+
+ public static void deleteGame(HeroClass cl, boolean deleteLevels) {
+
+ Game.instance.deleteFile(gameFile(cl));
+
+ if (deleteLevels) {
+ int depth = 1;
+ while (Game.instance.deleteFile(Messages.format(depthFile(cl), depth))) {
+ depth++;
+ }
+ for(int i=1; i<200; i++){
+ Game.instance.deleteFile(Messages.format(depthFile(cl), i));
+ }
+ }
+
+ GamesInProgress.delete(cl);
+ }
+
+ public static Bundle gameBundle(String fileName) throws IOException {
+
+ InputStream input = Game.instance.openFileInput(fileName);
+ Bundle bundle = Bundle.read(input);
+ input.close();
+
+ return bundle;
+ }
+
+ public static void preview(GamesInProgress.Info info, Bundle bundle) {
+ info.depth = bundle.getInt(DEPTH);
+ info.challenges = (bundle.getInt(CHALLENGES) != 0);
+ if (info.depth == -1) {
+ info.depth = bundle.getInt("maxDepth"); // FIXME
+ }
+ Hero.preview(info, bundle.getBundle(HERO));
+ }
+
+ public static void fail( String desc ) {
+ resultDescription = desc;
+ if (hero.belongings.getItem(Ankh.class) == null) {
+ Rankings.INSTANCE.submit(false);
+ }
+ }
+
+ public static void win( String desc) {
+
+ hero.belongings.identify();
+
+ if (challenges != 0) {
+ Badges.validateChampion();
+ }
+
+ resultDescription = desc;
+ Rankings.INSTANCE.submit( true );
+ }
+
+ public static void observe() {
+
+ if (level == null) {
+ return;
+ }
+
+ if (level.darkness()){
+ level.visited = visible;
+ level.updateFieldOfView(hero);
+ System.arraycopy(Level.fieldOfView, 0, visible, 0, visible.length);
+ BArray.or(level.visited, visible, level.visited);
+ } else {
+
+ level.updateFieldOfView(hero);
+ System.arraycopy(Level.fieldOfView, 0, visible, 0, visible.length);
+
+ BArray.or(level.visited, visible, level.visited);
+ }
+
+ GameScene.afterObserve();
+ }
+
+ private static boolean[] passable = new boolean[Level.getLength()];
+
+
+ public static int findPath(Char ch, int from, int to, boolean pass[],
+ boolean[] visible) {
+
+ if (Level.adjacent(from, to)) {
+ return Actor.findChar(to) == null && (pass[to] || Level.avoid[to]) ? to
+ : -1;
+ }
+
+ if (ch.flying || ch.buff(Amok.class) != null) {
+ BArray.or(pass, Level.avoid, passable);
+ } else {
+ System.arraycopy(pass, 0, passable, 0, Level.getLength());
+ }
+
+ for (Actor actor : Actor.all()) {
+ if (actor instanceof Char) {
+ int pos = ((Char) actor).pos;
+ if (visible[pos]) {
+ passable[pos] = false;
+ }
+ }
+ }
+
+ return PathFinder.getStep(from, to, passable);
+
+ }
+
+ public static int flee(Char ch, int cur, int from, boolean pass[],
+ boolean[] visible) {
+
+ if (ch.flying) {
+ BArray.or(pass, Level.avoid, passable);
+ } else {
+ System.arraycopy(pass, 0, passable, 0, Level.getLength());
+ }
+
+ for (Actor actor : Actor.all()) {
+ if (actor instanceof Char) {
+ int pos = ((Char) actor).pos;
+ if (visible[pos]) {
+ passable[pos] = false;
+ }
+ }
+ }
+ passable[cur] = true;
+
+ return PathFinder.getStepBack(cur, from, passable);
+
+ }
+
+ public static boolean checkNight(){
+ int hour=Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
+ return (hour > 19 || hour < 7);
+ }
+
+ public static int getMonth(){
+ int month=Calendar.getInstance().get(Calendar.MONTH);
+ return month;
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/DungeonTilemap.java b/java/com/hmdzl/spspd/DungeonTilemap.java
new file mode 100644
index 00000000..30c85e3e
--- /dev/null
+++ b/java/com/hmdzl/spspd/DungeonTilemap.java
@@ -0,0 +1,99 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd;
+
+import com.hmdzl.spspd.levels.Level;
+import com.watabou.noosa.Image;
+import com.watabou.noosa.TextureFilm;
+import com.watabou.noosa.Tilemap;
+import com.watabou.noosa.tweeners.AlphaTweener;
+import com.watabou.utils.Point;
+import com.watabou.utils.PointF;
+
+public class DungeonTilemap extends Tilemap {
+
+ public static final int SIZE = 16;
+
+ private static DungeonTilemap instance;
+
+ public DungeonTilemap() {
+ super(Dungeon.level.tilesTex(), new TextureFilm(
+ Dungeon.level.tilesTex(), SIZE, SIZE));
+ map(Dungeon.level.map, Level.getWidth());
+
+ instance = this;
+ }
+
+ public int screenToTile(int x, int y) {
+ Point p = camera().screenToCamera(x, y).offset(this.point().negate())
+ .invScale(SIZE).floor();
+ return p.x >= 0 && p.x < Level.getWidth() && p.y >= 0 && p.y < Level.HEIGHT ? p.x
+ + p.y * Level.getWidth()
+ : -1;
+ }
+
+ @Override
+ public boolean overlapsPoint(float x, float y) {
+ return true;
+ }
+
+ public void discover(int pos, int oldValue) {
+
+ final Image tile = tile(oldValue);
+ tile.point(tileToWorld(pos));
+
+ // For bright mode
+ tile.rm = tile.gm = tile.bm = rm;
+ tile.ra = tile.ga = tile.ba = ra;
+ parent.add(tile);
+
+ parent.add(new AlphaTweener(tile, 0, 0.6f) {
+ @Override
+ protected void onComplete() {
+ tile.killAndErase();
+ killAndErase();
+ };
+ });
+ }
+
+ public static PointF tileToWorld(int pos) {
+ return new PointF(pos % Level.getWidth(), pos / Level.getWidth()).scale(SIZE);
+ }
+
+ public static PointF tileCenterToWorld(int pos) {
+ return new PointF((pos % Level.getWidth() + 0.5f) * SIZE,
+ (pos / Level.getWidth() + 0.5f) * SIZE);
+ }
+
+ public static Image tile(int index) {
+ Image img = new Image(instance.texture);
+ img.frame(instance.tileset.get(index));
+ return img;
+ }
+
+ public static PointF raisedTileCenterToWorld( int pos ) {
+ return new PointF(
+ (pos % Dungeon.level.WIDTH + 0.5f) * SIZE,
+ (pos / Dungeon.level.WIDTH + 0.1f) * SIZE );
+ }
+
+ @Override
+ public boolean overlapsScreenPoint(int x, int y) {
+ return true;
+ }
+}
diff --git a/java/com/hmdzl/spspd/FogOfWar.java b/java/com/hmdzl/spspd/FogOfWar.java
new file mode 100644
index 00000000..c7b41618
--- /dev/null
+++ b/java/com/hmdzl/spspd/FogOfWar.java
@@ -0,0 +1,117 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd;
+
+import java.util.Arrays;
+
+import android.graphics.Bitmap;
+
+import com.hmdzl.spspd.scenes.GameScene;
+import com.watabou.gltextures.SmartTexture;
+import com.watabou.gltextures.TextureCache;
+import com.watabou.glwrap.Texture;
+import com.watabou.noosa.Image;
+
+public class FogOfWar extends Image {
+
+ private static final int VISIBLE = 0x00000000;
+ private static final int VISITED = 0xcc111111;
+ private static final int MAPPED = 0xcc442211;
+ private static final int INVISIBLE = 0xFF000000;
+
+ private int[] pixels;
+
+ private int pWidth;
+ private int pHeight;
+
+ private int width2;
+ private int height2;
+
+ public FogOfWar(int mapWidth, int mapHeight) {
+
+ super();
+
+ pWidth = mapWidth + 1;
+ pHeight = mapHeight + 1;
+
+ width2 = 1;
+ while (width2 < pWidth) {
+ width2 <<= 1;
+ }
+
+ height2 = 1;
+ while (height2 < pHeight) {
+ height2 <<= 1;
+ }
+
+ float size = DungeonTilemap.SIZE;
+ width = width2 * size;
+ height = height2 * size;
+
+ texture(new FogTexture());
+
+ scale.set(DungeonTilemap.SIZE, DungeonTilemap.SIZE);
+
+ x = y = -size / 2;
+ }
+
+ public void updateVisibility(boolean[] visible, boolean[] visited,
+ boolean[] mapped) {
+
+ if (pixels == null) {
+ pixels = new int[width2 * height2];
+ Arrays.fill(pixels, INVISIBLE);
+ }
+
+ for (int i = 1; i < pHeight - 1; i++) {
+ int pos = (pWidth - 1) * i;
+ for (int j = 1; j < pWidth - 1; j++) {
+ pos++;
+ int c = INVISIBLE;
+ if (visible[pos] && visible[pos - (pWidth - 1)]
+ && visible[pos - 1] && visible[pos - (pWidth - 1) - 1]) {
+ c = VISIBLE;
+ } else if (visited[pos] && visited[pos - (pWidth - 1)]
+ && visited[pos - 1] && visited[pos - (pWidth - 1) - 1]) {
+ c = VISITED;
+ } else if (mapped[pos] && mapped[pos - (pWidth - 1)]
+ && mapped[pos - 1] && mapped[pos - (pWidth - 1) - 1]) {
+ c = MAPPED;
+ }
+ pixels[i * width2 + j] = c;
+ }
+ }
+
+ texture.pixels(width2, height2, pixels);
+ }
+
+ private class FogTexture extends SmartTexture {
+
+ public FogTexture() {
+ super(Bitmap.createBitmap(width2, height2, Bitmap.Config.ARGB_8888));
+ filter(Texture.LINEAR, Texture.LINEAR);
+ TextureCache.add(FogOfWar.class, this);
+ }
+
+ @Override
+ public void reload() {
+ super.reload();
+ GameScene.afterObserve();
+ }
+ }
+}
diff --git a/java/com/hmdzl/spspd/GamesInProgress.java b/java/com/hmdzl/spspd/GamesInProgress.java
new file mode 100644
index 00000000..89f82b01
--- /dev/null
+++ b/java/com/hmdzl/spspd/GamesInProgress.java
@@ -0,0 +1,79 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd;
+
+import java.util.HashMap;
+
+import com.hmdzl.spspd.actors.hero.HeroClass;
+import com.watabou.utils.Bundle;
+
+public class GamesInProgress {
+
+ //private static HashMap state = new HashMap();
+ private static HashMap state = new HashMap<>();
+
+ public static Info check(HeroClass cl) {
+
+ if (state.containsKey(cl)) {
+
+ return state.get(cl);
+
+ } else {
+
+ Info info;
+ try {
+
+ Bundle bundle = Dungeon.gameBundle(Dungeon.gameFile(cl));
+ info = new Info();
+ Dungeon.preview(info, bundle);
+
+ } catch (Exception e) {
+ info = null;
+ }
+
+ state.put(cl, info);
+ return info;
+
+ }
+ }
+
+ public static void set(HeroClass cl, int depth, int level, int skins,
+ boolean challenges) {
+ Info info = new Info();
+ info.depth = depth;
+ info.level = level;
+ info.skins = skins;
+ info.challenges = challenges;
+ state.put(cl, info);
+ }
+
+ public static void setUnknown(HeroClass cl) {
+ state.remove(cl);
+ }
+
+ public static void delete(HeroClass cl) {
+ state.put(cl, null);
+ }
+
+ public static class Info {
+ public int depth;
+ public int level;
+ public int skins;
+ public boolean challenges;
+ }
+}
diff --git a/java/com/hmdzl/spspd/Journal.java b/java/com/hmdzl/spspd/Journal.java
new file mode 100644
index 00000000..385b26d7
--- /dev/null
+++ b/java/com/hmdzl/spspd/Journal.java
@@ -0,0 +1,123 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd;
+
+import java.util.ArrayList;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.watabou.utils.Bundlable;
+import com.watabou.utils.Bundle;
+
+public class Journal {
+
+ public enum Feature {
+ WELL_OF_HEALTH,
+ WELL_OF_AWARENESS,
+ WELL_OF_TRANSMUTATION,
+ ALCHEMY,
+ GARDEN,
+ STATUE,
+
+ GHOST,
+ WANDMAKER,
+ TROLL,
+ IMP,
+
+ MEMORY_FIRE;
+
+ public String desc() {
+ return Messages.get(this, name());
+ }
+ };
+
+ public static class Record implements Comparable, Bundlable {
+
+ private static final String FEATURE = "feature";
+ private static final String DEPTH = "depth";
+
+ public Feature feature;
+ public int depth;
+
+ public Record() {
+ }
+
+ public Record(Feature feature, int depth) {
+ this.feature = feature;
+ this.depth = depth;
+ }
+
+ @Override
+ public int compareTo(Record another) {
+ return another.depth - depth;
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ feature = Feature.valueOf(bundle.getString(FEATURE));
+ depth = bundle.getInt(DEPTH);
+ }
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ bundle.put(FEATURE, feature.toString());
+ bundle.put(DEPTH, depth);
+ }
+ }
+
+ public static ArrayList records;
+
+ public static void reset() {
+ records = new ArrayList();
+ }
+
+ private static final String JOURNAL = "journal";
+
+ public static void storeInBundle(Bundle bundle) {
+ bundle.put(JOURNAL, records);
+ }
+
+ public static void restoreFromBundle(Bundle bundle) {
+ records = new ArrayList();
+ for (Bundlable rec : bundle.getCollection(JOURNAL)) {
+ records.add((Record) rec);
+ }
+ }
+
+ public static void add(Feature feature) {
+ int size = records.size();
+ for (int i = 0; i < size; i++) {
+ Record rec = records.get(i);
+ if (rec.feature == feature && rec.depth == Dungeon.depth) {
+ return;
+ }
+ }
+
+ records.add(new Record(feature, Dungeon.depth));
+ }
+
+ public static void remove(Feature feature) {
+ int size = records.size();
+ for (int i = 0; i < size; i++) {
+ Record rec = records.get(i);
+ if (rec.feature == feature && rec.depth == Dungeon.depth) {
+ records.remove(i);
+ return;
+ }
+ }
+ }
+}
diff --git a/java/com/hmdzl/spspd/Preferences.java b/java/com/hmdzl/spspd/Preferences.java
new file mode 100644
index 00000000..35628016
--- /dev/null
+++ b/java/com/hmdzl/spspd/Preferences.java
@@ -0,0 +1,75 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd;
+
+import android.content.SharedPreferences;
+
+import com.watabou.noosa.Game;
+
+enum Preferences {
+
+ INSTANCE;
+
+ public static final String KEY_LANDSCAPE = "landscape";
+ public static final String KEY_IMMERSIVE = "immersive";
+ public static final String KEY_SCALE_UP = "scaleup";
+ public static final String KEY_MUSIC = "music";
+ public static final String KEY_SOUND_FX = "soundfx";
+ public static final String KEY_ZOOM = "zoom";
+ public static final String KEY_LAST_CLASS = "last_class";
+ public static final String KEY_CHALLENGES = "challenges";
+ public static final String KEY_QUICKSLOTS = "quickslots";
+ public static final String KEY_LANG = "language";
+ public static final String KEY_CLASSICFONT = "classic_font";
+ public static final String KEY_INTRO = "intro";
+ public static final String KEY_BRIGHTNESS = "brightness";
+ public static final String KEY_VERSION = "version";
+
+ private SharedPreferences prefs;
+
+ private SharedPreferences get() {
+ if (prefs == null) {
+ prefs = Game.instance.getPreferences(Game.MODE_PRIVATE);
+ }
+ return prefs;
+ }
+
+ int getInt(String key, int defValue) {
+ return get().getInt(key, defValue);
+ }
+
+ boolean getBoolean(String key, boolean defValue) {
+ return get().getBoolean(key, defValue);
+ }
+
+ String getString(String key, String defValue) {
+ return get().getString(key, defValue);
+ }
+
+ void put(String key, int value) {
+ get().edit().putInt(key, value).commit();
+ }
+
+ void put(String key, boolean value) {
+ get().edit().putBoolean(key, value).commit();
+ }
+
+ void put(String key, String value) {
+ get().edit().putString(key, value).commit();
+ }
+}
diff --git a/java/com/hmdzl/spspd/QuickSlot.java b/java/com/hmdzl/spspd/QuickSlot.java
new file mode 100644
index 00000000..24b4149a
--- /dev/null
+++ b/java/com/hmdzl/spspd/QuickSlot.java
@@ -0,0 +1,134 @@
+package com.hmdzl.spspd;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import com.hmdzl.spspd.items.Item;
+import com.watabou.utils.Bundlable;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Random;
+
+/**
+ * Created by debenhame on 16/01/2015.
+ */
+public class QuickSlot {
+
+ /**
+ * Slots contain objects which are also in a player's inventory. The one
+ * exception to this is when quantity is 0, which can happen for a stackable
+ * item that has been 'used up', these are refered to a placeholders.
+ */
+
+ // note that the current max size is coded at 4, due to UI constraints, but
+ // it could be much much bigger with no issue.
+ public static int SIZE = 6;
+ private Item[] slots = new Item[SIZE];
+
+ // direct array interaction methods, everything should build from these
+ // methods.
+ public void setSlot(int slot, Item item) {
+ clearItem(item); // we don't want to allow the same item in multiple
+ // slots.
+ slots[slot] = item;
+ }
+
+ public void clearSlot(int slot) {
+ slots[slot] = null;
+ }
+
+ public void reset() {
+ slots = new Item[SIZE];
+ }
+
+ public Item getItem(int slot) {
+ return slots[slot];
+ }
+
+ // utility methods, for easier use of the internal array.
+ public int getSlot(Item item) {
+ for (int i = 0; i < SIZE; i++)
+ if (getItem(i) == item)
+ return i;
+ return -1;
+ }
+
+ public Boolean isPlaceholder(int slot) {
+ return getItem(slot) != null && getItem(slot).quantity() == 0;
+ }
+
+ public Boolean isNonePlaceholder(int slot) {
+ return getItem(slot) != null && getItem(slot).quantity() > 0;
+ }
+
+ public void clearItem(Item item) {
+ if (contains(item))
+ clearSlot(getSlot(item));
+ }
+
+ public boolean contains(Item item) {
+ return getSlot(item) != -1;
+ }
+
+ public void replaceSimilar(Item item) {
+ for (int i = 0; i < SIZE; i++)
+ if (getItem(i) != null && item.isSimilar(getItem(i)))
+ setSlot(i, item);
+ }
+
+ public void convertToPlaceholder(Item item) {
+ Item placeholder = Item.virtual(item.getClass());
+
+ if (placeholder != null && contains(item))
+ for (int i = 0; i < SIZE; i++)
+ if (getItem(i) == item)
+ setSlot(i, placeholder);
+ }
+
+ public Item randomNonePlaceholder() {
+
+ ArrayList
- result = new ArrayList
- ();
+ for (int i = 0; i < SIZE; i++)
+ if (getItem(i) != null && !isPlaceholder(i))
+ result.add(getItem(i));
+
+ return Random.element(result);
+ }
+
+ private final String PLACEHOLDERS = "placeholders";
+ private final String PLACEMENTS = "placements";
+
+ /**
+ * Placements array is used as order is preserved while bundling, but exact
+ * index is not, so if we bundle both the placeholders (which preserves
+ * their order) and an array telling us where the placeholders are, we can
+ * reconstruct them perfectly.
+ */
+
+ public void storePlaceholders(Bundle bundle) {
+ ArrayList
- placeholders = new ArrayList
- (SIZE);
+ boolean[] placements = new boolean[SIZE];
+
+ for (int i = 0; i < SIZE; i++)
+ if (isPlaceholder(i)) {
+ placeholders.add(getItem(i));
+ placements[i] = true;
+ }
+ bundle.put(PLACEHOLDERS, placeholders);
+ bundle.put(PLACEMENTS, placements);
+ }
+
+ public void restorePlaceholders(Bundle bundle) {
+ Collection placeholders = bundle.getCollection(PLACEHOLDERS);
+ boolean[] placements = bundle.getBooleanArray(PLACEMENTS);
+
+ int i = 0;
+ for (Bundlable item : placeholders) {
+ while (!placements[i])
+ i++;
+ setSlot(i, (Item) item);
+ i++;
+ }
+
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/Rankings.java b/java/com/hmdzl/spspd/Rankings.java
new file mode 100644
index 00000000..dffe00d1
--- /dev/null
+++ b/java/com/hmdzl/spspd/Rankings.java
@@ -0,0 +1,225 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+import com.hmdzl.spspd.actors.hero.HeroClass;
+import com.hmdzl.spspd.messages.Messages;
+import com.watabou.noosa.Game;
+import com.watabou.utils.Bundlable;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.SystemTime;
+
+public enum Rankings {
+
+ INSTANCE;
+
+ public static final int TABLE_SIZE = 11;
+
+ public static final String RANKINGS_FILE = "rankings.dat";
+ public static final String DETAILS_FILE = "game_%d.dat";
+
+ public ArrayList records;
+ public int lastRecord;
+ public int totalNumber;
+ public int wonNumber;
+
+ public void submit(boolean win) {
+
+ load();
+
+ Record rec = new Record();
+
+ rec.info = Dungeon.resultDescription;
+ rec.win = win;
+ rec.heroClass = Dungeon.hero.heroClass;
+ rec.skin = 7-Dungeon.skins;
+ rec.herolevel = Dungeon.hero.lvl;
+ rec.depth = Dungeon.depth;
+ rec.score = score(win);
+
+ String gameFile = Messages.format( DETAILS_FILE, SystemTime.now );
+ try {
+ Dungeon.saveGame(gameFile);
+ rec.gameFile = gameFile;
+ } catch (IOException e) {
+ rec.gameFile = "";
+ }
+
+ records.add(rec);
+
+ Collections.sort(records, scoreComparator);
+
+ lastRecord = records.indexOf(rec);
+ int size = records.size();
+ while (size > TABLE_SIZE) {
+
+ Record removedGame;
+ if (lastRecord == size - 1) {
+ removedGame = records.remove(size - 2);
+ lastRecord--;
+ } else {
+ removedGame = records.remove(size - 1);
+ }
+
+ if (removedGame.gameFile.length() > 0) {
+ Game.instance.deleteFile(removedGame.gameFile);
+ }
+
+ size = records.size();
+ }
+
+ totalNumber++;
+ if (win) {
+ wonNumber++;
+ }
+
+ Badges.validateGamesPlayed();
+
+ save();
+ }
+
+ private int score(boolean win) {
+ return (Statistics.goldCollected + Dungeon.hero.lvl
+ * (win ? 26 : Dungeon.depth) * 100)
+ * (win ? 2 : 1);
+ }
+
+ private static final String RECORDS = "records";
+ private static final String LATEST = "latest";
+ private static final String TOTAL = "total";
+ private static final String WON = "won";
+
+ public void save() {
+ Bundle bundle = new Bundle();
+ bundle.put(RECORDS, records);
+ bundle.put(LATEST, lastRecord);
+ bundle.put(TOTAL, totalNumber);
+ bundle.put(WON, wonNumber);
+
+ try {
+ OutputStream output = Game.instance.openFileOutput(RANKINGS_FILE,
+ Game.MODE_PRIVATE);
+ Bundle.write(bundle, output);
+ output.close();
+ } catch (IOException e) {
+ }
+ }
+
+ public void load() {
+
+ if (records != null) {
+ return;
+ }
+
+ records = new ArrayList();
+
+ try {
+ InputStream input = Game.instance.openFileInput(RANKINGS_FILE);
+ Bundle bundle = Bundle.read(input);
+ input.close();
+
+ for (Bundlable record : bundle.getCollection(RECORDS)) {
+ records.add((Record) record);
+ }
+ lastRecord = bundle.getInt(LATEST);
+
+ totalNumber = bundle.getInt(TOTAL);
+ if (totalNumber == 0) {
+ totalNumber = records.size();
+ }
+
+ wonNumber = bundle.getInt(WON);
+ if (wonNumber == 0) {
+ for (Record rec : records) {
+ if (rec.win) {
+ wonNumber++;
+ }
+ }
+ }
+
+ } catch (IOException e) {
+
+ }
+ }
+
+ public static class Record implements Bundlable {
+
+ private static final String REASON = "reason";
+ private static final String WIN = "win";
+ private static final String SCORE = "score";
+ private static final String SKIN = "skin";
+ private static final String LEVEL = "level";
+ private static final String DEPTH = "depth";
+ private static final String GAME = "gameFile";
+
+ public String info;
+ public boolean win;
+
+ public HeroClass heroClass;
+ public int skin;
+ public int herolevel;
+ public int depth;
+
+ public int score;
+
+ public String gameFile;
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+
+ info = bundle.getString(REASON);
+ win = bundle.getBoolean(WIN);
+ score = bundle.getInt(SCORE);
+ heroClass = HeroClass.restoreInBundle(bundle);
+ skin = bundle.getInt(SKIN);
+ gameFile = bundle.getString(GAME);
+ depth = bundle.getInt(DEPTH);
+ herolevel = bundle.getInt(LEVEL);
+
+ }
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+
+ bundle.put(REASON, info);
+ bundle.put(WIN, win);
+ bundle.put(SCORE, score);
+
+ heroClass.storeInBundle(bundle);
+ bundle.put(SKIN, skin);
+ bundle.put(LEVEL, herolevel);
+ bundle.put(DEPTH, depth);
+
+ bundle.put(GAME, gameFile);
+ }
+ }
+
+ private static final Comparator scoreComparator = new Comparator() {
+ @Override
+ public int compare(Record lhs, Record rhs) {
+ return (int) Math.signum(rhs.score - lhs.score);
+ }
+ };
+}
diff --git a/java/com/hmdzl/spspd/ResultDescriptions.java b/java/com/hmdzl/spspd/ResultDescriptions.java
new file mode 100644
index 00000000..9de71acb
--- /dev/null
+++ b/java/com/hmdzl/spspd/ResultDescriptions.java
@@ -0,0 +1,49 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd;
+
+import com.hmdzl.spspd.messages.Messages;
+
+public class ResultDescriptions {
+
+ // Mobs
+ public static final String MOB = "MOB";
+ public static final String UNIQUE = "UNIQUE";
+ public static final String NAMED = "NAMED";
+
+ // Items
+ public static final String ITEM = "ITEM";
+ public static final String GLYPH = "GLYPH";
+
+ // Dungeon features
+ public static final String TRAP = "TRAP";
+
+ // Debuffs & blobs
+ public static final String BURNING = "BURNING";
+ public static final String HUNGER = "HUNGER";
+ public static final String POISON = "POISON";
+ public static final String GAS = "GAS";
+ public static final String BLEEDING = "BLEEDING";
+ public static final String OOZE = "OOZE";
+ public static final String FALL = "FALL";
+ public static final String COUNTDOWN = "COUNTDOWN";
+ public static final String CHEAT = "CHEAT";
+
+ public static final String WIN = "WIN";
+ public static final String WIN2 = "WIN2";
+}
diff --git a/java/com/hmdzl/spspd/SPSSettings.java b/java/com/hmdzl/spspd/SPSSettings.java
new file mode 100644
index 00000000..55d0f302
--- /dev/null
+++ b/java/com/hmdzl/spspd/SPSSettings.java
@@ -0,0 +1,129 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2017 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.hmdzl.spspd;
+
+import com.hmdzl.spspd.messages.Languages;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.watabou.noosa.Game;
+import com.watabou.noosa.RenderedText;
+import com.watabou.noosa.audio.Music;
+import com.watabou.noosa.audio.Sample;
+import com.watabou.utils.GameSettings;
+
+import java.util.Locale;
+
+public class SPSSettings extends GameSettings {
+
+ //Version info
+
+ public static final String KEY_VERSION = "version";
+
+ public static void version( int value) {
+ put( KEY_VERSION, value );
+ }
+
+ public static int version() {
+ return getInt( KEY_VERSION, 0 );
+ }
+
+ //Graphics
+
+ public static final String KEY_LANDSCAPE = "landscape";
+ public static final String KEY_SCALE = "scale";
+ public static final String KEY_ZOOM = "zoom";
+
+ public static boolean landscape() {
+ return getBoolean(KEY_LANDSCAPE, Game.dispWidth > Game.dispHeight);
+ }
+
+ public static void scale( int value ) {
+ put( KEY_SCALE, value );
+ }
+
+ public static int scale() {
+ return getInt( KEY_SCALE, 0 );
+ }
+
+ public static void zoom( int value ) {
+ put( KEY_ZOOM, value );
+ }
+
+ public static int zoom() {
+ return getInt( KEY_ZOOM, 0 );
+ }
+
+ //Interface
+
+ //Game State
+
+ public static final String KEY_CHALLENGES = "challenges";
+
+ public static void challenges( int value ) {
+ put( KEY_CHALLENGES, value );
+ }
+
+ //Audio
+
+ public static final String KEY_MUSIC = "music";
+
+ public static void music( boolean value ) {
+ Music.INSTANCE.enable( value );
+ put( KEY_MUSIC, value );
+ }
+
+ public static boolean music() {
+ return getBoolean( KEY_MUSIC, true );
+ }
+
+ //Languages and Font
+
+ public static final String KEY_LANG = "language";
+ public static final String KEY_SYSTEMFONT = "system_font";
+
+ public static void language(Languages lang) {
+ put( KEY_LANG, lang.code());
+ }
+
+ public static Languages language() {
+ String code = getString(KEY_LANG, null);
+ if (code == null){
+ return Languages.matchLocale(Locale.getDefault());
+ } else {
+ return Languages.matchCode(code);
+ }
+ }
+
+ public static void systemFont(boolean value){
+ put(KEY_SYSTEMFONT, value);
+ if (!value) {
+ RenderedText.setFont("pixelfont.ttf");
+ } else {
+ RenderedText.setFont( null );
+ }
+ }
+
+ public static boolean systemFont(){
+ return getBoolean(KEY_SYSTEMFONT,
+ (/*language() == Languages.KOREAN ||*/ language() == Languages.CHINESE));
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/ShatteredPixelDungeon.java b/java/com/hmdzl/spspd/ShatteredPixelDungeon.java
new file mode 100644
index 00000000..ccb89442
--- /dev/null
+++ b/java/com/hmdzl/spspd/ShatteredPixelDungeon.java
@@ -0,0 +1,334 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd;
+
+import javax.microedition.khronos.opengles.GL10;
+
+import android.annotation.SuppressLint;
+import android.content.pm.ActivityInfo;
+import android.os.Build;
+import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.View;
+
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.scenes.PixelScene;
+import com.hmdzl.spspd.scenes.TitleScene;
+import com.hmdzl.spspd.scenes.WelcomeScene;
+import com.watabou.noosa.Game;
+import com.watabou.noosa.audio.Music;
+import com.watabou.noosa.audio.Sample;
+import com.watabou.noosa.RenderedText;
+
+public class ShatteredPixelDungeon extends Game {
+
+ public ShatteredPixelDungeon() {
+ super(WelcomeScene.class);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ updateImmersiveMode();
+
+ DisplayMetrics metrics = new DisplayMetrics();
+ instance.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ boolean landscape = metrics.widthPixels > metrics.heightPixels;
+
+ if (Preferences.INSTANCE.getBoolean(Preferences.KEY_LANDSCAPE, false) != landscape) {
+ landscape(!landscape);
+ }
+
+ Music.INSTANCE.enable(music());
+ Sample.INSTANCE.enable(soundFx());
+
+ Sample.INSTANCE.load(Assets.SND_CLICK, Assets.SND_BADGE,
+ Assets.SND_GOLD,
+
+ Assets.SND_STEP, Assets.SND_WATER, Assets.SND_OPEN,
+ Assets.SND_UNLOCK, Assets.SND_ITEM, Assets.SND_DEWDROP,
+ Assets.SND_HIT, Assets.SND_MISS,
+
+ Assets.SND_DESCEND, Assets.SND_EAT, Assets.SND_READ,
+ Assets.SND_LULLABY, Assets.SND_DRINK, Assets.SND_SHATTER,
+ Assets.SND_ZAP, Assets.SND_LIGHTNING, Assets.SND_LEVELUP,
+ Assets.SND_DEATH, Assets.SND_CHALLENGE, Assets.SND_CURSED,
+ Assets.SND_EVOKE, Assets.SND_TRAP, Assets.SND_TOMB,
+ Assets.SND_ALERT, Assets.SND_MELD, Assets.SND_BOSS,
+ Assets.SND_BLAST, Assets.SND_PLANT, Assets.SND_RAY,
+ Assets.SND_BEACON, Assets.SND_TELEPORT, Assets.SND_CHARMS,
+ Assets.SND_MASTERY, Assets.SND_PUFF, Assets.SND_ROCKS,
+ Assets.SND_BURNING, Assets.SND_FALLING, Assets.SND_GHOST,
+ Assets.SND_SECRET, Assets.SND_BONES, Assets.SND_BEE,
+ Assets.SND_DEGRADE, Assets.SND_MIMIC);
+
+ if (!SPSSettings.systemFont()) {
+ RenderedText.setFont("pixelfont.ttf");
+ } else {
+ RenderedText.setFont( null );
+ }
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+
+ super.onWindowFocusChanged(hasFocus);
+
+ if (hasFocus) {
+ updateImmersiveMode();
+ }
+ }
+
+ public static void switchNoFade(Class extends PixelScene> c){
+ switchNoFade(c, null);
+ }
+
+ public static void switchNoFade(Class extends PixelScene> c, SceneChangeCallback callback) {
+ PixelScene.noFade = true;
+ switchScene( c, callback );
+ }
+
+ /*
+ * ---> Prefernces
+ */
+
+ public static void landscape(boolean value) {
+ Game.instance
+ .setRequestedOrientation(value ?
+ ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
+ : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ Preferences.INSTANCE.put(Preferences.KEY_LANDSCAPE, value);
+ }
+
+ public static boolean landscape() {
+ return width > height;
+ }
+
+ public static void scaleUp(boolean value) {
+ Preferences.INSTANCE.put(Preferences.KEY_SCALE_UP, value);
+ switchScene(TitleScene.class);
+ }
+
+ // *** IMMERSIVE MODE ****
+
+ private static boolean immersiveModeChanged = false;
+
+ @SuppressLint("NewApi")
+ public static void immerse(boolean value) {
+ Preferences.INSTANCE.put(Preferences.KEY_IMMERSIVE, value);
+
+ instance.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ updateImmersiveMode();
+ immersiveModeChanged = true;
+ }
+ });
+ }
+
+ @Override
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ super.onSurfaceChanged(gl, width, height);
+
+ if (immersiveModeChanged) {
+ requestedReset = true;
+ immersiveModeChanged = false;
+ }
+ }
+
+ private void updateDisplaySize(){
+ DisplayMetrics m = new DisplayMetrics();
+ if (immersed() && Build.VERSION.SDK_INT >= 19)
+ getWindowManager().getDefaultDisplay().getRealMetrics( m );
+ else
+ getWindowManager().getDefaultDisplay().getMetrics( m );
+ dispHeight = m.heightPixels;
+ dispWidth = m.widthPixels;
+
+ float dispRatio = dispWidth / (float)dispHeight;
+
+ float renderWidth = dispRatio > 1 ? PixelScene.MIN_WIDTH_L : PixelScene.MIN_WIDTH_P;
+ float renderHeight = dispRatio > 1 ? PixelScene.MIN_HEIGHT_L : PixelScene.MIN_HEIGHT_P;
+
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ view.getHolder().setSizeFromLayout();
+ }
+ });
+
+ }
+
+ @SuppressLint("NewApi")
+ public static void updateImmersiveMode() {
+ if (android.os.Build.VERSION.SDK_INT >= 19) {
+ try {
+ // Sometime NullPointerException happens here
+ instance.getWindow()
+ .getDecorView()
+ .setSystemUiVisibility(
+ immersed() ? View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+ : 0);
+ } catch (Exception e) {
+ reportException(e);
+ }
+ }
+ }
+
+ public static boolean immersed() {
+ return Preferences.INSTANCE
+ .getBoolean(Preferences.KEY_IMMERSIVE, false);
+ }
+
+ // *****************************
+
+ public static boolean scaleUp() {
+ return Preferences.INSTANCE.getBoolean(Preferences.KEY_SCALE_UP, true);
+ }
+
+ public static void zoom(int value) {
+ Preferences.INSTANCE.put(Preferences.KEY_ZOOM, value);
+ }
+
+ public static int zoom() {
+ return Preferences.INSTANCE.getInt(Preferences.KEY_ZOOM, 0);
+ }
+
+ public static void music(boolean value) {
+ Music.INSTANCE.enable(value);
+ Preferences.INSTANCE.put(Preferences.KEY_MUSIC, value);
+ }
+
+ public static boolean music() {
+ return Preferences.INSTANCE.getBoolean(Preferences.KEY_MUSIC, true);
+ }
+
+ public static void soundFx(boolean value) {
+ Sample.INSTANCE.enable(value);
+ Preferences.INSTANCE.put(Preferences.KEY_SOUND_FX, value);
+ }
+
+ public static boolean soundFx() {
+ return Preferences.INSTANCE.getBoolean(Preferences.KEY_SOUND_FX, true);
+ }
+
+ public static void brightness(boolean value) {
+ Preferences.INSTANCE.put(Preferences.KEY_BRIGHTNESS, value);
+ if (scene() instanceof GameScene) {
+ ((GameScene) scene()).brightness(value);
+ }
+ }
+
+ public static boolean brightness() {
+ return Preferences.INSTANCE.getBoolean(Preferences.KEY_BRIGHTNESS,
+ false);
+ }
+
+ /*public static void language(Languages lang) {
+ Preferences.INSTANCE.put( Preferences.KEY_LANG, lang.code());
+ if (lang == Languages.RUSSIAN || lang == Languages.CHINESE || lang == Languages.KOREAN)
+ RenderedText.setFont(null);
+ else if (classicFont())
+ RenderedText.setFont("pixelfont.ttf");
+ }*/
+
+ /*public static Languages language() {
+ String code = Preferences.INSTANCE.getString(Preferences.KEY_LANG, null);
+ if (code == null){
+ Languages lang = Languages.matchLocale(Locale.getDefault());
+ if (lang.status() == Languages.Status.REVIEWED)
+ return lang;
+ else
+ return Languages.ENGLISH;
+ }
+ else return Languages.matchCode(code);
+ }*/
+
+ /*public static void classicFont(boolean classic){
+ Preferences.INSTANCE.put(Preferences.KEY_CLASSICFONT, classic);
+ if (classic) {
+ RenderedText.setFont("pixelfont.ttf");
+ } else {
+ RenderedText.setFont( null );
+ }
+ }*/
+
+ /*public static boolean classicFont(){
+ Languages lang = ShatteredPixelDungeon.language();
+ if (lang == Languages.RUSSIAN ||lang == Languages.CHINESE || lang == Languages.KOREAN )
+ return false;
+ else
+ return Preferences.INSTANCE.getBoolean(Preferences.KEY_CLASSICFONT, true);
+ } */
+
+ public static void lastClass(int value) {
+ Preferences.INSTANCE.put(Preferences.KEY_LAST_CLASS, value);
+ }
+
+ public static int lastClass() {
+ return Preferences.INSTANCE.getInt(Preferences.KEY_LAST_CLASS, 0);
+ }
+
+ public static void challenges(int value) {
+ Preferences.INSTANCE.put(Preferences.KEY_CHALLENGES, value);
+ }
+
+ public static int challenges() {
+ return Preferences.INSTANCE.getInt(Preferences.KEY_CHALLENGES, 0);
+ }
+
+ public static void quickSlots(int value) {
+ Preferences.INSTANCE.put(Preferences.KEY_QUICKSLOTS, value);
+ }
+
+ public static int quickSlots() {
+ return Preferences.INSTANCE.getInt(Preferences.KEY_QUICKSLOTS, 1);
+ }
+
+ public static void intro(boolean value) {
+ Preferences.INSTANCE.put(Preferences.KEY_INTRO, value);
+ }
+
+ public static boolean intro() {
+ return Preferences.INSTANCE.getBoolean(Preferences.KEY_INTRO, true);
+ }
+
+ public static void version(int value) {
+ Preferences.INSTANCE.put(Preferences.KEY_VERSION, value);
+ }
+
+ public static int version() {
+ return Preferences.INSTANCE.getInt(Preferences.KEY_VERSION, 0);
+ }
+
+ /*
+ * <--- Preferences
+ */
+
+ public static void reportException(Throwable tr) {
+ Log.e("PD", Log.getStackTraceString(tr));
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/Skins.java b/java/com/hmdzl/spspd/Skins.java
new file mode 100644
index 00000000..2e8fa409
--- /dev/null
+++ b/java/com/hmdzl/spspd/Skins.java
@@ -0,0 +1,37 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd;
+
+public class Skins {
+
+ public static final int NORMAL = 0;
+ public static final int FIRST = 1;
+ public static final int SECOND = 2;
+ public static final int THIRD = 3;
+
+ public static final String[] NAME_IDS = {
+ "normal",
+ "first",
+ "second",
+ "third",
+ };
+
+ public static final int[] MASKS = {
+ NORMAL, FIRST,SECOND,THIRD};
+
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/Statistics.java b/java/com/hmdzl/spspd/Statistics.java
new file mode 100644
index 00000000..e76f66a3
--- /dev/null
+++ b/java/com/hmdzl/spspd/Statistics.java
@@ -0,0 +1,197 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd;
+
+import com.watabou.utils.Bundle;
+
+//move target 300 + d3*lvl
+
+public class Statistics {
+
+ public static int goldCollected;
+ public static int deepestFloor;
+ public static int realdeepestFloor;
+ public static int enemiesSlain;
+ public static int foodEaten;
+ public static int eggBreak;
+ public static int potionsCooked;
+ public static int piranhasKilled;
+ public static int archersKilled;
+ public static int skeletonsKilled;
+ public static int assassinsKilled;
+ public static int albinoPiranhasKilled;
+ public static int goldThievesKilled;
+ public static int shadowYogsKilled;
+ public static int nightHunt;
+ public static int ankhsUsed;
+ public static int ballsCooked;
+ public static int waters;
+ public static int sewerKills;
+ public static int prisonKills;
+ public static int petDies;
+
+ public static float duration;
+ public static int floormoves;
+ public static int prevfloormoves;
+ public static int moves;
+ public static float time;
+
+
+ public static boolean qualifiedForNoKilling = false;
+ public static boolean completedWithNoKilling = false;
+
+
+ public static boolean amuletObtained = false;
+ public static boolean orbObtained = false;
+
+
+ public static void reset() {
+
+ goldCollected = 0;
+ deepestFloor = 0;
+ realdeepestFloor = 0;
+ enemiesSlain = 0;
+ foodEaten = 0;
+ eggBreak = 0;
+ potionsCooked = 0;
+
+ piranhasKilled = 0;
+ archersKilled = 0;
+ assassinsKilled = 0;
+ skeletonsKilled = 0;
+ albinoPiranhasKilled = 0;
+ goldThievesKilled = 0;
+ shadowYogsKilled = 0;
+ nightHunt = 0;
+ ankhsUsed = 0;
+ ballsCooked = 0;
+ waters = 0;
+ sewerKills = 0;
+ prisonKills = 0;
+ petDies = 0;
+
+ duration = 0;
+ moves = 0;
+ floormoves = 0;
+ prevfloormoves = 0;
+ time = 360;
+
+ qualifiedForNoKilling = false;
+
+ amuletObtained = false;
+ orbObtained = false;
+
+ }
+
+ private static final String GOLD = "score";
+ private static final String DEEPEST = "maxDepth";
+ private static final String REALDEEPEST = "maxDepthReal";
+ private static final String SLAIN = "enemiesSlain";
+ private static final String FOOD = "foodEaten";
+ private static final String EGG = "eggBreak";
+ private static final String ALCHEMY = "potionsCooked";
+ private static final String PIRANHAS = "priranhas";
+ private static final String WATERS = "waters";
+
+ private static final String ARCHERS = "archers";
+ private static final String SKELETONS = "skeletons";
+ private static final String ASSASSINS = "assassins";
+ private static final String APIRANHAS = "apiranhas";
+ private static final String THIEVES = "thieves";
+ private static final String SYOGS = "syogs";
+ private static final String BALLS = "balls";
+ private static final String PRISONKILLS = "prisonKills";
+ private static final String SEWERKILLS = "sewerKills";
+ private static final String PETDIES = "petDies";
+
+ private static final String NIGHT = "nightHunt";
+ private static final String ANKHS = "ankhsUsed";
+ private static final String DURATION = "duration";
+ private static final String FLOORMOVES = "floormoves";
+ private static final String PREVFLOORMOVES = "prevfloormoves";
+ private static final String MOVES = "moves";
+ private static final String TIME = "time";
+ private static final String AMULET = "amuletObtained";
+ private static final String ORB = "orbObtained";
+
+ public static void storeInBundle(Bundle bundle) {
+ bundle.put(GOLD, goldCollected);
+ bundle.put(DEEPEST, deepestFloor);
+ bundle.put(REALDEEPEST, realdeepestFloor);
+ bundle.put(SLAIN, enemiesSlain);
+ bundle.put(FOOD, foodEaten);
+ bundle.put(EGG, eggBreak);
+ bundle.put(ALCHEMY, potionsCooked);
+ bundle.put(PIRANHAS, piranhasKilled);
+ bundle.put(ARCHERS, archersKilled);
+ bundle.put(SKELETONS, skeletonsKilled);
+ bundle.put(ASSASSINS, assassinsKilled);
+ bundle.put(APIRANHAS, albinoPiranhasKilled);
+ bundle.put(THIEVES, goldThievesKilled);
+ bundle.put(SYOGS, shadowYogsKilled);
+ bundle.put(BALLS, ballsCooked);
+ bundle.put(NIGHT, nightHunt);
+ bundle.put(ANKHS, ankhsUsed);
+ bundle.put(DURATION, duration);
+ bundle.put(FLOORMOVES, floormoves);
+ bundle.put(PREVFLOORMOVES, prevfloormoves);
+ bundle.put(MOVES, moves);
+ bundle.put(TIME, time);
+ bundle.put(AMULET, amuletObtained);
+ bundle.put(ORB, orbObtained);
+ bundle.put(WATERS, waters);
+ bundle.put(SEWERKILLS, sewerKills);
+ bundle.put(PRISONKILLS, prisonKills);
+ bundle.put(PETDIES, petDies);
+ }
+
+ public static void restoreFromBundle(Bundle bundle) {
+ goldCollected = bundle.getInt(GOLD);
+ deepestFloor = bundle.getInt(DEEPEST);
+ realdeepestFloor = bundle.getInt(REALDEEPEST);
+ enemiesSlain = bundle.getInt(SLAIN);
+ foodEaten = bundle.getInt(FOOD);
+ eggBreak = bundle.getInt(EGG);
+ potionsCooked = bundle.getInt(ALCHEMY);
+ piranhasKilled = bundle.getInt(PIRANHAS);
+ waters = bundle.getInt(WATERS);
+ sewerKills = bundle.getInt(SEWERKILLS);
+ prisonKills = bundle.getInt(PRISONKILLS);
+ petDies = bundle.getInt(PETDIES);
+
+ archersKilled = bundle.getInt(ARCHERS);
+ skeletonsKilled = bundle.getInt(SKELETONS);
+ assassinsKilled = bundle.getInt(ASSASSINS);
+ albinoPiranhasKilled = bundle.getInt(APIRANHAS);
+ goldThievesKilled = bundle.getInt(THIEVES);
+ shadowYogsKilled = bundle.getInt(SYOGS);
+ ballsCooked = bundle.getInt(BALLS);
+
+ nightHunt = bundle.getInt(NIGHT);
+ ankhsUsed = bundle.getInt(ANKHS);
+ duration = bundle.getFloat(DURATION);
+ floormoves = bundle.getInt(FLOORMOVES);
+ prevfloormoves = bundle.getInt(PREVFLOORMOVES);
+ moves = bundle.getInt(MOVES);
+ time = bundle.getInt(TIME);
+ amuletObtained = bundle.getBoolean(AMULET);
+ orbObtained = bundle.getBoolean(ORB);
+
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/Actor.java b/java/com/hmdzl/spspd/actors/Actor.java
new file mode 100644
index 00000000..6703840b
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/Actor.java
@@ -0,0 +1,288 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors;
+
+import java.util.Arrays;
+import java.util.HashSet;
+
+import android.util.SparseArray;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.Statistics;
+import com.hmdzl.spspd.actors.blobs.Blob;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.actors.mobs.Mob;
+import com.hmdzl.spspd.levels.Level;
+import com.watabou.utils.Bundlable;
+import com.watabou.utils.Bundle;
+
+public abstract class Actor implements Bundlable {
+
+ public static final float TICK = 1f;
+
+ private float time;
+
+ private int id = 0;
+
+ protected abstract boolean act();
+
+ protected void spend(float time) {
+ this.time += time;
+ }
+
+ protected void postpone(float time) {
+ if (this.time < now + time) {
+ this.time = now + time;
+ }
+ }
+
+ public float cooldown() {
+ return time - now;
+ }
+
+ protected void diactivate() {
+ time = Float.MAX_VALUE;
+ }
+
+ protected void onAdd() {
+ }
+
+ protected void onRemove() {
+ }
+
+ private static final String TIME = "time";
+ private static final String ID = "id";
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ bundle.put(TIME, time);
+ bundle.put(ID, id);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ time = bundle.getFloat(TIME);
+ id = bundle.getInt(ID);
+ }
+
+ private static int nextID = 1;
+
+ public int id() {
+ if (id > 0) {
+ return id;
+ } else {
+ return (id = nextID++);
+ }
+ }
+
+ // **********************
+ // *** Static members ***
+
+ private static HashSet all = new HashSet();
+ private static Actor current;
+
+ private static SparseArray ids = new SparseArray();
+
+ private static float now = 0;
+
+ private static Char[] chars = new Char[Level.getLength()];
+
+ public static float now(){
+ return now;
+ }
+
+ public static void clear() {
+
+ now = 0;
+
+ Arrays.fill(chars, null);
+ all.clear();
+
+ ids.clear();
+ }
+
+ public static void fixTime() {
+
+ if (Dungeon.hero != null && all.contains(Dungeon.hero)) {
+ Statistics.duration += now;
+ }
+
+ float min = Float.MAX_VALUE;
+ for (Actor a : all) {
+ if (a.time < min) {
+ min = a.time;
+ }
+ }
+ for (Actor a : all) {
+ a.time -= min;
+ }
+ now = 0;
+ }
+
+ public static void init() {
+
+ addDelayed(Dungeon.hero, -Float.MIN_VALUE);
+
+ for (Mob mob : Dungeon.level.mobs) {
+ add(mob);
+ }
+
+ for (Blob blob : Dungeon.level.blobs.values()) {
+ add(blob);
+ }
+
+ current = null;
+ }
+
+ private static final String NEXTID = "nextid";
+
+ public static void storeNextID(Bundle bundle) {
+ bundle.put(NEXTID, nextID);
+ }
+
+ public static void restoreNextID(Bundle bundle) {
+ nextID = bundle.getInt(NEXTID);
+ }
+
+ public static void resetNextID() {
+ nextID = 1;
+ }
+
+ public static void occupyCell(Char ch) {
+ chars[ch.pos] = ch;
+ }
+
+ public static void freeCell(int pos) {
+ chars[pos] = null;
+ }
+
+ /* protected */public void next() {
+ if (current == this) {
+ current = null;
+ }
+ }
+
+ public static void process() {
+
+ if (current != null) {
+ return;
+ }
+
+ boolean doNext;
+
+ do {
+ now = Float.MAX_VALUE;
+ current = null;
+
+ Arrays.fill(chars, null);
+
+ for (Actor actor : all) {
+ // Order of actions when time is equal:
+ // 1. Hero
+ // 2. Other Chars
+ // 3. Other Actors (e.g. blobs)
+ if (actor.time < now
+ || (actor instanceof Hero && actor.time == now)
+ || (actor instanceof Char && actor.time == now && !(current instanceof Hero))) {
+ now = actor.time;
+ current = actor;
+ }
+
+ if (actor instanceof Char) {
+ Char ch = (Char) actor;
+ chars[ch.pos] = ch;
+ }
+ }
+
+ if (current != null) {
+
+ if (current instanceof Char && ((Char) current).sprite.isMoving) {
+ // If it's character's turn to act, but its sprite
+ // is moving, wait till the movement is over
+ current = null;
+ break;
+ }
+
+ doNext = current.act();
+ if (doNext && !Dungeon.hero.isAlive()) {
+ doNext = false;
+ current = null;
+ }
+ } else {
+ doNext = false;
+ }
+
+ } while (doNext);
+ }
+
+ public static void add(Actor actor) {
+ add(actor, now);
+ }
+
+ public static void addDelayed(Actor actor, float delay) {
+ add(actor, now + delay);
+ }
+
+ private static void add(Actor actor, float time) {
+
+ if (all.contains(actor)) {
+ return;
+ }
+
+ ids.put(actor.id(), actor);
+
+ all.add(actor);
+ actor.time += time;
+ actor.onAdd();
+
+ if (actor instanceof Char) {
+ Char ch = (Char) actor;
+ chars[ch.pos] = ch;
+ for (Buff buff : ch.buffs()) {
+ all.add(buff);
+ buff.onAdd();
+ }
+ }
+ }
+
+ public static void remove(Actor actor) {
+
+ if (actor != null) {
+ all.remove(actor);
+ //chars.remove( actor );
+ actor.onRemove();
+
+ if (actor.id > 0) {
+ ids.remove(actor.id);
+ }
+ }
+ }
+
+ public static Char findChar(int pos) {
+ return chars[pos];
+ }
+
+ public static Actor findById(int id) {
+ return ids.get(id);
+ }
+
+ public static HashSet all() {
+ return all;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/Char.java b/java/com/hmdzl/spspd/actors/Char.java
new file mode 100644
index 00000000..22616d20
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/Char.java
@@ -0,0 +1,735 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+
+import com.hmdzl.spspd.Assets;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.buffs.ArmorBreak;
+import com.hmdzl.spspd.actors.buffs.AttackDown;
+import com.hmdzl.spspd.actors.buffs.AttackUp;
+import com.hmdzl.spspd.actors.buffs.Bleeding;
+import com.hmdzl.spspd.actors.buffs.Bless;
+import com.hmdzl.spspd.actors.buffs.BloodAngry;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Burning;
+import com.hmdzl.spspd.actors.buffs.Charm;
+import com.hmdzl.spspd.actors.buffs.Cold;
+import com.hmdzl.spspd.actors.buffs.Cripple;
+import com.hmdzl.spspd.actors.buffs.Chill;
+import com.hmdzl.spspd.actors.buffs.DamageUp;
+import com.hmdzl.spspd.actors.buffs.DefenceUp;
+import com.hmdzl.spspd.actors.buffs.Disarm;
+import com.hmdzl.spspd.actors.buffs.EarthImbue;
+import com.hmdzl.spspd.actors.buffs.FireImbue;
+import com.hmdzl.spspd.actors.buffs.Frost;
+import com.hmdzl.spspd.actors.buffs.FrostImbue;
+import com.hmdzl.spspd.actors.buffs.GlassShield;
+import com.hmdzl.spspd.actors.buffs.GrowSeed;
+import com.hmdzl.spspd.actors.buffs.Haste;
+import com.hmdzl.spspd.actors.buffs.HighAttack;
+import com.hmdzl.spspd.actors.buffs.HighVoice;
+import com.hmdzl.spspd.actors.buffs.Hot;
+import com.hmdzl.spspd.actors.buffs.Hunger;
+import com.hmdzl.spspd.actors.buffs.MechArmor;
+import com.hmdzl.spspd.actors.buffs.Needling;
+import com.hmdzl.spspd.actors.buffs.ParyAttack;
+import com.hmdzl.spspd.actors.buffs.Rhythm;
+import com.hmdzl.spspd.actors.buffs.Rhythm2;
+import com.hmdzl.spspd.actors.buffs.ShieldArmor;
+import com.hmdzl.spspd.actors.buffs.Shocked;
+import com.hmdzl.spspd.actors.buffs.StoneIce;
+import com.hmdzl.spspd.actors.buffs.Tar;
+import com.hmdzl.spspd.actors.buffs.MagicalSleep;
+import com.hmdzl.spspd.actors.buffs.Paralysis;
+import com.hmdzl.spspd.actors.buffs.Poison;
+import com.hmdzl.spspd.actors.buffs.Slow;
+import com.hmdzl.spspd.actors.buffs.Speed;
+import com.hmdzl.spspd.actors.buffs.Vertigo;
+import com.hmdzl.spspd.actors.buffs.BloodImbue;
+import com.hmdzl.spspd.actors.buffs.Wet;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.actors.hero.HeroClass;
+import com.hmdzl.spspd.actors.hero.HeroSubClass;
+import com.hmdzl.spspd.actors.mobs.Bestiary;
+import com.hmdzl.spspd.effects.Lightning;
+import com.hmdzl.spspd.items.wands.WandOfFirebolt;
+import com.hmdzl.spspd.items.weapon.enchantments.EnchantmentFire;
+import com.hmdzl.spspd.items.weapon.enchantments.EnchantmentFire2;
+import com.hmdzl.spspd.items.weapon.missiles.MissileWeapon;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.levels.Terrain;
+import com.hmdzl.spspd.levels.features.Door;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.utils.GLog;
+
+import com.watabou.noosa.Camera;
+import com.watabou.noosa.audio.Sample;
+import com.watabou.utils.Bundlable;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.GameMath;
+import com.watabou.utils.Random;
+
+public abstract class Char extends Actor {
+
+ protected static final String TXT_KILL = "%s killed you...";
+
+ public int pos = 0;
+
+ public CharSprite sprite;
+
+ public String name = "mob";
+
+ public int HT;
+ public int HP;
+
+ protected float baseSpeed = 1;
+
+ public int paralysed = 0;
+ public boolean rooted = false;
+ public boolean flying = false;
+ public int invisible = 0;
+
+ public int viewDistance = 8;
+
+ private HashSet buffs = new HashSet();
+
+ @Override
+ protected boolean act() {
+ Dungeon.level.updateFieldOfView(this);
+ return false;
+ }
+
+ private static final String POS = "pos";
+ private static final String TAG_HP = "HP";
+ private static final String TAG_HT = "HT";
+ private static final String BUFFS = "buffs";
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+
+ super.storeInBundle(bundle);
+
+ bundle.put(POS, pos);
+ bundle.put(TAG_HP, HP);
+ bundle.put(TAG_HT, HT);
+ bundle.put(BUFFS, buffs);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+
+ super.restoreFromBundle(bundle);
+
+ pos = bundle.getInt(POS);
+ HP = bundle.getInt(TAG_HP);
+ HT = bundle.getInt(TAG_HT);
+
+ for (Bundlable b : bundle.getCollection(BUFFS)) {
+ if (b != null) {
+ ((Buff) b).attachTo(this);
+ }
+ }
+ }
+
+ public boolean attack(Char enemy) {
+
+ boolean visibleFight = Dungeon.visible[pos]
+ || Dungeon.visible[enemy.pos];
+
+ if (hit(this, enemy, false)) {
+
+ /*if (visibleFight) {
+ GLog.i(TXT_HIT, name, enemy.name);
+ }*/
+
+ // FIXME
+ int dr = enemy.drRoll();
+
+ if (this instanceof Hero){
+ Hero h = (Hero)this;
+ if ((h.belongings.weapon instanceof MissileWeapon
+ && h.subClass == HeroSubClass.SNIPER )||
+ ( h.heroClass == HeroClass.FOLLOWER && Dungeon.skins == 2) ){
+ dr = 0;
+ }
+ }
+
+ int dmg = damageRoll();
+
+ AttackUp atkup = buff(AttackUp.class);
+ if (atkup != null) {
+ dmg *=(1f+atkup.level()*0.01f);
+ }
+
+ AttackDown atkdown = buff(AttackDown.class);
+ if (atkdown != null) {
+ dmg *=(1f-atkdown.level()*0.01f);
+ }
+
+ MechArmor marmor = buff(MechArmor.class);
+ if (marmor != null) {
+ dmg *=1.3f;
+ }
+
+ StoneIce si = buff(StoneIce.class);
+ if ( si != null){
+ dmg *= 1.4;
+ }
+
+ DamageUp dmgup = buff(DamageUp.class);
+ if (dmgup != null) {
+ dmg +=dmgup.level();
+ Buff.detach(this,DamageUp.class);
+ }
+
+
+ int effectiveDamage = Math.max(dmg - dr, 1);
+
+ effectiveDamage = attackProc(enemy, effectiveDamage);
+ effectiveDamage = enemy.defenseProc(this, effectiveDamage);
+
+ if (visibleFight) {
+ Sample.INSTANCE.play(Assets.SND_HIT, 1, 1,
+ Random.Float(0.8f, 1.25f));
+ }
+
+ // If the enemy is already dead, interrupt the attack.
+ // This matters as defence procs can sometimes inflict self-damage,
+ // such as armor glyphs.
+ if (!enemy.isAlive()) {
+ return true;
+ }
+
+ // TODO: consider revisiting this and shaking in more cases.
+ float shake = 0f;
+ if (enemy == Dungeon.hero)
+ shake = effectiveDamage / (enemy.HT / 4);
+
+ if (shake > 1f)
+ Camera.main.shake(GameMath.gate(1, shake, 5), 0.3f);
+
+ enemy.damage(effectiveDamage, this);
+
+ if (buff(FireImbue.class) != null)
+ buff(FireImbue.class).proc(enemy);
+ if (buff(EarthImbue.class) != null)
+ buff(EarthImbue.class).proc(enemy);
+ if (buff(BloodImbue.class) != null)
+ buff(BloodImbue.class).proc(enemy);
+ if (buff(FrostImbue.class) != null)
+ buff(FrostImbue.class).proc(enemy);
+ if (buff(Needling.class) != null)
+ buff(Needling.class).proc(enemy);
+
+ enemy.sprite.bloodBurstA(sprite.center(), effectiveDamage);
+ enemy.sprite.flash();
+
+ if (!enemy.isAlive() && visibleFight) {
+ if (enemy == Dungeon.hero) {
+ if (Bestiary.isUnique(this)) {
+ Dungeon.fail(Messages.format(ResultDescriptions.UNIQUE));
+ } else {
+ Dungeon.fail(Messages.format(ResultDescriptions.MOB));
+ }
+
+ }
+ }
+ return true;
+
+ } else {
+
+ if (visibleFight) {
+ String defense = enemy.defenseVerb();
+ enemy.sprite.showStatus(CharSprite.NEUTRAL, defense);
+ Sample.INSTANCE.play(Assets.SND_MISS);
+ }
+
+ return false;
+
+ }
+ }
+
+ public static boolean hit(Char attacker, Char defender, boolean magic) {
+ float acuRoll = Random.Float(attacker.hitSkill(defender));
+ float defRoll = Random.Float(defender.evadeSkill(attacker));
+ if (attacker.buff(Bless.class) != null) acuRoll *= 1.20f;
+ if (defender.buff(Bless.class) != null) defRoll *= 1.20f;
+ if (attacker.buff(Wet.class) != null) acuRoll *= 0.90f;
+ if (defender.buff(Wet.class) != null) defRoll *= 0.90f;
+ if (attacker.buff(Rhythm.class) != null) acuRoll *= 3.00f;
+ if (defender.buff(Rhythm.class) != null) defRoll *= 1.50f;
+ if (defender.buff(HighAttack.class) != null) defRoll *= 1.20f;
+ return (magic ? acuRoll * 2 : acuRoll) >= defRoll;
+ }
+
+ public int hitSkill(Char target) {
+ return 0;
+ }
+
+ public int evadeSkill(Char enemy) {
+ return 0;
+ }
+
+ public String defenseVerb() {
+ return Messages.get(this,"def_verb");
+ }
+
+ public int drRoll() {
+ return 0;
+ }
+
+ public int damageRoll() {
+ return 1;
+ }
+
+ public int attackProc(Char enemy, int damage) {
+ if (buff(Shocked.class)!=null){
+ Buff.detach(this,Shocked.class);
+ Buff.affect(this, Disarm.class,5f);
+ damage(this.HP/10,this);
+ ArrayList arcs = new ArrayList<>();
+ arcs.add(new Lightning.Arc(pos - Level.WIDTH, pos + Level.WIDTH));
+ arcs.add(new Lightning.Arc(pos - 1, pos + 1));
+ sprite.parent.add( new Lightning( arcs, null ) );
+ }
+
+ return damage;
+ }
+
+ public int defenseProc(Char enemy, int damage) {
+ return damage;
+ }
+
+ public float speed() {
+ if (buff(Cripple.class) != null){
+ return baseSpeed * 0.5f;
+ } else if (buff(Haste.class) != null){
+ return baseSpeed * 2.5f;
+ } else if (buff(Poison.class) != null) {
+ return baseSpeed * 0.9f;
+ } else if (buff(BloodAngry.class) != null) {
+ return baseSpeed * 1.2f;
+ } else if (buff(MechArmor.class) != null) {
+ return baseSpeed * 1.5f;
+ } else if (buff(StoneIce.class) != null) {
+ return baseSpeed * 0.8f;
+ } else{
+ return baseSpeed;
+ }
+
+
+ }
+
+ public void damage(int dmg, Object src) {
+
+ if (this.buff(Frost.class) != null) {
+ Buff.detach(this, Frost.class);
+ dmg = (int) Math.ceil(dmg *1.5);
+ }
+ if (this.buff(MagicalSleep.class) != null) {
+ Buff.detach(this, MagicalSleep.class);
+ dmg = (int) Math.ceil(dmg *1.5);
+ }
+
+ ArmorBreak ab = buff(ArmorBreak.class);
+ if (buff(ArmorBreak.class) != null){
+ dmg= (int) Math.ceil(dmg *(ab.level()*0.01+1));
+ }
+
+ ParyAttack paryatk = buff(ParyAttack.class);
+ if (buff(ParyAttack.class) != null){
+ dmg= (int) Math.ceil(dmg *Math.max((1-paryatk.level()*0.02),0.5));
+ }
+
+ if (buff(Hot.class) != null){
+ dmg = (int) Math.ceil(dmg * 1.2);
+ }
+
+ DefenceUp drup = buff(DefenceUp.class);
+ if (buff(DefenceUp.class) != null) {
+ dmg = (int) Math.ceil(dmg *(-drup.level()*0.01+1));
+ }
+
+ if (buff(GrowSeed.class) != null) {
+ dmg = (int) Math.ceil(dmg *0.8);
+ }
+
+ ShieldArmor sarmor = buff(ShieldArmor.class);
+ if (sarmor != null && !(src instanceof Hunger)) {
+ dmg = sarmor.absorb(dmg);
+ }
+
+ MechArmor marmor = buff(MechArmor.class);
+ if (marmor != null && !(src instanceof Hunger)) {
+ dmg = marmor.absorb(dmg);
+ }
+
+ if (HP <= 0 || dmg < 0) {
+ return;
+ }
+
+ Class> srcClass = src.getClass();
+ if (immunities().contains(srcClass)) {
+ dmg = 0;
+ } else if (resistances().contains(srcClass)) {
+ dmg = Random.IntRange(0, dmg);
+ } else if (weakness().contains(srcClass)) {
+ dmg = Random.IntRange(dmg+1, 2*dmg);
+ }
+
+ if (buff(Paralysis.class) != null) {
+ if (Random.Int(dmg) >= Random.Int(HP)) {
+ Buff.detach(this, Paralysis.class);
+ if (Dungeon.visible[pos]) {
+ GLog.i(Messages.get(this,"out_of_paralysis",name));
+ }
+ }
+ }
+
+ //GlassShield glass = buff(GlassShield.class);
+ if (buff(GlassShield.class) != null) {
+ if (dmg >= 10) {
+ dmg = 10;
+ Buff.detach(this, GlassShield.class);
+ }
+ }
+ //if (dmg > HP){
+ //Buff.detach(this,Corruption.class);}
+ HP -= dmg;
+
+
+ if (dmg > 0 || src instanceof Char) {
+ sprite.showStatus(HP > HT / 2 ? CharSprite.WARNING
+ : CharSprite.NEGATIVE, Integer.toString(dmg));
+ }
+
+ if (HP <= 0 || HT <= 0) {
+ die(src);
+ }
+ }
+
+ public void destroy() {
+ HP = 0;
+ Actor.remove(this);
+ Actor.freeCell(pos);
+ }
+
+ public void die(Object src) {
+ destroy();
+ sprite.die();
+ }
+
+ public boolean isAlive() {
+ return HP > 0 && HT > 0;
+ }
+
+ @Override
+ protected void spend(float time) {
+
+ float timeScale = 1f;
+ if (buff(Slow.class) != null) {
+ timeScale *= 0.67f;
+ } else if (buff( Chill.class ) != null) {
+ timeScale *= buff( Chill.class ).speedFactor();
+ }
+ if (buff(Speed.class) != null) {
+ timeScale *= 1.5f;
+ }
+ /*if (buff(Haste.class) != null) {
+ timeScale *= 1.5f;
+ }*/
+ if (buff(Cold.class) != null) {
+ timeScale *= 0.9f;
+ }
+
+ if (buff(Tar.class) != null) {
+ timeScale *= 0.8f;
+ }
+ if (buff(Burning.class) != null) {
+ timeScale *= 1.25f;
+ }
+
+ if (buff(Rhythm2.class) != null) {
+ timeScale *= 1.2f;
+ }
+
+ super.spend(time / timeScale);
+ }
+
+ public HashSet buffs() {
+ return buffs;
+ }
+
+ @SuppressWarnings("unchecked")
+ public HashSet buffs(Class c) {
+ HashSet filtered = new HashSet();
+ for (Buff b : buffs) {
+ if (c.isInstance(b)) {
+ filtered.add((T) b);
+ }
+ }
+ return filtered;
+ }
+
+ @SuppressWarnings("unchecked")
+ public T buff(Class c) {
+ for (Buff b : buffs) {
+ if (c.isInstance(b)) {
+ return (T) b;
+ }
+ }
+ return null;
+ }
+
+ public boolean isCharmedBy(Char ch) {
+ int chID = ch.id();
+ for (Buff b : buffs) {
+ if (b instanceof Charm && ((Charm) b).object == chID) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void add(Buff buff) {
+
+ buffs.add(buff);
+ Actor.add(buff);
+
+ if (sprite != null)
+ switch(buff.type){
+ case POSITIVE:
+ sprite.showStatus(CharSprite.POSITIVE, buff.toString()); break;
+ case NEGATIVE:
+ sprite.showStatus(CharSprite.NEGATIVE, buff.toString());break;
+ case NEUTRAL:
+ sprite.showStatus(CharSprite.NEUTRAL, buff.toString()); break;
+ case SILENT: default:
+ break; //show nothing
+ }
+
+ }
+
+ public void remove(Buff buff) {
+
+ buffs.remove(buff);
+ Actor.remove(buff);
+
+
+ }
+
+ public void remove(Class extends Buff> buffClass) {
+ for (Buff buff : buffs(buffClass)) {
+ remove(buff);
+ }
+ }
+
+ @Override
+ protected void onRemove() {
+ for (Buff buff : buffs.toArray(new Buff[buffs.size()])) {
+ buff.detach();
+ }
+ }
+
+ public void updateSpriteState() {
+ for (Buff buff : buffs) {
+ /*if (buff instanceof Burning) {
+ sprite.add(CharSprite.State.BURNING);
+ } else if (buff instanceof Levitation) {
+ sprite.add(CharSprite.State.LEVITATING);
+ } else if (buff instanceof Invisibility
+ || buff instanceof CloakOfShadows.cloakStealth) {
+ sprite.add(CharSprite.State.INVISIBLE);
+ } else if (buff instanceof Stun || buff instanceof Shieldblock) {
+ sprite.add(CharSprite.State.PARALYSED);
+ } else if (buff instanceof Frost) {
+ sprite.add(CharSprite.State.FROZEN);
+ } else if (buff instanceof Light) {
+ sprite.add(CharSprite.State.ILLUMINATED);
+ }*/
+ buff.fx( true );
+ }
+ }
+
+ public int stealth() {
+ return 0;
+ }
+
+ public int energybase() {
+ return 0;
+ }
+
+ public void move(int step) {
+
+ if (Level.adjacent(step, pos) && buff(Vertigo.class) != null) {
+ step = pos + Level.NEIGHBOURS8[Random.Int(8)];
+ if (!(Level.passable[step] || Level.avoid[step])
+ || Actor.findChar(step) != null)
+ return;
+ }
+
+ if (Dungeon.level.map[pos] == Terrain.OPEN_DOOR) {
+ Door.leave(pos);
+ }
+
+ pos = step;
+
+ if (flying && Dungeon.level.map[pos] == Terrain.DOOR) {
+ Door.enter(pos);
+ }
+
+ if (this != Dungeon.hero) {
+ sprite.visible = Dungeon.visible[pos];
+ }
+ }
+
+ public int distance(Char other) {
+ return Level.distance(pos, other.pos);
+ }
+
+ public void onMotionComplete() {
+ next();
+ }
+
+ public void onAttackComplete() {
+ next();
+ }
+
+ public void onOperateComplete() {
+ next();
+ }
+
+ private static final HashSet> EMPTY = new HashSet>();
+
+ public HashSet> resistances() {
+ return EMPTY;
+ }
+
+ public HashSet> immunities() {
+ return EMPTY;
+ }
+
+ public HashSet> weakness() {
+ return EMPTY;
+ }
+
+ //protected final HashSet resistances = new HashSet<>();
+
+ //returns percent effectiveness after resistances
+ //TODO currently resistances reduce effectiveness by a static 50%, and do not stack.
+ //public float resist( Class effect ){
+ //HashSet resists = new HashSet<>(resistances);
+ // for (Property p : properties()){
+ // resists.addAll(p.resistances());
+ // }
+ // for (Buff b : buffs()){
+ // resists.addAll(b.resistances());
+ // }
+
+ // float result = 1f;
+ // for (Class c : resists){
+ // if (c.isAssignableFrom(effect)){
+ // result *= 0.5f;
+ // }
+ // }
+ // return result * RingOfElements.restore(this, effect);
+ //}
+
+ //protected final HashSet immunities = new HashSet<>();
+
+ //public boolean isImmune(Class effect ){
+ //HashSet immunes = new HashSet<>(immunities);
+ //for (Property p : properties()){
+ //immunes.addAll(p.immunities());
+ //}
+ //for (Buff b : buffs()){
+ //immunes.addAll(b.immunities());
+ //}
+
+ //for (Class c : immunes){
+ //if (c.isAssignableFrom(effect)){
+ // return true;
+ //}
+ // }
+ //return false;
+ //}
+
+ protected HashSet properties = new HashSet<>();
+
+ public HashSet properties() { return properties; }
+
+ public enum Property{
+ BOSS,
+ MINIBOSS,
+ IMMOVABLE,
+
+ HUMAN,
+ ORC,
+ ELF,
+ //GNOLL,
+ DWARF,
+ TROLL,
+ DEMONIC,
+ GOBLIN,
+
+ BEAST,
+ DRAGON,
+ PLANT( new HashSet(),
+ new HashSet( Arrays.asList(Bleeding.class, ToxicGas.class, Poison.class)),
+ new HashSet( Arrays.asList(Burning.class, WandOfFirebolt.class,EnchantmentFire.class,EnchantmentFire2.class))
+ ),
+ ELEMENT,
+
+ MECH,
+ UNDEAD,
+ ALIEN,
+ UNKNOW;
+
+ private HashSet resistances;
+ private HashSet immunities;
+ private HashSet weakness;
+
+ Property(){
+ this(new HashSet(), new HashSet(),new HashSet());
+ }
+
+ Property( HashSet resistances, HashSet immunities,HashSet weakness){
+ this.resistances = resistances;
+ this.immunities = immunities;
+ this.weakness = weakness;
+ }
+
+ public HashSet resistances(){
+ return new HashSet<>(resistances);
+ }
+
+ public HashSet immunities(){
+ return new HashSet<>(immunities);
+ }
+ public HashSet weakness(){
+ return new HashSet<>(weakness);
+ }
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/animate/WeaponAnimate.java b/java/com/hmdzl/spspd/actors/animate/WeaponAnimate.java
new file mode 100644
index 00000000..cb1afa61
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/animate/WeaponAnimate.java
@@ -0,0 +1,35 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.animate;
+
+import java.text.DecimalFormat;
+import java.util.HashSet;
+
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class WeaponAnimate extends Actor {
+
+ @Override
+ public boolean act() {
+ return true;
+ }
+
+
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/Alchemy.java b/java/com/hmdzl/spspd/actors/blobs/Alchemy.java
new file mode 100644
index 00000000..0a62e805
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/Alchemy.java
@@ -0,0 +1,74 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.Journal;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.Speck;
+import com.watabou.utils.Bundle;
+
+public class Alchemy extends Blob {
+
+ protected int pos;
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+
+ for (int i = 0; i < LENGTH; i++) {
+ if (cur[i] > 0) {
+ pos = i;
+ break;
+ }
+ }
+ }
+
+ @Override
+ protected void evolve() {
+ volume = off[pos] = cur[pos];
+
+ if (Dungeon.visible[pos]) {
+ Journal.add(Journal.Feature.ALCHEMY);
+ }
+ }
+
+ /*@Override
+ public void seed(int cell, int amount) {
+ cur[pos] = 0;
+ pos = cell;
+ volume = cur[pos] = amount;
+ }*/
+
+ /*public static void transmute(int cell) {
+ Heap heap = Dungeon.level.heaps.get(cell);
+ if (heap != null) {
+
+ Item result = heap.transmute();
+ if (result != null) {
+ Dungeon.level.drop(result, cell).sprite.drop(cell);
+ }
+ }
+ }*/
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+ emitter.start(Speck.factory(Speck.BUBBLE), 0.4f, 0);
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/Alter.java b/java/com/hmdzl/spspd/actors/blobs/Alter.java
new file mode 100644
index 00000000..f7810c1f
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/Alter.java
@@ -0,0 +1,71 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.items.Heap;
+import com.hmdzl.spspd.items.weapon.Weapon;
+import com.watabou.utils.Bundle;
+
+public class Alter extends Blob {
+
+ protected int pos;
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+
+ for (int i = 0; i < LENGTH; i++) {
+ if (cur[i] > 0) {
+ pos = i;
+ break;
+ }
+ }
+ }
+
+ @Override
+ protected void evolve() {
+ volume = off[pos] = cur[pos];
+ }
+
+ @Override
+ public void seed(int cell, int amount) {
+ cur[pos] = 0;
+ pos = cell;
+ volume = cur[pos] = amount;
+ }
+
+ public static void transmute(int cell) {
+ Heap heap = Dungeon.level.heaps.get(cell);
+ if (heap != null) {
+
+ Weapon result = heap.consecrate();
+ if (result != null) {
+ Dungeon.level.drop(result, cell).sprite.drop(cell);
+ }
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+ emitter.start(Speck.factory(Speck.LIGHT), 0.4f, 0);
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/Blob.java b/java/com/hmdzl/spspd/actors/blobs/Blob.java
new file mode 100644
index 00000000..45bd4b03
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/Blob.java
@@ -0,0 +1,213 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import java.util.Arrays;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ShatteredPixelDungeon;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.utils.BArray;
+import com.watabou.utils.Bundle;
+
+public class Blob extends Actor {
+
+ public static final int WIDTH = Level.getWidth();
+ public static final int HEIGHT = Level.HEIGHT;
+ public static final int LENGTH = Level.getLength();
+
+ public int volume = 0;
+
+ public int[] cur;
+ protected int[] off;
+
+ public BlobEmitter emitter;
+
+ protected Blob() {
+
+ cur = new int[LENGTH];
+ off = new int[LENGTH];
+
+ volume = 0;
+ }
+
+ private static final String CUR = "cur";
+ private static final String START = "start";
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+
+ if (volume > 0) {
+
+ int start;
+ for (start = 0; start < LENGTH; start++) {
+ if (cur[start] > 0) {
+ break;
+ }
+ }
+ int end;
+ for (end = LENGTH - 1; end > start; end--) {
+ if (cur[end] > 0) {
+ break;
+ }
+ }
+
+ bundle.put(START, start);
+ bundle.put(CUR, trim(start, end + 1));
+
+ }
+ }
+
+ private int[] trim(int start, int end) {
+ int len = end - start;
+ int[] copy = new int[len];
+ System.arraycopy(cur, start, copy, 0, len);
+ return copy;
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+
+ super.restoreFromBundle(bundle);
+
+ int[] data = bundle.getIntArray(CUR);
+ if (data != null) {
+ int start = bundle.getInt(START);
+ for (int i = 0; i < data.length; i++) {
+ cur[i + start] = data[i];
+ volume += data[i];
+ }
+ }
+
+ if (Level.resizingNeeded) {
+ int[] cur = new int[Level.getLength()];
+ Arrays.fill(cur, 0);
+
+ int loadedMapSize = Level.loadedMapSize;
+ for (int i = 0; i < loadedMapSize; i++) {
+ System.arraycopy(this.cur, i * loadedMapSize, cur, i
+ * Level.getWidth(), loadedMapSize);
+ }
+
+ this.cur = cur;
+ }
+ }
+
+ @Override
+ public boolean act() {
+
+ spend(TICK);
+
+ if (volume > 0) {
+
+ volume = 0;
+ evolve();
+
+ int[] tmp = off;
+ off = cur;
+ cur = tmp;
+
+ }
+
+ return true;
+ }
+
+ public void use(BlobEmitter emitter) {
+ this.emitter = emitter;
+ }
+
+ protected void evolve() {
+
+ boolean[] notBlocking = BArray.not(Level.solid, null);
+
+ for (int i = 1; i < HEIGHT - 1; i++) {
+
+ int from = i * WIDTH + 1;
+ int to = from + WIDTH - 2;
+
+ for (int pos = from; pos < to; pos++) {
+ if (notBlocking[pos]) {
+
+ int count = 1;
+ int sum = cur[pos];
+
+ if (notBlocking[pos - 1]) {
+ sum += cur[pos - 1];
+ count++;
+ }
+ if (notBlocking[pos + 1]) {
+ sum += cur[pos + 1];
+ count++;
+ }
+ if (notBlocking[pos - WIDTH]) {
+ sum += cur[pos - WIDTH];
+ count++;
+ }
+ if (notBlocking[pos + WIDTH]) {
+ sum += cur[pos + WIDTH];
+ count++;
+ }
+
+ int value = sum >= count ? (sum / count) - 1 : 0;
+ off[pos] = value;
+
+ volume += value;
+ } else {
+ off[pos] = 0;
+ }
+ }
+ }
+ }
+
+ public void seed(int cell, int amount) {
+ cur[cell] += amount;
+ volume += amount;
+ }
+
+ public void clear(int cell) {
+ volume -= cur[cell];
+ cur[cell] = 0;
+ }
+
+ public String tileDesc() {
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static T seed(int cell, int amount, Class type) {
+ try {
+
+ T gas = (T) Dungeon.level.blobs.get(type);
+ if (gas == null) {
+ gas = type.newInstance();
+ Dungeon.level.blobs.put(type, gas);
+ }
+
+ gas.seed(cell, amount);
+
+ return gas;
+
+ } catch (Exception e) {
+ ShatteredPixelDungeon.reportException(e);
+ return null;
+ }
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/ConfusionGas.java b/java/com/hmdzl/spspd/actors/blobs/ConfusionGas.java
new file mode 100644
index 00000000..a8567148
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/ConfusionGas.java
@@ -0,0 +1,56 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Locked;
+import com.hmdzl.spspd.actors.buffs.Vertigo;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.messages.Messages;
+
+public class ConfusionGas extends Blob {
+
+ @Override
+ protected void evolve() {
+ super.evolve();
+
+ Char ch;
+ for (int i = 0; i < LENGTH; i++) {
+ if (cur[i] > 0 && (ch = Actor.findChar(i)) != null) {
+ if (!ch.immunities().contains(this.getClass()))
+ Buff.prolong(ch, Vertigo.class, 2);
+ Buff.prolong(ch, Locked.class,2f);
+ }
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+
+ emitter.pour(Speck.factory(Speck.CONFUSION), 0.6f);
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/blobs/CorruptGas.java b/java/com/hmdzl/spspd/actors/blobs/CorruptGas.java
new file mode 100644
index 00000000..29617023
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/CorruptGas.java
@@ -0,0 +1,84 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.Badges;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Bleeding;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Cripple;
+import com.hmdzl.spspd.actors.buffs.Vertigo;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.messages.Messages;
+import com.watabou.utils.Random;
+
+public class CorruptGas extends Blob implements Hero.Doom {
+
+ @Override
+ protected void evolve() {
+ super.evolve();
+
+ int levelDamage = 5 + Dungeon.depth/2;
+ int bleedDamage = 5 + Dungeon.depth/2;
+
+ Char ch;
+ for (int i = 0; i < LENGTH; i++) {
+ if (cur[i] > 0 && (ch = Actor.findChar(i)) != null) {
+
+ if (!ch.immunities().contains(ConfusionGas.class)){
+ Buff.prolong(ch, Vertigo.class, 2);
+ }
+
+ if (!ch.immunities().contains(this.getClass())){
+ Buff.affect(ch, Bleeding.class).set(bleedDamage);
+ Buff.prolong(ch, Cripple.class, Cripple.DURATION);
+
+ int damage = (ch.HT/2 + levelDamage) / 40;
+ if (Random.Int(40) < (ch.HT/2 + levelDamage) % 40) {
+ damage++;
+ }
+
+ ch.damage(damage, this);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+
+ emitter.pour(Speck.factory(Speck.CORRUPT), 0.6f);
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+
+ @Override
+ public void onDeath() {
+
+ Badges.validateDeathFromGas();
+
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/DarkGas.java b/java/com/hmdzl/spspd/actors/blobs/DarkGas.java
new file mode 100644
index 00000000..8c2a1e5b
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/DarkGas.java
@@ -0,0 +1,54 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Blindness;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.messages.Messages;
+
+public class DarkGas extends Blob {
+
+ @Override
+ protected void evolve() {
+ super.evolve();
+
+ Char ch;
+ for (int i = 0; i < LENGTH; i++) {
+ if (cur[i] > 0 && (ch = Actor.findChar(i)) != null) {
+ if (!ch.immunities().contains(this.getClass()))
+ Buff.prolong(ch, Blindness.class, 2);
+ }
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+
+ emitter.pour(Speck.factory(Speck.DARKNESS), 0.6f);
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/blobs/ElectriShock.java b/java/com/hmdzl/spspd/actors/blobs/ElectriShock.java
new file mode 100644
index 00000000..ccae19b7
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/ElectriShock.java
@@ -0,0 +1,104 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Paralysis;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.particles.EnergyParticle;
+import com.hmdzl.spspd.items.Heap;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.messages.Messages;
+import com.watabou.utils.Random;
+
+public class ElectriShock extends Blob {
+
+ @Override
+ protected void evolve() {
+
+ //boolean[] shockable = Level.shockable;
+
+ int from = WIDTH + 1;
+ int to = Level.getLength() - WIDTH - 1;
+
+
+ for (int pos = from; pos < to; pos++) {
+
+ int shock;
+ boolean shelf = false;
+
+ if (cur[pos] > 0) {
+
+ shocking(pos);
+
+ shock = cur[pos] - 1;
+
+ if (shock <= 0){ }
+ } else {
+ shock = 0;
+ }
+
+ volume += (off[pos] = shock);
+ }
+
+ }
+
+ private void shocking(int pos) {
+ Char ch = Actor.findChar(pos);
+ if (ch != null ) {
+ //Buff.detach(ch,Corruption.class);
+ ch.damage( Math.max( 1, Random.Int( ch.HP / 100, ch.HP / 50 ) ), this );
+ Buff.prolong(ch, Paralysis.class,1f);
+
+ }
+ Heap heap = Dungeon.level.heaps.get(pos);
+ if (heap != null) {
+ heap.lit();
+ }
+
+ }
+
+ @Override
+ public void seed(int cell, int amount) {
+ if (cur[cell] == 0) {
+ volume += amount;
+ cur[cell] = amount;
+ /*} else {
+ volume += amount - cur[cell];
+ cur[cell] = amount;*/
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+ emitter.start(EnergyParticle.FACTORY, 0.03f, 0);
+ }
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+
+ public void onDeath() {
+ Dungeon.fail(Messages.format(ResultDescriptions.GAS));
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/Fire.java b/java/com/hmdzl/spspd/actors/blobs/Fire.java
new file mode 100644
index 00000000..2af6160e
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/Fire.java
@@ -0,0 +1,154 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Burning;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.particles.FlameParticle;
+import com.hmdzl.spspd.items.Heap;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.levels.Terrain;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.items.Generator;
+import com.watabou.utils.Random;
+
+public class Fire extends Blob {
+
+ @Override
+ protected void evolve() {
+
+ boolean[] flamable = Level.flamable;
+
+ int from = WIDTH + 1;
+ int to = Level.getLength() - WIDTH - 1;
+
+ boolean observe = false;
+
+ for (int pos = from; pos < to; pos++) {
+
+ int fire;
+ boolean shelf = false;
+
+ Blob blob = Dungeon.level.blobs.get( TarGas.class );
+
+ if (blob != null) {
+
+ int par[] = blob.cur;
+
+ for (int i=0; i < LENGTH; i++) {
+
+ if (cur[i] > 0) {
+ blob.volume -= par[i];
+ par[i] = 0;
+ }
+ }
+ }
+
+ if (cur[pos] > 0) {
+
+ burn(pos);
+
+ fire = cur[pos] - 1;
+ if (fire <= 0 && flamable[pos]) {
+
+ if(Dungeon.level.map[pos]==Terrain.BOOKSHELF){
+ shelf=true;
+ }
+
+ int oldTile = Dungeon.level.map[pos];
+ Level.set(pos, Terrain.EMBERS);
+
+ if (shelf && Random.Float()<.10){
+ Dungeon.level.drop(Generator.random(Generator.Category.SCROLL), pos);
+ }
+
+ observe = true;
+ GameScene.updateMap(pos);
+ if (Dungeon.visible[pos]) {
+ GameScene.discoverTile(pos, oldTile);
+ }
+ }
+
+ } else {
+
+ if (flamable[pos]
+ && (cur[pos - 1] > 0 || cur[pos + 1] > 0
+ || cur[pos - WIDTH] > 0 || cur[pos + WIDTH] > 0)) {
+ fire = 4;
+ burn(pos);
+ } else {
+ fire = 0;
+ }
+
+ }
+
+ volume += (off[pos] = fire);
+
+ }
+
+ if (observe) {
+ Dungeon.observe();
+ }
+ }
+
+ private void burn(int pos) {
+ Char ch = Actor.findChar(pos);
+ if (ch != null ) {
+ Buff.affect(ch, Burning.class).reignite(ch);
+ }
+ Heap heap = Dungeon.level.heaps.get(pos);
+ if (heap != null) {
+ heap.burn();
+ }
+
+ if( Dungeon.level.map[pos] == Terrain.SECRET_DOOR) {
+
+ GameScene.discoverTile( pos, Dungeon.level.map[pos] );
+
+ Level.set( pos, Terrain.DOOR);
+
+ GameScene.updateMap( pos );
+ }
+ }
+
+ @Override
+ public void seed(int cell, int amount) {
+ if (cur[cell] == 0) {
+ volume += amount;
+ cur[cell] = amount;
+ /*} else {
+ volume += amount - cur[cell];
+ cur[cell] = amount;*/
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+ emitter.start(FlameParticle.FACTORY, 0.1f, 0);
+ }
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/Foliage.java b/java/com/hmdzl/spspd/actors/blobs/Foliage.java
new file mode 100644
index 00000000..13e39f45
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/Foliage.java
@@ -0,0 +1,87 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.Journal;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Shadows;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.particles.ShaftParticle;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.levels.Terrain;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.scenes.GameScene;
+
+public class Foliage extends Blob {
+
+ @Override
+ protected void evolve() {
+
+ int from = WIDTH + 1;
+ int to = Level.getLength() - WIDTH - 1;
+
+ int[] map = Dungeon.level.map;
+ boolean regrowth = false;
+
+ boolean visible = false;
+
+ for (int pos = from; pos < to; pos++) {
+ if (cur[pos] > 0) {
+
+ off[pos] = cur[pos];
+ volume += off[pos];
+
+ if (map[pos] == Terrain.EMBERS) {
+ map[pos] = Terrain.GRASS;
+ regrowth = true;
+ }
+
+ visible = visible || Dungeon.visible[pos];
+
+ } else {
+ off[pos] = 0;
+ }
+ }
+
+ Hero hero = Dungeon.hero;
+ if (hero.isAlive() && hero.visibleEnemies() == 0 && cur[hero.pos] > 0) {
+ Buff.affect(hero, Shadows.class).prolong();
+ }
+
+ if (regrowth) {
+ GameScene.updateMap();
+ }
+
+ if (visible) {
+ Journal.add(Journal.Feature.GARDEN);
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+ emitter.start(ShaftParticle.FACTORY, 0.9f, 0);
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/Freezing.java b/java/com/hmdzl/spspd/actors/blobs/Freezing.java
new file mode 100644
index 00000000..f49bf2cc
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/Freezing.java
@@ -0,0 +1,63 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Frost;
+import com.hmdzl.spspd.effects.CellEmitter;
+import com.hmdzl.spspd.effects.particles.SnowParticle;
+import com.hmdzl.spspd.items.Heap;
+import com.hmdzl.spspd.levels.Level;
+import com.watabou.utils.Random;
+
+public class Freezing {
+
+ // Returns true, if this cell is visible
+ public static boolean affect(int cell, Fire fire) {
+
+ Char ch = Actor.findChar(cell);
+ if (ch != null) {
+ if (Level.water[ch.pos]) {
+ Buff.prolong(ch, Frost.class,
+ Frost.duration(ch) * Random.Float(5f, 7.5f));
+ } else {
+ Buff.prolong(ch, Frost.class,
+ Frost.duration(ch) * Random.Float(1.0f, 1.5f));
+ }
+ }
+
+ if (fire != null) {
+ fire.clear(cell);
+ }
+
+ Heap heap = Dungeon.level.heaps.get(cell);
+ if (heap != null) {
+ heap.freeze();
+ }
+
+ if (Dungeon.visible[cell]) {
+ CellEmitter.get(cell).start(SnowParticle.FACTORY, 0.2f, 6);
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/FrostGas.java b/java/com/hmdzl/spspd/actors/blobs/FrostGas.java
new file mode 100644
index 00000000..428c3b9d
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/FrostGas.java
@@ -0,0 +1,99 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Chill;
+import com.hmdzl.spspd.actors.buffs.Frost;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.effects.particles.SnowParticle;
+import com.hmdzl.spspd.items.Heap;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.messages.Messages;
+
+public class FrostGas extends Blob {
+
+ @Override
+ protected void evolve() {
+
+ int from = WIDTH + 1;
+ int to = Level.getLength() - WIDTH - 1;
+
+ for (int pos = from; pos < to; pos++) {
+
+ int ice;
+
+
+ if (cur[pos] > 0) {
+
+ ice(pos);
+
+ ice = cur[pos] - 1;
+ if (ice <= 0){ }
+ } else {
+ ice = 0;
+ }
+
+ volume += (off[pos] = ice);
+
+ }
+
+ }
+
+ private void ice(int pos) {
+ Char ch = Actor.findChar( pos );
+ if (ch != null && !ch.immunities().contains(this.getClass())) {
+ if (ch.buff(Frost.class) != null){
+ Buff.affect(ch, Frost.class, 2f);
+ } else {
+ Buff.affect(ch, Chill.class, 3f);
+ Chill chill = ch.buff(Chill.class);
+ if (chill != null && chill.cooldown() >= 10f){
+ Buff.affect(ch, Frost.class, 5f);
+ }
+ }
+ }
+
+ Heap heap = Dungeon.level.heaps.get( pos );
+ if (heap != null) heap.freeze();
+ }
+
+ @Override
+ public void seed(int cell, int amount) {
+ if (cur[cell] == 0) {
+ volume += amount;
+ cur[cell] = amount;
+ /*} else {
+ volume += amount - cur[cell];
+ cur[cell] = amount;*/
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+ emitter.start(SnowParticle.FACTORY, 0.05f, 0);
+ }
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/GooWarn.java b/java/com/hmdzl/spspd/actors/blobs/GooWarn.java
new file mode 100644
index 00000000..f6100a9d
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/GooWarn.java
@@ -0,0 +1,53 @@
+package com.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.GooSprite;
+
+/**
+ * Created by Evan on 29/09/2014.
+ */
+public class GooWarn extends Blob {
+
+ // cosmetic blob, used to warn noobs that goo's pump up should, infact, be
+ // avoided.
+
+ // Thanks to Watabou for the much better particle effect, I was lazy and
+ // just re-colored flames initially
+
+ protected int pos;
+
+ @Override
+ protected void evolve() {
+ for (int i = 0; i < LENGTH; i++) {
+
+ int offv = cur[i] > 0 ? cur[i] - 1 : 0;
+ off[i] = offv;
+
+ if (offv > 0) {
+ volume += offv;
+ }
+ }
+
+ }
+
+ @Override
+ public void seed(int cell, int amount) {
+ int diff = amount - cur[cell];
+ if (diff > 0) {
+ cur[cell] = amount;
+ volume += diff;
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+ emitter.pour(GooSprite.GooParticle.FACTORY, 0.03f);
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/HealLight.java b/java/com/hmdzl/spspd/actors/blobs/HealLight.java
new file mode 100644
index 00000000..c91e679b
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/HealLight.java
@@ -0,0 +1,63 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.particles.ShaftParticle;
+
+public class HealLight extends Blob implements Hero.Doom{
+
+ @Override
+ protected void evolve() {
+
+ super.evolve();
+
+ Char ch;
+ for (int i = 0; i < LENGTH; i++) {
+ if (cur[i] > 0 && (ch = Actor.findChar(i)) != null) {
+ if (ch.HP
+ */
+package com.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.effects.particles.MemoryParticle;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.scenes.LoadSaveScene;
+import com.watabou.noosa.Game;
+import com.watabou.noosa.audio.Sample;
+import com.hmdzl.spspd.Assets;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.Journal;
+import com.hmdzl.spspd.Journal.Feature;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.watabou.utils.Bundle;
+
+import java.io.IOException;
+
+public class MemoryFire extends Blob {
+
+ protected int pos;
+
+ @Override
+ public void restoreFromBundle( Bundle bundle ) {
+ super.restoreFromBundle( bundle );
+
+ for (int i=0; i < LENGTH; i++) {
+ if (cur[i] > 0) {
+ pos = i;
+ break;
+ }
+ }
+ }
+
+ @Override
+ protected void evolve() {
+ volume = off[pos] = cur[pos];
+ Char ch = Actor.findChar( pos );
+ MemoryFire fire = (MemoryFire)Dungeon.level.blobs.get( MemoryFire.class );
+ if (ch != null && ch == Dungeon.hero) {
+ if (Dungeon.visible[pos]) {
+ Sample.INSTANCE.play( Assets.SND_BURNING );
+ fire.seed( fire.pos, 0 );
+ Journal.remove( Feature.MEMORY_FIRE );
+ try {
+ Dungeon.saveAll();
+ } catch (IOException e) {
+ //
+ }
+ Dungeon.canSave=true;
+ Game.switchScene(LoadSaveScene.class);
+ //GameScene.show(new WndMemory());
+ }
+ }
+ if (Dungeon.visible[pos]) {
+ Journal.add( Feature.MEMORY_FIRE );
+ }
+ }
+
+ @Override
+ public void seed( int cell, int amount ) {
+ cur[pos] = 0;
+ pos = cell;
+ volume = cur[pos] = amount;
+ }
+
+ @Override
+ public void use( BlobEmitter emitter ) {
+ super.use( emitter );
+
+ emitter.pour( MemoryParticle.FACTORY, 0.04f );
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+
+
+ /*public class WndMemory extends Window {
+
+ private static final int WIDTH = 120;
+ private static final int MARGIN = 2;
+ private static final int BUTTON_WIDTH = WIDTH - MARGIN * 2;
+ private static final int BUTTON_HEIGHT = 20;
+
+ public WndMemory() {
+ super();
+
+ IconTitle titlebar = new IconTitle();
+ titlebar.setRect(0, 0, WIDTH, 0);
+ add(titlebar);
+
+ RenderedTextMultiline tfMesage = PixelScene.renderMultiline( Messages.get(this, "SorN"), 8 );
+ tfMesage.maxWidth(WIDTH - MARGIN * 2);
+ tfMesage.setPos(MARGIN, titlebar.bottom() + MARGIN);
+ add( tfMesage );
+
+ RedButton btnSave = new RedButton(Messages.get(MemoryFire.class,"save")) {
+ @Override
+ protected void onClick() {
+ Game.switchScene(LoadSaveScene.class);
+ }
+ };
+ btnSave.setRect(MARGIN, pos + MARGIN, BUTTON_WIDTH,
+ BUTTON_HEIGHT);
+ add( btnSave );
+
+ RedButton btnNosave = new RedButton(Messages.get(MemoryFire.class,"no_save")) {
+ @Override
+ protected void onClick() {
+ hide();
+ }
+ };
+ btnNosave.setRect(MARGIN, pos + MARGIN, BUTTON_WIDTH, BUTTON_HEIGHT);
+ add(btnNosave);
+
+ resize(WIDTH, (int) btnNosave.bottom());
+ }
+ }*/
+
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/blobs/ParalyticGas.java b/java/com/hmdzl/spspd/actors/blobs/ParalyticGas.java
new file mode 100644
index 00000000..1d873705
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/ParalyticGas.java
@@ -0,0 +1,54 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Paralysis;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.messages.Messages;
+
+public class ParalyticGas extends Blob {
+
+ @Override
+ protected void evolve() {
+ super.evolve();
+
+ Char ch;
+ for (int i = 0; i < LENGTH; i++) {
+ if (cur[i] > 0 && (ch = Actor.findChar(i)) != null) {
+ if (!ch.immunities().contains(this.getClass()))
+ Buff.prolong(ch, Paralysis.class, Paralysis.duration(ch));
+ }
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+
+ emitter.pour(Speck.factory(Speck.PARALYSIS), 0.6f);
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/Portal.java b/java/com/hmdzl/spspd/actors/blobs/Portal.java
new file mode 100644
index 00000000..80097983
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/Portal.java
@@ -0,0 +1,58 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.particles.ShaftParticle;
+import com.watabou.utils.Bundle;
+
+public class Portal extends Blob {
+
+ protected int pos;
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+
+ for (int i = 0; i < LENGTH; i++) {
+ if (cur[i] > 0) {
+ pos = i;
+ break;
+ }
+ }
+ }
+
+ @Override
+ protected void evolve() {
+ volume = off[pos] = cur[pos];
+ }
+
+ @Override
+ public void seed(int cell, int amount) {
+ cur[pos] = 0;
+ pos = cell;
+ volume = cur[pos] = amount;
+ }
+
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+ emitter.start(ShaftParticle.FACTORY, 0.9f, 0);
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/Regrowth.java b/java/com/hmdzl/spspd/actors/blobs/Regrowth.java
new file mode 100644
index 00000000..66634c1c
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/Regrowth.java
@@ -0,0 +1,78 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Roots;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.particles.LeafParticle;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.levels.Terrain;
+import com.hmdzl.spspd.scenes.GameScene;
+
+public class Regrowth extends Blob {
+
+ @Override
+ protected void evolve() {
+ super.evolve();
+
+ if (volume > 0) {
+
+ boolean mapUpdated = false;
+
+ for (int i = 0; i < LENGTH; i++) {
+ if (off[i] > 0) {
+ int c = Dungeon.level.map[i];
+ if (c == Terrain.EMPTY || c == Terrain.EMBERS
+ || c == Terrain.EMPTY_DECO) {
+
+ Level.set(i, cur[i] > 9 ? Terrain.HIGH_GRASS
+ : Terrain.GRASS);
+ mapUpdated = true;
+
+ } else if (c == Terrain.GRASS && cur[i] > 9) {
+
+ Level.set(i, Terrain.HIGH_GRASS);
+ mapUpdated = true;
+
+ }
+
+ Char ch = Actor.findChar(i);
+ if (ch != null) {
+ Buff.prolong(ch, Roots.class, TICK);
+ }
+ }
+ }
+
+ if (mapUpdated) {
+ GameScene.updateMap();
+ Dungeon.observe();
+ }
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+
+ emitter.start(LeafParticle.LEVEL_SPECIFIC, 0.2f, 0);
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/ShockWeb.java b/java/com/hmdzl/spspd/actors/blobs/ShockWeb.java
new file mode 100644
index 00000000..d73f6946
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/ShockWeb.java
@@ -0,0 +1,72 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Roots;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.particles.ShockWebParticle;
+import com.hmdzl.spspd.messages.Messages;
+
+public class ShockWeb extends Blob {
+
+ @Override
+ protected void evolve() {
+
+ for (int i = 0; i < LENGTH; i++) {
+
+ int offv = cur[i] > 0 ? cur[i] - 1 : 0;
+ off[i] = offv;
+
+ if (offv > 0) {
+
+ volume += offv;
+
+ Char ch = Actor.findChar(i);
+ if (ch != null) {
+ int damage = 5;
+ ch.damage(damage, this);
+ Buff.prolong(ch, Roots.class, TICK);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+
+ emitter.pour(ShockWebParticle.FACTORY, 0.4f);
+ }
+
+ @Override
+ public void seed(int cell, int amount) {
+ int diff = amount - cur[cell];
+ if (diff > 0) {
+ cur[cell] = amount;
+ volume += diff;
+ }
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/SlowWeb.java b/java/com/hmdzl/spspd/actors/blobs/SlowWeb.java
new file mode 100644
index 00000000..d6f1b993
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/SlowWeb.java
@@ -0,0 +1,71 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Roots;
+import com.hmdzl.spspd.actors.buffs.Slow;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.particles.WebParticle;
+import com.hmdzl.spspd.messages.Messages;
+
+public class SlowWeb extends Blob {
+
+ @Override
+ protected void evolve() {
+
+ for (int i = 0; i < LENGTH; i++) {
+
+ int offv = cur[i] > 0 ? cur[i] - 1 : 0;
+ off[i] = offv;
+
+ if (offv > 0) {
+
+ volume += offv;
+
+ Char ch = Actor.findChar(i);
+ if (ch != null) {
+ Buff.prolong(ch, Slow.class, TICK);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+
+ emitter.pour(WebParticle.FACTORY, 0.4f);
+ }
+
+ @Override
+ public void seed(int cell, int amount) {
+ int diff = amount - cur[cell];
+ if (diff > 0) {
+ cur[cell] = amount;
+ volume += diff;
+ }
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/StenchGas.java b/java/com/hmdzl/spspd/actors/blobs/StenchGas.java
new file mode 100644
index 00000000..0a7a6503
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/StenchGas.java
@@ -0,0 +1,40 @@
+package com.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Ooze;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.messages.Messages;
+
+/**
+ * Created by debenhame on 08/10/2014.
+ */
+public class StenchGas extends Blob {
+
+ @Override
+ protected void evolve() {
+ super.evolve();
+
+ Char ch;
+ for (int i = 0; i < LENGTH; i++) {
+ if (cur[i] > 0 && (ch = Actor.findChar(i)) != null) {
+ if (!ch.immunities().contains(this.getClass()))
+ Buff.affect(ch, Ooze.class);
+ }
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+
+ emitter.pour(Speck.factory(Speck.STENCH), 0.6f);
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/TarGas.java b/java/com/hmdzl/spspd/actors/blobs/TarGas.java
new file mode 100644
index 00000000..3b80b08b
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/TarGas.java
@@ -0,0 +1,85 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Burning;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.buffs.Tar;
+import com.hmdzl.spspd.messages.Messages;
+import com.watabou.utils.Random;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.scenes.GameScene;
+
+
+public class TarGas extends Blob {
+
+ @Override
+ protected void evolve() {
+ super.evolve();
+
+ Char ch;
+ for (int i = 0; i < LENGTH; i++) {
+ if (cur[i] > 0 && (ch = Actor.findChar(i)) != null) {
+ if (!ch.immunities().contains(this.getClass()))
+ Buff.affect(ch,Tar.class);
+ if ( ch.buff( Burning.class ) != null ) {GameScene.add(Blob.seed(ch.pos, 2, Fire.class));
+ }
+ }
+ }
+
+ Blob blob = Dungeon.level.blobs.get( Fire.class );
+ if (blob != null) {
+
+ for (int pos=0; pos < LENGTH; pos++) {
+
+ if ( cur[pos] > 0 && blob.cur[ pos ] < 2 ) {
+
+ int flammability = 0;
+
+ for (int n : Level.NEIGHBOURS8) {
+ if ( blob.cur[ pos + n ] > 0 ) {
+ flammability++;
+ }
+ }
+ if( Random.Int( 4 ) < flammability ) {
+ blob.volume += ( blob.cur[ pos ] = 2 );
+ volume -= ( cur[pos] / 2 );
+ cur[pos] -=( cur[pos] / 2 );
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+
+ emitter.pour(Speck.factory(Speck.TARGAS,true ), 0.6f);
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/blobs/ToxicGas.java b/java/com/hmdzl/spspd/actors/blobs/ToxicGas.java
new file mode 100644
index 00000000..a9163512
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/ToxicGas.java
@@ -0,0 +1,73 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.Badges;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.messages.Messages;
+import com.watabou.utils.Random;
+
+public class ToxicGas extends Blob implements Hero.Doom {
+
+ @Override
+ protected void evolve() {
+ super.evolve();
+
+ int levelDamage = 5 + Dungeon.depth * 5;
+
+ Char ch;
+ for (int i = 0; i < LENGTH; i++) {
+ if (cur[i] > 0 && (ch = Actor.findChar(i)) != null) {
+
+ int damage = (ch.HT + levelDamage) / 40;
+ if (Random.Int(40) < (ch.HT + levelDamage) % 40) {
+ damage++;
+ }
+
+ ch.damage(damage, this);
+ }
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+
+ emitter.pour(Speck.factory(Speck.TOXIC), 0.6f);
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+
+ @Override
+ public void onDeath() {
+
+ Badges.validateDeathFromGas();
+
+ Dungeon.fail(Messages.format(ResultDescriptions.GAS));
+ //GLog.n("You died from a toxic gas..");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/VenomGas.java b/java/com/hmdzl/spspd/actors/blobs/VenomGas.java
new file mode 100644
index 00000000..6deeb651
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/VenomGas.java
@@ -0,0 +1,83 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Venom;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.messages.Messages;
+import com.watabou.utils.Bundle;
+
+public class VenomGas extends Blob {
+
+ private int strength = 0;
+
+ @Override
+ protected void evolve() {
+ super.evolve();
+
+ if (volume == 0){
+ strength = 0;
+ } else {
+ Char ch;
+ for (int i = 0; i < LENGTH; i++) {
+ if (cur[i] > 0 && (ch = Actor.findChar(i)) != null) {
+ if (!ch.immunities().contains(this.getClass()))
+ Buff.affect(ch, Venom.class).set(2f, strength);
+ }
+ }
+ }
+ }
+
+ public void setStrength(int str){
+ if (str > strength)
+ strength = str;
+ }
+
+ private static final String STRENGTH = "strength";
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ strength = bundle.getInt( STRENGTH );
+ }
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put( STRENGTH, strength );
+ }
+
+ @Override
+ public void use( BlobEmitter emitter ) {
+ super.use( emitter );
+
+ emitter.pour( Speck.factory(Speck.VENOM), 0.6f );
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/Water.java b/java/com/hmdzl/spspd/actors/blobs/Water.java
new file mode 100644
index 00000000..a0c788ec
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/Water.java
@@ -0,0 +1,70 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.particles.LeafParticle;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.levels.Terrain;
+import com.hmdzl.spspd.scenes.GameScene;
+
+public class Water extends Blob {
+
+ @Override
+ protected void evolve() {
+ super.evolve();
+
+ if (volume > 0) {
+
+ boolean mapUpdated = false;
+
+ for (int i = 0; i < LENGTH; i++) {
+ if (off[i] > 0) {
+ int c = Dungeon.level.map[i];
+ if (c == Terrain.EMPTY || c == Terrain.EMBERS
+ || c == Terrain.EMPTY_DECO) {
+
+ Level.set(i, cur[i] > 9 ? Terrain.HIGH_GRASS
+ : Terrain.GRASS);
+ mapUpdated = true;
+
+ } else if (c == Terrain.GRASS && cur[i] > 9) {
+
+ Level.set(i, Terrain.HIGH_GRASS);
+ mapUpdated = true;
+
+ }
+
+ }
+ }
+
+ if (mapUpdated) {
+ GameScene.updateMap();
+ Dungeon.observe();
+ }
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+
+ emitter.start(LeafParticle.LEVEL_SPECIFIC, 0.2f, 0);
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/WaterOfAwareness.java b/java/com/hmdzl/spspd/actors/blobs/WaterOfAwareness.java
new file mode 100644
index 00000000..e96a8335
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/WaterOfAwareness.java
@@ -0,0 +1,105 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.Assets;
+import com.hmdzl.spspd.Badges;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.DungeonTilemap;
+import com.hmdzl.spspd.Journal;
+import com.hmdzl.spspd.Journal.Feature;
+import com.hmdzl.spspd.actors.buffs.Awareness;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.Identification;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.levels.Terrain;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.utils.GLog;
+import com.watabou.noosa.audio.Sample;
+
+public class WaterOfAwareness extends WellWater {
+
+ @Override
+ protected boolean affectHero(Hero hero) {
+
+ Sample.INSTANCE.play(Assets.SND_DRINK);
+ emitter.parent.add(new Identification(DungeonTilemap
+ .tileCenterToWorld(pos)));
+
+ hero.belongings.observe();
+
+ for (int i = 0; i < Level.getLength(); i++) {
+
+ int terr = Dungeon.level.map[i];
+ if ((Terrain.flags[terr] & Terrain.SECRET) != 0) {
+
+ //Level.set(i, Terrain.discover(terr));
+ //GameScene.updateMap(i);
+ Dungeon.level.discover( i );
+
+ if (Dungeon.visible[i]) {
+ GameScene.discoverTile(i, terr);
+ }
+ }
+ }
+
+ Buff.affect(hero, Awareness.class, Awareness.DURATION);
+ Dungeon.observe();
+
+ Dungeon.hero.interrupt();
+
+ GLog.p( Messages.get(this, "procced"));
+
+ Journal.remove(Feature.WELL_OF_AWARENESS);
+
+ return true;
+ }
+
+ @Override
+ protected Item affectItem(Item item) {
+ if (item.isIdentified()) {
+ return null;
+ } else {
+ item.identify();
+ Badges.validateItemLevelAquired(item);
+
+ emitter.parent.add(new Identification(DungeonTilemap
+ .tileCenterToWorld(pos)));
+
+ Journal.remove(Feature.WELL_OF_AWARENESS);
+
+ return item;
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+ emitter.pour(Speck.factory(Speck.QUESTION), 0.3f);
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/WaterOfHealth.java b/java/com/hmdzl/spspd/actors/blobs/WaterOfHealth.java
new file mode 100644
index 00000000..f08116a2
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/WaterOfHealth.java
@@ -0,0 +1,80 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.Assets;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.Journal;
+import com.hmdzl.spspd.Journal.Feature;
+import com.hmdzl.spspd.actors.buffs.Hunger;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.CellEmitter;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.effects.particles.ShaftParticle;
+import com.hmdzl.spspd.items.DewVial;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.items.potions.PotionOfHealing;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.utils.GLog;
+import com.watabou.noosa.audio.Sample;
+
+public class WaterOfHealth extends WellWater {
+
+ @Override
+ protected boolean affectHero(Hero hero) {
+
+ Sample.INSTANCE.play(Assets.SND_DRINK);
+
+ PotionOfHealing.heal(hero);
+ hero.belongings.uncurseEquipped();
+ hero.buff(Hunger.class).satisfy(Hunger.STARVING);
+
+ CellEmitter.get(pos).start(ShaftParticle.FACTORY, 0.2f, 3);
+
+ Dungeon.hero.interrupt();
+
+ GLog.p( Messages.get(this, "procced"));
+
+ Journal.remove(Feature.WELL_OF_HEALTH);
+
+ return true;
+ }
+
+ @Override
+ protected Item affectItem(Item item) {
+ if (item instanceof DewVial && !((DewVial) item).isFull()) {
+ ((DewVial) item).fill();
+ Journal.remove(Feature.WELL_OF_HEALTH);
+ return item;
+ }
+ Journal.remove(Feature.WELL_OF_HEALTH);
+ return null;
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+ emitter.start(Speck.factory(Speck.HEALING), 0.5f, 0);
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/WaterOfTransmutation.java b/java/com/hmdzl/spspd/actors/blobs/WaterOfTransmutation.java
new file mode 100644
index 00000000..b43d69f2
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/WaterOfTransmutation.java
@@ -0,0 +1,229 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.Journal;
+import com.hmdzl.spspd.Journal.Feature;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.items.Generator;
+import com.hmdzl.spspd.items.Generator.Category;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.items.artifacts.Artifact;
+import com.hmdzl.spspd.items.potions.Potion;
+import com.hmdzl.spspd.items.potions.PotionOfHealing;
+import com.hmdzl.spspd.items.potions.PotionOfMending;
+import com.hmdzl.spspd.items.potions.PotionOfMight;
+import com.hmdzl.spspd.items.potions.PotionOfStrength;
+import com.hmdzl.spspd.items.rings.Ring;
+import com.hmdzl.spspd.items.scrolls.Scroll;
+import com.hmdzl.spspd.items.scrolls.ScrollOfMagicalInfusion;
+import com.hmdzl.spspd.items.scrolls.ScrollOfUpgrade;
+import com.hmdzl.spspd.items.wands.Wand;
+import com.hmdzl.spspd.items.armor.Armor;
+import com.hmdzl.spspd.items.weapon.melee.MeleeWeapon;
+import com.hmdzl.spspd.messages.Messages;
+
+public class WaterOfTransmutation extends WellWater {
+
+ @Override
+ protected Item affectItem(Item item) {
+
+ if (item instanceof MeleeWeapon) {
+ item = changeWeapon((MeleeWeapon) item);
+ } else if (item instanceof Armor) {
+ item = changeArmor((Armor) item);
+ } else if (item instanceof Scroll) {
+ item = changeScroll((Scroll) item);
+ } else if (item instanceof Potion) {
+ item = changePotion((Potion) item);
+ } else if (item instanceof Ring) {
+ item = changeRing((Ring) item);
+ } else if (item instanceof Wand) {
+ item = changeWand((Wand) item);
+ } else if (item instanceof Artifact) {
+ item = changeArtifact((Artifact) item);
+ } else {
+ item = null;
+ }
+
+ if (item != null) {
+ Journal.remove(Feature.WELL_OF_TRANSMUTATION);
+ }
+
+ return item;
+
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+ emitter.start(Speck.factory(Speck.CHANGE), 0.2f, 0);
+ }
+
+ private MeleeWeapon changeWeapon(MeleeWeapon w) {
+
+ MeleeWeapon n;
+ do {
+ n = (MeleeWeapon) Generator.random(Category.MELEEWEAPON);
+ } while (n.getClass() == w.getClass());
+
+ n.level = 0;
+
+ int level = w.level;
+ if (level > 0) {
+ n.upgrade(level);
+ } else if (level < 0) {
+ n.degrade(-level);
+ }
+
+ n.enchantment = w.enchantment;
+ n.reinforced = w.reinforced;
+ n.levelKnown = w.levelKnown;
+ n.cursedKnown = w.cursedKnown;
+ n.cursed = w.cursed;
+
+ return n;
+
+ }
+
+ private Armor changeArmor(Armor r) {
+ Armor n;
+ do {
+ n = (Armor) Generator.random(Category.ARMOR);
+ } while (n.getClass() == r.getClass());
+
+ n.level = 0;
+
+ int level = r.level;
+ if (level > 0) {
+ n.upgrade(level);
+ } else if (level < 0) {
+ n.degrade(-level);
+ }
+ n.glyph = r.glyph;
+ n.reinforced = r.reinforced;
+ n.levelKnown = r.levelKnown;
+ n.cursedKnown = r.cursedKnown;
+ n.cursed = r.cursed;
+
+ return n;
+ }
+
+
+ private Ring changeRing(Ring r) {
+ Ring n;
+ do {
+ n = (Ring) Generator.random(Category.RING);
+ } while (n.getClass() == r.getClass());
+
+ n.level = 0;
+
+ int level = r.level;
+ if (level > 0) {
+ n.upgrade(level);
+ } else if (level < 0) {
+ n.degrade(-level);
+ }
+ n.reinforced = r.reinforced;
+ n.levelKnown = r.levelKnown;
+ n.cursedKnown = r.cursedKnown;
+ n.cursed = r.cursed;
+
+ return n;
+ }
+
+ private Artifact changeArtifact(Artifact a) {
+ Artifact n ;
+ do {
+ n = (Artifact) Generator.random(Category.ARTIFACT);
+ } while (n.getClass() == a.getClass());
+
+ if (n != null) {
+ n.cursedKnown = a.cursedKnown;
+ n.cursed = a.cursed;
+ n.levelKnown = a.levelKnown;
+ n.transferUpgrade(a.visiblyUpgraded());
+ }
+
+ return n;
+ }
+
+ private Wand changeWand(Wand w) {
+
+ Wand n;
+ do {
+ n = (Wand) Generator.random(Category.WAND);
+ } while (n.getClass() == w.getClass());
+
+ n.level = 0;
+ n.updateLevel();
+ n.upgrade(w.level);
+
+ n.reinforced = w.reinforced;
+ n.levelKnown = w.levelKnown;
+ n.cursedKnown = w.cursedKnown;
+ n.cursed = w.cursed;
+
+ return n;
+ }
+
+ private Scroll changeScroll(Scroll s) {
+ if (s instanceof ScrollOfUpgrade) {
+
+ return new ScrollOfMagicalInfusion();
+
+ } else if (s instanceof ScrollOfMagicalInfusion) {
+
+ return new ScrollOfUpgrade();
+
+ } else {
+
+ Scroll n;
+ do {
+ n = (Scroll) Generator.random(Category.SCROLL);
+ } while (n.getClass() == s.getClass());
+ return n;
+ }
+ }
+
+ private Potion changePotion(Potion p) {
+ if (p instanceof PotionOfStrength) {
+
+ return new PotionOfMight();
+
+ } else if (p instanceof PotionOfMending){
+
+ return new PotionOfHealing();
+
+ } else {
+
+ Potion n;
+ do {
+ n = (Potion) Generator.random(Category.POTION);
+ } while (n.getClass() == p.getClass());
+ return n;
+ }
+ }
+
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/WaterOfUpgradeEating.java b/java/com/hmdzl/spspd/actors/blobs/WaterOfUpgradeEating.java
new file mode 100644
index 00000000..83f89588
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/WaterOfUpgradeEating.java
@@ -0,0 +1,100 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.items.Stylus;
+import com.hmdzl.spspd.items.UpgradeBlobRed;
+import com.hmdzl.spspd.items.UpgradeBlobViolet;
+import com.hmdzl.spspd.items.UpgradeBlobYellow;
+import com.hmdzl.spspd.items.potions.Potion;
+import com.hmdzl.spspd.items.scrolls.Scroll;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.plants.Seedpod;
+import com.watabou.utils.Random;
+
+public class WaterOfUpgradeEating extends WellWater {
+
+ @Override
+ protected Item affectItem(Item item) {
+
+ if (item.isUpgradable()) {
+ item = eatUpgradable((Item) item);
+ } else if (item instanceof Scroll
+ || item instanceof Potion
+ || item instanceof Stylus) {
+ item = eatStandard((Item) item);
+ } else {
+ item = null;
+ }
+
+ return item;
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+ emitter.start(Speck.factory(Speck.CHANGE), 0.2f, 0);
+ }
+
+ private Item eatUpgradable(Item w) {
+
+ int ups = w.level;
+
+ Item n = null;
+
+ if (Random.Float()<(ups/10)){
+
+ n = new UpgradeBlobViolet();
+
+ } else if (Random.Float()<(ups/5)) {
+
+ n = new UpgradeBlobRed();
+
+ } else if (Random.Float()<(ups/3)) {
+
+ n = new UpgradeBlobYellow();
+
+ } else {
+
+ n =new Seedpod.Seed() ;
+ }
+
+ return n;
+ }
+
+ private Item eatStandard(Item w) {
+
+ Item n = null;
+
+ if (Random.Float()<0.1f){
+ n = new UpgradeBlobYellow();
+ } else {
+ n = new Seedpod.Seed() ;
+ }
+
+ return n;
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/Web.java b/java/com/hmdzl/spspd/actors/blobs/Web.java
new file mode 100644
index 00000000..345ba4d4
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/Web.java
@@ -0,0 +1,70 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Roots;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.particles.WebParticle;
+import com.hmdzl.spspd.messages.Messages;
+
+public class Web extends Blob {
+
+ @Override
+ protected void evolve() {
+
+ for (int i = 0; i < LENGTH; i++) {
+
+ int offv = cur[i] > 0 ? cur[i] - 1 : 0;
+ off[i] = offv;
+
+ if (offv > 0) {
+
+ volume += offv;
+
+ Char ch = Actor.findChar(i);
+ if (ch != null) {
+ Buff.prolong(ch, Roots.class, TICK);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+
+ emitter.pour(WebParticle.FACTORY, 0.4f);
+ }
+
+ @Override
+ public void seed(int cell, int amount) {
+ int diff = amount - cur[cell];
+ if (diff > 0) {
+ cur[cell] = amount;
+ volume += diff;
+ }
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/WellWater.java b/java/com/hmdzl/spspd/actors/blobs/WellWater.java
new file mode 100644
index 00000000..9a3f438e
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/WellWater.java
@@ -0,0 +1,166 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.blobs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.Journal;
+import com.hmdzl.spspd.Journal.Feature;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.items.Heap;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.levels.Terrain;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Random;
+
+public class WellWater extends Blob {
+
+ public int pos;
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+
+ for (int i = 0; i < LENGTH; i++) {
+ if (cur[i] > 0) {
+ pos = i;
+ break;
+ }
+ }
+ }
+
+ @Override
+ protected void evolve() {
+ volume = off[pos] = cur[pos];
+
+ if (Dungeon.visible[pos]) {
+ if (this instanceof WaterOfAwareness) {
+ Journal.add(Feature.WELL_OF_AWARENESS);
+ } else if (this instanceof WaterOfHealth) {
+ Journal.add(Feature.WELL_OF_HEALTH);
+ } else if (this instanceof WaterOfTransmutation) {
+ Journal.add(Feature.WELL_OF_TRANSMUTATION);
+ }
+ }
+ }
+
+
+ protected boolean affect() {
+
+ Heap heap;
+
+ if (pos == Dungeon.hero.pos && affectHero(Dungeon.hero)) {
+
+ volume = off[pos] = cur[pos] = 0;
+ return true;
+
+ } else if ((heap = Dungeon.level.heaps.get(pos)) != null) {
+
+ Item oldItem = heap.peek();
+ Item newItem = affectItem(oldItem);
+
+ if (newItem != null) {
+
+ if (newItem == oldItem) {
+
+ } else if (oldItem.quantity() > 1) {
+
+ oldItem.quantity(oldItem.quantity() - 1);
+ heap.drop(newItem);
+
+ } else {
+ heap.replace(oldItem, newItem);
+ }
+
+ heap.sprite.link();
+ volume = off[pos] = cur[pos] = 0;
+
+ return true;
+
+ } else {
+
+ int newPlace;
+ do {
+ newPlace = pos + Level.NEIGHBOURS8[Random.Int(8)];
+ } while (!Level.passable[newPlace] && !Level.avoid[newPlace]);
+ Dungeon.level.drop(heap.pickUp(), newPlace).sprite.drop(pos);
+
+ return false;
+
+ }
+
+ } else {
+
+ return false;
+
+ }
+ }
+
+ protected boolean affectHero(Hero hero) {
+ return false;
+ }
+
+ protected Item affectItem(Item item) {
+ return null;
+ }
+
+ @Override
+ public void seed(int cell, int amount) {
+ cur[pos] = 0;
+ pos = cell;
+ volume = cur[pos] = amount;
+ }
+
+ public static void affectCell(int cell) {
+
+ Class>[] waters = { WaterOfHealth.class, WaterOfAwareness.class,
+ WaterOfTransmutation.class};
+
+ for (Class> waterClass : waters) {
+ WellWater water = (WellWater) Dungeon.level.blobs.get(waterClass);
+ if (water != null && water.volume > 0 && water.pos == cell
+ && water.affect()) {
+
+ Level.set(cell, Terrain.EMPTY_WELL);
+ GameScene.updateMap(cell);
+
+ return;
+ }
+ }
+ }
+
+ public static boolean affectCellPlant(int cell) {
+
+ boolean transmuted = false;
+
+ Class>[] waters = { WaterOfHealth.class, WaterOfAwareness.class,
+ WaterOfTransmutation.class};
+
+ for (Class> waterClass : waters) {
+ WellWater water = (WellWater) Dungeon.level.blobs.get(waterClass);
+ if (water != null && water.volume > 0 && water.pos == cell
+ && water.affect()) {
+
+ GameScene.updateMap(cell);
+ transmuted = true;
+ }
+ }
+ return transmuted;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/blobs/weather/WeatherOfDead.java b/java/com/hmdzl/spspd/actors/blobs/weather/WeatherOfDead.java
new file mode 100644
index 00000000..aac908a1
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/weather/WeatherOfDead.java
@@ -0,0 +1,55 @@
+package com.hmdzl.spspd.actors.blobs.weather;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.blobs.Blob;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.DeadRaise;
+import com.hmdzl.spspd.actors.buffs.Hot;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.particles.DeadParticle;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.messages.Messages;
+
+public class WeatherOfDead extends Blob {
+
+ protected int pos;
+
+ @Override
+ protected void evolve() {
+ int from = WIDTH + 1;
+ int to = Level.LENGTH - WIDTH - 1;
+
+ int[] map = Dungeon.level.map;
+
+ for (int pos=from; pos < to; pos++) {
+ if (cur[pos] > 0) {
+
+ off[pos] = cur[pos];
+ volume += off[pos];
+
+ } else {
+ off[pos] = 0;
+ }
+ }
+
+ Hero hero = Dungeon.hero;
+ if (hero.isAlive() && cur[hero.pos] > 0) {
+ Buff.prolong( hero, DeadRaise.class, 2f );
+ Buff.detach(hero,Hot.class);
+ }
+
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+ emitter.start(DeadParticle.FACTORY, 0.3f, 0);
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/blobs/weather/WeatherOfQuite.java b/java/com/hmdzl/spspd/actors/blobs/weather/WeatherOfQuite.java
new file mode 100644
index 00000000..9fa1379c
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/weather/WeatherOfQuite.java
@@ -0,0 +1,53 @@
+package com.hmdzl.spspd.actors.blobs.weather;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.blobs.Blob;
+import com.hmdzl.spspd.actors.buffs.Bless;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.particles.ShaftParticle;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.messages.Messages;
+
+public class WeatherOfQuite extends Blob {
+
+ protected int pos;
+
+ @Override
+ protected void evolve() {
+ int from = WIDTH + 1;
+ int to = Level.LENGTH - WIDTH - 1;
+
+ int[] map = Dungeon.level.map;
+
+ for (int pos=from; pos < to; pos++) {
+ if (cur[pos] > 0) {
+
+ off[pos] = cur[pos];
+ volume += off[pos];
+
+ } else {
+ off[pos] = 0;
+ }
+ }
+
+ Hero hero = Dungeon.hero;
+ if (hero.isAlive() && cur[hero.pos] > 0) {
+ Buff.prolong( hero, Bless.class, 5f );
+ }
+
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+ emitter.start( ShaftParticle.FACTORY, 0.8f, 0);
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/blobs/weather/WeatherOfRain.java b/java/com/hmdzl/spspd/actors/blobs/weather/WeatherOfRain.java
new file mode 100644
index 00000000..884d8c91
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/weather/WeatherOfRain.java
@@ -0,0 +1,55 @@
+package com.hmdzl.spspd.actors.blobs.weather;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.blobs.Blob;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Dry;
+import com.hmdzl.spspd.actors.buffs.Wet;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.particles.RainParticle;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.messages.Messages;
+
+public class WeatherOfRain extends Blob {
+
+ protected int pos;
+
+ @Override
+ protected void evolve() {
+
+ int from = WIDTH + 1;
+ int to = Level.LENGTH - WIDTH - 1;
+
+ int[] map = Dungeon.level.map;
+
+ for (int pos=from; pos < to; pos++) {
+ if (cur[pos] > 0) {
+
+ off[pos] = cur[pos];
+ volume += off[pos];
+
+ } else {
+ off[pos] = 0;
+ }
+ }
+
+ Hero hero = Dungeon.hero;
+ if (hero.isAlive() && cur[hero.pos] > 0) {
+ Buff.prolong( hero, Wet.class, Wet.DURATION );
+ Buff.detach(hero,Dry.class);
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+ emitter.start(RainParticle.FACTORY, 0.8f, 0);
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/blobs/weather/WeatherOfSand.java b/java/com/hmdzl/spspd/actors/blobs/weather/WeatherOfSand.java
new file mode 100644
index 00000000..50815020
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/weather/WeatherOfSand.java
@@ -0,0 +1,54 @@
+package com.hmdzl.spspd.actors.blobs.weather;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.blobs.Blob;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Dry;
+import com.hmdzl.spspd.actors.buffs.Wet;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.particles.SandParticle;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.messages.Messages;
+
+public class WeatherOfSand extends Blob {
+
+ protected int pos;
+
+ @Override
+ protected void evolve() {
+ int from = WIDTH + 1;
+ int to = Level.LENGTH - WIDTH - 1;
+
+ int[] map = Dungeon.level.map;
+
+ for (int pos=from; pos < to; pos++) {
+ if (cur[pos] > 0) {
+
+ off[pos] = cur[pos];
+ volume += off[pos];
+
+ } else {
+ off[pos] = 0;
+ }
+ }
+
+ Hero hero = Dungeon.hero;
+ if (hero.isAlive() && cur[hero.pos] > 0) {
+ Buff.prolong( hero, Dry.class, Dry.DURATION );
+ Buff.detach(hero,Wet.class);
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+ emitter.start(SandParticle.FACTORY, 0.5f, 0);
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/blobs/weather/WeatherOfSnow.java b/java/com/hmdzl/spspd/actors/blobs/weather/WeatherOfSnow.java
new file mode 100644
index 00000000..1fdbed87
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/weather/WeatherOfSnow.java
@@ -0,0 +1,55 @@
+package com.hmdzl.spspd.actors.blobs.weather;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.blobs.Blob;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Cold;
+import com.hmdzl.spspd.actors.buffs.Hot;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.particles.SnowParticle;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.messages.Messages;
+
+public class WeatherOfSnow extends Blob {
+
+ protected int pos;
+
+ @Override
+ protected void evolve() {
+ int from = WIDTH + 1;
+ int to = Level.LENGTH - WIDTH - 1;
+
+ int[] map = Dungeon.level.map;
+
+ for (int pos=from; pos < to; pos++) {
+ if (cur[pos] > 0) {
+
+ off[pos] = cur[pos];
+ volume += off[pos];
+
+ } else {
+ off[pos] = 0;
+ }
+ }
+
+ Hero hero = Dungeon.hero;
+ if (hero.isAlive() && cur[hero.pos] > 0) {
+ Buff.prolong( hero, Cold.class, Cold.DURATION );
+ Buff.detach(hero,Hot.class);
+ }
+
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+ emitter.start(SnowParticle.FACTORY, 0.5f, 0);
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/blobs/weather/WeatherOfSun.java b/java/com/hmdzl/spspd/actors/blobs/weather/WeatherOfSun.java
new file mode 100644
index 00000000..97f57c1e
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/blobs/weather/WeatherOfSun.java
@@ -0,0 +1,54 @@
+package com.hmdzl.spspd.actors.blobs.weather;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.blobs.Blob;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Cold;
+import com.hmdzl.spspd.actors.buffs.Hot;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.effects.BlobEmitter;
+import com.hmdzl.spspd.effects.particles.ShaftParticle;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.messages.Messages;
+
+public class WeatherOfSun extends Blob {
+
+ protected int pos;
+
+ @Override
+ protected void evolve() {
+ int from = WIDTH + 1;
+ int to = Level.LENGTH - WIDTH - 1;
+
+ int[] map = Dungeon.level.map;
+
+ for (int pos=from; pos < to; pos++) {
+ if (cur[pos] > 0) {
+
+ off[pos] = cur[pos];
+ volume += off[pos];
+
+ } else {
+ off[pos] = 0;
+ }
+ }
+
+ Hero hero = Dungeon.hero;
+ if (hero.isAlive() && cur[hero.pos] > 0) {
+ Buff.prolong( hero, Hot.class, Hot.DURATION );
+ Buff.detach(hero,Cold.class);
+ }
+ }
+
+ @Override
+ public void use(BlobEmitter emitter) {
+ super.use(emitter);
+ emitter.start(ShaftParticle.FACTORY, 0.9f, 0);
+ }
+
+ @Override
+ public String tileDesc() {
+ return Messages.get(this, "desc");
+ }
+
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/AflyBless.java b/java/com/hmdzl/spspd/actors/buffs/AflyBless.java
new file mode 100644
index 00000000..1679fd43
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/AflyBless.java
@@ -0,0 +1,49 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class AflyBless extends FlavourBuff {
+
+ public static final float DURATION = 200f;
+
+ {
+ type = buffType.POSITIVE;
+ }
+
+
+ @Override
+ public int icon() {
+ return BuffIndicator.NO_FUSHIGI;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Amok.java b/java/com/hmdzl/spspd/actors/buffs/Amok.java
new file mode 100644
index 00000000..52510154
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Amok.java
@@ -0,0 +1,52 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.mobs.Mob;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Amok extends FlavourBuff {
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.AMOK;
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ if (target instanceof Mob)
+ ((Mob)target).aggro( null );
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Arcane.java b/java/com/hmdzl/spspd/actors/buffs/Arcane.java
new file mode 100644
index 00000000..ed315833
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Arcane.java
@@ -0,0 +1,41 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Arcane extends FlavourBuff {
+
+ public static final float DURATION = 30f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.ARCANE;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/ArmorBreak.java b/java/com/hmdzl/spspd/actors/buffs/ArmorBreak.java
new file mode 100644
index 00000000..d8599590
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/ArmorBreak.java
@@ -0,0 +1,92 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class ArmorBreak extends FlavourBuff {
+
+ private int level = 0;
+ private static final String LEVEL = "level";
+ protected float left;
+ private static final String LEFT = "left";
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(LEVEL, level);
+ bundle.put(LEFT, left);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ level = bundle.getInt(LEVEL);
+ left = bundle.getFloat(LEFT);
+ }
+
+ public void set(float duration) {
+ this.left = duration;
+ };
+ public static final float DURATION = 10f;
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ public boolean act() {
+
+ spend(TICK);
+ left -= TICK;
+ if (left <= 0)
+ detach();
+ return true;
+
+ }
+
+ public int level() {
+ return level;
+ }
+
+ public void level(int value) {
+ if (level < value) {
+ level = value;
+ }
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.ARMOR_BREAK;
+ }
+
+
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns(),level());
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/AttackDown.java b/java/com/hmdzl/spspd/actors/buffs/AttackDown.java
new file mode 100644
index 00000000..3637893d
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/AttackDown.java
@@ -0,0 +1,88 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class AttackDown extends FlavourBuff {
+
+ private int level = 0;
+ private static final String LEVEL = "level";
+ protected float left;
+ private static final String LEFT = "left";
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(LEVEL, level);
+ bundle.put(LEFT, left);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ level = bundle.getInt(LEVEL);
+ left = bundle.getFloat(LEFT);
+ }
+
+ public void set(float duration) {
+ this.left = duration;
+ };
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ public boolean act() {
+
+ spend(TICK);
+ left -= TICK;
+ if (left <= 0)
+ detach();
+ return true;
+
+ }
+ @Override
+ public int icon() {
+ return BuffIndicator.WEAKNESS;
+ }
+
+ public int level() {
+ return level;
+ }
+
+ public void level(int value) {
+ if (level < value) {
+ level = value;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns(),level());
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/AttackUp.java b/java/com/hmdzl/spspd/actors/buffs/AttackUp.java
new file mode 100644
index 00000000..2317c3b5
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/AttackUp.java
@@ -0,0 +1,88 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class AttackUp extends FlavourBuff {
+
+ private int level = 0;
+ private static final String LEVEL = "level";
+ protected float left;
+ private static final String LEFT = "left";
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(LEVEL, level);
+ bundle.put(LEFT, left);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ level = bundle.getInt(LEVEL);
+ left = bundle.getFloat(LEFT);
+ }
+
+ public void set(float duration) {
+ this.left = duration;
+ };
+
+ {
+ type = buffType.POSITIVE;
+ }
+
+ public boolean act() {
+
+ spend(TICK);
+ left -= TICK;
+ if (left <= 0)
+ detach();
+ return true;
+
+ }
+ @Override
+ public int icon() {
+ return BuffIndicator.ATTACK_UP;
+ }
+
+ public int level() {
+ return level;
+ }
+
+ public void level(int value) {
+ if (level < value) {
+ level = value;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns(),level());
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Awareness.java b/java/com/hmdzl/spspd/actors/buffs/Awareness.java
new file mode 100644
index 00000000..12e0e25e
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Awareness.java
@@ -0,0 +1,52 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Awareness extends FlavourBuff {
+
+ public static final float DURATION = 2f;
+
+ {
+ type = buffType.POSITIVE;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.MIND_VISION;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ Dungeon.observe();
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Barkskin.java b/java/com/hmdzl/spspd/actors/buffs/Barkskin.java
new file mode 100644
index 00000000..a4197530
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Barkskin.java
@@ -0,0 +1,85 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class Barkskin extends Buff {
+
+ private int barkleft = 0;
+
+ private static final String BARKLEFT = "barkleft";
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(BARKLEFT, barkleft);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ barkleft = bundle.getInt(BARKLEFT);
+ }
+
+ @Override
+ public boolean act() {
+ if (target.isAlive()) {
+
+ spend(TICK);
+ barkleft = (int)barkleft/2;
+ if (barkleft <= 1) {
+ detach();
+ }
+
+ } else {
+
+ detach();
+
+ }
+
+ return true;
+ }
+
+ public int level() {
+ return barkleft;
+ }
+
+ public void level(int value) {
+ if (barkleft < value) {
+ barkleft = value;
+ }
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.BARKSKIN;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", barkleft);
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/BerryRegeneration.java b/java/com/hmdzl/spspd/actors/buffs/BerryRegeneration.java
new file mode 100644
index 00000000..cd910de2
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/BerryRegeneration.java
@@ -0,0 +1,92 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.hero.HeroSubClass;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class BerryRegeneration extends Buff {
+
+ private int regenleft = 0;
+
+ private static final String REGENLEFT = "regenleft";
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(REGENLEFT, regenleft);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ regenleft = bundle.getInt(REGENLEFT);
+ }
+
+ public int level() {
+ return regenleft;
+ }
+
+ public void level(int value) {
+ if (regenleft < value) {
+ regenleft = value;
+ }
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.REGEN;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", regenleft);
+ }
+
+ @Override
+ public boolean act() {
+ if (target.isAlive()) {
+ if (Dungeon.hero.subClass == HeroSubClass.PASTOR && target.HP < target.HT*1.5){
+ target.HP += 2 * (5+Math.round(regenleft/25));
+ } else if (target.HP < target.HT) {
+ target.HP += Math.min(5+Math.round(regenleft/25),(target.HT-target.HP));
+ }
+
+ spend(TICK);
+ if (--regenleft <= 0) {
+ detach();
+ }
+
+ } else {
+
+ detach();
+
+ }
+
+ return true;
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Bleeding.java b/java/com/hmdzl/spspd/actors/buffs/Bleeding.java
new file mode 100644
index 00000000..5cd0fbb3
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Bleeding.java
@@ -0,0 +1,107 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.effects.Splash;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.PointF;
+import com.watabou.utils.Random;
+
+public class Bleeding extends Buff {
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ protected int level;
+
+ 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);
+ }
+
+ public void set(int level) {
+ this.level = level;
+ };
+
+ @Override
+ public int icon() {
+ return BuffIndicator.BLEEDING;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public boolean act() {
+ if (target.isAlive()) {
+
+ if ((level = Random.Int(level / 3, level/2)) > 0) {
+
+ target.damage(level, this);
+ if (target.sprite.visible) {
+ Splash.at(target.sprite.center(), -PointF.PI / 2,
+ PointF.PI / 6, target.sprite.blood(),
+ Math.min(10 * level / target.HT, 10));
+ }
+
+ if (target == Dungeon.hero && !target.isAlive()) {
+ Dungeon.fail(Messages.format(ResultDescriptions.BLEEDING));
+ //GLog.n("You bled to death...");
+ }
+
+ spend(TICK);
+ } else {
+ detach();
+ }
+
+ } else {
+
+ detach();
+
+ }
+
+ return true;
+ }
+
+ @Override
+ public String heroMessage() {
+ return Messages.get(this, "heromsg");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", level);
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Bless.java b/java/com/hmdzl/spspd/actors/buffs/Bless.java
new file mode 100644
index 00000000..30947fb5
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Bless.java
@@ -0,0 +1,85 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.blobs.ConfusionGas;
+import com.hmdzl.spspd.actors.blobs.CorruptGas;
+import com.hmdzl.spspd.actors.blobs.ElectriShock;
+import com.hmdzl.spspd.actors.blobs.Fire;
+import com.hmdzl.spspd.actors.blobs.Freezing;
+import com.hmdzl.spspd.actors.blobs.ParalyticGas;
+import com.hmdzl.spspd.actors.blobs.Regrowth;
+import com.hmdzl.spspd.actors.blobs.ShockWeb;
+import com.hmdzl.spspd.actors.blobs.StenchGas;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.blobs.VenomGas;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfRain;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSand;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSnow;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSun;
+import com.hmdzl.spspd.actors.blobs.Web;
+import com.hmdzl.spspd.levels.traps.LightningTrap;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Bless extends FlavourBuff {
+
+ public static final float DURATION = 30f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.BLESS;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ {
+ immunities.add( ParalyticGas.class );
+ immunities.add( ToxicGas.class );
+ immunities.add( ConfusionGas.class );
+ immunities.add( StenchGas.class );
+ immunities.add( VenomGas.class );
+ immunities.add( CorruptGas.class );
+ immunities.add( Fire.class );
+ immunities.add( Freezing.class );
+ immunities.add( ElectriShock.class );
+ immunities.add( LightningTrap.Electricity.class );
+ immunities.add( Regrowth.class );
+ immunities.add( Web.class );
+ immunities.add( ShockWeb.class );
+ immunities.add( Hot.class );
+ immunities.add( Cold.class );
+ immunities.add( Wet.class );
+ immunities.add( Dry.class );
+ immunities.add(WeatherOfRain.class);
+ immunities.add(WeatherOfSand.class);
+ immunities.add(WeatherOfSnow.class);
+ immunities.add(WeatherOfSun.class);
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Blindness.java b/java/com/hmdzl/spspd/actors/buffs/Blindness.java
new file mode 100644
index 00000000..f43d099e
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Blindness.java
@@ -0,0 +1,55 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Blindness extends FlavourBuff {
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ Dungeon.observe();
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.BLINDNESS;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String heroMessage() {
+ return Messages.get(this, "heromsg");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/BloodAngry.java b/java/com/hmdzl/spspd/actors/buffs/BloodAngry.java
new file mode 100644
index 00000000..04ffbf2c
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/BloodAngry.java
@@ -0,0 +1,102 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.blobs.ConfusionGas;
+import com.hmdzl.spspd.actors.blobs.CorruptGas;
+import com.hmdzl.spspd.actors.blobs.ElectriShock;
+import com.hmdzl.spspd.actors.blobs.Fire;
+import com.hmdzl.spspd.actors.blobs.Freezing;
+import com.hmdzl.spspd.actors.blobs.ParalyticGas;
+import com.hmdzl.spspd.actors.blobs.Regrowth;
+import com.hmdzl.spspd.actors.blobs.ShockWeb;
+import com.hmdzl.spspd.actors.blobs.StenchGas;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.blobs.VenomGas;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfRain;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSand;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSnow;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSun;
+import com.hmdzl.spspd.actors.blobs.Web;
+import com.hmdzl.spspd.levels.traps.LightningTrap;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class BloodAngry extends Buff {
+
+ public static final float DURATION = 30f;
+
+ private float left;
+ private static final String LEFT = "left";
+
+ @Override
+ public int icon() {
+ return BuffIndicator.BLOODANGRY;
+ }
+
+ @Override
+ public boolean act() {
+
+ if (target.HP > target.HT/3){
+ target.HP = Math.max(target.HT/3, target.HP - 1);
+ }
+ spend(TICK);
+ left -= TICK;
+ if (left <= 0){
+ detach();
+ } else
+ if (target.HP < target.HT/3){
+ target.HP = Math.max(target.HT/3, target.HP + 1);
+ }
+ spend(TICK);
+ left -= TICK;
+ if (left <= 0){
+ detach();
+ }
+ return true;
+ }
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(LEFT, left);
+
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ left = bundle.getInt(LEFT);
+ }
+ public void set(float left){
+ this.left = left;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", left);
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/BloodImbue.java b/java/com/hmdzl/spspd/actors/buffs/BloodImbue.java
new file mode 100644
index 00000000..bc19f6f4
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/BloodImbue.java
@@ -0,0 +1,76 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Random;
+
+/**
+ * Created by debenhame on 19/11/2014.
+ */
+public class BloodImbue extends FlavourBuff {
+
+ public static final float DURATION = 10f;
+
+ {
+ type = buffType.POSITIVE;
+ }
+
+
+ public void proc(Char enemy) {
+ switch (Random.Int(4)){
+ case 0:
+ Buff.affect(enemy, Cripple.class,3);
+ break;
+ case 1:
+ Buff.affect(enemy, Roots.class,3);
+ break;
+ case 2:
+ Buff.affect(enemy, Paralysis.class,3);
+ break;
+ case 3:
+ break;
+ }
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.PBLOOD;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+
+ {
+ immunities.add(Paralysis.class);
+ immunities.add(Roots.class);
+ immunities.add(Slow.class);
+ immunities.add(Bleeding.class);
+ immunities.add(Weakness.class);
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/BoxStar.java b/java/com/hmdzl/spspd/actors/buffs/BoxStar.java
new file mode 100644
index 00000000..597acab9
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/BoxStar.java
@@ -0,0 +1,60 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Random;
+
+public class BoxStar extends FlavourBuff {
+
+ {
+ type = buffType.POSITIVE;
+ }
+
+ public int proc(int damage, Char attacker) {
+
+ damage = 0;
+ return damage;
+ }
+
+ public int icon() {
+ return BuffIndicator.UNKNOW_BOX;
+ }
+
+ //@Override
+ //public void fx(boolean on) {
+ //if (on) target.sprite.add(CharSprite.State.ILLUMINATED);
+ //else target.sprite.remove(CharSprite.State.ILLUMINATED);
+ //}
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Buff.java b/java/com/hmdzl/spspd/actors/buffs/Buff.java
new file mode 100644
index 00000000..4f1e17d0
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Buff.java
@@ -0,0 +1,136 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import java.text.DecimalFormat;
+import java.util.HashSet;
+
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Buff extends Actor {
+
+ public Char target;
+
+ public enum buffType {POSITIVE, NEGATIVE, NEUTRAL, SILENT};
+ public buffType type = buffType.SILENT;
+
+ public HashSet> resistances = new HashSet>();
+
+ public HashSet> immunities = new HashSet>();
+
+ public boolean attachTo(Char target) {
+
+ if (target.immunities().contains(getClass())) {
+ return false;
+ }
+
+ this.target = target;
+ target.add(this);
+
+ if (target.buffs().contains(this)){
+ if (target.sprite != null) fx( true );
+ return true;
+ } else
+ return false;
+ }
+
+ public void detach() {
+ fx( false );
+ target.remove(this);
+ }
+
+ @Override
+ public boolean act() {
+ diactivate();
+ return true;
+ }
+
+ public int icon() {
+ return BuffIndicator.NONE;
+ }
+
+ public void fx(boolean on) {
+ //do nothing by default
+ };
+
+ public String heroMessage(){
+ return null;
+ }
+
+ public String desc(){
+ return "";
+ }
+
+ //to handle the common case of showing how many turns are remaining in a buff description.
+ protected String dispTurns(float input){
+ return new DecimalFormat("#.##").format(input);
+ }
+
+ public static T append(Char target, Class buffClass) {
+ try {
+ T buff = buffClass.newInstance();
+ buff.attachTo(target);
+ return buff;
+ } catch (Exception e) {
+ //ShatteredPixelDungeon.reportException(e);
+ return null;
+ }
+ }
+
+ public static T append(Char target,
+ Class buffClass, float duration) {
+ T buff = append(target, buffClass);
+ buff.spend(duration);
+ return buff;
+ }
+
+ public static T affect(Char target, Class buffClass) {
+ T buff = target.buff(buffClass);
+ if (buff != null) {
+ return buff;
+ } else {
+ return append(target, buffClass);
+ }
+ }
+
+ public static T affect(Char target,
+ Class buffClass, float duration) {
+ T buff = affect(target, buffClass);
+ buff.spend(duration);
+ return buff;
+ }
+
+ public static T prolong(Char target,
+ Class buffClass, float duration) {
+ T buff = affect(target, buffClass);
+ buff.postpone(duration);
+ return buff;
+ }
+
+ public static void detach(Buff buff) {
+ if (buff != null) {
+ buff.detach();
+ }
+ }
+
+ public static void detach(Char target, Class extends Buff> cl) {
+ detach(target.buff(cl));
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Burning.java b/java/com/hmdzl/spspd/actors/buffs/Burning.java
new file mode 100644
index 00000000..6c9dbbb4
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Burning.java
@@ -0,0 +1,189 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Badges;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.Blob;
+import com.hmdzl.spspd.actors.blobs.Fire;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.actors.mobs.Thief;
+import com.hmdzl.spspd.effects.particles.ElmoParticle;
+import com.hmdzl.spspd.items.Heap;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.items.food.meatfood.ChargrilledMeat;
+import com.hmdzl.spspd.items.food.meatfood.MysteryMeat;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.items.scrolls.Scroll;
+import com.hmdzl.spspd.items.scrolls.ScrollOfMagicalInfusion;
+import com.hmdzl.spspd.items.scrolls.ScrollOfUpgrade;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.hmdzl.spspd.utils.GLog;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Random;
+
+public class Burning extends Buff implements Hero.Doom {
+
+ private static final String TXT_BURNS_UP = "%s burns up!";
+ private static final String TXT_BURNED_TO_DEATH = "You burned to death...";
+
+ private static final float DURATION = 8f;
+
+ private float left;
+
+ private static final String LEFT = "left";
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(LEFT, left);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ left = bundle.getFloat(LEFT);
+ }
+
+ @Override
+ public boolean act() {
+
+ if (target.isAlive()) {
+
+ if (target instanceof Hero) {
+ Buff.prolong(target, Light.class, TICK * 1.01f);
+ }
+
+ target.damage(Random.Int(1, Math.min(1000,target.HT/20)), this);
+ Buff.detach( target, Chill.class);
+
+ if (target instanceof Hero) {
+
+ Hero hero = (Hero) target;
+ Item item = hero.belongings.randomUnequipped();
+ if (item instanceof Scroll
+ && !(item instanceof ScrollOfUpgrade || item instanceof ScrollOfMagicalInfusion)){
+
+ item = item.detach(hero.belongings.backpack);
+ GLog.w(Messages.get(this, "burnsup", item.toString()));
+
+ Heap.burnFX(hero.pos);
+
+ } else if (item instanceof MysteryMeat) {
+
+ item = item.detach(hero.belongings.backpack);
+ ChargrilledMeat steak = new ChargrilledMeat();
+ if (!steak.collect(hero.belongings.backpack)) {
+ Dungeon.level.drop(steak, hero.pos).sprite.drop();
+ }
+ GLog.w(Messages.get(this, "burnsup", item.toString()));
+
+ Heap.burnFX(hero.pos);
+
+ }
+
+ } else if (target instanceof Thief) {
+
+ Item item = ((Thief) target).item;
+
+ if (item instanceof Scroll &&
+ !(item instanceof ScrollOfUpgrade || item instanceof ScrollOfMagicalInfusion)) {
+ target.sprite.emitter().burst( ElmoParticle.FACTORY, 6 );
+ ((Thief)target).item = null;
+ }
+
+ }
+
+ } else {
+ detach();
+ }
+
+ if (Level.flamable[target.pos]) {
+ GameScene.add(Blob.seed(target.pos, 4, Fire.class));
+ }
+
+ spend(TICK);
+ left -= TICK;
+
+ if (left <= 0 || (Level.water[target.pos] && !target.flying)) {
+
+ detach();
+ }
+
+ return true;
+ }
+
+ public void reignite(Char ch) {
+ left = duration(ch);
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.FIRE;
+ }
+
+ @Override
+ public void fx(boolean on) {
+ if (on) target.sprite.add(CharSprite.State.BURNING);
+ else target.sprite.remove(CharSprite.State.BURNING);
+ }
+
+
+ @Override
+ public String heroMessage() {
+ return Messages.get(this, "heromsg");
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ public static float duration(Char ch) {
+ Resistance r = ch.buff(Resistance.class);
+ Tar tar = ch.buff(Tar.class);
+ if (ch.isAlive() && tar!=null){
+ return DURATION;
+ } else return r != null ? r.durationFactor() * DURATION : DURATION;
+
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns(left));
+ }
+
+ @Override
+ public void onDeath() {
+
+ Badges.validateDeathFromFire();
+
+ Dungeon.fail(Messages.format(ResultDescriptions.BURNING));
+ //GLog.n(TXT_BURNED_TO_DEATH);
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Charm.java b/java/com/hmdzl/spspd/actors/buffs/Charm.java
new file mode 100644
index 00000000..8731fee1
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Charm.java
@@ -0,0 +1,72 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class Charm extends FlavourBuff {
+
+ public int object = 0;
+
+ private static final String OBJECT = "object";
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(OBJECT, object);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ object = bundle.getInt(OBJECT);
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.HEART;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ public static float durationFactor(Char ch) {
+ Resistance r = ch.buff(Resistance.class);
+ return r != null ? r.durationFactor() : 1;
+ }
+
+ @Override
+ public String heroMessage() {
+ return Messages.get(this, "heromsg");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Chill.java b/java/com/hmdzl/spspd/actors/buffs/Chill.java
new file mode 100644
index 00000000..81ab6899
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Chill.java
@@ -0,0 +1,117 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.actors.mobs.Thief;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.items.food.meatfood.FrozenCarpaccio;
+import com.hmdzl.spspd.items.food.meatfood.MysteryMeat;
+import com.hmdzl.spspd.items.potions.Potion;
+import com.hmdzl.spspd.items.potions.PotionOfMight;
+import com.hmdzl.spspd.items.potions.PotionOfStrength;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.hmdzl.spspd.utils.GLog;
+import com.watabou.utils.Random;
+
+import java.text.DecimalFormat;
+
+public class Chill extends FlavourBuff {
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public boolean attachTo(Char target) {
+ //can't chill what's frozen!
+ if (target.buff(Frost.class) != null) return false;
+
+ if (super.attachTo(target)){
+ Burning.detach( target, Burning.class );
+
+ //chance of potion breaking is the same as speed factor.
+ if (Random.Float(1f) > speedFactor() && target instanceof Hero) {
+
+ Hero hero = (Hero)target;
+ Item item = hero.belongings.randomUnequipped();
+ if (item instanceof Potion
+ && !(item instanceof PotionOfStrength || item instanceof PotionOfMight)) {
+
+ item = item.detach( hero.belongings.backpack );
+ GLog.w(Messages.get(this, "freezes", item.toString()));
+ ((Potion) item).shatter(hero.pos);
+
+ } else if (item instanceof MysteryMeat) {
+
+ item = item.detach( hero.belongings.backpack );
+ FrozenCarpaccio carpaccio = new FrozenCarpaccio();
+ if (!carpaccio.collect( hero.belongings.backpack )) {
+ Dungeon.level.drop( carpaccio, target.pos ).sprite.drop();
+ }
+ GLog.w(Messages.get(this, "freezes", item.toString()));
+
+ }
+ } else if (target instanceof Thief) {
+
+ Item item = ((Thief) target).item;
+
+ if (item instanceof Potion && !(item instanceof PotionOfStrength || item instanceof PotionOfMight)) {
+ ((Potion) ((Thief) target).item).shatter(target.pos);
+ ((Thief) target).item = null;
+ }
+
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ //reduces speed by 10% for every turn remaining, capping at 50%
+ public float speedFactor(){
+ return Math.max(0.5f, 1 - cooldown()*0.1f);
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.FROST;
+ }
+
+ //@Override
+ public void fx(boolean on) {
+ if (on) target.sprite.add(CharSprite.State.CHILLED);
+ else target.sprite.remove(CharSprite.State.CHILLED);
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns(), new DecimalFormat("#.##").format((1f-speedFactor())*100f));
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Cold.java b/java/com/hmdzl/spspd/actors/buffs/Cold.java
new file mode 100644
index 00000000..c3f52a0e
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Cold.java
@@ -0,0 +1,48 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Cold extends FlavourBuff {
+
+ public static final float DURATION = 10f;
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.COLD;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Combo.java b/java/com/hmdzl/spspd/actors/buffs/Combo.java
new file mode 100644
index 00000000..c0cdecde
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Combo.java
@@ -0,0 +1,76 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Badges;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.hmdzl.spspd.utils.GLog;
+
+public class Combo extends Buff {
+
+ private static String TXT_COMBO = "%d hit combo!";
+
+ public int count = 0;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.COMBO;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ public int hit(Char enemy, int damage) {
+
+ count++;
+
+ if (count >= 3) {
+
+ Badges.validateMasteryCombo(count);
+
+ GLog.p( Messages.get(this, "combo", count));
+ postpone(1.41f - Math.min(0.8f,count / 20f));
+ return (int) (damage * (count - 2) / 10f);
+
+ } else {
+
+ postpone(1.1f);
+ return 0;
+
+ }
+ }
+
+ @Override
+ public boolean act() {
+ detach();
+ return true;
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc") +
+ (count <= 2 ?
+ Messages.get(this, "notenough") :
+ Messages.get(this, "bonusdmg", ((count - 2) * 20f)));
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Corruption.java b/java/com/hmdzl/spspd/actors/buffs/Corruption.java
new file mode 100644
index 00000000..a3fd2e0d
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Corruption.java
@@ -0,0 +1,72 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2019 Evan Debenham
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Corruption extends Buff {
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ private float buildToDamage = 0f;
+
+ @Override
+ public boolean act() {
+ buildToDamage += target.HT/200f;
+
+ int damage = (int)buildToDamage;
+ buildToDamage -= damage;
+
+ if (damage > 0 && damage < target.HP)
+ target.damage(damage, this);
+
+ spend(TICK);
+
+ return true;
+ }
+
+ @Override
+ public void fx(boolean on) {
+ if (on) target.sprite.add( CharSprite.State.DARKENED );
+ else if (target.invisible == 0) target.sprite.remove( CharSprite.State.DARKENED );
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.CORRUPT;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/CountDown.java b/java/com/hmdzl/spspd/actors/buffs/CountDown.java
new file mode 100644
index 00000000..3b6d74aa
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/CountDown.java
@@ -0,0 +1,85 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.effects.particles.ShadowParticle;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class CountDown extends Buff {
+
+ private int ticks = 0;
+
+ private static final String TICKS = "ticks";
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(TICKS, ticks);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ ticks = bundle.getInt(TICKS);
+ }
+
+
+ @Override
+ public int icon() {
+ return BuffIndicator.COUNTDOWN;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", ticks);
+ }
+
+ @Override
+ public boolean act() {
+ if (target.isAlive()) {
+ ticks++;
+ if (ticks>5){
+ target.sprite.emitter().burst(ShadowParticle.CURSE, 6);
+ target.damage(Math.round(target.HT / 4), this);
+ detach();
+ }
+ }
+
+ if (!target.isAlive() && target == Dungeon.hero) {
+ Dungeon.fail(Messages.format(ResultDescriptions.COUNTDOWN));
+ //GLog.n(TXT_HERO_KILLED, toString());
+ }
+
+ spend(TICK);
+
+ return true;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Cripple.java b/java/com/hmdzl/spspd/actors/buffs/Cripple.java
new file mode 100644
index 00000000..54d68e33
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Cripple.java
@@ -0,0 +1,50 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Cripple extends FlavourBuff {
+
+ public static final float DURATION = 10f;
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.CRIPPLE;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String heroMessage() {
+ return Messages.get(this, "heromsg");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/DamageUp.java b/java/com/hmdzl/spspd/actors/buffs/DamageUp.java
new file mode 100644
index 00000000..9e08955d
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/DamageUp.java
@@ -0,0 +1,76 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class DamageUp extends FlavourBuff {
+
+ private int level = 0;
+ private static final String LEVEL = "level";
+ protected float left;
+ @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);
+ }
+
+ {
+ type = buffType.POSITIVE;
+ }
+
+ public boolean act() {
+ spend(TICK);
+ return true;
+ }
+ @Override
+ public int icon() {
+ return BuffIndicator.ATTACK_UP;
+ }
+
+ public int level() {
+ return level;
+ }
+
+ public void level(int value) {
+ if (level < value) {
+ level = value;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc",level());
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/DeadRaise.java b/java/com/hmdzl/spspd/actors/buffs/DeadRaise.java
new file mode 100644
index 00000000..f1de81fc
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/DeadRaise.java
@@ -0,0 +1,48 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class DeadRaise extends FlavourBuff {
+
+ public static final float DURATION = 5f;
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.TERROR;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/DefenceUp.java b/java/com/hmdzl/spspd/actors/buffs/DefenceUp.java
new file mode 100644
index 00000000..894865ef
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/DefenceUp.java
@@ -0,0 +1,90 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class DefenceUp extends FlavourBuff {
+
+ private int level = 0;
+ private static final String LEVEL = "level";
+ protected float left;
+ private static final String LEFT = "left";
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(LEVEL, level);
+ bundle.put(LEFT, left);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ level = bundle.getInt(LEVEL);
+ left = bundle.getFloat(LEFT);
+ }
+
+ public void set(float duration) {
+ this.left = duration;
+ };
+
+ {
+ type = buffType.POSITIVE;
+ }
+
+ private static final float DURATION = 20f;
+
+ public boolean act() {
+
+ spend(TICK);
+ left -= TICK;
+ if (left <= 0)
+ detach();
+ return true;
+
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.ARMOR;
+ }
+
+ public int level() {
+ return level;
+ }
+
+ public void level(int value) {
+ if (level < value) {
+ level = value;
+ }
+ }
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns(),level());
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Dewcharge.java b/java/com/hmdzl/spspd/actors/buffs/Dewcharge.java
new file mode 100644
index 00000000..81e7afc1
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Dewcharge.java
@@ -0,0 +1,42 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Dewcharge extends FlavourBuff {
+
+ public static final float DURATION = 300f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.DEWCHARGE;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns(cooldown()+1));
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Disarm.java b/java/com/hmdzl/spspd/actors/buffs/Disarm.java
new file mode 100644
index 00000000..6ad8c9e5
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Disarm.java
@@ -0,0 +1,52 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Disarm extends FlavourBuff {
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ private static final float DURATION = 5f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.DISARM;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @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;
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/Drowsy.java b/java/com/hmdzl/spspd/actors/buffs/Drowsy.java
new file mode 100644
index 00000000..eba176f6
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Drowsy.java
@@ -0,0 +1,65 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Random;
+
+public class Drowsy extends Buff {
+
+ {
+ type = buffType.NEUTRAL;
+ }
+
+
+ @Override
+ public int icon() {
+ return BuffIndicator.DROWSY;
+ }
+
+ @Override
+ public boolean attachTo(Char target) {
+ if (!target.immunities().contains(Sleep.class)
+ && super.attachTo(target)) {
+ if (cooldown() == 0)
+ spend(Random.Int(3, 6));
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean act() {
+ Buff.affect(target, MagicalSleep.class);
+
+ detach();
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns(cooldown()+1));
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Dry.java b/java/com/hmdzl/spspd/actors/buffs/Dry.java
new file mode 100644
index 00000000..5a6e23fc
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Dry.java
@@ -0,0 +1,48 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Dry extends FlavourBuff {
+
+ public static final float DURATION = 10f;
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.DRY;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/EarthImbue.java b/java/com/hmdzl/spspd/actors/buffs/EarthImbue.java
new file mode 100644
index 00000000..a482c2c6
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/EarthImbue.java
@@ -0,0 +1,59 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.effects.CellEmitter;
+import com.hmdzl.spspd.effects.particles.EarthParticle;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+/**
+ * Created by debenhame on 19/11/2014.
+ */
+public class EarthImbue extends FlavourBuff {
+
+ public static final float DURATION = 30f;
+
+ public void proc(Char enemy) {
+ Buff.affect(enemy, Roots.class, 2);
+ CellEmitter.bottom(enemy.pos).start(EarthParticle.FACTORY, 0.05f, 8);
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.PEARTH;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+
+ {
+ immunities.add(Paralysis.class);
+ immunities.add(Roots.class);
+ immunities.add(Slow.class);
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/ExitFind.java b/java/com/hmdzl/spspd/actors/buffs/ExitFind.java
new file mode 100644
index 00000000..502a473e
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/ExitFind.java
@@ -0,0 +1,42 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.messages.Messages;
+
+public class ExitFind extends FlavourBuff {
+
+ public static final float DURATION = 1f;
+
+ {
+ type = buffType.POSITIVE;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ Dungeon.observe();
+ }
+
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/Feed.java b/java/com/hmdzl/spspd/actors/buffs/Feed.java
new file mode 100644
index 00000000..e94e33f0
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Feed.java
@@ -0,0 +1,61 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.blobs.ConfusionGas;
+import com.hmdzl.spspd.actors.blobs.CorruptGas;
+import com.hmdzl.spspd.actors.blobs.ElectriShock;
+import com.hmdzl.spspd.actors.blobs.Fire;
+import com.hmdzl.spspd.actors.blobs.Freezing;
+import com.hmdzl.spspd.actors.blobs.ParalyticGas;
+import com.hmdzl.spspd.actors.blobs.Regrowth;
+import com.hmdzl.spspd.actors.blobs.ShockWeb;
+import com.hmdzl.spspd.actors.blobs.StenchGas;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.blobs.VenomGas;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfRain;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSand;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSnow;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSun;
+import com.hmdzl.spspd.actors.blobs.Web;
+import com.hmdzl.spspd.levels.traps.LightningTrap;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Feed extends FlavourBuff {
+
+ public static final float DURATION = 30f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.FEED;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/FireImbue.java b/java/com/hmdzl/spspd/actors/buffs/FireImbue.java
new file mode 100644
index 00000000..789daf07
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/FireImbue.java
@@ -0,0 +1,100 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.effects.particles.FlameParticle;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.levels.Terrain;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Random;
+
+/**
+ * Created by debenhame on 19/11/2014.
+ */
+public class FireImbue extends Buff {
+
+ public static final float DURATION = 30f;
+
+ protected float left;
+
+ private static final String LEFT = "left";
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(LEFT, left);
+
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ left = bundle.getFloat(LEFT);
+ }
+
+ public void set(float duration) {
+ this.left = duration;
+ };
+
+ @Override
+ public boolean act() {
+ if (Dungeon.level.map[target.pos] == Terrain.GRASS) {
+ Level.set(target.pos, Terrain.EMBERS);
+ GameScene.updateMap(target.pos);
+ }
+
+ spend(TICK);
+ left -= TICK;
+ if (left <= 0)
+ detach();
+
+ return true;
+ }
+
+ public void proc(Char enemy) {
+ if (Random.Int(2) == 0)
+ Buff.affect(enemy, Burning.class).reignite(enemy);
+
+ enemy.sprite.emitter().burst(FlameParticle.FACTORY, 2);
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.PFIRE;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns(left));
+ }
+
+ {
+ immunities.add(Burning.class);
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/FlavourBuff.java b/java/com/hmdzl/spspd/actors/buffs/FlavourBuff.java
new file mode 100644
index 00000000..2dac2e99
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/FlavourBuff.java
@@ -0,0 +1,36 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import java.text.DecimalFormat;
+
+//buff whose only logic is to wait and detach after a time.
+public class FlavourBuff extends Buff {
+
+ @Override
+ public boolean act() {
+ detach();
+ return true;
+ }
+
+ //flavour buffs can all just rely on cooldown()
+ protected String dispTurns() {
+ //add one turn as buffs act last, we want them to end at 1 visually, even if they end at 0 internally.
+ return dispTurns(cooldown()+1f);
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/ForeverShadow.java b/java/com/hmdzl/spspd/actors/buffs/ForeverShadow.java
new file mode 100644
index 00000000..b45f415b
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/ForeverShadow.java
@@ -0,0 +1,93 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.ConfusionGas;
+import com.hmdzl.spspd.actors.blobs.CorruptGas;
+import com.hmdzl.spspd.actors.blobs.ElectriShock;
+import com.hmdzl.spspd.actors.blobs.Fire;
+import com.hmdzl.spspd.actors.blobs.Freezing;
+import com.hmdzl.spspd.actors.blobs.ParalyticGas;
+import com.hmdzl.spspd.actors.blobs.Regrowth;
+import com.hmdzl.spspd.actors.blobs.ShockWeb;
+import com.hmdzl.spspd.actors.blobs.StenchGas;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.blobs.VenomGas;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfRain;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSand;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSnow;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSun;
+import com.hmdzl.spspd.actors.blobs.Web;
+import com.hmdzl.spspd.levels.traps.LightningTrap;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class ForeverShadow extends FlavourBuff {
+
+ public static final float DURATION = 30f;
+
+ {
+ type = buffType.POSITIVE;
+ }
+
+ @Override
+ public boolean attachTo(Char target) {
+ if (super.attachTo(target)) {
+ target.invisible++;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void detach() {
+ if (target.invisible > 0)
+ target.invisible--;
+ super.detach();
+ }
+
+ @Override
+ public void fx(boolean on) {
+ if (on) target.sprite.add( CharSprite.State.INVISIBLE );
+ else if (target.invisible == 0) target.sprite.remove( CharSprite.State.INVISIBLE );
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.BLESS;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+
+
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/Frost.java b/java/com/hmdzl/spspd/actors/buffs/Frost.java
new file mode 100644
index 00000000..d2df6c5d
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Frost.java
@@ -0,0 +1,135 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.Freezing;
+import com.hmdzl.spspd.actors.blobs.FrostGas;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSnow;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.actors.mobs.Thief;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.items.food.meatfood.FrozenCarpaccio;
+import com.hmdzl.spspd.items.food.meatfood.MysteryMeat;
+import com.hmdzl.spspd.items.potions.Potion;
+import com.hmdzl.spspd.items.potions.PotionOfMight;
+import com.hmdzl.spspd.items.potions.PotionOfStrength;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.utils.GLog;
+
+public class Frost extends FlavourBuff {
+
+ private static final float DURATION = 5f;
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public boolean attachTo(Char target) {
+ if (super.attachTo(target)) {
+
+ target.paralysed++;
+ Buff.detach( target, Burning.class );
+ Buff.detach( target, Chill.class );
+
+ if (target instanceof Hero) {
+
+ Hero hero = (Hero) target;
+ Item item = hero.belongings.randomUnequipped();
+ if (item instanceof Potion
+ && !(item instanceof PotionOfStrength || item instanceof PotionOfMight)){
+
+ item = item.detach(hero.belongings.backpack);
+ GLog.w( Messages.get(this, "freezes", item.toString()));
+ ((Potion) item).shatter(hero.pos);
+
+ } else if (item instanceof MysteryMeat) {
+
+ item = item.detach(hero.belongings.backpack);
+ FrozenCarpaccio carpaccio = new FrozenCarpaccio();
+ if (!carpaccio.collect(hero.belongings.backpack)) {
+ Dungeon.level.drop(carpaccio, target.pos).sprite.drop();
+ }
+ GLog.w( Messages.get(this, "freezes", item.toString()));
+
+ }
+ } else if (target instanceof Thief){
+ Item item = ((Thief) target).item;
+
+ if (item instanceof Potion && !(item instanceof PotionOfStrength || item instanceof PotionOfMight)) {
+ ((Potion) ((Thief) target).item).shatter(target.pos);
+ ((Thief) target).item = null;
+ }
+ }
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ if (target.paralysed > 0)
+ target.paralysed--;
+ if (Level.water[target.pos])
+ Buff.prolong(target, Chill.class, 4f);
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.FROST;
+ }
+
+ //@Override
+ public void fx(boolean on) {
+ if (on) target.sprite.add(CharSprite.State.FROZEN);
+ else target.sprite.remove(CharSprite.State.FROZEN);
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @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;
+ }
+
+ {
+ immunities.add( Chill.class );
+ immunities.add( FrostGas.class );
+ immunities.add( Freezing.class );
+ immunities.add( Cold.class );
+ immunities.add(WeatherOfSnow.class);
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/FrostImbue.java b/java/com/hmdzl/spspd/actors/buffs/FrostImbue.java
new file mode 100644
index 00000000..a0e1abe8
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/FrostImbue.java
@@ -0,0 +1,62 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2019 Evan Debenham
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.effects.particles.SnowParticle;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.noosa.Image;
+
+public class FrostImbue extends FlavourBuff {
+
+ {
+ type = buffType.POSITIVE;
+ }
+
+ public static final float DURATION = 50f;
+
+ public void proc(Char enemy){
+ Buff.affect(enemy, Chill.class, 2f);
+ enemy.sprite.emitter().burst( SnowParticle.FACTORY, 2 );
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.FROST;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+
+ {
+ immunities.add( Frost.class );
+ immunities.add( Chill.class );
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/FullMoonStrength.java b/java/com/hmdzl/spspd/actors/buffs/FullMoonStrength.java
new file mode 100644
index 00000000..871e01ad
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/FullMoonStrength.java
@@ -0,0 +1,70 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.Statistics;
+import com.hmdzl.spspd.messages.Messages;
+import com.watabou.utils.Bundle;
+
+public class FullMoonStrength extends Buff {
+
+ public static float LEVEL = 0.4f;
+
+ private int hits = (Dungeon.checkNight() ? Math.max(8, Math.round(Statistics.deepestFloor/5)+9) : Math.max(2, Math.round(Statistics.deepestFloor/5)+3));
+
+
+ private static final String HITS = "hits";
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(HITS, hits);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ hits = bundle.getInt(HITS);
+ }
+
+ //private int hits = Math.max(2, Math.round(Statistics.deepestFloor/5)+3);
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String heroMessage() {
+ return Messages.get(this, "heromsg");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc");
+ }
+
+ @Override
+ public void detach() {
+ hits--;
+ if(hits==0){
+ super.detach();
+ }
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Fury.java b/java/com/hmdzl/spspd/actors/buffs/Fury.java
new file mode 100644
index 00000000..7a7812cd
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Fury.java
@@ -0,0 +1,57 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Fury extends Buff {
+
+ public static float LEVEL = 0.5f;
+
+ @Override
+ public boolean act() {
+ if (target.HP > target.HT * LEVEL) {
+ detach();
+ }
+
+ spend(TICK);
+
+ return true;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.FURY;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String heroMessage() {
+ return Messages.get(this, "heromsg");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/GasesImmunity.java b/java/com/hmdzl/spspd/actors/buffs/GasesImmunity.java
new file mode 100644
index 00000000..23c4011d
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/GasesImmunity.java
@@ -0,0 +1,67 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.blobs.ConfusionGas;
+import com.hmdzl.spspd.actors.blobs.DarkGas;
+import com.hmdzl.spspd.actors.blobs.ParalyticGas;
+import com.hmdzl.spspd.actors.blobs.StenchGas;
+import com.hmdzl.spspd.actors.blobs.TarGas;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfDead;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfRain;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSand;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSnow;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSun;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class GasesImmunity extends FlavourBuff {
+
+ public static final float DURATION = 15f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.IMMUNITY;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ {
+ immunities.add(ParalyticGas.class);
+ immunities.add(ToxicGas.class);
+ immunities.add(ConfusionGas.class);
+ immunities.add(StenchGas.class);
+ immunities.add(DarkGas.class);
+ immunities.add(TarGas.class);
+ immunities.add(Locked.class);
+ immunities.add(WeatherOfDead.class);
+ immunities.add(WeatherOfRain.class);
+ immunities.add(WeatherOfSun.class);
+ immunities.add(WeatherOfSnow.class);
+ immunities.add(WeatherOfSand.class);
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/GlassShield.java b/java/com/hmdzl/spspd/actors/buffs/GlassShield.java
new file mode 100644
index 00000000..b9c79f63
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/GlassShield.java
@@ -0,0 +1,81 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class GlassShield extends Buff {
+
+ {
+ type = buffType.POSITIVE;
+ }
+
+ private int turns = 0;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.GLASS_SHIELD;
+ }
+
+ @Override
+ public void detach() {
+ turns--;
+ if(turns<=0){
+ super.detach();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc",turns());
+ }
+
+ private static final String TURNS = "turns";
+
+ public int turns() {
+ return turns;
+ }
+
+ public void turns(int value) {
+ if (turns< value) {
+ turns = value;
+ }
+ }
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(TURNS, turns);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ turns = bundle.getInt(TURNS);
+ }
+
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/GoldTouch.java b/java/com/hmdzl/spspd/actors/buffs/GoldTouch.java
new file mode 100644
index 00000000..b6f8bcb8
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/GoldTouch.java
@@ -0,0 +1,62 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.blobs.ConfusionGas;
+import com.hmdzl.spspd.actors.blobs.CorruptGas;
+import com.hmdzl.spspd.actors.blobs.ElectriShock;
+import com.hmdzl.spspd.actors.blobs.Fire;
+import com.hmdzl.spspd.actors.blobs.Freezing;
+import com.hmdzl.spspd.actors.blobs.ParalyticGas;
+import com.hmdzl.spspd.actors.blobs.Regrowth;
+import com.hmdzl.spspd.actors.blobs.ShockWeb;
+import com.hmdzl.spspd.actors.blobs.StenchGas;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.blobs.VenomGas;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfRain;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSand;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSnow;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSun;
+import com.hmdzl.spspd.actors.blobs.Web;
+import com.hmdzl.spspd.levels.traps.LightningTrap;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class GoldTouch extends FlavourBuff {
+
+ public static final float DURATION = 30f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.GOLDTOUCH;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/GrowSeed.java b/java/com/hmdzl/spspd/actors/buffs/GrowSeed.java
new file mode 100644
index 00000000..25909034
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/GrowSeed.java
@@ -0,0 +1,130 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Random;
+
+public class GrowSeed extends Buff implements Hero.Doom {
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ private static final float DURATION = 10f;
+
+ private float left;
+
+ private static final String LEFT = "left";
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(LEFT, left);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ left = bundle.getFloat(LEFT);
+ }
+
+ @Override
+ public boolean act() {
+
+ if (target.isAlive()) {
+
+ int dmg = Random.Int(1, target.HT/20);
+
+ target.damage(dmg, this);
+
+ int p = target.pos;
+ for (int n : Level.NEIGHBOURS8) {
+ Char ch = Actor.findChar(n+p);
+ if (ch != null && ch != target && ch.isAlive()) {
+ ch.HP +=Random.Int( Math.min(dmg,ch.HT - ch.HP));
+ }
+ }
+
+
+ } else {
+ detach();
+ }
+
+
+ spend(TICK);
+ left -= TICK;
+
+ if (left <= 0) {
+
+ detach();
+ }
+
+ return true;
+ }
+
+ public void reignite(Char ch) {
+ left = duration(ch);
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.GROW_SEED;
+ }
+
+ @Override
+ public void fx(boolean on) {
+ if (on) target.sprite.add(CharSprite.State.REGROW);
+ else target.sprite.remove(CharSprite.State.REGROW);
+ }
+
+ @Override
+ public String heroMessage() {
+ return Messages.get(this, "heromsg");
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns(left));
+ }
+
+ public static float duration(Char ch) {
+ Resistance r = ch.buff(Resistance.class);
+ return r != null ? r.durationFactor() * DURATION : DURATION;
+ }
+
+ @Override
+ public void onDeath() {
+ Dungeon.fail(Messages.format(ResultDescriptions.ITEM));
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Haste.java b/java/com/hmdzl/spspd/actors/buffs/Haste.java
new file mode 100644
index 00000000..791bf797
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Haste.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Haste extends FlavourBuff {
+
+ public static final float DURATION = 10f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.HASTE;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/HighAttack.java b/java/com/hmdzl/spspd/actors/buffs/HighAttack.java
new file mode 100644
index 00000000..2c039547
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/HighAttack.java
@@ -0,0 +1,125 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.levels.Terrain;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class HighAttack extends Buff {
+
+ public static final float DURATION = 30f;
+
+ private int level = 0;
+ private static final String LEVEL = "level";
+ public static boolean nearwall = false;
+
+ @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);
+ }
+
+
+
+ {
+ type = buffType.POSITIVE;
+ }
+
+ @Override
+ public boolean attachTo(Char target) {
+ if (super.attachTo(target)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public boolean act() {
+
+ if (target.isAlive()) {
+ for (int i = 0; i < Level.NEIGHBOURS8.length; i++) {
+ final int pos = target.pos + Level.NEIGHBOURS8[i];
+ if (Dungeon.level.map[pos] == Terrain.WALL ||
+ Dungeon.level.map[pos] == Terrain.WALL_DECO ||
+ Dungeon.level.map[pos] == Terrain.UNBREAK_WALL ||
+ Dungeon.level.map[pos] == Terrain.CHASM_WALL ||
+ Dungeon.level.map[pos] == Terrain.DOOR ||
+ Dungeon.level.map[pos] == Terrain.OPEN_DOOR||
+ Dungeon.level.map[pos] == Terrain.SECRET_DOOR||
+ Dungeon.level.map[pos] == Terrain.BARRICADE ||
+ Dungeon.level.map[pos] == Terrain.BOOKSHELF
+ ) {
+ nearwall = true;
+ }
+ }
+ if (nearwall == false){
+ detach();
+ } else {
+ level++;
+ spend(TICK);
+ nearwall = false;
+ }
+
+ } else {
+ detach();
+ }
+
+ return true;
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.HIGH_ATTACK;
+ }
+
+ public int level() {
+ return level;
+ }
+
+ public void level(int value) {
+ if (level < value) {
+ level = value;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc",level);
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/HighLight.java b/java/com/hmdzl/spspd/actors/buffs/HighLight.java
new file mode 100644
index 00000000..5143aaf5
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/HighLight.java
@@ -0,0 +1,64 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class HighLight extends FlavourBuff {
+
+ public static final float DURATION = 500f;
+ public static final int DISTANCE = 10;
+
+ @Override
+ public boolean attachTo(Char target) {
+ if (super.attachTo(target)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.LIGHT;
+ }
+
+ @Override
+ public void fx(boolean on) {
+ if (on) target.sprite.add(CharSprite.State.ILLUMINATED);
+ else target.sprite.remove(CharSprite.State.ILLUMINATED);
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/HighVoice.java b/java/com/hmdzl/spspd/actors/buffs/HighVoice.java
new file mode 100644
index 00000000..d4305d6c
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/HighVoice.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.hmdzl.spspd.utils.GLog;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Random;
+
+public class HighVoice extends FlavourBuff {
+
+ public static final float DURATION = 10f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.VOICE_UP;
+ }
+
+ protected float left;
+ private static final String LEFT = "left";
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(LEFT, left);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ left = bundle.getFloat(LEFT);
+ }
+
+ public void set(float duration) {
+ this.left = duration;
+ };
+
+ @Override
+ public boolean act() {
+ if (target.isAlive()) {
+ if (target.buff(HighVoice.class) != null && Random.Int(8) == 0) {
+ if (target.HP > target.HT*0.75 ){
+ Buff.affect(target,Haste.class,5f);
+ GLog.p(Messages.get(this,"speed",Dungeon.hero.givenName()));
+ } else {
+ target.HP += (int)(target.HT/4);
+ GLog.p(Messages.get(this,"heal",Dungeon.hero.givenName()));
+ }
+ }
+ left -= TICK;
+ if (left <= 2)
+ detach();
+ spend(TICK);
+
+
+ } else {
+
+ detach();
+
+ }
+
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Hot.java b/java/com/hmdzl/spspd/actors/buffs/Hot.java
new file mode 100644
index 00000000..3208298f
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Hot.java
@@ -0,0 +1,48 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Hot extends FlavourBuff {
+
+ public static final float DURATION = 10f;
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.HOT;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Hunger.java b/java/com/hmdzl/spspd/actors/buffs/Hunger.java
new file mode 100644
index 00000000..61fbab21
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Hunger.java
@@ -0,0 +1,219 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Badges;
+import com.hmdzl.spspd.Challenges;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.items.artifacts.Artifact;
+import com.hmdzl.spspd.items.artifacts.HornOfPlenty;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.hmdzl.spspd.utils.GLog;
+import com.watabou.utils.Bundle;
+
+public class Hunger extends Buff implements Hero.Doom {
+
+ private static final float STEP = 10f;
+
+ public static final float OVERFED = 150f;
+ public static final float HUNGRY = 600f;
+ public static final float STARVING = 800f;
+
+ private float level;
+ private float partialDamage;
+
+ private static final String LEVEL = "level";
+ private static final String PARTIALDAMAGE = "partialDamage";
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(LEVEL, level);
+ bundle.put( PARTIALDAMAGE, partialDamage );
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ level = bundle.getFloat(LEVEL);
+ partialDamage = bundle.getFloat(PARTIALDAMAGE);
+ }
+
+ @Override
+ public boolean act() {
+ if (target.isAlive()) {
+
+ Hero hero = (Hero) target;
+
+ if (isStarving()) {
+
+ partialDamage += target.HT/100f;
+
+ if (partialDamage > 1){
+ target.damage( (int)partialDamage, this);
+ partialDamage -= (int)partialDamage;
+ }
+
+ } else {
+
+ float newLevel = level + STEP;
+ boolean statusUpdated = false;
+ if (newLevel <= OVERFED && level > OVERFED) {
+
+ GLog.n(Messages.get(this, "onoverfed"));
+ statusUpdated = true;
+
+ } else if (newLevel >= OVERFED && level < OVERFED) {
+
+ statusUpdated = true;
+
+ } else if (newLevel >= STARVING) {
+
+ GLog.n(Messages.get(this, "onstarving"));
+ //hero.resting = false;
+ hero.damage(1, this);
+ statusUpdated = true;
+
+ hero.interrupt();
+
+ } else if (newLevel >= HUNGRY && level < HUNGRY) {
+
+ GLog.w(Messages.get(this, "onhungry"));
+ statusUpdated = true;
+
+ }
+ level = newLevel;
+
+ if (statusUpdated) {
+ BuffIndicator.refreshHero();
+ }
+
+ }
+ spend(target.buff(Shadows.class) == null ? STEP : STEP * 1.5f);
+
+ } else {
+
+ diactivate();
+
+ }
+
+ return true;
+ }
+
+ public void satisfy(float energy) {
+ Artifact.ArtifactBuff buff = target
+ .buff(HornOfPlenty.hornRecharge.class);
+ if (buff != null && buff.isCursed()) {
+ energy = Math.round(energy * 0.75f);
+ GLog.n(Messages.get(this, "cursedhorn"));
+ }
+ if (level>=800f) {
+ energy = Math.round(energy * 1.5f);
+ }
+ if(Dungeon.isChallenged(Challenges.ENERGY_LOST)){
+ energy = Math.round(energy * 0.4f);
+ }
+
+ reduceHunger( energy );
+
+ }
+
+ public void reduceHunger( float energy ) {
+
+ level -= energy;
+ if (level < 0) {
+ level = 0;
+ } else if (level > STARVING) {
+ level = STARVING;
+ }
+
+ BuffIndicator.refreshHero();
+ }
+
+ public boolean isStarving() {
+ return level >= STARVING;
+ }
+
+ public boolean isOverfed() {
+ return level <= OVERFED;
+ }
+
+ public boolean isHungry() {
+ return (level >= HUNGRY && level < STARVING);
+ }
+
+ public int hungerLevel() {
+ return (int) level;
+ }
+
+ @Override
+ public int icon() {
+ if (level < OVERFED) {
+ return BuffIndicator.OVERFED;
+ } else if (level < HUNGRY) {
+ return BuffIndicator.NONE;
+ } else if (level < STARVING) {
+ return BuffIndicator.HUNGER;
+ } else {
+ return BuffIndicator.STARVATION;
+ }
+ }
+
+ @Override
+ public String toString() {
+ if (level < OVERFED) {
+ return Messages.get(this, "overfed");
+ } else if (level < HUNGRY) {
+ return Messages.get(this, "normal");
+ } else if (level < STARVING) {
+ return Messages.get(this, "hungry");
+ } else {
+ return Messages.get(this, "starving");
+ }
+ }
+
+ @Override
+ public String desc() {
+ String result;
+ if (level < OVERFED) {
+ result = Messages.get(this, "desc_intro_overfed");
+ } else if (level < HUNGRY) {
+ result = Messages.get(this, "desc_intro_normal");
+ } else if (level < STARVING) {
+ result = Messages.get(this, "desc_intro_hungry");
+ } else {
+ result = Messages.get(this, "desc_intro_starving");
+ }
+
+ result += Messages.get(this, "desc");
+
+ return result;
+ }
+
+ @Override
+ public void onDeath() {
+
+ Badges.validateDeathFromHunger();
+
+ Dungeon.fail(Messages.format(ResultDescriptions.HUNGER));
+ //GLog.n(TXT_DEATH);
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Invisibility.java b/java/com/hmdzl/spspd/actors/buffs/Invisibility.java
new file mode 100644
index 00000000..f3e9295f
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Invisibility.java
@@ -0,0 +1,93 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.artifacts.CloakOfShadows;
+import com.hmdzl.spspd.items.artifacts.TimekeepersHourglass;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Invisibility extends FlavourBuff {
+
+ public static final float DURATION = 15f;
+
+ {
+ type = buffType.POSITIVE;
+ }
+
+ @Override
+ public boolean attachTo(Char target) {
+ if (super.attachTo(target)) {
+ target.invisible++;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void detach() {
+ if (target.invisible > 0)
+ target.invisible--;
+ super.detach();
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.INVISIBLE;
+ }
+
+ @Override
+ public void fx(boolean on) {
+ if (on) target.sprite.add( CharSprite.State.INVISIBLE );
+ else if (target.invisible == 0) target.sprite.remove( CharSprite.State.INVISIBLE );
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+
+ public static void dispel() {
+ Invisibility buff = Dungeon.hero.buff(Invisibility.class);
+ if (buff != null) {
+ buff.detach();
+ }
+ CloakOfShadows.cloakStealth cloakBuff = Dungeon.hero
+ .buff(CloakOfShadows.cloakStealth.class);
+ if (cloakBuff != null) {
+ cloakBuff.act();
+ cloakBuff.detach();
+ }
+ // this isn't a form of invisibilty, but it is meant to dispel at the
+ // same time as it.
+ TimekeepersHourglass.timeFreeze timeFreeze = Dungeon.hero
+ .buff(TimekeepersHourglass.timeFreeze.class);
+ if (timeFreeze != null) {
+ timeFreeze.detach();
+ }
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Levitation.java b/java/com/hmdzl/spspd/actors/buffs/Levitation.java
new file mode 100644
index 00000000..9494cbc7
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Levitation.java
@@ -0,0 +1,68 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Levitation extends FlavourBuff {
+
+ public static final float DURATION = 20f;
+
+ @Override
+ public boolean attachTo(Char target) {
+ if (super.attachTo(target)) {
+ target.flying = true;
+ Buff.detach(target, Roots.class);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void detach() {
+ target.flying = false;
+ Dungeon.level.press(target.pos, target);
+ super.detach();
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.LEVITATION;
+ }
+
+ @Override
+ public void fx(boolean on) {
+ if (on) target.sprite.add(CharSprite.State.LEVITATING);
+ else target.sprite.remove(CharSprite.State.LEVITATING);
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Light.java b/java/com/hmdzl/spspd/actors/buffs/Light.java
new file mode 100644
index 00000000..cbda0228
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Light.java
@@ -0,0 +1,72 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Light extends FlavourBuff {
+
+ public static final float DURATION = 300f;
+ public static final int DISTANCE = 6;
+
+ @Override
+ public boolean attachTo(Char target) {
+ if (super.attachTo(target)) {
+ if (Dungeon.level != null) {
+ target.viewDistance = Math.max(Dungeon.level.viewDistance,
+ DISTANCE);
+ Dungeon.observe();
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void detach() {
+ target.viewDistance = Dungeon.level.viewDistance;
+ Dungeon.observe();
+ super.detach();
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.LIGHT;
+ }
+
+ @Override
+ public void fx(boolean on) {
+ if (on) target.sprite.add(CharSprite.State.ILLUMINATED);
+ else target.sprite.remove(CharSprite.State.ILLUMINATED);
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Locked.java b/java/com/hmdzl/spspd/actors/buffs/Locked.java
new file mode 100644
index 00000000..95417523
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Locked.java
@@ -0,0 +1,52 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Locked extends FlavourBuff {
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ private static final float DURATION = 10f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.LOCKED_FLOOR;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @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;
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/LokisPoison.java b/java/com/hmdzl/spspd/actors/buffs/LokisPoison.java
new file mode 100644
index 00000000..479a3c1f
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/LokisPoison.java
@@ -0,0 +1,121 @@
+/*
+` * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Badges;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.effects.CellEmitter;
+import com.hmdzl.spspd.effects.particles.PoisonParticle;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class LokisPoison extends Buff implements Hero.Doom {
+
+ protected float left;
+
+ private static final String LEFT = "left";
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(LEFT, left);
+
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ left = bundle.getFloat(LEFT);
+ }
+
+ public void set(float duration) {
+ this.left = duration;
+ };
+
+ @Override
+ public int icon() {
+ return BuffIndicator.POISON;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String heroMessage() {
+ return Messages.get(this, "heromsg");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns(left));
+ }
+
+
+ @Override
+ public boolean attachTo(Char target) {
+ if (super.attachTo(target) && target.sprite != null){
+ CellEmitter.center(target.pos).burst( PoisonParticle.SPLASH, 5 );
+ return true;
+ } else
+ return false;
+ }
+
+ @Override
+ public boolean act() {
+ if (target.isAlive()) {
+
+ target.damage((int) (left / 2) + 1, this);
+ spend(TICK);
+
+ if ((left -= TICK) <= 0) {
+ detach();
+ }
+
+ } else {
+
+ detach();
+
+ }
+
+ return true;
+ }
+
+ public static float durationFactor(Char ch) {
+ Resistance r = ch.buff(Resistance.class);
+ return r != null ? r.durationFactor() : 1;
+ }
+
+ @Override
+ public void onDeath() {
+ Badges.validateDeathFromPoison();
+
+ Dungeon.fail(Messages.format(ResultDescriptions.POISON));
+ //GLog.n("You died from poison...");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/MagicImmunity.java b/java/com/hmdzl/spspd/actors/buffs/MagicImmunity.java
new file mode 100644
index 00000000..12530abf
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/MagicImmunity.java
@@ -0,0 +1,74 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.actors.blobs.ConfusionGas;
+import com.hmdzl.spspd.actors.blobs.CorruptGas;
+import com.hmdzl.spspd.actors.blobs.ParalyticGas;
+import com.hmdzl.spspd.actors.blobs.StenchGas;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.mobs.BrokenRobot;
+import com.hmdzl.spspd.actors.mobs.Eye;
+import com.hmdzl.spspd.actors.mobs.Warlock;
+import com.hmdzl.spspd.actors.mobs.Yog;
+import com.hmdzl.spspd.levels.traps.LightningTrap;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class MagicImmunity extends FlavourBuff {
+
+ public static final float DURATION = 10f;
+
+ {
+ type = buffType.POSITIVE;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.DISPEL;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+
+ {
+ immunities.add(ParalyticGas.class);
+ immunities.add(ToxicGas.class);
+ immunities.add(ConfusionGas.class);
+ immunities.add(StenchGas.class);
+ immunities.add(Burning.class);
+ immunities.add(ToxicGas.class);
+ immunities.add(Poison.class);
+ immunities.add(LightningTrap.Electricity.class);
+ immunities.add(Warlock.class);
+ immunities.add(Eye.class);
+ immunities.add(Yog.BurningFist.class);
+ immunities.add(BrokenRobot.class);
+ immunities.add(CorruptGas.class);
+ }
+}
+
diff --git a/java/com/hmdzl/spspd/actors/buffs/MagicalSleep.java b/java/com/hmdzl/spspd/actors/buffs/MagicalSleep.java
new file mode 100644
index 00000000..1c1ec546
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/MagicalSleep.java
@@ -0,0 +1,93 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.actors.mobs.Mob;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.hmdzl.spspd.utils.GLog;
+
+public class MagicalSleep extends Buff {
+
+ private static final float STEP = 1f;
+ public static final float SWS = 1.5f;
+
+ @Override
+ public boolean attachTo(Char target) {
+ if (super.attachTo(target)
+ && !target.immunities().contains(Sleep.class)) {
+
+ if (target instanceof Hero)
+ if (target.HP == target.HT) {
+ GLog.i(Messages.get(this, "toohealthy"));
+ detach();
+ return true;
+ } else {
+ 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).restoreHealth = true;
+ if (target.HP == target.HT) {
+ 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).restoreHealth = 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/java/com/hmdzl/spspd/actors/buffs/MechArmor.java b/java/com/hmdzl/spspd/actors/buffs/MechArmor.java
new file mode 100644
index 00000000..6c87d472
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/MechArmor.java
@@ -0,0 +1,88 @@
+package com.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class MechArmor extends Buff {
+
+ private static final float STEP = 1f;
+
+ private int level;
+
+
+ @Override
+ public boolean act() {
+
+ if (target.isAlive()) {
+ spend(TICK);
+ level --;
+ if (level <= 1) {
+ detach();
+ Buff.detach( target, ShieldArmor.class );
+ }
+
+ } else {
+
+ detach();
+
+ }
+
+ return true;
+ //spend(STEP);
+ //return true;
+ }
+
+ public int absorb(int damage) {
+ if (level <= damage) {
+ detach();
+ return damage - level;
+ } else {
+ level -= damage;
+ return 0;
+ }
+ }
+
+ public void level(int value) {
+ if (level < value) {
+ level = value;
+ }
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.MECHARMOR;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", level);
+ }
+
+ 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);
+ }
+
+ //@Override
+ public void fx(boolean on) {
+ if (on) target.sprite.add(CharSprite.State.ILLUMINATED);
+ else target.sprite.remove(CharSprite.State.ILLUMINATED);
+ }
+ }
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/MindVision.java b/java/com/hmdzl/spspd/actors/buffs/MindVision.java
new file mode 100644
index 00000000..a43f24da
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/MindVision.java
@@ -0,0 +1,50 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class MindVision extends FlavourBuff {
+
+ public static final float DURATION = 40f;
+
+ public int distance = 2;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.MIND_VISION;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ Dungeon.observe();
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/MirrorShield.java b/java/com/hmdzl/spspd/actors/buffs/MirrorShield.java
new file mode 100644
index 00000000..8008616a
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/MirrorShield.java
@@ -0,0 +1,64 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Random;
+
+public class MirrorShield extends FlavourBuff {
+
+ {
+ type = buffType.POSITIVE;
+ }
+
+ public int proc(int damage, Char attacker) {
+
+ int deflected = Random.NormalIntRange(damage/2, damage);
+ damage = 0;
+
+ attacker.damage(deflected, this);
+
+ return damage;
+ }
+
+ public int icon() {
+ return BuffIndicator.MIRROR_SHIELD;
+ }
+
+ @Override
+ public void fx(boolean on) {
+ if (on) target.sprite.add(CharSprite.State.ILLUMINATED);
+ else target.sprite.remove(CharSprite.State.ILLUMINATED);
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Muscle.java b/java/com/hmdzl/spspd/actors/buffs/Muscle.java
new file mode 100644
index 00000000..5edc7634
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Muscle.java
@@ -0,0 +1,49 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Muscle extends FlavourBuff {
+
+ public static final float DURATION = 200f;
+
+ {
+ type = buffType.POSITIVE;
+ }
+
+
+ @Override
+ public int icon() {
+ return BuffIndicator.PBLOOD;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Needling.java b/java/com/hmdzl/spspd/actors/buffs/Needling.java
new file mode 100644
index 00000000..5689508c
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Needling.java
@@ -0,0 +1,80 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.ConfusionGas;
+import com.hmdzl.spspd.actors.blobs.CorruptGas;
+import com.hmdzl.spspd.actors.blobs.ElectriShock;
+import com.hmdzl.spspd.actors.blobs.Fire;
+import com.hmdzl.spspd.actors.blobs.Freezing;
+import com.hmdzl.spspd.actors.blobs.ParalyticGas;
+import com.hmdzl.spspd.actors.blobs.Regrowth;
+import com.hmdzl.spspd.actors.blobs.ShockWeb;
+import com.hmdzl.spspd.actors.blobs.StenchGas;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.blobs.VenomGas;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfRain;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSand;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSnow;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSun;
+import com.hmdzl.spspd.actors.blobs.Web;
+import com.hmdzl.spspd.levels.traps.LightningTrap;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Random;
+
+public class Needling extends FlavourBuff {
+
+ public static final float DURATION = 30f;
+
+ {
+ type = buffType.POSITIVE;
+ }
+
+ public void proc(Char enemy) {
+ switch (Random.Int(2)){
+ case 0:
+ Buff.affect(enemy, ArmorBreak.class,5f).level(50);
+ break;
+ case 1:
+ Buff.affect(enemy, Bleeding.class).set(10);
+ break;
+ }
+ }
+
+
+ @Override
+ public int icon() {
+ return BuffIndicator.NEEDLING;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/NewCombo.java b/java/com/hmdzl/spspd/actors/buffs/NewCombo.java
new file mode 100644
index 00000000..d56df304
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/NewCombo.java
@@ -0,0 +1,306 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2019 Evan Debenham
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Assets;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.actors.mobs.Mob;
+import com.hmdzl.spspd.effects.Pushing;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.scenes.CellSelector;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.sprites.ItemSprite;
+import com.hmdzl.spspd.sprites.ItemSpriteSheet;
+import com.hmdzl.spspd.ui.ActionIndicator;
+import com.hmdzl.spspd.ui.AttackIndicator;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.hmdzl.spspd.utils.GLog;
+import com.watabou.noosa.Image;
+import com.watabou.noosa.audio.Sample;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Callback;
+import com.watabou.utils.Random;
+
+public class NewCombo extends Buff implements ActionIndicator.Action {
+
+ private int count = 0;
+ private float comboTime = 0f;
+ private int misses = 0;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.COMBO;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ public void hit() {
+
+ count++;
+ comboTime = 4f;
+ misses = 0;
+
+ if (count >= 2) {
+
+ ActionIndicator.setAction( this );
+ GLog.p( Messages.get(this, "combo", count) );
+
+ }
+
+ }
+
+ public void miss(){
+ misses++;
+ comboTime = 4f;
+ if (misses >= 2){
+ detach();
+ }
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ ActionIndicator.clearAction(this);
+ }
+
+ @Override
+ public boolean act() {
+ comboTime-=TICK;
+ spend(TICK);
+ if (comboTime <= 0) {
+ detach();
+ }
+ return true;
+ }
+
+ @Override
+ public String desc() {
+ String desc = Messages.get(this, "desc");
+
+ if (count >= 8)desc += "\n\n" + Messages.get(this, "crush_desc");
+ else if (count >= 6)desc += "\n\n" + Messages.get(this, "slam_desc");
+ else if (count >= 4)desc += "\n\n" + Messages.get(this, "cleave_desc");
+ else if (count >= 2)desc += "\n\n" + Messages.get(this, "clobber_desc");
+
+ return desc;
+ }
+
+ private static final String COUNT = "count";
+ private static final String TIME = "combotime";
+ private static final String MISSES= "misses";
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(COUNT, count);
+ bundle.put(TIME, comboTime);
+ bundle.put(MISSES, misses);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ count = bundle.getInt( COUNT );
+ if (count >= 2) ActionIndicator.setAction(this);
+ comboTime = bundle.getFloat( TIME );
+ misses = bundle.getInt( MISSES );
+ }
+
+ @Override
+ public Image getIcon() {
+ Image icon;
+
+ icon = new ItemSprite(new Item(){ {image = ItemSpriteSheet.ERROR_WEAPON; }});
+
+ if (count >= 8)icon.tint(0xFFFFCC00);
+ else if (count >= 6)icon.tint(0xFFFFFF00);
+ else if (count >= 4)icon.tint(0xFFCCFF00);
+ else icon.tint(0xFF00FF00);
+
+ return icon;
+ }
+
+ @Override
+ public void doAction() {
+ GameScene.selectCell(finisher);
+ }
+
+ private enum finisherType{
+ CLOBBER, CLEAVE, SLAM, CRUSH;
+ }
+
+ private CellSelector.Listener finisher = new CellSelector.Listener() {
+
+ private finisherType type;
+
+ @Override
+ public void onSelect(Integer cell) {
+ if (cell == null) return;
+ final Char enemy = Actor.findChar( cell );
+ if (enemy == null || !((Hero)target).canAttack(enemy) || target.isCharmedBy( enemy )){
+ GLog.w( Messages.get(NewCombo.class, "bad_target") );
+ } else {
+ target.sprite.attack(cell, new Callback() {
+ @Override
+ public void call() {
+ if (count >= 8)type = finisherType.CRUSH;
+ else if (count >= 6)type = finisherType.SLAM;
+ else if (count >= 4)type = finisherType.CLEAVE;
+ else type = finisherType.CLOBBER;
+ doAttack(enemy);
+ }
+ });
+ }
+ }
+
+ private void doAttack(final Char enemy){
+
+ AttackIndicator.target(enemy);
+
+ int dmg = target.damageRoll();
+
+ //variance in damage dealt
+ switch(type){
+ case CLOBBER:
+ dmg = Math.round(dmg*0.6f);
+ break;
+ case CLEAVE:
+ dmg = Math.round(dmg*1.5f);
+ break;
+ case SLAM:
+ //rolls 2 times, takes the highest roll
+ int dmgReroll = target.damageRoll();
+ if (dmgReroll > dmg) dmg = dmgReroll;
+ dmg = Math.round(dmg*1.6f);
+ break;
+ case CRUSH:
+ //rolls 4 times, takes the highest roll
+ for (int i = 1; i < 4; i++) {
+ dmgReroll = target.damageRoll();
+ if (dmgReroll > dmg) dmg = dmgReroll;
+ }
+ dmg = Math.round(dmg*2.5f);
+ break;
+ }
+
+ dmg -= Random.IntRange( 0, enemy.drRoll() );
+ dmg = target.attackProc(enemy, dmg);
+ dmg = enemy.defenseProc(target, dmg);
+ enemy.damage( dmg, this );
+
+ //special effects
+ switch (type){
+ case CLOBBER:
+ if (enemy.isAlive()){
+ if (!enemy.properties().contains(Char.Property.IMMOVABLE)){
+ for (int i = 0; i < Level.NEIGHBOURS8.length; i++) {
+ int ofs = Level.NEIGHBOURS8[i];
+ if (enemy.pos - target.pos == ofs) {
+ int newPos = enemy.pos + ofs;
+ if ((Level.passable[newPos] || Level.avoid[newPos]) && Actor.findChar( newPos ) == null) {
+
+ Actor.addDelayed( new Pushing( enemy, enemy.pos, newPos ), -1 );
+
+ enemy.pos = newPos;
+ // FIXME
+ if (enemy instanceof Mob) {
+ Dungeon.level.mobPress( (Mob)enemy );
+ } else {
+ Dungeon.level.press( newPos, enemy );
+ }
+
+ }
+ break;
+ }
+ }
+ }
+ Buff.prolong(enemy, Vertigo.class, Random.NormalIntRange(1, 4));
+ }
+ break;
+ case SLAM:
+ Buff.affect(target,ShieldArmor.class).level((int)(dmg/5));
+ break;
+ default:
+ //nothing
+ break;
+ }
+
+ if (target.buff(FireImbue.class) != null)
+ target.buff(FireImbue.class).proc(enemy);
+ if (target.buff(EarthImbue.class) != null)
+ target.buff(EarthImbue.class).proc(enemy);
+ if (target.buff(FrostImbue.class) != null)
+ target.buff(FrostImbue.class).proc(enemy);
+ if (target.buff(BloodImbue.class) != null)
+ target.buff(BloodImbue.class).proc(enemy);
+
+ Sample.INSTANCE.play( Assets.SND_HIT, 1, 1, Random.Float( 0.8f, 1.25f ) );
+ enemy.sprite.bloodBurstA( target.sprite.center(), dmg );
+ enemy.sprite.flash();
+
+ if (!enemy.isAlive()){
+ GLog.i( Messages.capitalize(Messages.get(Char.class, "defeat", enemy.name)) );
+ }
+
+ Hero hero = (Hero)target;
+
+ //Post-attack behaviour
+ switch(type) {
+ case CLEAVE:
+ if (!enemy.isAlive()) {
+ //combo isn't reset, but rather increments with a cleave kill, and grants more time.
+ hit();
+ comboTime = 10f;
+ } else {
+ detach();
+ ActionIndicator.clearAction(NewCombo.this);
+ }
+ hero.spendAndNext(hero.attackDelay());
+ break;
+
+ default:
+ detach();
+ ActionIndicator.clearAction(NewCombo.this);
+ hero.spendAndNext(hero.attackDelay());
+ break;
+ }
+
+ }
+
+ @Override
+ public String prompt() {
+ if (count >= 8)return Messages.get(NewCombo.class, "crush_prompt");
+ else if (count >= 6)return Messages.get(NewCombo.class, "slam_prompt");
+ else if (count >= 4)return Messages.get(NewCombo.class, "cleave_prompt");
+ else return Messages.get(NewCombo.class, "clobber_prompt");
+ }
+ };
+ }
+
diff --git a/java/com/hmdzl/spspd/actors/buffs/Notice.java b/java/com/hmdzl/spspd/actors/buffs/Notice.java
new file mode 100644
index 00000000..44dfcc2f
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Notice.java
@@ -0,0 +1,63 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.blobs.ConfusionGas;
+import com.hmdzl.spspd.actors.blobs.CorruptGas;
+import com.hmdzl.spspd.actors.blobs.ElectriShock;
+import com.hmdzl.spspd.actors.blobs.Fire;
+import com.hmdzl.spspd.actors.blobs.Freezing;
+import com.hmdzl.spspd.actors.blobs.ParalyticGas;
+import com.hmdzl.spspd.actors.blobs.Regrowth;
+import com.hmdzl.spspd.actors.blobs.ShockWeb;
+import com.hmdzl.spspd.actors.blobs.StenchGas;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.blobs.VenomGas;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfRain;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSand;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSnow;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSun;
+import com.hmdzl.spspd.actors.blobs.Web;
+import com.hmdzl.spspd.levels.traps.LightningTrap;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Notice extends FlavourBuff {
+
+ public static final float DURATION = 30f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.NOTICE;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/Ooze.java b/java/com/hmdzl/spspd/actors/buffs/Ooze.java
new file mode 100644
index 00000000..8b8b0e20
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Ooze.java
@@ -0,0 +1,71 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Random;
+
+public class Ooze extends Buff {
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.OOZE;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String heroMessage() {
+ return Messages.get(this, "heromsg");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc");
+ }
+
+ @Override
+ public boolean act() {
+ if (target.isAlive()) {
+ if (Dungeon.depth > 4)
+ target.damage(Dungeon.depth / 5, this);
+ else if (Random.Int(2) == 0)
+ target.damage(1, this);
+ if (!target.isAlive() && target == Dungeon.hero) {
+ Dungeon.fail(Messages.format(ResultDescriptions.OOZE));
+ //GLog.n(TXT_HERO_KILLED, toString());
+ }
+ spend(TICK);
+ }
+ if (Level.water[target.pos]) {
+ detach();
+ }
+ return true;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Paralysis.java b/java/com/hmdzl/spspd/actors/buffs/Paralysis.java
new file mode 100644
index 00000000..4130a313
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Paralysis.java
@@ -0,0 +1,81 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Paralysis extends FlavourBuff {
+
+ private static final float DURATION = 10f;
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public boolean attachTo(Char target) {
+ if (super.attachTo(target)) {
+ target.paralysed++;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ if (target.paralysed > 0)
+ target.paralysed--;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.PARALYSIS;
+ }
+
+ @Override
+ public void fx(boolean on) {
+ if (on) target.sprite.add(CharSprite.State.PARALYSED);
+ else target.sprite.remove(CharSprite.State.PARALYSED);
+ }
+
+ @Override
+ public String heroMessage() {
+ return Messages.get(this, "heromsg");
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @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;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/ParyAttack.java b/java/com/hmdzl/spspd/actors/buffs/ParyAttack.java
new file mode 100644
index 00000000..cb244278
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/ParyAttack.java
@@ -0,0 +1,104 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class ParyAttack extends Buff {
+
+ private int pos;
+ private int level = 0;
+ private static final String LEVEL = "level";
+ private static final String POS = "pos";
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(POS, pos);
+ bundle.put(LEVEL, level);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ pos = bundle.getInt(POS);
+ level = bundle.getInt(LEVEL);
+ }
+
+ {
+ type = buffType.POSITIVE;
+ }
+
+
+ @Override
+ public boolean attachTo(Char target) {
+ pos = target.pos;
+ return super.attachTo(target);
+ }
+
+ public boolean act() {
+
+ if (target.isAlive()) {
+
+ if (target.pos != pos) {
+ detach();
+ }
+
+ level++;
+ spend(TICK);
+
+ } else {
+ detach();
+ }
+
+ return true;
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.BLESS;
+ }
+
+ public int level() {
+ return level;
+ }
+
+ public void level(int value) {
+ if (level < value) {
+ level = value;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc",level/2.5);
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/PinCushion.java b/java/com/hmdzl/spspd/actors/buffs/PinCushion.java
new file mode 100644
index 00000000..0c30d261
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/PinCushion.java
@@ -0,0 +1,45 @@
+package com.hmdzl.spspd.actors.buffs;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.items.weapon.missiles.MissileWeapon;
+import com.watabou.utils.Bundle;
+
+/**
+ * Created by debenhame on 06/02/2015.
+ */
+public class PinCushion extends Buff {
+
+ private ArrayList items = new ArrayList();
+
+ public void stick(MissileWeapon item) {
+ items.add(item);
+ }
+
+ @Override
+ public void detach() {
+ for (Item item : items)
+ Dungeon.level.drop(item, target.pos).sprite.drop();
+ super.detach();
+ }
+
+ private static final String ITEMS = "items";
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ bundle.put(ITEMS, items);
+ super.storeInBundle(bundle);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ items = new ArrayList(
+ (Collection) ((Collection>) bundle
+ .getCollection(ITEMS)));
+ super.restoreFromBundle(bundle);
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Poison.java b/java/com/hmdzl/spspd/actors/buffs/Poison.java
new file mode 100644
index 00000000..beebf50c
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Poison.java
@@ -0,0 +1,116 @@
+/*
+` * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Badges;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.effects.CellEmitter;
+import com.hmdzl.spspd.effects.particles.PoisonParticle;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class Poison extends Buff implements Hero.Doom {
+
+ protected float left;
+
+ private static final String LEFT = "left";
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(LEFT, left);
+
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ left = bundle.getFloat(LEFT);
+ }
+
+ public void set(float duration) {
+ this.left = duration;
+ };
+
+ @Override
+ public int icon() {
+ return BuffIndicator.POISON;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String heroMessage() {
+ return Messages.get(this, "heromsg");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns(left));
+ }
+
+ @Override
+ public boolean attachTo(Char target) {
+ if (super.attachTo(target) && target.sprite != null){
+ CellEmitter.center(target.pos).burst( PoisonParticle.SPLASH, 5 );
+ return true;
+ } else
+ return false;
+ }
+
+ @Override
+ public boolean act() {
+ if (target.isAlive()) {
+
+ target.damage((int) (left / 2) + 1, this);
+ spend(TICK);
+
+ if ((left -= TICK) <= 0) {
+ detach();
+ }
+
+ } else {
+
+ detach();
+
+ }
+
+ return true;
+ }
+
+ public static float durationFactor(Char ch) {
+ Resistance r = ch.buff(Resistance.class);
+ return r != null ? r.durationFactor() : 1;
+ }
+
+ @Override
+ public void onDeath() {
+ Badges.validateDeathFromPoison();
+
+ Dungeon.fail(Messages.format(ResultDescriptions.POISON));
+ //GLog.n("You died from poison...");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Recharging.java b/java/com/hmdzl/spspd/actors/buffs/Recharging.java
new file mode 100644
index 00000000..88191b1e
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Recharging.java
@@ -0,0 +1,53 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Recharging extends FlavourBuff {
+
+ public static final float DURATION = 40f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.RECHARGING;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ //want to process partial turns for this buff, and not count it when it's expiring.
+ //firstly, if this buff has half a turn left, should give out half the benefit.
+ //secondly, recall that buffs execute in random order, so this can cause a problem where we can't simply check
+ //if this buff is still attached, must instead directly check its remaining time, and act accordingly.
+ //otherwise this causes inconsistent behaviour where this may detach before, or after, a wand charger acts.
+ public float remainder() {
+ return Math.min(1f, this.cooldown());
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Regeneration.java b/java/com/hmdzl/spspd/actors/buffs/Regeneration.java
new file mode 100644
index 00000000..e6dd6522
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Regeneration.java
@@ -0,0 +1,62 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.actors.hero.HeroClass;
+import com.hmdzl.spspd.actors.hero.HeroSubClass;
+import com.hmdzl.spspd.items.artifacts.ChaliceOfBlood;
+
+public class Regeneration extends Buff {
+
+ private static final float REGENERATION_DELAY = 25;
+
+ @Override
+ public boolean act() {
+ if (target.isAlive()) {
+ if (!((Hero) target).isStarving()){
+ if (Dungeon.hero.subClass == HeroSubClass.PASTOR && target.HP < target.HT*1.5){
+ target.HP += 2*Math.max(1,(int)(Dungeon.hero.lvl/5));
+ } else if (target.HP < target.HT) {
+ target.HP += Math.min((target.HT - target.HP),Math.max(1,(int)(Dungeon.hero.lvl/5)));
+ }
+ }
+
+ ChaliceOfBlood.chaliceRegen regenBuff = Dungeon.hero
+ .buff(ChaliceOfBlood.chaliceRegen.class);
+
+ if (regenBuff != null) {
+ if (regenBuff.isCursed()) {
+ spend(REGENERATION_DELAY * 2f);
+ } else {
+ spend(Math.max(REGENERATION_DELAY - 2*regenBuff.level(), 5f));
+ }
+ } else if (Dungeon.hero.heroClass== HeroClass.PERFORMER && Dungeon.skins == 2) {
+ spend(REGENERATION_DELAY*0.6f);
+ } else { spend(REGENERATION_DELAY);}
+
+ } else {
+
+ diactivate();
+
+ }
+
+ return true;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Rhythm.java b/java/com/hmdzl/spspd/actors/buffs/Rhythm.java
new file mode 100644
index 00000000..d5365df6
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Rhythm.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Rhythm extends FlavourBuff {
+
+ public static final float DURATION = 10f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.RHYTHM;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/Rhythm2.java b/java/com/hmdzl/spspd/actors/buffs/Rhythm2.java
new file mode 100644
index 00000000..7ad51d7c
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Rhythm2.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Rhythm2 extends FlavourBuff {
+
+ public static final float DURATION = 10f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.RHYTHM2;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/Roots.java b/java/com/hmdzl/spspd/actors/buffs/Roots.java
new file mode 100644
index 00000000..5d9c08e1
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Roots.java
@@ -0,0 +1,65 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Roots extends FlavourBuff {
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public boolean attachTo(Char target) {
+ if (!target.flying && super.attachTo(target)) {
+ target.rooted = true;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void detach() {
+ target.rooted = false;
+ super.detach();
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.ROOTS;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String heroMessage() {
+ return Messages.get(this, "heromsg");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Shadows.java b/java/com/hmdzl/spspd/actors/buffs/Shadows.java
new file mode 100644
index 00000000..8204e2ec
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Shadows.java
@@ -0,0 +1,106 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Assets;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.noosa.audio.Sample;
+import com.watabou.utils.Bundle;
+
+public class Shadows extends Invisibility {
+
+ protected float left;
+
+ private static final String LEFT = "left";
+
+ {
+ type = buffType.SILENT;
+ }
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(LEFT, left);
+
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ left = bundle.getFloat(LEFT);
+ }
+
+ @Override
+ public boolean attachTo(Char target) {
+ if (super.attachTo(target)) {
+ Sample.INSTANCE.play(Assets.SND_MELD);
+ Dungeon.observe();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ Dungeon.observe();
+ }
+
+ @Override
+ public boolean act() {
+ if (target.isAlive()) {
+
+ spend(TICK * 2);
+
+ if (--left <= 0 || Dungeon.hero.visibleEnemies() > 0) {
+ detach();
+ }
+
+ } else {
+
+ detach();
+
+ }
+
+ return true;
+ }
+
+ public void prolong() {
+ left = 2;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.SHADOWS;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc");
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Shield.java b/java/com/hmdzl/spspd/actors/buffs/Shield.java
new file mode 100644
index 00000000..660a103b
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Shield.java
@@ -0,0 +1,59 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.Statistics;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Shield extends Buff {
+
+ public static float LEVEL = 0.4f;
+
+ private int hits = (Dungeon.checkNight() ? Math.max(8, Math.round(Statistics.deepestFloor/5)+9) : Math.max(2, Math.round(Statistics.deepestFloor/5)+3));
+ //private int hits = Math.max(2, Math.round(Statistics.deepestFloor/5)+3);
+
+ {
+ type = buffType.POSITIVE;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.DISPEL;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc");
+ }
+
+ @Override
+ public void detach() {
+ hits--;
+ if(hits==0){
+ super.detach();
+ }
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/ShieldArmor.java b/java/com/hmdzl/spspd/actors/buffs/ShieldArmor.java
new file mode 100644
index 00000000..3949dc36
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/ShieldArmor.java
@@ -0,0 +1,65 @@
+package com.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class ShieldArmor extends Buff {
+
+ private static final float STEP = 1f;
+
+ private int level;
+
+
+ @Override
+ public boolean act() {
+ spend(STEP);
+ return true;
+ }
+
+ public int absorb(int damage) {
+ if (level <= damage) {
+ detach();
+ return damage - level;
+ } else {
+ level -= damage;
+ return 0;
+ }
+ }
+
+ public void level(int value) {
+ if (level < value) {
+ level = value;
+ }
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.ARMOR;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", level);
+ }
+
+ 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);
+ }
+ }
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/Shieldblock.java b/java/com/hmdzl/spspd/actors/buffs/Shieldblock.java
new file mode 100644
index 00000000..f70dcff6
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Shieldblock.java
@@ -0,0 +1,73 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Shieldblock extends FlavourBuff {
+
+ private static final float DURATION = 10f;
+
+ @Override
+ public boolean attachTo(Char target) {
+ if (super.attachTo(target)) {
+ target.paralysed ++ ;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ if (target.paralysed > 0)
+ target.paralysed--;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.SHIELDBLOCK;
+ }
+
+ @Override
+ public void fx(boolean on) {
+ if (on) target.sprite.add(CharSprite.State.PARALYSED);
+ else target.sprite.remove(CharSprite.State.PARALYSED);
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @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;
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Shocked.java b/java/com/hmdzl/spspd/actors/buffs/Shocked.java
new file mode 100644
index 00000000..be81e3a4
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Shocked.java
@@ -0,0 +1,109 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Yet Another Pixel Dungeon
+ * Copyright (C) 2015-2016 Considered Hamster
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Shocked extends FlavourBuff {
+
+ //private static final String TXT_DISARMED = "Sudden shock have made you drop your %s on the ground!";
+ public static final float DURATION = 5f;
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.SHOCKED;
+ }
+
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+
+ /*@Override
+ public boolean act(){
+
+ Wet wet = target.buff(Wet.class);
+
+
+ if( target.isAlive()){
+ if( !target.flying && Level.water[ target.pos ] || wet!= null){
+ discharge();
+ } else spend(TICK);
+ }
+
+ if (Level.flamable[target.pos] && !target.flying) {
+ detach();
+ }
+ return super.act();
+ }
+
+ public void discharge() {
+
+ target.damage(Random.IntRange(target.HT/4,target.HT/6),this);
+
+// target.sprite.showStatus( CharSprite.NEGATIVE, "ZAP!");
+
+ if( target instanceof Hero ) {
+
+ Camera.main.shake( 2, 0.3f );
+
+ Hero hero = (Hero)target;
+ EquipableItem weapon = hero.belongings.weapon;
+
+ if( weapon != null && !(weapon instanceof Knuckles || weapon instanceof FightGloves)
+ && !weapon.cursed) {
+ GLog.w(Messages.get(this, "knock",weapon.name()));
+ weapon.doDrop(hero);
+
+ }
+
+ } else {
+ Buff.prolong(target,Paralysis.class,2f );
+ }
+
+ /*if (target.sprite.visible) {
+ target.sprite.centerEmitter().burst( SparkParticle.FACTORY, (int)Math.ceil( duration ) + 1 );
+ }
+
+ detach();
+ };
+
+ @Override
+ public void onDeath() {
+
+ //Badges.validateDeathFromFire();
+
+ Dungeon.fail(Messages.format(ResultDescriptions.POISON));
+ //GLog.n(TXT_BURNED_TO_DEATH);
+ }*/
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Silent.java b/java/com/hmdzl/spspd/actors/buffs/Silent.java
new file mode 100644
index 00000000..ad235d6e
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Silent.java
@@ -0,0 +1,52 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Silent extends FlavourBuff {
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ private static final float DURATION = 5f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.SILENT;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @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;
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/Sleep.java b/java/com/hmdzl/spspd/actors/buffs/Sleep.java
new file mode 100644
index 00000000..f6a7e292
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Sleep.java
@@ -0,0 +1,24 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+public class Sleep extends FlavourBuff {
+
+ public static final float SWS = 1.5f;
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Slow.java b/java/com/hmdzl/spspd/actors/buffs/Slow.java
new file mode 100644
index 00000000..bad42534
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Slow.java
@@ -0,0 +1,52 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Slow extends FlavourBuff {
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ private static final float DURATION = 10f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.SLOW;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @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;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/SnipersMark.java b/java/com/hmdzl/spspd/actors/buffs/SnipersMark.java
new file mode 100644
index 00000000..eef33234
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/SnipersMark.java
@@ -0,0 +1,57 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class SnipersMark extends FlavourBuff {
+
+ public int object = 0;
+
+ private static final String OBJECT = "object";
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(OBJECT, object);
+
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ object = bundle.getInt(OBJECT);
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.MARK;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc");
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/SoulBless.java b/java/com/hmdzl/spspd/actors/buffs/SoulBless.java
new file mode 100644
index 00000000..88547b7d
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/SoulBless.java
@@ -0,0 +1,62 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.blobs.ConfusionGas;
+import com.hmdzl.spspd.actors.blobs.CorruptGas;
+import com.hmdzl.spspd.actors.blobs.ElectriShock;
+import com.hmdzl.spspd.actors.blobs.Fire;
+import com.hmdzl.spspd.actors.blobs.Freezing;
+import com.hmdzl.spspd.actors.blobs.ParalyticGas;
+import com.hmdzl.spspd.actors.blobs.Regrowth;
+import com.hmdzl.spspd.actors.blobs.ShockWeb;
+import com.hmdzl.spspd.actors.blobs.StenchGas;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.blobs.VenomGas;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfRain;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSand;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSnow;
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSun;
+import com.hmdzl.spspd.actors.blobs.Web;
+import com.hmdzl.spspd.levels.traps.LightningTrap;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class SoulBless extends FlavourBuff {
+
+ public static final float DURATION = 30f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.BLESS;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/SoulMark.java b/java/com/hmdzl/spspd/actors/buffs/SoulMark.java
new file mode 100644
index 00000000..8928455d
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/SoulMark.java
@@ -0,0 +1,54 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class SoulMark extends FlavourBuff {
+
+ public static final float DURATION = 10f;
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.CORRUPT;
+ }
+
+ public void fx(boolean on) {
+ if (on) target.sprite.add(CharSprite.State.MARKED);
+ else target.sprite.remove(CharSprite.State.MARKED);
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/SpAttack.java b/java/com/hmdzl/spspd/actors/buffs/SpAttack.java
new file mode 100644
index 00000000..85dc0b75
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/SpAttack.java
@@ -0,0 +1,44 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class SpAttack extends FlavourBuff {
+
+ public static final float DURATION = 30f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.SMASH;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Speed.java b/java/com/hmdzl/spspd/actors/buffs/Speed.java
new file mode 100644
index 00000000..6612dc72
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Speed.java
@@ -0,0 +1,24 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+public class Speed extends FlavourBuff {
+
+ public static final float DURATION = 10f;
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/StoneIce.java b/java/com/hmdzl/spspd/actors/buffs/StoneIce.java
new file mode 100644
index 00000000..2c35efc8
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/StoneIce.java
@@ -0,0 +1,136 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Badges;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class StoneIce extends Buff {
+
+ private int pos;
+ private float left;
+ private static final String LEFT = "left";
+ private static final String POS = "pos";
+ private static final float DURATION = 8f;
+
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(POS, pos);
+ bundle.put(LEFT, left);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ pos = bundle.getInt(POS);
+ left = bundle.getInt(LEFT);
+ }
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+
+ @Override
+ public boolean attachTo(Char target) {
+ pos = target.pos;
+ return super.attachTo(target);
+ }
+
+ public boolean act() {
+
+ if (target.isAlive()) {
+
+ if (target.pos != pos) {
+ pos = 0;
+ if (target.pos != -1) pos = target.pos;
+ target.damage(Math.min(1000,target.HT/20),this);
+ }
+
+ Buff.detach( target, Burning.class);
+
+ } else {
+ detach();
+ }
+
+ spend(TICK);
+ left -= TICK;
+
+ if (left <= 0 ) {
+ detach();
+ }
+
+ return true;
+ }
+
+ public void reignite(Char ch) {
+ left = duration(ch);
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.STONE_ICE;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc",left);
+ }
+
+ public void set(float duration) {
+ this.left = duration;
+ };
+
+ public float level() { return left; }
+
+ public void level(int value) {
+ if (left < value) {
+ left = value;
+ }
+ }
+
+ public static float duration(Char ch) {
+ if (ch.isAlive() && (Level.water[ch.pos] && !ch.flying)){
+ return DURATION;
+ } else return DURATION;
+
+ }
+
+ public void onDeath() {
+
+ Badges.validateDeathFromFire();
+ Dungeon.fail(Messages.format(ResultDescriptions.BURNING));
+
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Strength.java b/java/com/hmdzl/spspd/actors/buffs/Strength.java
new file mode 100644
index 00000000..fb29363f
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Strength.java
@@ -0,0 +1,55 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Strength extends Buff {
+
+ public static float LEVEL = 0.4f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.MOON_FURY;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc");
+ }
+
+ @Override
+ public void detach() {
+
+ Buff buff = Dungeon.hero.buff(FullMoonStrength.class);
+ if (buff != null){
+
+ buff.detach();
+ } else {
+ super.detach();
+ }
+
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Tar.java b/java/com/hmdzl/spspd/actors/buffs/Tar.java
new file mode 100644
index 00000000..48dfc687
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Tar.java
@@ -0,0 +1,65 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Tar extends Buff {
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.TAR;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String heroMessage() {
+ return Messages.get(this, "heromsg");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc");
+ }
+
+ @Override
+ public boolean act() {
+ if (target.isAlive()) {
+ Burning burning = target.buff(Burning.class);
+ if (target.isAlive() && burning!=null){
+ Buff.affect(target,Burning.class).reignite(target);
+ }
+ spend(TICK);
+ }
+ if (Level.water[target.pos] && !target.flying) {
+ detach();
+ }
+
+ return true;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/TargetShoot.java b/java/com/hmdzl/spspd/actors/buffs/TargetShoot.java
new file mode 100644
index 00000000..a7d10d4f
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/TargetShoot.java
@@ -0,0 +1,41 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class TargetShoot extends FlavourBuff {
+
+ public static final float DURATION = 30f;
+
+ @Override
+ public int icon() {
+ return BuffIndicator.MARK;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Taunt.java b/java/com/hmdzl/spspd/actors/buffs/Taunt.java
new file mode 100644
index 00000000..b589bdbb
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Taunt.java
@@ -0,0 +1,41 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class Taunt extends Buff {
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public boolean act() {
+ if (target.isAlive()) {
+ spend(TICK);
+ }
+ return true;
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Terror.java b/java/com/hmdzl/spspd/actors/buffs/Terror.java
new file mode 100644
index 00000000..f4c2db7a
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Terror.java
@@ -0,0 +1,66 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class Terror extends FlavourBuff {
+
+ public static final float DURATION = 10f;
+
+ public int object = 0;
+
+ private static final String OBJECT = "object";
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(OBJECT, object);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ object = bundle.getInt(OBJECT);
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.TERROR;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+
+ public static void recover(Char target) {
+ Terror terror = target.buff(Terror.class);
+ if (terror != null && terror.cooldown() < DURATION) {
+ target.remove(terror);
+ }
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/ToxicImbue.java b/java/com/hmdzl/spspd/actors/buffs/ToxicImbue.java
new file mode 100644
index 00000000..4f96c8a6
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/ToxicImbue.java
@@ -0,0 +1,87 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.blobs.Blob;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+/**
+ * Created by debenhame on 19/11/2014.
+ */
+public class ToxicImbue extends Buff {
+
+ public static final float DURATION = 30f;
+
+ protected float left;
+
+ private static final String LEFT = "left";
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(LEFT, left);
+
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ left = bundle.getFloat(LEFT);
+ }
+
+ public void set(float duration) {
+ this.left = duration;
+ };
+
+ @Override
+ public boolean act() {
+ GameScene.add(Blob.seed(target.pos, 50, ToxicGas.class));
+
+ spend(TICK);
+ left -= TICK;
+ if (left <= 0)
+ detach();
+
+ return true;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.PTOXIC;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns(left));
+ }
+
+ {
+ immunities.add(ToxicGas.class);
+ immunities.add(Poison.class);
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Venom.java b/java/com/hmdzl/spspd/actors/buffs/Venom.java
new file mode 100644
index 00000000..93e82959
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Venom.java
@@ -0,0 +1,91 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.watabou.utils.Bundle;
+
+public class Venom extends Poison implements Hero.Doom {
+
+ private int damage = 1;
+
+ private static final String DAMAGE = "damage";
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public void storeInBundle( Bundle bundle ) {
+ super.storeInBundle( bundle );
+ bundle.put( DAMAGE, damage );
+
+ }
+
+ @Override
+ public void restoreFromBundle( Bundle bundle ) {
+ super.restoreFromBundle( bundle );
+ damage = bundle.getInt( DAMAGE );
+ }
+
+ public void set(float duration, int damage) {
+ set(duration);
+ this.damage = damage;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.POISON;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns(left), damage);
+ }
+
+ @Override
+ public boolean act() {
+ if (target.isAlive()) {
+ target.damage(damage, this);
+ if (damage < ((Dungeon.depth+1)/2)+1)
+ damage++;
+
+ //want it to act after the cloud of venom it came from.
+ spend( TICK+0.1f );
+ if ((left -= TICK) <= 0) {
+ detach();
+ }
+ } else {
+ detach();
+ }
+
+ return true;
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Vertigo.java b/java/com/hmdzl/spspd/actors/buffs/Vertigo.java
new file mode 100644
index 00000000..1770e246
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Vertigo.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Vertigo extends FlavourBuff {
+
+ public static final float DURATION = 10f;
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.VERTIGO;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @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;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/WarGroove.java b/java/com/hmdzl/spspd/actors/buffs/WarGroove.java
new file mode 100644
index 00000000..00a75d11
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/WarGroove.java
@@ -0,0 +1,44 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class WarGroove extends Buff {
+
+ @Override
+ public int icon() {
+ return BuffIndicator.WARGROOVE;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc");
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/Weakness.java b/java/com/hmdzl/spspd/actors/buffs/Weakness.java
new file mode 100644
index 00000000..00759a12
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Weakness.java
@@ -0,0 +1,80 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.items.rings.RingOfElements.Resistance;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Weakness extends FlavourBuff {
+
+ private static final float DURATION = 40f;
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.WEAKNESS;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public boolean attachTo(Char target) {
+ if (super.attachTo(target) && target==Dungeon.hero) {
+ Hero hero = (Hero) target;
+ hero.weakened = true;
+ hero.belongings.discharge();
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ if (target==Dungeon.hero){
+ ((Hero) target).weakened = false;
+ }
+ }
+
+ public static float duration(Char ch) {
+ Resistance r = ch.buff(Resistance.class);
+ return r != null ? r.durationFactor() * DURATION : DURATION;
+ }
+
+ @Override
+ public String heroMessage() {
+ return Messages.get(this, "heromsg");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/Wet.java b/java/com/hmdzl/spspd/actors/buffs/Wet.java
new file mode 100644
index 00000000..bfb079ef
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/Wet.java
@@ -0,0 +1,48 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2015 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.hmdzl.spspd.actors.buffs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class Wet extends FlavourBuff {
+
+ public static final float DURATION = 10f;
+
+ {
+ type = buffType.NEGATIVE;
+ }
+
+ @Override
+ public int icon() {
+ return BuffIndicator.WET;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc", dispTurns());
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/buffs/armorbuff/GlyphDark.java b/java/com/hmdzl/spspd/actors/buffs/armorbuff/GlyphDark.java
new file mode 100644
index 00000000..c72c4d9b
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/armorbuff/GlyphDark.java
@@ -0,0 +1,27 @@
+package com.hmdzl.spspd.actors.buffs.armorbuff;
+
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfDead;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.CountDown;
+import com.hmdzl.spspd.actors.buffs.DeadRaise;
+import com.hmdzl.spspd.actors.buffs.Silent;
+import com.hmdzl.spspd.actors.buffs.Weakness;
+import com.hmdzl.spspd.actors.mobs.DwarfLich;
+import com.hmdzl.spspd.actors.mobs.Fiend;
+import com.hmdzl.spspd.actors.mobs.Warlock;
+
+public class GlyphDark extends Buff {
+
+ {
+ immunities.add( Weakness.class );
+ immunities.add( CountDown.class );
+ immunities.add( DeadRaise.class );
+ immunities.add( Silent.class );
+ immunities.add( WeatherOfDead.class );
+
+ resistances.add( DwarfLich.class );
+ resistances.add( Warlock.class );
+ resistances.add( Fiend.class );
+ }
+
+ }
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/armorbuff/GlyphEarth.java b/java/com/hmdzl/spspd/actors/buffs/armorbuff/GlyphEarth.java
new file mode 100644
index 00000000..3092dc4b
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/armorbuff/GlyphEarth.java
@@ -0,0 +1,22 @@
+package com.hmdzl.spspd.actors.buffs.armorbuff;
+
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSand;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Ooze;
+import com.hmdzl.spspd.actors.buffs.Poison;
+import com.hmdzl.spspd.actors.buffs.Roots;
+import com.hmdzl.spspd.actors.buffs.Weakness;
+import com.hmdzl.spspd.actors.mobs.DwarfLich;
+import com.hmdzl.spspd.actors.mobs.Fiend;
+import com.hmdzl.spspd.actors.mobs.Warlock;
+
+ public class GlyphEarth extends Buff {
+
+ {
+ immunities.add( Roots.class );
+ immunities.add( Ooze.class );
+ immunities.add( Poison.class );
+ immunities.add(WeatherOfSand.class );
+ }
+
+ }
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/armorbuff/GlyphElectricity.java b/java/com/hmdzl/spspd/actors/buffs/armorbuff/GlyphElectricity.java
new file mode 100644
index 00000000..275e7465
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/armorbuff/GlyphElectricity.java
@@ -0,0 +1,29 @@
+package com.hmdzl.spspd.actors.buffs.armorbuff;
+
+import com.hmdzl.spspd.actors.blobs.ElectriShock;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Locked;
+import com.hmdzl.spspd.actors.buffs.Shocked;
+import com.hmdzl.spspd.actors.buffs.Weakness;
+import com.hmdzl.spspd.actors.mobs.DwarfLich;
+import com.hmdzl.spspd.actors.mobs.Fiend;
+import com.hmdzl.spspd.actors.mobs.GnollShaman;
+import com.hmdzl.spspd.actors.mobs.Shell;
+import com.hmdzl.spspd.actors.mobs.Warlock;
+import com.hmdzl.spspd.items.wands.WandOfLightning;
+import com.hmdzl.spspd.levels.traps.LightningTrap;
+
+public class GlyphElectricity extends Buff {
+
+ {
+ resistances.add( Shell.class );
+ resistances.add( GnollShaman.class );
+
+ immunities.add( WandOfLightning.class );
+ immunities.add( Shocked.class );
+ immunities.add( ElectriShock.class );
+ immunities.add( Locked.class );
+ immunities.add( LightningTrap.Electricity.class );
+ }
+
+ }
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/armorbuff/GlyphFire.java b/java/com/hmdzl/spspd/actors/buffs/armorbuff/GlyphFire.java
new file mode 100644
index 00000000..680781ef
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/armorbuff/GlyphFire.java
@@ -0,0 +1,29 @@
+package com.hmdzl.spspd.actors.buffs.armorbuff;
+
+import com.hmdzl.spspd.actors.blobs.Fire;
+import com.hmdzl.spspd.actors.blobs.TarGas;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Burning;
+import com.hmdzl.spspd.actors.buffs.Hot;
+import com.hmdzl.spspd.actors.buffs.Tar;
+import com.hmdzl.spspd.actors.buffs.Weakness;
+import com.hmdzl.spspd.actors.mobs.DwarfLich;
+import com.hmdzl.spspd.actors.mobs.Fiend;
+import com.hmdzl.spspd.actors.mobs.FireElemental;
+import com.hmdzl.spspd.actors.mobs.Warlock;
+import com.hmdzl.spspd.actors.mobs.Yog;
+
+public class GlyphFire extends Buff {
+
+ {
+ immunities.add( Burning.class );
+ resistances.add( FireElemental.class );
+ resistances.add( Yog.BurningFist.class );
+ immunities.add( Fire.class );
+ immunities.add( Tar.class );
+ immunities.add( TarGas.class );
+
+ immunities.add( Hot.class );
+ }
+
+ }
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/armorbuff/GlyphIce.java b/java/com/hmdzl/spspd/actors/buffs/armorbuff/GlyphIce.java
new file mode 100644
index 00000000..0f56b4ed
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/armorbuff/GlyphIce.java
@@ -0,0 +1,24 @@
+
+package com.hmdzl.spspd.actors.buffs.armorbuff;
+
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSnow;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Chill;
+import com.hmdzl.spspd.actors.buffs.Cold;
+import com.hmdzl.spspd.actors.buffs.Frost;
+import com.hmdzl.spspd.actors.buffs.Weakness;
+import com.hmdzl.spspd.actors.mobs.DwarfLich;
+import com.hmdzl.spspd.actors.mobs.Fiend;
+import com.hmdzl.spspd.actors.mobs.Warlock;
+
+public class GlyphIce extends Buff {
+
+ {
+ immunities.add( Frost.class );
+ immunities.add( Cold.class );
+ immunities.add( Chill.class );
+ immunities.add(WeatherOfSnow.class );
+
+ }
+
+ }
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/armorbuff/GlyphLight.java b/java/com/hmdzl/spspd/actors/buffs/armorbuff/GlyphLight.java
new file mode 100644
index 00000000..0830f055
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/armorbuff/GlyphLight.java
@@ -0,0 +1,23 @@
+package com.hmdzl.spspd.actors.buffs.armorbuff;
+
+import com.hmdzl.spspd.actors.blobs.weather.WeatherOfSun;
+import com.hmdzl.spspd.actors.buffs.Blindness;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Charm;
+import com.hmdzl.spspd.actors.buffs.Vertigo;
+import com.hmdzl.spspd.actors.buffs.Weakness;
+import com.hmdzl.spspd.actors.mobs.DwarfLich;
+import com.hmdzl.spspd.actors.mobs.Fiend;
+import com.hmdzl.spspd.actors.mobs.SewerHeart;
+import com.hmdzl.spspd.actors.mobs.Warlock;
+
+ public class GlyphLight extends Buff {
+
+ {
+ immunities.add( Blindness.class );
+ immunities.add( Vertigo.class );
+ immunities.add( Charm.class );
+ immunities.add(WeatherOfSun.class );
+ }
+
+ }
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/faithbuff/BalanceFaith.java b/java/com/hmdzl/spspd/actors/buffs/faithbuff/BalanceFaith.java
new file mode 100644
index 00000000..540958b7
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/faithbuff/BalanceFaith.java
@@ -0,0 +1,48 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs.faithbuff;
+
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class BalanceFaith extends Buff {
+
+ @Override
+ public int icon() {
+ return BuffIndicator.BALANCE_FAITH;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc");
+ }
+
+ @Override
+ public boolean act() {
+ if (target.isAlive()) {
+ spend(TICK);
+ }
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/faithbuff/DemonFaith.java b/java/com/hmdzl/spspd/actors/buffs/faithbuff/DemonFaith.java
new file mode 100644
index 00000000..23fe10d7
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/faithbuff/DemonFaith.java
@@ -0,0 +1,48 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs.faithbuff;
+
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class DemonFaith extends Buff {
+
+ @Override
+ public int icon() {
+ return BuffIndicator.DEMON_FAITH;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc");
+ }
+
+ @Override
+ public boolean act() {
+ if (target.isAlive()) {
+ spend(TICK);
+ }
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/faithbuff/HumanFaith.java b/java/com/hmdzl/spspd/actors/buffs/faithbuff/HumanFaith.java
new file mode 100644
index 00000000..1cf39972
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/faithbuff/HumanFaith.java
@@ -0,0 +1,48 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs.faithbuff;
+
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class HumanFaith extends Buff {
+
+ @Override
+ public int icon() {
+ return BuffIndicator.HUMAN_FAITH;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc");
+ }
+
+ @Override
+ public boolean act() {
+ if (target.isAlive()) {
+ spend(TICK);
+ }
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/faithbuff/LifeFaith.java b/java/com/hmdzl/spspd/actors/buffs/faithbuff/LifeFaith.java
new file mode 100644
index 00000000..da6022e7
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/faithbuff/LifeFaith.java
@@ -0,0 +1,48 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs.faithbuff;
+
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class LifeFaith extends Buff {
+
+ @Override
+ public int icon() {
+ return BuffIndicator.LIFE_FAITH;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc");
+ }
+
+ @Override
+ public boolean act() {
+ if (target.isAlive()) {
+ spend(TICK);
+ }
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/buffs/faithbuff/MechFaith.java b/java/com/hmdzl/spspd/actors/buffs/faithbuff/MechFaith.java
new file mode 100644
index 00000000..ffeba214
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/buffs/faithbuff/MechFaith.java
@@ -0,0 +1,48 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.buffs.faithbuff;
+
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.ui.BuffIndicator;
+
+public class MechFaith extends Buff {
+
+ @Override
+ public int icon() {
+ return BuffIndicator.MECH_FAITH;
+ }
+
+ @Override
+ public String toString() {
+ return Messages.get(this, "name");
+ }
+
+ @Override
+ public String desc() {
+ return Messages.get(this, "desc");
+ }
+
+ @Override
+ public boolean act() {
+ if (target.isAlive()) {
+ spend(TICK);
+ }
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/hero/Belongings.java b/java/com/hmdzl/spspd/actors/hero/Belongings.java
new file mode 100644
index 00000000..07f1ebea
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/hero/Belongings.java
@@ -0,0 +1,355 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.hero;
+
+import java.util.Iterator;
+
+import com.hmdzl.spspd.Badges;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.items.KindOfArmor;
+import com.hmdzl.spspd.items.KindOfWeapon;
+import com.hmdzl.spspd.items.KindofMisc;
+import com.hmdzl.spspd.items.bags.Bag;
+import com.hmdzl.spspd.items.keys.IronKey;
+import com.hmdzl.spspd.items.keys.Key;
+import com.hmdzl.spspd.items.scrolls.ScrollOfRemoveCurse;
+import com.hmdzl.spspd.items.wands.Wand;
+import com.hmdzl.spspd.items.weapon.guns.GunWeapon;
+import com.hmdzl.spspd.messages.Messages;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Random;
+
+public class Belongings implements Iterable
- {
+
+ public static final int BACKPACK_SIZE = 29;
+
+ private Hero owner;
+
+ public Bag backpack;
+
+ public KindOfWeapon weapon = null;
+ public KindOfArmor armor = null;
+ public KindofMisc misc1 = null;
+ public KindofMisc misc2 = null;
+ public KindofMisc misc3 = null;
+
+ public Belongings(Hero owner) {
+ this.owner = owner;
+
+ backpack = new Bag() {
+ {
+ name = Messages.get(Bag.class, "name");
+ size = BACKPACK_SIZE;
+ }
+ };
+ backpack.owner = owner;
+ }
+
+ private static final String WEAPON = "weapon";
+ private static final String ARMOR = "armor";
+ private static final String MISC1 = "misc1";
+ private static final String MISC2 = "misc2";
+ private static final String MISC3 = "misc3";
+
+ public void storeInBundle(Bundle bundle) {
+
+ backpack.storeInBundle(bundle);
+
+ bundle.put(WEAPON, weapon);
+ bundle.put(ARMOR, armor);
+ bundle.put(MISC1, misc1);
+ bundle.put(MISC2, misc2);
+ bundle.put(MISC3, misc3);
+ }
+
+ public void restoreFromBundle(Bundle bundle) {
+
+ backpack.clear();
+ backpack.restoreFromBundle(bundle);
+
+ weapon = (KindOfWeapon) bundle.get(WEAPON);
+ if (weapon != null) {
+ weapon.activate(owner);
+ }
+
+ armor = (KindOfArmor) bundle.get(ARMOR);
+ if (armor != null) {
+ armor.activate(owner);
+ }
+ //armor = (Armor) bundle.get(ARMOR);
+
+ misc1 = (KindofMisc) bundle.get(MISC1);
+ if (misc1 != null) {
+ misc1.activate(owner);
+ }
+
+ misc2 = (KindofMisc) bundle.get(MISC2);
+ if (misc2 != null) {
+ misc2.activate(owner);
+ }
+
+ misc3 = (KindofMisc) bundle.get(MISC3);
+ if (misc3 != null) {
+ misc3.activate(owner);
+ }
+
+ }
+
+ @SuppressWarnings("unchecked")
+ public T getItem(Class itemClass) {
+
+ for (Item item : this) {
+ if (itemClass.isInstance(item)) {
+ return (T) item;
+ }
+ }
+
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public T getKey(Class kind, int depth) {
+
+ for (Item item : backpack) {
+ if (item.getClass() == kind && ((Key) item).depth == depth) {
+ return (T) item;
+ }
+ }
+
+ return null;
+ }
+
+ public void countIronKeys() {
+
+ IronKey.curDepthQuantity = 0;
+
+ for (Item item : backpack) {
+ if (item instanceof IronKey
+ && ((IronKey) item).depth == Dungeon.depth) {
+ IronKey.curDepthQuantity += item.quantity();
+ }
+ }
+ }
+
+ public void identify() {
+ for (Item item : this) {
+ item.identify();
+ }
+ }
+
+ public void observe() {
+ if (weapon != null) {
+ weapon.identify();
+ Badges.validateItemLevelAquired(weapon);
+ }
+ if (armor != null) {
+ armor.identify();
+ Badges.validateItemLevelAquired(armor);
+ }
+ if (misc1 != null) {
+ misc1.identify();
+ Badges.validateItemLevelAquired(misc1);
+ }
+ if (misc2 != null) {
+ misc2.identify();
+ Badges.validateItemLevelAquired(misc2);
+ }
+ if (misc3 != null) {
+ misc3.identify();
+ Badges.validateItemLevelAquired(misc3);
+ }
+ for (Item item : backpack) {
+ item.cursedKnown = true;
+ }
+ }
+
+ public void observeS() {
+ for (Item item : backpack) {
+ item.cursedKnown = true;
+ }
+ }
+
+ public void uncurseEquipped() {
+ ScrollOfRemoveCurse.uncurse(owner, armor, weapon, misc1, misc2, misc3);
+ }
+
+ public Item randomUnequipped() {
+ return Random.element(backpack.items);
+ }
+
+ public void resurrect(int depth) {
+
+ for (Item item : backpack.items.toArray( new Item[0])) {
+ if (item instanceof Key) {
+ if (((Key)item).depth == depth) {
+ item.detachAll( backpack );
+ }
+ } else if (item.unique) {
+ item.detachAll(backpack);
+ //you keep the bag itself, not its contents.
+ if (item instanceof Bag){
+ ((Bag)item).clear();
+ }
+ item.collect();
+ } else if (!item.isEquipped( owner )) {
+ item.detachAll( backpack );
+ }
+ }
+
+ if (weapon != null) {
+ weapon.cursed = false;
+ weapon.activate(owner);
+ }
+
+ if (armor != null) {
+ armor.cursed = false;
+ armor.activate(owner);
+ }
+
+ if (misc1 != null) {
+ misc1.cursed = false;
+ misc1.activate(owner);
+ }
+ if (misc2 != null) {
+ misc2.cursed = false;
+ misc2.activate(owner);
+ }
+ if (misc3 != null) {
+ misc3.cursed = false;
+ misc3.activate(owner);
+ }
+ }
+
+ public int charge(boolean full) {
+
+ int count = 0;
+
+ for (Item item : this) {
+ if (item instanceof Wand) {
+ Wand wand = (Wand) item;
+ if (wand.curCharges < wand.maxCharges) {
+ wand.curCharges = full ? wand.maxCharges
+ : wand.curCharges + 1;
+ count++;
+
+ wand.updateQuickslot();
+ }
+ }
+ }
+
+ return count;
+ }
+
+ public int relord() {
+
+ int count = 0;
+
+ for (Item item : this) {
+ if (item instanceof GunWeapon) {
+ GunWeapon gunweapon = (GunWeapon) item;
+ gunweapon.charge = gunweapon.charge + 1;
+ count++;
+ gunweapon.updateQuickslot();
+ }
+ }
+ return count;
+ }
+
+ public int discharge() {
+
+ int count = 0;
+
+ for (Item item : this) {
+ if (item instanceof Wand) {
+ Wand wand = (Wand) item;
+ if (wand.curCharges > 0) {
+ wand.curCharges--;
+ count++;
+
+ wand.updateQuickslot();
+ }
+ }
+ }
+
+ return count;
+ }
+
+ @Override
+ public Iterator
- iterator() {
+ return new ItemIterator();
+ }
+
+ private class ItemIterator implements Iterator
- {
+
+ private int index = 0;
+
+ private Iterator
- backpackIterator = backpack.iterator();
+
+ private Item[] equipped = { weapon, armor, misc1, misc2 ,misc3 };
+ private int backpackIndex = equipped.length;
+
+ @Override
+ public boolean hasNext() {
+
+ for (int i = index; i < backpackIndex; i++) {
+ if (equipped[i] != null) {
+ return true;
+ }
+ }
+
+ return backpackIterator.hasNext();
+ }
+
+ @Override
+ public Item next() {
+
+ while (index < backpackIndex) {
+ Item item = equipped[index++];
+ if (item != null) {
+ return item;
+ }
+ }
+
+ return backpackIterator.next();
+ }
+
+ @Override
+ public void remove() {
+ switch (index) {
+ case 0:
+ equipped[0] = weapon = null;
+ break;
+ case 1:
+ equipped[1] = armor = null;
+ break;
+ case 2:
+ equipped[2] = misc1 = null;
+ break;
+ case 3:
+ equipped[3] = misc2 = null;
+ break;
+ case 4:
+ equipped[4] = misc3 = null;
+ break;
+ default:
+ backpackIterator.remove();
+ }
+ }
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/hero/Hero.java b/java/com/hmdzl/spspd/actors/hero/Hero.java
new file mode 100644
index 00000000..3e58c032
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/hero/Hero.java
@@ -0,0 +1,2394 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.hero;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+
+import com.hmdzl.spspd.Challenges;
+import com.hmdzl.spspd.actors.buffs.AflyBless;
+import com.hmdzl.spspd.actors.buffs.Arcane;
+import com.hmdzl.spspd.actors.buffs.ArmorBreak;
+import com.hmdzl.spspd.actors.buffs.AttackUp;
+import com.hmdzl.spspd.actors.buffs.BloodAngry;
+import com.hmdzl.spspd.actors.buffs.BoxStar;
+import com.hmdzl.spspd.actors.buffs.Burning;
+import com.hmdzl.spspd.actors.buffs.Charm;
+import com.hmdzl.spspd.actors.buffs.DamageUp;
+import com.hmdzl.spspd.actors.buffs.DeadRaise;
+import com.hmdzl.spspd.actors.buffs.Disarm;
+import com.hmdzl.spspd.actors.buffs.Dry;
+import com.hmdzl.spspd.actors.buffs.GlassShield;
+import com.hmdzl.spspd.actors.buffs.GoldTouch;
+import com.hmdzl.spspd.actors.buffs.Haste;
+import com.hmdzl.spspd.actors.buffs.HighAttack;
+import com.hmdzl.spspd.actors.buffs.HighLight;
+import com.hmdzl.spspd.actors.buffs.HighVoice;
+import com.hmdzl.spspd.actors.buffs.Locked;
+import com.hmdzl.spspd.actors.buffs.MirrorShield;
+import com.hmdzl.spspd.actors.buffs.Muscle;
+import com.hmdzl.spspd.actors.buffs.NewCombo;
+import com.hmdzl.spspd.actors.buffs.Notice;
+import com.hmdzl.spspd.actors.buffs.ParyAttack;
+import com.hmdzl.spspd.actors.buffs.Rhythm;
+import com.hmdzl.spspd.actors.buffs.Rhythm2;
+import com.hmdzl.spspd.actors.buffs.Shocked;
+import com.hmdzl.spspd.actors.buffs.Silent;
+import com.hmdzl.spspd.actors.buffs.Terror;
+import com.hmdzl.spspd.actors.buffs.WarGroove;
+import com.hmdzl.spspd.actors.buffs.faithbuff.BalanceFaith;
+import com.hmdzl.spspd.actors.buffs.faithbuff.DemonFaith;
+import com.hmdzl.spspd.actors.buffs.faithbuff.HumanFaith;
+import com.hmdzl.spspd.actors.buffs.faithbuff.LifeFaith;
+import com.hmdzl.spspd.actors.buffs.faithbuff.MechFaith;
+import com.hmdzl.spspd.actors.mobs.SommonSkeleton;
+import com.hmdzl.spspd.effects.Lightning;
+import com.hmdzl.spspd.items.DolyaSlate;
+import com.hmdzl.spspd.items.Generator;
+import com.hmdzl.spspd.items.KindOfArmor;
+import com.hmdzl.spspd.items.armor.glyphs.Iceglyph;
+import com.hmdzl.spspd.items.artifacts.AlienBag;
+import com.hmdzl.spspd.items.artifacts.EtherealChains;
+import com.hmdzl.spspd.items.artifacts.Pylon;
+import com.hmdzl.spspd.items.misc.AttackShield;
+import com.hmdzl.spspd.items.misc.BShovel;
+import com.hmdzl.spspd.items.misc.CopyBall;
+import com.hmdzl.spspd.items.misc.DanceLion;
+import com.hmdzl.spspd.items.misc.FourClover;
+import com.hmdzl.spspd.items.misc.GunOfSoldier;
+import com.hmdzl.spspd.items.misc.HealBag;
+import com.hmdzl.spspd.items.misc.HorseTotem;
+import com.hmdzl.spspd.items.misc.JumpF;
+import com.hmdzl.spspd.items.misc.JumpP;
+import com.hmdzl.spspd.items.misc.JumpS;
+import com.hmdzl.spspd.items.misc.PotionOfMage;
+import com.hmdzl.spspd.items.misc.RangeBag;
+import com.hmdzl.spspd.items.misc.SavageHelmet;
+import com.hmdzl.spspd.items.misc.Shovel;
+import com.hmdzl.spspd.items.rings.RingOfMagic;
+import com.hmdzl.spspd.items.wands.WandOfFlow;
+import com.hmdzl.spspd.items.misc.MissileShield;
+import com.hmdzl.spspd.mechanics.Ballistica;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.Assets;
+import com.hmdzl.spspd.Badges;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.GamesInProgress;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.Statistics;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Barkskin;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Combo;
+import com.hmdzl.spspd.actors.buffs.Dewcharge;
+import com.hmdzl.spspd.actors.buffs.Drowsy;
+import com.hmdzl.spspd.actors.buffs.Fury;
+import com.hmdzl.spspd.actors.buffs.Hunger;
+import com.hmdzl.spspd.actors.buffs.Invisibility;
+import com.hmdzl.spspd.actors.buffs.Light;
+import com.hmdzl.spspd.actors.buffs.Paralysis;
+import com.hmdzl.spspd.actors.buffs.Regeneration;
+import com.hmdzl.spspd.actors.buffs.SnipersMark;
+import com.hmdzl.spspd.actors.buffs.Strength;
+import com.hmdzl.spspd.actors.buffs.Vertigo;
+import com.hmdzl.spspd.actors.mobs.Mob;
+import com.hmdzl.spspd.actors.mobs.npcs.NPC;
+import com.hmdzl.spspd.actors.mobs.pets.PET;
+import com.hmdzl.spspd.effects.CellEmitter;
+import com.hmdzl.spspd.effects.CheckedCell;
+import com.hmdzl.spspd.effects.Flare;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.items.Amulet;
+import com.hmdzl.spspd.items.Ankh;
+import com.hmdzl.spspd.items.Dewdrop;
+import com.hmdzl.spspd.items.eggs.Egg;
+import com.hmdzl.spspd.items.Heap;
+import com.hmdzl.spspd.items.Heap.Type;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.items.KindOfWeapon;
+import com.hmdzl.spspd.items.artifacts.CapeOfThorns;
+import com.hmdzl.spspd.items.artifacts.DriedRose;
+import com.hmdzl.spspd.items.artifacts.TalismanOfForesight;
+import com.hmdzl.spspd.items.artifacts.TimekeepersHourglass;
+import com.hmdzl.spspd.items.keys.GoldenKey;
+import com.hmdzl.spspd.items.keys.GoldenSkeletonKey;
+import com.hmdzl.spspd.items.keys.IronKey;
+import com.hmdzl.spspd.items.keys.Key;
+import com.hmdzl.spspd.items.keys.SkeletonKey;
+import com.hmdzl.spspd.items.misc.AutoPotion.AutoHealPotion;
+import com.hmdzl.spspd.items.potions.Potion;
+import com.hmdzl.spspd.items.potions.PotionOfHealing;
+import com.hmdzl.spspd.items.potions.PotionOfMight;
+import com.hmdzl.spspd.items.potions.PotionOfStrength;
+import com.hmdzl.spspd.items.rings.RingOfElements;
+import com.hmdzl.spspd.items.rings.RingOfForce;
+import com.hmdzl.spspd.items.rings.RingOfFuror;
+import com.hmdzl.spspd.items.rings.RingOfHaste;
+import com.hmdzl.spspd.items.rings.RingOfMight;
+import com.hmdzl.spspd.items.rings.RingOfTenacity;
+import com.hmdzl.spspd.items.scrolls.Scroll;
+import com.hmdzl.spspd.items.scrolls.ScrollOfMagicMapping;
+import com.hmdzl.spspd.items.scrolls.ScrollOfMagicalInfusion;
+import com.hmdzl.spspd.items.scrolls.ScrollOfUpgrade;
+import com.hmdzl.spspd.items.weapon.melee.MeleeWeapon;
+import com.hmdzl.spspd.items.misc.Jumpshoes;
+import com.hmdzl.spspd.items.misc.JumpW;
+import com.hmdzl.spspd.items.misc.JumpM;
+import com.hmdzl.spspd.items.misc.JumpR;
+import com.hmdzl.spspd.items.misc.JumpH;
+import com.hmdzl.spspd.items.misc.Ankhshield;
+import com.hmdzl.spspd.items.OrbOfZot;
+import com.hmdzl.spspd.items.weapon.missiles.MissileWeapon;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.levels.Terrain;
+import com.hmdzl.spspd.levels.features.AlchemyPot;
+import com.hmdzl.spspd.levels.features.Chasm;
+import com.hmdzl.spspd.levels.features.Sign;
+import com.hmdzl.spspd.plants.Earthroot;
+import com.hmdzl.spspd.plants.Sungrass;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.scenes.InterlevelScene;
+import com.hmdzl.spspd.scenes.SurfaceScene;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.sprites.HeroSprite;
+import com.hmdzl.spspd.ui.AttackIndicator;
+import com.hmdzl.spspd.ui.BuffIndicator;
+import com.hmdzl.spspd.ui.QuickSlotButton;
+import com.hmdzl.spspd.utils.GLog;
+import com.hmdzl.spspd.windows.WndAscend;
+import com.hmdzl.spspd.windows.WndDescend;
+import com.hmdzl.spspd.windows.WndMessage;
+import com.hmdzl.spspd.windows.WndResurrect;
+import com.hmdzl.spspd.windows.WndTradeItem;
+import com.hmdzl.spspd.utils.BArray;
+import com.watabou.noosa.Camera;
+import com.watabou.noosa.Game;
+import com.watabou.noosa.audio.Sample;
+import com.watabou.utils.PathFinder;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Random;
+
+import static com.hmdzl.spspd.Dungeon.hero;
+
+public class Hero extends Char {
+
+ private static final String TXT_VALUE = "%+d";
+
+ public static final int STARTING_STR = 10;
+ public static final int STARTING_MAGIC = 0;
+
+
+ private static final float TIME_TO_REST = 1f;
+ private static final float TIME_TO_SEARCH = 2f;
+
+ public HeroClass heroClass = HeroClass.ROGUE;
+ public HeroSubClass subClass = HeroSubClass.NONE;
+
+ public int hitSkill = 10;
+ public int evadeSkill = 5;
+ public int magicSkill = 0;
+
+ public boolean ready = false;
+
+ public boolean haspet = false;
+ public boolean petfollow = false;
+ public int petType = 0;
+ public int petLevel = 0;
+ public int petHP = 0;
+ public int petExperience = 0;
+ public int petCooldown = 0;
+
+ private boolean damageInterrupt = true;
+ public HeroAction curAction = null;
+ public HeroAction lastAction = null;
+
+ private Char enemy;
+
+ private Item theKey;
+ private Item theSkeletonKey;
+
+ public boolean restoreHealth = false;
+
+ public MissileWeapon rangedWeapon = null;
+ public Belongings belongings;
+
+ public int STR;
+ public boolean weakened = false;
+
+ public float awareness;
+
+ public int lvl = 1;
+ public int exp = 0;
+
+ private ArrayList visibleEnemies;
+
+ public Hero() {
+ super();
+ name = Messages.get(this, "name");
+
+ HP = HT = 30;
+ STR = STARTING_STR;
+ magicSkill = STARTING_MAGIC;
+
+ awareness = 0.1f;
+
+ belongings = new Belongings(this);
+
+ visibleEnemies = new ArrayList();
+ }
+
+ public int STR() {
+ int STR = this.STR;
+
+ for (Buff buff : buffs(RingOfMight.Might.class)) {
+ STR += (int)(((RingOfMight.Might) buff).level/5);
+ }
+
+ if (buff(Muscle.class)!= null)
+ STR += 2 ;
+
+ if (buff(AflyBless.class)!= null)
+ STR += 1 ;
+
+ return weakened ? STR - 3 : STR;
+ }
+
+ public int magicSkill() {
+ int magicSkill = this.magicSkill;
+
+ for (Buff buff : buffs(RingOfMagic.Magic.class)) {
+ magicSkill += Math.min(30,((RingOfMagic.Magic) buff).level);
+ }
+ if (subClass == HeroSubClass.BATTLEMAGE)
+ magicSkill += 5;
+ if (subClass == HeroSubClass.SUPERSTAR)
+ magicSkill += 4;
+ if (buff(Arcane.class)!= null)
+ magicSkill += 10;
+
+ return magicSkill;
+ }
+
+ private static final String ATTACK = "hitSkill";
+ private static final String DEFENSE = "evadeSkill";
+ private static final String MAGIC = "magicSkill";
+ private static final String STRENGTH = "STR";
+ private static final String LEVEL = "lvl";
+ private static final String EXPERIENCE = "exp";
+ private static final String HASPET = "haspet";
+ private static final String PETFOLLOW = "petfollow";
+ private static final String PETTYPE = "petType";
+ private static final String PETLEVEL = "petLevel";
+ private static final String PETHP = "petHP";
+ private static final String PETEXP = "petExperience";
+ private static final String PETCOOLDOWN = "petCooldown";
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+
+ super.storeInBundle(bundle);
+
+ heroClass.storeInBundle(bundle);
+ subClass.storeInBundle(bundle);
+
+ bundle.put(ATTACK, hitSkill);
+ bundle.put(DEFENSE, evadeSkill);
+ bundle.put(MAGIC, magicSkill);
+
+ bundle.put(STRENGTH, STR);
+
+ bundle.put(LEVEL, lvl);
+ bundle.put(EXPERIENCE, exp);
+ bundle.put(HASPET, haspet);
+ bundle.put(PETFOLLOW, petfollow);
+ bundle.put(PETTYPE, petType);
+ bundle.put(PETLEVEL, petLevel);
+ bundle.put(PETHP, petHP);
+ bundle.put(PETEXP, petExperience);
+ bundle.put(PETCOOLDOWN, petCooldown);
+
+ belongings.storeInBundle(bundle);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+
+ heroClass = HeroClass.restoreInBundle(bundle);
+ subClass = HeroSubClass.restoreInBundle(bundle);
+
+ hitSkill = bundle.getInt(ATTACK);
+ evadeSkill = bundle.getInt(DEFENSE);
+ magicSkill = bundle.getInt(MAGIC);
+
+ STR = bundle.getInt(STRENGTH);
+ updateAwareness();
+
+ lvl = bundle.getInt(LEVEL);
+ exp = bundle.getInt(EXPERIENCE);
+ haspet = bundle.getBoolean(HASPET);
+ petfollow = bundle.getBoolean(PETFOLLOW);
+ petType = bundle.getInt(PETTYPE);
+ petLevel = bundle.getInt(PETLEVEL);
+ petHP = bundle.getInt(PETHP);
+ petExperience = bundle.getInt(PETEXP);
+ petCooldown = bundle.getInt(PETCOOLDOWN);
+
+ belongings.restoreFromBundle(bundle);
+ }
+
+ public static void preview(GamesInProgress.Info info, Bundle bundle) {
+ info.level = bundle.getInt(LEVEL);
+ }
+
+ public String className() {
+ return subClass == null || subClass == HeroSubClass.NONE ? heroClass
+ .title() : subClass.title();
+ }
+
+ public String givenName() {
+ return name.equals(Messages.get(this, "name")) ? className() : name;
+ }
+
+ public void live() {
+ Buff.affect(this, Regeneration.class);
+ Buff.affect(this, Hunger.class);
+ }
+
+ public int useskin() {
+ return belongings.armor == null ? 0 : 7 - Dungeon.skins;
+ }
+
+ public boolean shoot(Char enemy, MissileWeapon wep) {
+
+ rangedWeapon = wep;
+ boolean result = attack(enemy);
+ Invisibility.dispel();
+ rangedWeapon = null;
+
+ return result;
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ float accuracy = 1;
+
+ KindOfWeapon wep = rangedWeapon != null ? rangedWeapon
+ : belongings.weapon;
+ if (wep != null) {
+ return (int) (hitSkill * accuracy * wep.acuracyFactor(this));
+ } else {
+ return (int) (hitSkill * accuracy);
+ }
+ }
+
+ @Override
+ public int evadeSkill(Char enemy) {
+ float evasion = 1;
+ if (paralysed > 0) {
+ evasion /= 2;
+ }
+ KindOfArmor arm = belongings.armor;
+ if (arm != null) {
+ return (int) (evadeSkill * evasion * arm.dexterityFactor(this));
+ } else {
+ return (int) (evadeSkill * evasion);
+ }
+ }
+
+ @Override
+ public int drRoll() {
+ KindOfArmor arm = belongings.armor;
+ int dr;
+ //int bonus = 0;
+ //for (Buff buff : buffs(RingOfForce.Force.class)) {
+ //bonus += ((RingOfForce.Force) buff).level;
+ //}
+ Barkskin barkskin = buff(Barkskin.class);
+ if (arm != null) {
+ dr = arm.drRoll(this);
+ } else {
+ //int str = 6;
+ //dr = bonus == 0 ? str > 1 ? Random.NormalIntRange(1, str) : 1
+ //: bonus > 0 ? str > 0 ? Random.NormalIntRange(str / 2
+ //+ bonus, (int) (str * 0.5f * bonus) + str * 2) : 1
+ //: 0;
+ dr = 0;
+ }
+
+ //if (bonus > 0){ dr *= Math.min(3f,(1f + (bonus/15)*1f));}
+
+ if (dr < 0)
+ dr = 0;
+ if (barkskin != null) {
+ dr += barkskin.level();
+ }
+ if (Dungeon.hero.heroClass == HeroClass.SOLDIER && Dungeon.skins == 2) {
+ dr += Dungeon.hero.lvl;
+ }
+ return (int)dr;
+ }
+
+ @Override
+ public int damageRoll() {
+ KindOfWeapon wep = rangedWeapon != null ? rangedWeapon
+ : belongings.weapon;
+ int dmg;
+ int bonus = 0;
+ for (Buff buff : buffs(RingOfForce.Force.class)) {
+ bonus += ((RingOfForce.Force) buff).level;
+ }
+
+ if (wep != null) {
+ dmg = wep.damageRoll(this);
+ } else {
+ int str = 6;
+ dmg = bonus == 0 ? str > 1 ? Random.NormalIntRange(1, str) : 1
+ : bonus > 0 ? str > 0 ? Random.NormalIntRange(str / 2
+ + bonus, (int) (str * 0.5f * bonus) + str * 2) : 1
+ : 0;
+ }
+ if (bonus > 0){ dmg *= Math.min(3f,(1f + (bonus*1.00/10)*1f));}
+
+ if (dmg < 0)
+ dmg = 0;
+
+ if (buff(Fury.class) != null){ dmg *= 1.30f; }
+
+ if (buff(Strength.class) != null){ dmg *= 3f; Buff.detach(this, Strength.class);}
+
+ HighAttack hatk = buff(HighAttack.class);
+ if (buff(HighAttack.class) != null){
+ dmg *= hatk.level();
+ Buff.detach(this, HighAttack.class);
+ }
+
+ ParyAttack paryatk = buff(ParyAttack.class);
+ if (buff(ParyAttack.class) != null){
+ dmg *= (1+paryatk.level()*0.4);
+ }
+
+
+ if (buff(WarGroove.class) != null){ dmg *= 1.5f; Buff.detach(this, WarGroove.class);}
+
+ if (buff(Dry.class) != null){ dmg *= 0.80f; }
+
+ if (buff(BloodAngry.class) != null){ dmg *= 1.50f; }
+
+ if (buff(Rhythm2.class) != null){ dmg *= 1.20f; }
+ /*AttackUp atkup = buff(AttackUp.class);
+ if (atkup != null) {
+ dmg *=(1f+atkup.level()*0.01f);
+ }
+
+ AttackDown atkdown = buff(AttackDown.class);
+ if (atkdown != null) {
+ dmg *=(1f-atkdown.level()*0.01f);
+ }*/
+
+ Hunger hunger = buff(Hunger.class);
+ if (hunger != null && hunger.isStarving()) { dmg *= 0.8f;}
+ if (hunger != null && hunger.isHungry()) { dmg *= 0.9f;}
+ if (hunger != null && hunger.isOverfed()) { dmg *= 1.2f; }
+
+ return (int) dmg;
+
+ }
+
+
+ @Override
+ public float speed() {
+
+ float speed = super.speed();
+
+ int hasteLevel = 0;
+ for (Buff buff : buffs(RingOfHaste.Haste.class)) {
+ hasteLevel += ((RingOfHaste.Haste) buff).level;
+ }
+
+
+ if (hasteLevel != 0) {
+ if (hasteLevel < 30){
+ speed *= (1+(hasteLevel*1.00/10));
+ }
+ else speed *=4;
+ }
+
+ if (hero.heroClass == HeroClass.HUNTRESS && Dungeon.skins == 2) {
+ speed += 0.5f;
+
+ }
+
+ return ((HeroSprite) sprite).sprint(subClass == HeroSubClass.FREERUNNER && !isStarving()) ? invisible > 0 ? 2.5f * speed
+ : 1.5f * speed : speed;
+
+
+ }
+
+ public boolean canAttack(Char enemy){
+ if (enemy == null || pos == enemy.pos)
+ return false;
+
+ //can always attack adjacent enemies
+ if (Dungeon.level.adjacent(pos, enemy.pos))
+ return true;
+
+ KindOfWeapon wep = hero.belongings.weapon;
+
+ if (wep != null && Dungeon.level.distance( pos, enemy.pos ) <= wep.reachFactor(this)){
+
+ boolean[] passable = BArray.not(Level.solid, null);
+ for (Mob m : Dungeon.level.mobs)
+ passable[m.pos] = false;
+
+ PathFinder.buildDistanceMap(enemy.pos, passable, wep.reachFactor(this));
+
+ return PathFinder.distance[pos] <= wep.reachFactor(this);
+
+ } else {
+ return false;
+ }
+ }
+
+
+ public float attackDelay() {
+ KindOfWeapon wep = rangedWeapon != null ? rangedWeapon
+ : belongings.weapon;
+ if (wep != null) {
+
+ return wep.speedFactor(this);
+
+ } else {
+ // Normally putting furor speed on unarmed attacks would be
+ // unnecessary
+ // But there's going to be that one guy who gets a furor+force ring
+ // combo
+ // This is for that one guy, you shall get your fists of fury!
+ int bonus = 0;
+ for (Buff buff : buffs(RingOfFuror.Furor.class)) {
+ bonus += ((RingOfFuror.Furor) buff).level;
+ }
+ return (float) ( 1 / Math.min( 4, 1 + bonus * 1.00 / 10) );
+ }
+ }
+
+ @Override
+ public void spend(float time) {
+ justMoved = false;
+ TimekeepersHourglass.timeFreeze freeze = buff(TimekeepersHourglass.timeFreeze.class);
+ if (freeze != null) {
+ freeze.processTime(time);
+ return;
+ } else if (Statistics.time < 1440 ) {
+ Statistics.time += time;
+ Dungeon.observe();
+ } else if ( Statistics.time > 1440 ) {
+ Statistics.time += time;
+ Statistics.time -= 1440;
+ //Dungeon.observe();
+ } else {
+ Statistics.time = 0;
+ //Dungeon.observe();
+ }
+
+ super.spend(time);
+ };
+
+ public void spendAndNext(float time) {
+ busy();
+ spend(time);
+ next();
+ }
+
+ @Override
+ public boolean act() {
+
+ super.act();
+
+ Statistics.moves++;
+
+ Light light = buff(Light.class);
+ if (buff(HighLight.class) != null){
+ viewDistance = 8;
+ Dungeon.observe();
+ } else if ((Statistics.time > 360 && Statistics.time <601 ) || (Statistics.time > 840 && Statistics.time < 1081 )) {
+ viewDistance = 6;
+ Dungeon.observe();
+ } else if (Statistics.time < 841 && Statistics.time > 600) {
+ viewDistance = 8;
+ Dungeon.observe();
+ } else if (Statistics.time > 1080 && light == null) {
+ viewDistance = 4;
+ Dungeon.observe();
+ } else if (Statistics.time < 361 && light == null) {
+ viewDistance = 2;
+ Dungeon.observe();
+ } else {viewDistance = 5;
+ Dungeon.observe();}
+
+
+ if(Dungeon.dewDraw || Dungeon.dewWater){ Dungeon.level.currentmoves++;}
+
+ if (paralysed > 0) {
+
+ curAction = null;
+
+ spendAndNext(TICK);
+ return false;
+ }
+
+ Egg egg = belongings.getItem(Egg.class);
+ if (egg!=null){
+ egg.moves++;
+ }
+
+ DolyaSlate journal = belongings.getItem(DolyaSlate.class);
+ if (journal!=null && (Dungeon.depth < 26)
+ && (journal.level>1 || journal.rooms[0])
+ && journal.charge spawnPoints = new ArrayList();
+ for (int i = 0; i < Level.NEIGHBOURS8.length; i++) {
+ int p = pos + Level.NEIGHBOURS8[i];
+ if (Actor.findChar(p) == null
+ && (Level.passable[p] || Level.avoid[p])) {
+ spawnPoints.add(p);
+ }
+ }
+
+ if (spawnPoints.size() > 0) {
+ SommonSkeleton.spawnAt(Random.element(spawnPoints));
+ Sample.INSTANCE.play(Assets.SND_CURSED);
+ }
+ }
+
+
+ /*
+ Heap heap = Dungeon.level.heaps.get(pos);
+ if (heap != null){
+ heap.dewcollect();
+ }
+ */
+
+ checkVisibleMobs();
+
+ if (curAction == null) {
+
+ if (restoreHealth) {
+ spend(TIME_TO_REST);
+ next();
+ return false;
+ }
+
+ ready();
+ return false;
+
+ } else {
+
+ restoreHealth = false;
+
+ ready = false;
+
+ if (curAction instanceof HeroAction.Move) {
+
+ return actMove((HeroAction.Move) curAction);
+
+ } else if (curAction instanceof HeroAction.Interact) {
+
+ return actInteract((HeroAction.Interact) curAction);
+
+ } else if (curAction instanceof HeroAction.InteractPet) {
+
+ return actInteractPet((HeroAction.InteractPet) curAction);
+
+ } else if (curAction instanceof HeroAction.Buy) {
+
+ return actBuy((HeroAction.Buy) curAction);
+
+ } else if (curAction instanceof HeroAction.PickUp) {
+
+ return actPickUp((HeroAction.PickUp) curAction);
+
+ } else if (curAction instanceof HeroAction.OpenChest) {
+
+ return actOpenChest((HeroAction.OpenChest) curAction);
+
+ } else if (curAction instanceof HeroAction.Unlock) {
+
+ return actUnlock((HeroAction.Unlock) curAction);
+
+ } else if (curAction instanceof HeroAction.Descend) {
+
+ return actDescend((HeroAction.Descend) curAction);
+
+ } else if (curAction instanceof HeroAction.Ascend) {
+
+ return actAscend((HeroAction.Ascend) curAction);
+
+ } else if (curAction instanceof HeroAction.Attack) {
+
+ return actAttack((HeroAction.Attack) curAction);
+
+ /*} else if (curAction instanceof HeroAction.Cook) {
+
+ return actCook( (HeroAction.Cook)curAction );*/
+
+ }
+ }
+
+ return false;
+ }
+
+ public void busy() {
+ ready = false;
+ }
+
+ private void ready() {
+ sprite.idle();
+ curAction = null;
+ damageInterrupt = true;
+ ready = true;
+
+ AttackIndicator.updateState();
+
+ GameScene.ready();
+ }
+
+ public void interrupt() {
+ if (isAlive() && curAction != null
+ && curAction instanceof HeroAction.Move && curAction.dst != pos) {
+ lastAction = curAction;
+ }
+ curAction = null;
+ }
+
+ public void resume() {
+ curAction = lastAction;
+ lastAction = null;
+ damageInterrupt = false;
+ act();
+ }
+
+
+ public boolean justMoved = false;
+
+ private boolean actMove(HeroAction.Move action) {
+
+ if (getCloser(action.dst)) {
+ justMoved = true;
+ return true;
+
+ } else {
+ if (Dungeon.level.map[pos] == Terrain.SIGN && pos != Dungeon.level.pitSign) {
+ Sign.read(pos);
+ } else if (Dungeon.level.map[pos] == Terrain.SIGN && pos == Dungeon.level.pitSign){
+ Sign.readPit(pos);
+ } else if (Dungeon.level.map[pos] == Terrain.ALCHEMY){
+ AlchemyPot.cook(pos);
+ }
+ ready();
+
+ return false;
+ }
+ }
+
+ private boolean actInteract(HeroAction.Interact action) {
+
+ NPC npc = action.npc;
+
+ if (Level.adjacent(pos, npc.pos)) {
+
+ ready();
+ sprite.turnTo(pos, npc.pos);
+ //npc.interact();
+ //return false;
+ return npc.interact();
+
+ } else {
+
+ if (Level.fieldOfView[npc.pos] && getCloser(npc.pos)) {
+
+ return true;
+
+ } else {
+ ready();
+ return false;
+ }
+
+ }
+ }
+
+ private boolean actInteractPet(HeroAction.InteractPet action) {
+
+ PET pet = action.pet;
+
+ if (Level.adjacent(pos, pet.pos)) {
+
+ ready();
+ sprite.turnTo(pos, pet.pos);
+ //pet.interact();
+ //return false;
+ return pet.interact();
+
+ } else {
+
+ if (Level.fieldOfView[pet.pos] && getCloser(pet.pos)) {
+
+ return true;
+
+ } else {
+ ready();
+ return false;
+ }
+
+ }
+ }
+
+ private boolean actBuy(HeroAction.Buy action) {
+ int dst = action.dst;
+ if (pos == dst || Level.adjacent(pos, dst)) {
+
+ ready();
+
+ Heap heap = Dungeon.level.heaps.get(dst);
+ if (heap != null && heap.type == Type.FOR_SALE && heap.size() == 1) {
+ GameScene.show(new WndTradeItem(heap, true));
+ }
+
+ return false;
+
+ } else if (getCloser(dst)) {
+
+ return true;
+
+ } else {
+ ready();
+ return false;
+ }
+ }
+
+ /*private boolean actAlchemy( HeroAction.Alchemy action ) {
+ int dst = action.dst;
+ if (Dungeon.level.distance(dst, pos) <= 1) {
+
+ ready();
+ GameScene.show(new WndAlchemy());
+ return false;
+
+ } else if (getCloser( dst )) {
+
+ return true;
+
+ } else {
+ ready();
+ return false;
+ }
+ }*/
+
+ private boolean actPickUp(HeroAction.PickUp action) {
+ int dst = action.dst;
+ if (pos == dst) {
+
+ Heap heap = Dungeon.level.heaps.get(pos);
+ if (heap != null) {
+ Item item = heap.pickUp();
+ if (item.doPickUp(this)) {
+
+ if (item instanceof Dewdrop
+ || item instanceof TimekeepersHourglass.sandBag
+ || item instanceof DriedRose.Petal) {
+ // Do Nothing
+ } else {
+
+ boolean important = ((item instanceof ScrollOfUpgrade || item instanceof ScrollOfMagicalInfusion) && ((Scroll) item)
+ .isKnown())
+ || ((item instanceof PotionOfStrength || item instanceof PotionOfMight) && ((Potion) item)
+ .isKnown());
+ if (important) {
+ GLog.p(Messages.get(this, "you_now_have", item.name()));
+ } else {
+ GLog.i(Messages.get(this, "you_now_have", item.name()));
+ }
+
+ // Alright, if anyone complains about not knowing the
+ // vial doesn't revive
+ // after this... I'm done, I'm just done.
+ }
+
+ curAction = null;
+ } else {
+ Dungeon.level.drop(item, pos).sprite.drop();
+ ready();
+ }
+ } else {
+ ready();
+ }
+
+ return false;
+
+ } else if (getCloser(dst)) {
+
+ return true;
+
+ } else {
+ ready();
+ return false;
+ }
+ }
+
+ private boolean actOpenChest(HeroAction.OpenChest action) {
+ int dst = action.dst;
+ if (Level.adjacent(pos, dst) || pos == dst) {
+
+ Heap heap = Dungeon.level.heaps.get(dst);
+ if (heap != null
+ && (heap.type != Type.HEAP && heap.type != Type.FOR_SALE)) {
+
+ theKey = null;
+ theSkeletonKey = null;
+
+ if (heap.type == Type.LOCKED_CHEST
+ || heap.type == Type.CRYSTAL_CHEST
+ //|| heap.type == Type.MONSTERBOX
+ ) {
+
+ theKey = belongings.getKey(GoldenKey.class, Dungeon.depth);
+ theSkeletonKey = belongings.getKey(GoldenSkeletonKey.class, 0);
+
+ if (theKey == null && theSkeletonKey == null) {
+ GLog.w( Messages.get(this, "locked_chest"));
+ ready();
+ return false;
+ }
+ }
+
+ switch (heap.type) {
+ case TOMB:
+ Sample.INSTANCE.play(Assets.SND_TOMB);
+ Camera.main.shake(1, 0.5f);
+ break;
+ case SKELETON:
+ case REMAINS:
+ break;
+ default:
+ Sample.INSTANCE.play(Assets.SND_UNLOCK);
+ }
+
+ spend(Key.TIME_TO_UNLOCK);
+ sprite.operate(dst);
+
+ } else {
+ ready();
+ }
+
+ return false;
+
+ } else if (getCloser(dst)) {
+
+ return true;
+
+ } else {
+ ready();
+ return false;
+ }
+ }
+
+ private boolean actUnlock(HeroAction.Unlock action) {
+ int doorCell = action.dst;
+ if (Level.adjacent(pos, doorCell)) {
+
+ theKey = null;
+ int door = Dungeon.level.map[doorCell];
+
+ if (door == Terrain.LOCKED_DOOR) {
+
+ theKey = belongings.getKey(IronKey.class, Dungeon.depth);
+
+ } else if (door == Terrain.LOCKED_EXIT) {
+
+ theKey = belongings.getKey(SkeletonKey.class, Dungeon.depth);
+
+ }
+
+ if (theKey != null) {
+
+ spend(Key.TIME_TO_UNLOCK);
+ sprite.operate(doorCell);
+
+ Sample.INSTANCE.play(Assets.SND_UNLOCK);
+
+ } else {
+ GLog.w( Messages.get(Hero.class, "locked_door"));
+ ready();
+ }
+
+ return false;
+
+ } else if (getCloser(doorCell)) {
+
+ return true;
+
+ } else {
+ ready();
+ return false;
+ }
+ }
+
+ private PET checkpet(){
+ for (Mob mob : Dungeon.level.mobs) {
+ if(mob instanceof PET) {
+ return (PET) mob;
+ }
+ }
+ return null;
+ }
+
+ private boolean checkpetNear(){
+ for (int n : Level.NEIGHBOURS8) {
+ int c = pos + n;
+ if (Actor.findChar(c) instanceof PET) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean actDescend(HeroAction.Descend action) {
+ int stairs = action.dst;
+
+ if (!Dungeon.level.forcedone && ( Dungeon.dewDraw || Dungeon.dewWater )
+ && (Dungeon.level.checkdew()>0
+ || hero.buff(Dewcharge.class) != null))
+ {
+ GameScene.show(new WndDescend());
+ ready();
+ return false;
+ }
+
+ if (!Dungeon.level.forcedone &&
+ ( Dungeon.dewDraw || Dungeon.dewWater ) &&
+ !Dungeon.level.cleared &&
+ !Dungeon.notClearableLevel(Dungeon.depth))
+ {
+ GameScene.show(new WndDescend());
+ ready();
+ return false;
+ }
+
+
+ if (pos == stairs && pos == Dungeon.level.exit && !Dungeon.level.sealedlevel){
+
+ curAction = null;
+
+ if(Dungeon.dewDraw || Dungeon.dewWater) {
+
+ for (int i = 0; i < Level.LENGTH; i++) {
+
+ if (!Dungeon.level.cleared && (Dungeon.dewDraw || Dungeon.dewWater) && !Dungeon.notClearableLevel(Dungeon.depth)) {
+ Dungeon.level.cleared = true;
+ Statistics.prevfloormoves = 0;
+ }
+ }
+ }
+
+ PET pet = checkpet();
+ if(pet!=null && checkpetNear()){
+ hero.petType=pet.type;
+ hero.petLevel=pet.level;
+ hero.petHP=pet.HP;
+ hero.petExperience=pet.experience;
+ hero.petCooldown=pet.cooldown;
+ pet.destroy();
+ petfollow=true;
+ } else if (hero.haspet && hero.petfollow) {
+ petfollow=true;
+ } else {
+ petfollow=false;
+ }
+
+ Buff buff = buff(TimekeepersHourglass.timeFreeze.class);
+ if (buff != null) buff.detach();
+
+ InterlevelScene.mode = InterlevelScene.Mode.DESCEND;
+ Game.switchScene(InterlevelScene.class);
+
+ return false;
+
+ } else if (getCloser(stairs)) {
+
+ return true;
+
+ } else {
+ ready();
+ return false;
+ }
+ }
+
+ private boolean actAscend(HeroAction.Ascend action) {
+ int stairs = action.dst;
+ if (pos == stairs && pos == Dungeon.level.entrance) {
+
+ if (Dungeon.depth == 1) {
+
+ if (belongings.getItem(Amulet.class) == null) {
+ GameScene.show(new WndMessage(Messages.get(this, "leave")));
+ ready();
+
+ } else if (Dungeon.level.forcedone){
+ Dungeon.win(Messages.format(ResultDescriptions.WIN));
+ Dungeon.deleteGame(hero.heroClass, true);
+ Game.switchScene(SurfaceScene.class);
+ } else {
+ GameScene.show(new WndAscend());
+ ready();
+ }
+
+ } else if (Dungeon.depth == 34) {
+ curAction = null;
+
+ Hunger hunger = buff(Hunger.class);
+ if (hunger != null && !hunger.isStarving()) {
+ hunger.satisfy(-Hunger.STARVING / 10);
+ }
+
+ PET pet = checkpet();
+ if(pet!=null && checkpetNear()){
+ hero.petType=pet.type;
+ hero.petLevel=pet.level;
+ hero.petHP=pet.HP;
+ hero.petExperience=pet.experience;
+ hero.petCooldown=pet.cooldown;
+ pet.destroy();
+ petfollow=true;
+ } else if (hero.haspet && hero.petfollow) {
+ petfollow=true;
+ } else {
+ petfollow=false;
+ }
+
+ Buff buff = buff(TimekeepersHourglass.timeFreeze.class);
+ if (buff != null)
+ buff.detach();
+
+ for (Mob mob : Dungeon.level.mobs.toArray(new Mob[0]))
+ if (mob instanceof DriedRose.GhostHero)
+ mob.destroy();
+
+ InterlevelScene.mode = InterlevelScene.Mode.ASCEND;
+ Game.switchScene(InterlevelScene.class);
+
+
+ } else if (Dungeon.depth == 41) {
+ curAction = null;
+
+ Hunger hunger = buff(Hunger.class);
+ if (hunger != null && !hunger.isStarving()) {
+ hunger.satisfy(-Hunger.STARVING / 10);
+ }
+
+ PET pet = checkpet();
+ if(pet!=null && checkpetNear()){
+ hero.petType=pet.type;
+ hero.petLevel=pet.level;
+ hero.petHP=pet.HP;
+ hero.petExperience=pet.experience;
+ hero.petCooldown=pet.cooldown;
+ pet.destroy();
+ petfollow=true;
+ } else if (hero.haspet && hero.petfollow) {
+ petfollow=true;
+ } else {
+ petfollow=false;
+ }
+
+ Buff buff = buff(TimekeepersHourglass.timeFreeze.class);
+ if (buff != null)
+ buff.detach();
+
+ for (Mob mob : Dungeon.level.mobs.toArray(new Mob[0]))
+ if (mob instanceof DriedRose.GhostHero)
+ mob.destroy();
+
+ InterlevelScene.mode = InterlevelScene.Mode.ASCEND;
+ Game.switchScene(InterlevelScene.class);
+
+ } else if (Dungeon.depth > 26 && !Dungeon.townCheck(Dungeon.depth)){
+ ready();
+ } else if (Dungeon.depth == 55 || Dungeon.depth == 99){
+ ready();
+ } else if (Dungeon.depth > 55 && Dungeon.level.locked){
+ ready();
+ } else {
+
+ curAction = null;
+
+ Hunger hunger = buff(Hunger.class);
+ if (hunger != null && !hunger.isStarving()) {
+ hunger.satisfy(-Hunger.STARVING / 10);
+ }
+
+ PET pet = checkpet();
+ if(pet!=null && checkpetNear()){
+ hero.petType=pet.type;
+ hero.petLevel=pet.level;
+ hero.petHP=pet.HP;
+ hero.petExperience=pet.experience;
+ hero.petCooldown=pet.cooldown;
+ pet.destroy();
+ petfollow=true;
+ } else if (hero.haspet && hero.petfollow) {
+ petfollow=true;
+ } else {
+ petfollow=false;
+ }
+
+ Buff buff = buff(TimekeepersHourglass.timeFreeze.class);
+ if (buff != null)
+ buff.detach();
+
+ for (Mob mob : Dungeon.level.mobs.toArray(new Mob[0]))
+ if (mob instanceof DriedRose.GhostHero)
+ mob.destroy();
+
+ InterlevelScene.mode = InterlevelScene.Mode.ASCEND;
+ Game.switchScene(InterlevelScene.class);
+ }
+
+ return false;
+
+ } else if (getCloser(stairs)) {
+
+ return true;
+
+ } else {
+ ready();
+ return false;
+ }
+ }
+
+ private boolean actAttack(HeroAction.Attack action) {
+
+ enemy = action.target;
+
+ if (enemy.isAlive() && canAttack( enemy ) && !isCharmedBy( enemy ) && (buff(Disarm.class) == null)) {
+
+ Invisibility.dispel();
+ spend( attackDelay());
+ sprite.attack( enemy.pos );
+
+ return false;
+
+ } else {
+
+ if (Level.fieldOfView[enemy.pos] && getCloser( enemy.pos )) {
+
+ return true;
+
+ } else {
+ ready();
+ return false;
+ }
+
+ }
+ }
+
+ public Char enemy(){
+ return enemy;
+ }
+
+ public void rest(boolean fullRest) {
+ //search(true);
+ spendAndNext(TIME_TO_REST);
+ if (!fullRest) {
+ sprite.showStatus(CharSprite.DEFAULT, Messages.get(this, "wait"));
+ }
+ restoreHealth = fullRest;
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+ KindOfWeapon wep = rangedWeapon != null ? rangedWeapon
+ : belongings.weapon;
+
+ if (wep != null){
+ wep.proc(this, enemy, damage);
+ }
+
+ AttackShield atkshield = belongings.getItem(AttackShield.class);
+ if (atkshield!=null && atkshield.charge arcs = new ArrayList<>();
+ arcs.add(new Lightning.Arc(pos - Level.WIDTH, pos + Level.WIDTH));
+ arcs.add(new Lightning.Arc(pos - 1, pos + 1));
+ sprite.parent.add( new Lightning( arcs, null ) );
+ }
+ if (buff(GoldTouch.class)!=null){
+ if (rangedWeapon == null && Dungeon.gold < (int)((1000000/(Math.max(1,20-Statistics.deepestFloor))))) {
+ int earngold = Math.min(1000 * hero.lvl, damage);
+ Dungeon.gold += earngold;
+
+ hero.sprite.showStatus(CharSprite.NEUTRAL, TXT_VALUE, earngold);
+ }
+ }
+
+ if (buff(HighVoice.class)!=null && Random.Int(5) == 0){
+ Buff.affect(this, AttackUp.class,8f).level(30);
+ GLog.p(Messages.get(HighVoice.class,"atkup",Dungeon.hero.givenName()));
+ }
+
+ if (buff(MechFaith.class)!= null && ((enemy.properties().contains(Property.BEAST))
+ || (enemy.properties().contains(Property.PLANT))
+ || (enemy.properties().contains(Property.ELEMENT))) ){
+ damage=(int)(damage*1.5);
+ }
+
+ if (buff(LifeFaith.class)!= null && ((enemy.properties().contains(Property.MECH))
+ || (enemy.properties().contains(Property.ALIEN))
+ || (enemy.properties().contains(Property.GOBLIN))) ){
+ damage=(int)(damage*1.5);
+ }
+
+ if (buff(DemonFaith.class)!= null && ((enemy.properties().contains(Property.HUMAN))
+ || (enemy.properties().contains(Property.ORC))
+ || (enemy.properties().contains(Property.ELF))
+ || (enemy.properties().contains(Property.DWARF))
+ || (enemy.properties().contains(Property.TROLL)))){
+ damage=(int)(damage*1.5);
+ }
+
+ if (buff(HumanFaith.class)!= null && ((enemy.properties().contains(Property.DRAGON))
+ || (enemy.properties().contains(Property.DEMONIC))
+ || (enemy.properties().contains(Property.UNKNOW))
+ || (enemy.properties().contains(Property.UNDEAD))) ){
+ damage=(int)(damage*1.5);
+ }
+
+ if (buff(BalanceFaith.class)!= null && ((enemy.properties().contains(Property.BOSS))
+ || (enemy.properties().contains(Property.MINIBOSS))) ){
+ damage=(int)(damage*1.5);
+ }
+
+ HorseTotem horseTotem = belongings.getItem(HorseTotem.class);
+ HorseTotem.HorseTotemBless totembuff = buff(HorseTotem.HorseTotemBless.class);
+ if (totembuff != null) {
+ int x = Random.Int(1,damage/3);
+ damage +=x;
+ Buff.prolong(this, Haste.class,4f);
+ } else if (horseTotem!=null && Random.Int(5)==0) {
+ int x = Random.Int(1,damage/3);
+ damage +=x;
+ Buff.prolong(this, Haste.class,4f);
+ }
+
+ RangeBag.RangeBagBless rangeBless = buff(RangeBag.RangeBagBless.class);
+ if (rangeBless != null){
+ if (enemy.HP <= damage && Random.Int(6) == 0) {
+ Dungeon.level.drop(Generator.random(Generator.Category.LINKDROP), enemy.pos).sprite.drop();
+ }
+ }
+
+ return damage;
+
+ }
+
+ @Override
+ public int defenseProc(Char enemy, int damage) {
+
+ KindOfArmor arm = belongings.armor;
+
+ if (buff(HighVoice.class)!=null && Random.Int(5) == 0){
+ Buff.affect(this, GlassShield.class).turns(2);
+ GLog.p(Messages.get(HighVoice.class,"save",Dungeon.hero.givenName()));
+ }
+
+ CapeOfThorns.Thorns thorns = buff(CapeOfThorns.Thorns.class);
+ if (thorns != null) {
+ damage = thorns.proc(damage, enemy);
+ }
+
+ MirrorShield mirror = buff(MirrorShield.class);
+ if (mirror != null) {
+ damage = mirror.proc(damage, enemy);
+ }
+
+ BoxStar star = buff(BoxStar.class);
+ if (star != null) {
+ damage = star.proc(damage, enemy);
+ }
+
+ Earthroot.Armor earmor = buff(Earthroot.Armor.class);
+ if (earmor != null) {
+ damage = earmor.absorb(damage);
+ }
+
+ Sungrass.Health health = buff(Sungrass.Health.class);
+ if (health != null) {
+ health.absorb(damage);
+ }
+
+ SavageHelmet helmet = belongings.getItem(SavageHelmet.class);
+ SavageHelmet.SavageHelmetBless helmetbuff = buff(SavageHelmet.SavageHelmetBless.class);
+ if (helmetbuff != null) {
+ helmetbuff.absorb(damage);
+ } else if (helmet!=null && Random.Int(5)==0) {
+ int x = Random.Int(1,damage/2);
+ damage -=x;
+ Buff.affect(this, DamageUp.class).level(x);
+ }
+
+ if (arm != null) {
+ arm.proc(enemy, this, damage);
+ }
+
+ switch (subClass) {
+ case LEADER:
+ switch (Random.Int (10)){
+ case 0:
+ int oppositeDefender = enemy.pos + (enemy.pos - pos);
+ Ballistica trajectory = new Ballistica(enemy.pos, oppositeDefender, Ballistica.MAGIC_BOLT);
+ WandOfFlow.throwChar(enemy, trajectory, 1);
+ break;
+ case 1:
+ Buff.prolong(enemy,Silent.class,5f);
+ break;
+ case 2:
+ Buff.prolong(enemy,Disarm.class,5f);
+ break;
+ case 3:
+ Buff.prolong(enemy,Terror.class,5f);
+ break;
+ case 4:
+ Buff.prolong(enemy,ArmorBreak.class,5f).level(35);
+ break;
+ case 5:
+ Buff.prolong(enemy,Locked.class,5f);
+ break;
+
+ default:
+ break;
+
+ }
+ }
+ return damage;
+ }
+
+ @Override
+ public void damage(int dmg, Object src) {
+ if (buff(TimekeepersHourglass.timeStasis.class) != null)
+ return;
+
+ if (!(src instanceof Hunger || src instanceof Iceglyph.DeferedDamage)
+ && damageInterrupt){
+ interrupt();
+ restoreHealth = false;
+ }
+
+ if (this.buff(Drowsy.class) != null) {
+ Buff.detach(this, Drowsy.class);
+ GLog.w(Messages.get(this, "pain_resist"));
+ }
+
+ if (enemy != null) {
+ if (buff(LifeFaith.class) != null) {
+ if ((enemy.properties().contains(Property.BEAST))
+ || (enemy.properties().contains(Property.PLANT))
+ || (enemy.properties().contains(Property.ELEMENT))) {
+ dmg = (int) Math.ceil(dmg * 0.75);
+ }
+ }
+
+ if (buff(MechFaith.class) != null) {
+ if ((enemy.properties().contains(Property.MECH))
+ || (enemy.properties().contains(Property.ALIEN))
+ || (enemy.properties().contains(Property.GOBLIN))) {
+ dmg = (int) Math.ceil(dmg * 0.75);
+ }
+ }
+
+ if (buff(HumanFaith.class) != null) {
+ if ((enemy.properties().contains(Property.HUMAN))
+ || (enemy.properties().contains(Property.ORC))
+ || (enemy.properties().contains(Property.ELF))
+ || (enemy.properties().contains(Property.DWARF))
+ || (enemy.properties().contains(Property.TROLL))) {
+ dmg = (int) Math.ceil(dmg * 0.75);
+ }
+ }
+
+ if (buff(DemonFaith.class) != null) {
+ if ((enemy.properties().contains(Property.DRAGON))
+ || (enemy.properties().contains(Property.DEMONIC))
+ || (enemy.properties().contains(Property.UNKNOW))
+ || (enemy.properties().contains(Property.UNDEAD))) {
+ dmg = (int) Math.ceil(dmg * 0.75);
+ }
+ }
+
+ if (buff(BalanceFaith.class) != null) {
+ if ((enemy.properties().contains(Property.BOSS))
+ || (enemy.properties().contains(Property.MINIBOSS))) {
+ dmg = (int) Math.ceil(dmg * 0.75);
+ }
+ }
+ }
+
+ int tenacity = 0;
+ for (Buff buff : buffs(RingOfTenacity.Tenacity.class)) {
+ tenacity += ((RingOfTenacity.Tenacity) buff).level;
+ }
+
+ if (tenacity != 0) // (HT - HP)/HT = heroes current % missing health.
+ dmg = (int) Math.ceil(dmg * Math.max(0.60, (1- 1.00*tenacity/75)));
+
+ if (buff(Fury.class) != null){dmg = (int) Math.ceil(dmg * 0.75);}
+ if (buff(BloodAngry.class) != null){dmg = (int) Math.ceil(dmg * 0.80);}
+ if (buff(Rhythm2.class) != null){dmg = (int) Math.ceil(dmg * 0.90);}
+
+ if (subClass == HeroSubClass.LEADER){dmg = (int) Math.ceil(dmg * 0.80);}
+
+ //if (buff(Hot.class) != null){dmg = (int) Math.ceil(dmg * 1.20);}
+
+ /*DefenceUp drup = buff(DefenceUp.class);
+ if (buff(DefenceUp.class) != null) {
+ dmg = (int) Math.ceil(dmg *(-drup.level()*0.01+1));
+ }*/
+
+ /*ArmorBreak ab = buff(ArmorBreak.class);
+ if (buff(ArmorBreak.class) != null){
+ dmg= (int) Math.ceil(dmg *(ab.level()*0.01+1));
+ }*/
+
+
+
+ super.damage(dmg, src);
+
+
+ if (subClass == HeroSubClass.BERSERKER && 0 < HP
+ && HP <= HT * Fury.LEVEL) {
+ Buff.affect(this, Fury.class);
+ }
+
+ if (this.buff(AutoHealPotion.class) != null && ((float) HP / HT)<.1) {
+ PotionOfHealing pot = hero.belongings.getItem(PotionOfHealing.class);
+ if (pot != null) {
+ pot.detach(hero.belongings.backpack,1);
+ /*
+ if(!(Dungeon.hero.belongings.getItem(PotionOfHealing.class).quantity() > 0)){
+ pot.detachAll(Dungeon.hero.belongings.backpack);
+ }
+ */
+ GLog.w(Messages.get(this, "auto_potion"));
+ pot.apply(this);
+ }
+ else if (pot==null){
+ GLog.w(Messages.get(this, "auto_potion_no"));
+ }
+
+ }
+
+ }
+
+ private void checkVisibleMobs() {
+ ArrayList visible = new ArrayList();
+
+ boolean newMob = false;
+ Mob closest = null;
+
+ for (Mob m : Dungeon.level.mobs) {
+ if (Level.fieldOfView[m.pos] && m.hostile) {
+ visible.add(m);
+ if (!visibleEnemies.contains(m)) {
+ newMob = true;
+ }
+ if (closest == null){
+ closest = m;
+ } else if (distance(closest) > distance(m)) {
+ closest = m;
+ }
+ }
+ }
+
+ if (closest != null && (QuickSlotButton.lastTarget == null ||
+ !QuickSlotButton.lastTarget.isAlive() ||
+ !Dungeon.visible[QuickSlotButton.lastTarget.pos])){
+ QuickSlotButton.target(closest);
+ }
+
+ if (newMob) {
+ interrupt();
+ restoreHealth = false;
+ }
+
+ visibleEnemies = visible;
+ }
+
+ public int visibleEnemies() {
+ return visibleEnemies.size();
+ }
+
+ public Mob visibleEnemy(int index) {
+ return visibleEnemies.get(index % visibleEnemies.size());
+ }
+
+ private boolean getCloser(final int target) {
+
+ if (rooted) {
+ Camera.main.shake(1, 1f);
+ return false;
+ }
+
+ int step = -1;
+
+ if (Level.adjacent(pos, target)) {
+
+ if (Actor.findChar(target) == null) {
+ if (Level.pit[target] && !flying && !Chasm.jumpConfirmed) {
+ if (!Level.solid[target]) {
+ Chasm.heroJump(this);
+ interrupt();
+ }
+ return false;
+ }
+ if (Level.passable[target] || Level.avoid[target]) {
+ step = target;
+ }
+ }
+
+ } else {
+
+ int len = Level.getLength();
+ boolean[] p = Level.passable;
+ boolean[] v = Dungeon.level.visited;
+ boolean[] m = Dungeon.level.mapped;
+ boolean[] passable = new boolean[len];
+ for (int i = 0; i < len; i++) {
+ passable[i] = p[i] && (v[i] || m[i]);
+ }
+
+ step = Dungeon.findPath(this, pos, target, passable,
+ Level.fieldOfView);
+ }
+
+ if (step != -1) {
+
+ int oldPos = pos;
+ move(step);
+ sprite.move(oldPos, pos);
+ spend(1 / speed());
+
+ return true;
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
+ public boolean handle(int cell) {
+
+ if (cell == -1) {
+ return false;
+ }
+
+ Char ch;
+ Heap heap;
+ if (Level.fieldOfView[cell]
+ && (ch = Actor.findChar(cell)) instanceof Mob) {
+
+ if (ch instanceof NPC) {
+ curAction = new HeroAction.Interact((NPC) ch);
+ } else if (ch instanceof PET) {
+ curAction = new HeroAction.InteractPet((PET) ch);
+ } else {
+ curAction = new HeroAction.Attack(ch);
+ }
+
+ } else if ((heap = Dungeon.level.heaps.get(cell)) != null) {
+
+ switch (heap.type) {
+ case HEAP:
+ curAction = new HeroAction.PickUp(cell);
+ break;
+ case FOR_SALE:
+ curAction = heap.size() == 1 && heap.peek().price() > 0 ? new HeroAction.Buy(
+ cell) : new HeroAction.PickUp(cell);
+ break;
+ default:
+ curAction = new HeroAction.OpenChest(cell);
+ }
+
+ } else if (Dungeon.level.map[cell] == Terrain.LOCKED_DOOR
+ || Dungeon.level.map[cell] == Terrain.LOCKED_EXIT) {
+
+ curAction = new HeroAction.Unlock(cell);
+
+ } else if (cell == Dungeon.level.exit && (Dungeon.depth < 26)) {
+
+ curAction = new HeroAction.Descend(cell);
+
+ } else if (cell == Dungeon.level.entrance) {
+
+ curAction = new HeroAction.Ascend(cell);
+
+ } else {
+
+ curAction = new HeroAction.Move(cell);
+ lastAction = null;
+
+ }
+
+ return act();
+ }
+
+ public void earnExp(int exp) {
+
+ this.exp += exp;
+
+ float percent = exp/(float)maxExp();
+
+ EtherealChains.chainsRecharge chains = buff(EtherealChains.chainsRecharge.class);
+ if (chains != null) chains.gainExp(percent);
+
+ AlienBag.bagRecharge bags = buff(AlienBag.bagRecharge.class);
+ if (bags != null) bags.gainExp(percent);
+
+ Pylon.beaconRecharge pylon = buff(Pylon.beaconRecharge.class);
+ if (pylon != null) pylon.gainExp(percent);
+
+ boolean levelUp = false;
+ while (this.exp >= maxExp()) {
+ this.exp -= maxExp();
+ lvl++;
+
+ if (Dungeon.isChallenged(Challenges.LISTLESS)){
+ HT += 2;
+ HP += 1;
+ hitSkill++;
+ evadeSkill++;
+ } else if (lvl < 12) {
+ HT += 4;
+ HP += 4;
+ hitSkill++;
+ evadeSkill++;
+ } else {
+ HT += 5;
+ HP += 5;
+ hitSkill++;
+ evadeSkill++;}
+ FourClover.FourCloverBless fcb = buff(FourClover.FourCloverBless.class);
+ if (fcb != null){
+ HT+=5;
+ magicSkill++;
+ Dungeon.gold+=1000;
+ hero.sprite.showStatus(CharSprite.NEUTRAL, TXT_VALUE, 1000);
+
+ }
+ if (heroClass == HeroClass.SOLDIER){
+ HT+=3;
+ }
+ if (lvl < 10) {
+ updateAwareness();
+ }
+
+ levelUp = true;
+ }
+
+ if (levelUp) {
+
+ GLog.p(Messages.get(this, "new_level"), lvl );
+ sprite.showStatus(CharSprite.POSITIVE, Messages.get(Hero.class, "level_up") );
+ Sample.INSTANCE.play(Assets.SND_LEVELUP);
+
+ Badges.validateLevelReached();
+
+ int value = HT - HP;
+ if (value > 0) {
+ HP += value;
+ sprite.emitter().burst(Speck.factory(Speck.HEALING), 1);
+ }
+
+ buff(Hunger.class).satisfy(10);
+ if(hero.heroClass == HeroClass.PERFORMER){
+ Buff.prolong(hero,Rhythm.class,100);
+ Buff.affect(hero,GlassShield.class).turns(1);
+ }
+ if(hero.subClass == HeroSubClass.SUPERSTAR){
+ Buff.prolong(hero,Rhythm2.class,100);
+ }
+ }
+ }
+
+ public int maxExp() {
+ return 7 + lvl * 8;
+ }
+
+ void updateAwareness() {
+ awareness = (float) (1 - Math.pow((heroClass == HeroClass.ROGUE ? 0.85
+ : 0.90), (1 + Math.min(lvl, 9)) * 0.5));
+ }
+
+ public boolean isStarving() {
+ return buff(Hunger.class) != null
+ && buff(Hunger.class).isStarving();
+ }
+
+ public boolean isHungry() {
+ return buff(Hunger.class) != null
+ && buff(Hunger.class).isHungry();
+ }
+
+ public boolean isOverfed() {
+ return buff(Hunger.class) != null
+ && buff(Hunger.class).isOverfed();
+ }
+
+ @Override
+ public void add(Buff buff) {
+
+ if (buff(TimekeepersHourglass.timeStasis.class) != null)
+ return;
+
+ super.add(buff);
+
+ if (sprite != null) {
+ String msg = buff.heroMessage();
+ if (msg != null){
+ GLog.w(msg);
+ }
+
+ if (buff instanceof RingOfMight.Might) {
+ if (((RingOfMight.Might) buff).level > 0) {
+ HT += ((RingOfMight.Might) buff).level * 10;
+ }
+ } else if (buff instanceof Paralysis || buff instanceof Vertigo) {
+ interrupt();
+ }
+
+ }
+ BuffIndicator.refreshHero();
+ }
+
+ @Override
+ public void remove(Buff buff) {
+ super.remove(buff);
+ if (buff instanceof RingOfMight.Might) {
+ if (((RingOfMight.Might) buff).level > 0) {
+ HT -= ((RingOfMight.Might) buff).level * 10;
+ hero.damage(1, this);
+ if (!hero.isAlive()) {
+ Dungeon.fail(Messages.format(ResultDescriptions.ITEM));
+ }
+
+ }
+ }
+
+ BuffIndicator.refreshHero();
+ }
+
+ @Override
+ public int stealth() {
+ int stealth = super.stealth();
+ int shadow = 1;
+ KindOfArmor arm = belongings.armor;
+ if (arm != null) {
+ stealth += shadow * arm.stealthFactor(this);
+ } else {
+ stealth += shadow;
+ }
+ if (hero.subClass == HeroSubClass.AGENT){
+ stealth += 5;
+ }
+ if (hero.heroClass == HeroClass.ROGUE && Dungeon.skins == 2){
+ stealth += 8;
+ }
+ return stealth;
+ }
+
+ @Override
+ public int energybase() {
+ int energybase = super.energybase();
+ int energy = 1;
+ KindOfArmor arm = belongings.armor;
+ if (arm != null) {
+ energybase += energy * arm.energyFactor(this);
+ } else {
+ energybase += energy;
+ }
+ return energybase;
+ }
+
+ @Override
+ public void die(Object cause) {
+
+ curAction = null;
+
+ Ankh ankh = null;
+
+ // look for ankhs in player inventory, prioritize ones which are
+ // blessed.
+ for (Item item : belongings) {
+ if (item instanceof Ankh) {
+ if (ankh == null || ((Ankh) item).isBlessed()) {
+ ankh = (Ankh) item;
+ }
+ }
+ }
+
+ if (ankh != null && ankh.isBlessed() && this.HT > 0) {
+
+ this.HP = HT;
+
+ Buff.detach(this, Paralysis.class);
+ spend(-cooldown());
+
+ new Flare(8, 32).color(0xFFFF66, true).show(sprite, 2f);
+ CellEmitter.get(this.pos)
+ .start(Speck.factory(Speck.LIGHT), 0.2f, 3);
+
+ ankh.detach(belongings.backpack);
+
+ Sample.INSTANCE.play(Assets.SND_TELEPORT);
+ GLog.w(Messages.get(this, "revive"));
+ Statistics.ankhsUsed++;
+ return;
+ }
+
+ Actor.fixTime();
+ super.die(cause);
+
+ if (ankh == null) {
+ reallyDie(cause);
+ } else {
+
+ //ankh.detach(belongings.backpack);
+ Dungeon.deleteGame(hero.heroClass, false);
+ GameScene.show(new WndResurrect(ankh, cause));
+
+ }
+ }
+
+ public static void reallyDie(Object cause) {
+
+ int length = Level.getLength();
+ int[] map = Dungeon.level.map;
+ boolean[] visited = Dungeon.level.visited;
+ boolean[] discoverable = Level.discoverable;
+
+ for (int i = 0; i < length; i++) {
+
+ int terr = map[i];
+
+ if (discoverable[i]) {
+
+ visited[i] = true;
+ if ((Terrain.flags[terr] & Terrain.SECRET) != 0) {
+ //Level.set(i, Terrain.discover(terr));
+ //GameScene.updateMap(i);
+ Dungeon.level.discover( i );
+ }
+ }
+ }
+
+ Dungeon.observe();
+
+ hero.belongings.identify();
+
+ int pos = hero.pos;
+
+ ArrayList passable = new ArrayList();
+ for (Integer ofs : Level.NEIGHBOURS8) {
+ int cell = pos + ofs;
+ if ((Level.passable[cell] || Level.avoid[cell])
+ && Dungeon.level.heaps.get(cell) == null) {
+ passable.add(cell);
+ }
+ }
+ Collections.shuffle(passable);
+
+ ArrayList
- items = new ArrayList
- (
+ hero.belongings.backpack.items);
+ for (Integer cell : passable) {
+ if (items.isEmpty()) {
+ break;
+ }
+
+ Item item = Random.element(items);
+ Dungeon.level.drop(item, cell).sprite.drop(pos);
+ items.remove(item);
+ }
+
+ GameScene.gameOver();
+
+ if (cause instanceof Hero.Doom) {
+ ((Hero.Doom) cause).onDeath();
+ }
+
+ Dungeon.deleteGame(hero.heroClass, true);
+ }
+
+ @Override
+ public void move(int step) {
+ super.move(step);
+
+ if (!flying) {
+
+ if (Level.water[pos]) {
+ Sample.INSTANCE.play(Assets.SND_WATER, 1, 1,
+ Random.Float(0.8f, 1.25f));
+ } else {
+ Sample.INSTANCE.play(Assets.SND_STEP);
+ }
+ Dungeon.level.press(pos, this);
+ }
+ }
+
+ @Override
+ public void onMotionComplete() {
+ Dungeon.observe();
+ search(false);
+
+ super.onMotionComplete();
+ }
+
+
+ @Override
+ public void onAttackComplete() {
+
+ AttackIndicator.target(enemy);
+
+ //attack(enemy);
+
+ boolean hit = attack( enemy );
+
+ if (buff(AttackShield.LongBuff.class)!=null && belongings.weapon == null){
+ if (hit) {
+ Buff.affect( this, NewCombo.class ).hit();
+ } else {
+ NewCombo newcombo = buff(NewCombo.class);
+ if (newcombo != null) newcombo.miss();
+ }
+ }
+ curAction = null;
+
+ Invisibility.dispel();
+
+ super.onAttackComplete();
+ }
+
+ @Override
+ public void onOperateComplete() {
+
+ if (curAction instanceof HeroAction.Unlock) {
+
+ if (theKey != null) {
+ theKey.detach(belongings.backpack);
+ theKey = null;
+ }
+
+ int doorCell = ((HeroAction.Unlock) curAction).dst;
+ int door = Dungeon.level.map[doorCell];
+
+ Level.set(doorCell, door == Terrain.LOCKED_DOOR ? Terrain.DOOR
+ : Terrain.UNLOCKED_EXIT);
+ GameScene.updateMap(doorCell);
+
+ } else if (curAction instanceof HeroAction.OpenChest) {
+
+ if (theKey != null) {
+ theKey.detach(belongings.backpack);
+ theKey = null;
+ } else if (theKey == null && theSkeletonKey != null) {
+ theSkeletonKey.detach(belongings.backpack);
+ theSkeletonKey = null;
+ }
+
+ Heap heap = Dungeon.level.heaps
+ .get(((HeroAction.OpenChest) curAction).dst);
+ if (heap.type == Type.SKELETON || heap.type == Type.REMAINS) {
+ Sample.INSTANCE.play(Assets.SND_BONES);
+ }
+ heap.open(this);
+ }
+ curAction = null;
+
+ super.onOperateComplete();
+ }
+
+ public boolean search(boolean intentional) {
+
+ boolean smthFound = false;
+
+ int positive = 0;
+ int negative = 0;
+ Light light = buff(Light.class);
+ if (light != null){
+ positive = 1;
+ }
+ int distance = 1 + positive + negative;
+
+
+
+ float level = intentional ? (2 * awareness - awareness * awareness)
+ : awareness;
+ if (distance <= 0) {
+ level /= 2 - distance;
+ distance = 1;
+ }
+
+ int cx = pos % Level.getWidth();
+ int cy = pos / Level.getWidth();
+ int ax = cx - distance;
+ if (ax < 0) {
+ ax = 0;
+ }
+ int bx = cx + distance;
+ if (bx >= Level.getWidth()) {
+ bx = Level.getWidth() - 1;
+ }
+ int ay = cy - distance;
+ if (ay < 0) {
+ ay = 0;
+ }
+ int by = cy + distance;
+ if (by >= Level.HEIGHT) {
+ by = Level.HEIGHT - 1;
+ }
+
+ TalismanOfForesight.Foresight foresight = buff(TalismanOfForesight.Foresight.class);
+ boolean notice = buff(Notice.class) != null;
+ // cursed talisman of foresight makes unintentionally finding things
+ // impossible.
+ if (foresight != null && foresight.isCursed()) {
+ level = -1;
+ }
+
+ for (int y = ay; y <= by; y++) {
+ for (int x = ax, p = ax + y * Level.getWidth(); x <= bx; x++, p++) {
+
+ if (Dungeon.visible[p]) {
+
+ if (intentional) {
+ sprite.parent.addToBack(new CheckedCell(p));
+ }
+
+ if (Level.secret[p]
+ && (intentional || Random.Float() < level || notice)) {
+
+ int oldValue = Dungeon.level.map[p];
+
+ GameScene.discoverTile(p, oldValue);
+
+ //Level.set(p, Terrain.discover(oldValue));
+
+ //GameScene.updateMap(p);
+
+ Dungeon.level.discover( p );
+
+ ScrollOfMagicMapping.discover(p);
+
+ smthFound = true;
+
+ if (foresight != null && !foresight.isCursed())
+ foresight.charge();
+ }
+ }
+ }
+ }
+
+ if (intentional) {
+ sprite.showStatus(CharSprite.DEFAULT, Messages.get(this, "search"));
+ sprite.operate(pos);
+ if (foresight != null && foresight.isCursed()) {
+ GLog.n(Messages.get(this, "search_distracted"));
+ spendAndNext(TIME_TO_SEARCH * 3);
+ } else {
+ spendAndNext(TIME_TO_SEARCH);
+ }
+
+ }
+
+ if (smthFound) {
+ GLog.w(Messages.get(this, "noticed_smth"));
+ Sample.INSTANCE.play(Assets.SND_SECRET);
+ interrupt();
+ }
+
+ return smthFound;
+ }
+
+
+ public void resurrect(int resetLevel) {
+
+ HP = HT;
+ Dungeon.gold = 0;
+ exp = 0;
+
+ belongings.resurrect(resetLevel);
+
+ live();
+ }
+
+ @Override
+ public HashSet> resistances() {
+ RingOfElements.Resistance r = buff(RingOfElements.Resistance.class);
+ return r == null ? super.resistances() : r.resistances();
+ }
+
+ @Override
+ public HashSet> immunities() {
+ HashSet> immunities = new HashSet>();
+ for (Buff buff : buffs()) {
+ for (Class> immunity : buff.immunities)
+ immunities.add(immunity);
+ }
+ return immunities;
+ }
+
+ @Override
+ public void next() {
+ super.next();
+ }
+
+ public static interface Doom {
+ public void onDeath();
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/hero/HeroAction.java b/java/com/hmdzl/spspd/actors/hero/HeroAction.java
new file mode 100644
index 00000000..39e7d4bf
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/hero/HeroAction.java
@@ -0,0 +1,99 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.hero;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.mobs.npcs.NPC;
+import com.hmdzl.spspd.actors.mobs.pets.PET;
+
+public class HeroAction {
+
+ public int dst;
+
+ public static class Move extends HeroAction {
+ public Move(int dst) {
+ this.dst = dst;
+ }
+ }
+
+ public static class PickUp extends HeroAction {
+ public PickUp(int dst) {
+ this.dst = dst;
+ }
+ }
+
+ public static class OpenChest extends HeroAction {
+ public OpenChest(int dst) {
+ this.dst = dst;
+ }
+ }
+
+ public static class Buy extends HeroAction {
+ public Buy(int dst) {
+ this.dst = dst;
+ }
+ }
+
+ public static class Interact extends HeroAction {
+ public NPC npc;
+
+ public Interact(NPC npc) {
+ this.npc = npc;
+ }
+ }
+
+ public static class InteractPet extends HeroAction {
+ public PET pet;
+
+ public InteractPet(PET pet) {
+ this.pet = pet;
+ }
+ }
+
+ public static class Unlock extends HeroAction {
+ public Unlock(int door) {
+ this.dst = door;
+ }
+ }
+
+ public static class Descend extends HeroAction {
+ public Descend(int stairs) {
+ this.dst = stairs;
+ }
+ }
+
+ public static class Ascend extends HeroAction {
+ public Ascend(int stairs) {
+ this.dst = stairs;
+ }
+ }
+
+ /*public static class Cook extends HeroAction {
+ public Cook(int pot) {
+ this.dst = pot;
+ }
+ }*/
+
+ public static class Attack extends HeroAction {
+ public Char target;
+
+ public Attack( Char target) {
+ this.target = target;
+ }
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/hero/HeroClass.java b/java/com/hmdzl/spspd/actors/hero/HeroClass.java
new file mode 100644
index 00000000..5af1cc16
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/hero/HeroClass.java
@@ -0,0 +1,814 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.hero;
+
+import com.hmdzl.spspd.Assets;
+import com.hmdzl.spspd.Badges;
+import com.hmdzl.spspd.Challenges;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.items.Ankh;
+import com.hmdzl.spspd.items.ArmorKit;
+import com.hmdzl.spspd.items.DolyaSlate;
+import com.hmdzl.spspd.items.Elevator;
+import com.hmdzl.spspd.items.ExpOre;
+import com.hmdzl.spspd.items.Palantir;
+import com.hmdzl.spspd.items.PowerHand;
+import com.hmdzl.spspd.items.SaveYourLife;
+import com.hmdzl.spspd.items.SoulCollect;
+import com.hmdzl.spspd.items.Stylus;
+import com.hmdzl.spspd.items.TriForce;
+import com.hmdzl.spspd.items.Weightstone;
+import com.hmdzl.spspd.items.armor.normalarmor.BaseArmor;
+import com.hmdzl.spspd.items.armor.normalarmor.DiscArmor;
+import com.hmdzl.spspd.items.armor.normalarmor.LeatherArmor;
+import com.hmdzl.spspd.items.armor.normalarmor.LifeArmor;
+import com.hmdzl.spspd.items.armor.normalarmor.RubberArmor;
+import com.hmdzl.spspd.items.artifacts.AlienBag;
+import com.hmdzl.spspd.items.artifacts.EtherealChains;
+import com.hmdzl.spspd.items.artifacts.Pylon;
+import com.hmdzl.spspd.items.artifacts.TimekeepersHourglass;
+import com.hmdzl.spspd.items.bags.PotionBandolier;
+import com.hmdzl.spspd.items.bags.SeedPouch;
+import com.hmdzl.spspd.items.bags.WandHolster;
+import com.hmdzl.spspd.items.bombs.FireBomb;
+import com.hmdzl.spspd.items.bombs.IceBomb;
+import com.hmdzl.spspd.items.bombs.StormBomb;
+import com.hmdzl.spspd.items.challengelists.CaveChallenge;
+import com.hmdzl.spspd.items.challengelists.CityChallenge;
+import com.hmdzl.spspd.items.challengelists.CourageChallenge;
+import com.hmdzl.spspd.items.challengelists.PowerChallenge;
+import com.hmdzl.spspd.items.challengelists.PrisonChallenge;
+import com.hmdzl.spspd.items.challengelists.SewerChallenge;
+import com.hmdzl.spspd.items.challengelists.WisdomChallenge;
+import com.hmdzl.spspd.items.journalpages.Vault;
+import com.hmdzl.spspd.items.medicine.Hardpill;
+import com.hmdzl.spspd.items.medicine.Powerpill;
+import com.hmdzl.spspd.items.medicine.Smashpill;
+import com.hmdzl.spspd.items.misc.AttackShield;
+import com.hmdzl.spspd.items.misc.AttackShoes;
+import com.hmdzl.spspd.items.misc.BShovel;
+import com.hmdzl.spspd.items.misc.CopyBall;
+import com.hmdzl.spspd.items.misc.DanceLion;
+import com.hmdzl.spspd.items.misc.DemoScroll;
+import com.hmdzl.spspd.items.misc.FaithSign;
+import com.hmdzl.spspd.items.misc.GnollMark;
+import com.hmdzl.spspd.items.misc.HealBag;
+import com.hmdzl.spspd.items.misc.HorseTotem;
+import com.hmdzl.spspd.items.misc.JumpF;
+import com.hmdzl.spspd.items.misc.MKbox;
+import com.hmdzl.spspd.items.misc.MechPocket;
+import com.hmdzl.spspd.items.misc.RangeBag;
+import com.hmdzl.spspd.items.misc.SavageHelmet;
+import com.hmdzl.spspd.items.misc.UndeadBook;
+import com.hmdzl.spspd.items.nornstone.BlueNornStone;
+import com.hmdzl.spspd.items.nornstone.GreenNornStone;
+import com.hmdzl.spspd.items.nornstone.OrangeNornStone;
+import com.hmdzl.spspd.items.nornstone.PurpleNornStone;
+import com.hmdzl.spspd.items.nornstone.YellowNornStone;
+import com.hmdzl.spspd.items.potions.PotionOfHealing;
+import com.hmdzl.spspd.items.rings.RingOfForce;
+import com.hmdzl.spspd.items.rings.RingOfMight;
+import com.hmdzl.spspd.items.scrolls.ScrollOfRegrowth;
+import com.hmdzl.spspd.items.scrolls.ScrollOfTerror;
+import com.hmdzl.spspd.items.TomeOfMastery;
+import com.hmdzl.spspd.items.armor.normalarmor.VestArmor;
+import com.hmdzl.spspd.items.armor.normalarmor.WoodenArmor;
+import com.hmdzl.spspd.items.bags.ScrollHolder;
+import com.hmdzl.spspd.items.bombs.DungeonBomb;
+import com.hmdzl.spspd.items.food.Honey;
+import com.hmdzl.spspd.items.food.staplefood.NormalRation;
+import com.hmdzl.spspd.items.food.staplefood.Pasty;
+import com.hmdzl.spspd.items.journalpages.SafeSpotPage;
+import com.hmdzl.spspd.items.journalpages.Sokoban2;
+import com.hmdzl.spspd.items.journalpages.Sokoban3;
+import com.hmdzl.spspd.items.journalpages.Sokoban4;
+import com.hmdzl.spspd.items.misc.Ankhshield;
+import com.hmdzl.spspd.items.armor.normalarmor.ClothArmor;
+import com.hmdzl.spspd.items.artifacts.CloakOfShadows;
+import com.hmdzl.spspd.items.bags.KeyRing;
+import com.hmdzl.spspd.items.eggs.RandomEgg;
+import com.hmdzl.spspd.items.food.completefood.PetFood;
+import com.hmdzl.spspd.items.journalpages.Sokoban1;
+import com.hmdzl.spspd.items.journalpages.Town;
+import com.hmdzl.spspd.items.misc.GunOfSoldier;
+import com.hmdzl.spspd.items.misc.JumpP;
+import com.hmdzl.spspd.items.misc.JumpS;
+import com.hmdzl.spspd.items.misc.PotionOfMage;
+import com.hmdzl.spspd.items.misc.Shovel;
+import com.hmdzl.spspd.items.potions.PotionOfInvisibility;
+import com.hmdzl.spspd.items.potions.PotionOfLiquidFlame;
+import com.hmdzl.spspd.items.potions.PotionOfMending;
+import com.hmdzl.spspd.items.potions.PotionOfMight;
+import com.hmdzl.spspd.items.potions.PotionOfMindVision;
+import com.hmdzl.spspd.items.potions.PotionOfPurity;
+import com.hmdzl.spspd.items.potions.PotionOfStrength;
+import com.hmdzl.spspd.items.reward.SewerReward;
+import com.hmdzl.spspd.items.scrolls.ScrollOfIdentify;
+import com.hmdzl.spspd.items.scrolls.ScrollOfLullaby;
+import com.hmdzl.spspd.items.scrolls.ScrollOfMagicMapping;
+import com.hmdzl.spspd.items.scrolls.ScrollOfMagicalInfusion;
+import com.hmdzl.spspd.items.scrolls.ScrollOfRage;
+import com.hmdzl.spspd.items.scrolls.ScrollOfRemoveCurse;
+import com.hmdzl.spspd.items.scrolls.ScrollOfUpgrade;
+import com.hmdzl.spspd.items.wands.CannonOfMage;
+import com.hmdzl.spspd.items.wands.WandOfDisintegration;
+import com.hmdzl.spspd.items.wands.WandOfFirebolt;
+import com.hmdzl.spspd.items.wands.WandOfFlock;
+import com.hmdzl.spspd.items.wands.WandOfFreeze;
+import com.hmdzl.spspd.items.wands.WandOfLightning;
+import com.hmdzl.spspd.items.wands.WandOfMagicMissile;
+import com.hmdzl.spspd.items.weapon.guns.GunA;
+import com.hmdzl.spspd.items.weapon.guns.GunC;
+import com.hmdzl.spspd.items.weapon.guns.Sling;
+import com.hmdzl.spspd.items.weapon.melee.Dagger;
+import com.hmdzl.spspd.items.weapon.melee.Glaive;
+import com.hmdzl.spspd.items.weapon.melee.Knuckles;
+import com.hmdzl.spspd.items.weapon.melee.Rapier;
+import com.hmdzl.spspd.items.weapon.melee.ShortSword;
+import com.hmdzl.spspd.items.weapon.melee.MageBook;
+import com.hmdzl.spspd.items.weapon.melee.Spear;
+import com.hmdzl.spspd.items.weapon.melee.Triangolo;
+import com.hmdzl.spspd.items.weapon.melee.Whip;
+import com.hmdzl.spspd.items.weapon.melee.WoodenStaff;
+import com.hmdzl.spspd.items.weapon.melee.special.DiamondPickaxe;
+import com.hmdzl.spspd.items.weapon.melee.special.FireCracker;
+import com.hmdzl.spspd.items.weapon.melee.special.LinkSword;
+import com.hmdzl.spspd.items.weapon.melee.special.ShadowEater;
+import com.hmdzl.spspd.items.weapon.melee.zero.EmptyPotion;
+import com.hmdzl.spspd.items.weapon.missiles.Boomerang;
+import com.hmdzl.spspd.items.weapon.missiles.EmpBola;
+import com.hmdzl.spspd.items.weapon.missiles.ErrorAmmo;
+import com.hmdzl.spspd.items.misc.JumpW;
+import com.hmdzl.spspd.items.misc.JumpH;
+import com.hmdzl.spspd.items.misc.JumpM;
+import com.hmdzl.spspd.items.misc.JumpR;
+import com.hmdzl.spspd.items.weapon.missiles.EscapeKnive;
+import com.hmdzl.spspd.items.misc.MissileShield;
+import com.hmdzl.spspd.items.weapon.missiles.ManyKnive;
+import com.hmdzl.spspd.items.weapon.missiles.PocketBall;
+import com.hmdzl.spspd.items.weapon.missiles.PoisonDart;
+import com.hmdzl.spspd.items.weapon.missiles.Skull;
+import com.hmdzl.spspd.items.weapon.missiles.Smoke;
+import com.hmdzl.spspd.items.weapon.missiles.TaurcenBow;
+import com.hmdzl.spspd.items.weapon.spammo.BattleAmmo;
+import com.hmdzl.spspd.items.weapon.spammo.GoldAmmo;
+import com.hmdzl.spspd.items.weapon.spammo.HeavyAmmo;
+import com.hmdzl.spspd.items.weapon.spammo.WoodenAmmo;
+import com.hmdzl.spspd.plants.Dewcatcher;
+import com.hmdzl.spspd.plants.Seedpod;
+import com.watabou.utils.Bundle;
+import com.hmdzl.spspd.messages.Messages;
+
+public enum HeroClass {
+
+ WARRIOR( "warrior" , "warrior_name"),
+ MAGE( "mage", "mage_name"),
+ ROGUE( "rogue","rogue_name" ),
+ HUNTRESS( "huntress", "huntress_name"),
+ PERFORMER( "performer", "performer_name"),
+ SOLDIER( "soldier", "soldier_name"),
+ FOLLOWER( "follower", "follower_name");
+
+
+ private String title;
+ private String title2;
+
+ private HeroClass(String title, String title2) {
+ this.title = title;
+ this.title2 = title2;
+ }
+
+
+ public void initHero(Hero hero) {
+
+ hero.heroClass = this;
+
+ initCommon( hero );
+
+ switch (this) {
+ case WARRIOR:
+ initWarrior( hero );
+ break;
+
+ case MAGE:
+ initMage( hero );
+ break;
+
+ case ROGUE:
+ initRogue( hero );
+ break;
+
+ case HUNTRESS:
+ initHuntress( hero );
+ break;
+
+ case PERFORMER:
+ initPerformer( hero );
+ break;
+
+ case SOLDIER:
+ initSoldier( hero );
+ break;
+
+ case FOLLOWER:
+ initFollower( hero );
+ break;
+
+ }
+
+ /*if (Badges.isUnlocked(masteryBadge())) {
+ new TomeOfMastery().collect();
+ }*/
+
+ hero.updateAwareness();
+ }
+
+ private static void initCommon(Hero hero) {
+ new KeyRing().collect();
+ new NormalRation().identify().collect();
+
+ if (Dungeon.skins != 3) {
+ new Ankhshield().collect();
+ }
+ if (Dungeon.skins == 3) {
+ EtherealChains chains = new EtherealChains();
+ (hero.belongings.misc3 = chains).identify();
+ hero.belongings.misc3.activate(hero);
+ new EmpBola(7).collect();
+ new PoisonDart(7).collect();
+ new Smoke(7).collect();
+ new Weightstone().collect();
+ new Stylus().collect();
+ new PotionOfHealing().identify().collect();
+ }
+
+ if (Dungeon.skins == 0) {
+ new RandomEgg().collect();
+ new PetFood().collect();
+ new PocketBall().collect();
+ }
+
+ if (Dungeon.isChallenged(Challenges.ITEM_PHOBIA)){
+ Dungeon.gold += 1000;
+ }
+ if (Dungeon.isChallenged(Challenges.LISTLESS)){
+ new PotionOfMight().collect();
+ new PotionOfMight().setKnown();
+ new Honey().collect();
+ }
+ if (Dungeon.isChallenged(Challenges.NIGHTMARE_VIRUS)){
+ new Ankh().collect();
+ }
+ if (Dungeon.isChallenged(Challenges.ENERGY_LOST)){
+ new Pasty().collect();
+ }
+ if (Dungeon.isChallenged(Challenges.DEW_REJECTION)){
+ new Dewcatcher.Seed().collect();
+ new Dewcatcher.Seed().collect();
+ }
+ if (Dungeon.isChallenged(Challenges.DARKNESS)){
+ new ScrollOfMagicMapping().collect();
+ new ScrollOfMagicMapping().collect();
+ new ScrollOfMagicMapping().setKnown();
+ }
+ if (Dungeon.isChallenged(Challenges.ABRASION)){
+ new ScrollOfUpgrade().collect();
+ new ScrollOfUpgrade().setKnown();
+ new ScrollOfMagicalInfusion().collect();
+ new ScrollOfMagicalInfusion().setKnown();
+ }
+ if (Dungeon.isChallenged(Challenges.TEST_TIME)){
+ new Elevator().collect();
+ new ArmorKit().collect();
+ new SafeSpotPage().collect();
+ new Town().collect();
+ new SewerChallenge().collect();
+ new PrisonChallenge().collect();
+ new CaveChallenge().collect();
+ new CityChallenge().collect();
+ new ScrollHolder().collect();
+ new SeedPouch().collect();
+ new PotionBandolier().collect();
+ new WandHolster().collect();
+ new Sokoban1().collect();
+ new Sokoban2().collect();
+ new Sokoban3().collect();
+ new Sokoban4().collect();
+ new DolyaSlate().collect();
+ new Vault().collect();
+ new CourageChallenge().collect();
+ new PowerChallenge().collect();
+ new WisdomChallenge().collect();
+ new TriForce().collect();
+ new Palantir().collect();
+
+ new SoulCollect().collect();
+ new ErrorAmmo(20).collect();
+ new PowerHand().collect();
+ new TomeOfMastery().collect();
+ new ShadowEater().collect();
+ for(int i=0; i<199; i++){
+ new ScrollOfMagicalInfusion().identify().collect();
+ new ScrollOfUpgrade().identify().collect();
+ new ScrollOfIdentify().identify().collect();
+ new ScrollOfMagicMapping().identify().collect();
+ new ExpOre().collect();
+ new Pasty().collect();
+ new PotionOfMindVision().identify().collect();
+ new PotionOfStrength().identify().collect();
+ new YellowNornStone().collect();
+ new BlueNornStone().collect();
+ new OrangeNornStone().collect();
+ new PurpleNornStone().collect();
+ new GreenNornStone().collect();
+ }
+ for(int i=0; i<10; i++){
+ new Seedpod.Seed().collect();
+ new ScrollOfRegrowth().collect();
+ }
+ new WandOfFlock().upgrade(10).identify().collect();
+ new SewerReward().collect();
+ new SaveYourLife().collect();
+ new FireCracker().collect();
+
+ Dungeon.gold = 10000;
+ //Dungeon.gold = 10000000;
+ hero.HT=hero.HP=10000;
+ //hero.STR = hero.STR + 20;
+ Dungeon.depth = 1;
+
+ }
+ }
+
+ public Badges.Badge masteryBadge() {
+ switch (this) {
+ case WARRIOR:
+ return Badges.Badge.MASTERY_WARRIOR;
+ case MAGE:
+ return Badges.Badge.MASTERY_MAGE;
+ case ROGUE:
+ return Badges.Badge.MASTERY_ROGUE;
+ case HUNTRESS:
+ return Badges.Badge.MASTERY_HUNTRESS;
+ case PERFORMER:
+ return Badges.Badge.MASTERY_PERFORMER;
+ case SOLDIER:
+ return Badges.Badge.MASTERY_SOLDIER;
+ case FOLLOWER:
+ return Badges.Badge.MASTERY_FOLLOWER;
+ }
+
+ return null;
+ }
+
+
+ private static void initWarrior(Hero hero) {
+
+ if (Dungeon.skins == 1) {
+ (hero.belongings.armor = new VestArmor()).identify().upgrade(1);
+ RingOfForce force = new RingOfForce();
+ (hero.belongings.misc1 = force).identify().upgrade(1);
+ hero.belongings.misc1.activate(hero);
+
+ RingOfMight might = new RingOfMight();
+ (hero.belongings.misc2 = might).identify().upgrade(1);
+ hero.belongings.misc2.activate(hero);
+
+ new AttackShield().collect();
+ new JumpW().collect();
+
+ } else if (Dungeon.skins == 2) {
+ hero.HT+=36;
+ hero.STR -=4;
+ hero.hitSkill-=4;
+ hero.evadeSkill+=1;
+ hero.magicSkill+=6;
+ (hero.belongings.armor = new BaseArmor()).upgrade(6).identify();
+ new WandOfFirebolt().upgrade(6).identify().collect();
+ new DemoScroll().collect();
+ new PotionOfStrength().collect();
+ new PotionOfStrength().collect();
+ new PotionOfStrength().collect();
+ new PotionOfStrength().collect();
+ Dungeon.gold+=666;
+ new JumpW().collect();
+
+ } else if (Dungeon.skins == 3) {
+
+ (hero.belongings.weapon = new Spear()).identify();
+ (hero.belongings.armor = new DiscArmor()).identify();
+ new MissileShield().collect();
+ new SavageHelmet().collect();
+
+ hero.STR += 2;
+ Dungeon.limitedDrops.strengthPotions.count+=2;
+
+ } else {
+ (hero.belongings.weapon = new ShortSword()).identify();
+ (hero.belongings.armor = new WoodenArmor()).identify();
+ new MissileShield().collect();
+ new Powerpill().collect();
+ new Smashpill().collect();
+ new Hardpill().collect();
+ new JumpW().collect();
+ }
+
+ new PotionOfStrength().setKnown();
+ new ScrollOfUpgrade().setKnown();
+
+ }
+
+ private static void initMage(Hero hero) {
+
+ if (Dungeon.skins == 1) {
+ hero.STR+=4;
+
+ (hero.belongings.weapon = new Whip()).identify().upgrade(2);
+ (hero.belongings.armor = new LeatherArmor()).identify().upgrade(1);
+
+ Dungeon.limitedDrops.strengthPotions.count+=4;
+ new CannonOfMage().identify().collect();
+ new JumpM().collect();
+ } else if (Dungeon.skins == 2) {
+ hero.HT-=10;
+ hero.hitSkill-=5;
+ hero.evadeSkill+=2;
+ hero.magicSkill+=3;
+ (hero.belongings.weapon = new Dagger()).identify();
+ (hero.belongings.armor = new VestArmor()).identify();
+ new WandOfFirebolt().upgrade(1).identify().collect();
+ new WandOfFreeze().upgrade(1).identify().collect();
+ new WandOfLightning().upgrade(1).identify().collect();
+ new GnollMark().collect();
+ new JumpM().collect();
+ } else if (Dungeon.skins == 3) {
+
+ (hero.belongings.weapon = new WoodenStaff()).identify();
+ (hero.belongings.armor = new VestArmor()).identify();
+
+ new WandOfFirebolt().identify().collect();
+ new WandOfFreeze().identify().collect();
+ new GnollMark().collect();
+ new PotionOfMage().identify().collect();
+
+ } else {
+ (hero.belongings.weapon = new MageBook()).identify();
+ (hero.belongings.armor = new ClothArmor()).identify();
+ new WandOfMagicMissile().identify().collect();
+ new WandOfDisintegration().identify().collect();
+ new PotionOfMage().identify().collect();
+ new JumpM().collect();
+
+ }
+ hero.magicSkill = hero.magicSkill + 3;
+ new ScrollOfIdentify().setKnown();
+ new PotionOfLiquidFlame().setKnown();
+
+ }
+
+ private static void initRogue(Hero hero) {
+ if (Dungeon.skins == 1) {
+ (hero.belongings.weapon = new LinkSword()).identify();
+ hero.belongings.weapon.activate(hero);
+ (hero.belongings.armor = new WoodenArmor()).identify();
+ hero.STR += 1;
+ Dungeon.limitedDrops.strengthPotions.count++;
+ EtherealChains ec = new EtherealChains();
+ (hero.belongings.misc1 = ec).identify();
+ hero.belongings.misc1.activate(hero);
+ new JumpR().collect();
+ } else if (Dungeon.skins == 2) {
+ hero.HT-=20;
+ hero.evadeSkill+=3;
+ hero.magicSkill+=3;
+ (hero.belongings.weapon = new Dagger()).identify();
+ (hero.belongings.armor = new ClothArmor()).identify();
+ new UndeadBook().collect();
+ new Skull(5).collect();
+ new JumpR().collect();
+ } else if (Dungeon.skins == 3) {
+
+ (hero.belongings.weapon = new Glaive()).identify();
+ (hero.belongings.armor = new DiscArmor()).identify();
+
+ CloakOfShadows cloak = new CloakOfShadows();
+ (hero.belongings.misc1 = cloak).identify();
+ hero.belongings.misc1.activate(hero);
+
+ new HorseTotem().identify().collect();
+
+ hero.STR += 4;
+ Dungeon.limitedDrops.strengthPotions.count+=4;
+
+ } else {
+
+ (hero.belongings.weapon = new Dagger()).identify();
+ (hero.belongings.armor = new VestArmor()).identify();
+
+ CloakOfShadows cloak = new CloakOfShadows();
+ (hero.belongings.misc1 = cloak).identify();
+ hero.belongings.misc1.activate(hero);
+
+ new Smoke(3).identify().collect();
+ new JumpR().collect();
+ }
+
+ new ScrollOfMagicMapping().setKnown();
+ new PotionOfInvisibility().setKnown();
+ }
+
+ private static void initHuntress(Hero hero) {
+ if (Dungeon.skins == 1) {
+ hero.STR+=1;
+ (hero.belongings.weapon = new Dagger()).identify().upgrade(1);
+ (hero.belongings.armor = new RubberArmor()).identify().upgrade(1);
+ Dungeon.limitedDrops.strengthPotions.count++;
+ TimekeepersHourglass th = new TimekeepersHourglass();
+ (hero.belongings.misc1 = th).identify();
+ hero.belongings.misc1.activate(hero);
+
+ new ManyKnive().upgrade(1).identify().collect();
+
+ EscapeKnive knife = new EscapeKnive(5);
+ knife.identify().collect();
+ new JumpH().collect();
+ } else if (Dungeon.skins == 2) {
+ hero.HT-=10;
+ hero.hitSkill+=5;
+ hero.evadeSkill+=3;
+ (hero.belongings.weapon = new Knuckles()).identify();
+ (hero.belongings.armor = new ClothArmor()).identify();
+ new TaurcenBow().identify().collect();
+ new JumpH().collect();
+ } else if (Dungeon.skins == 3) {
+
+ (hero.belongings.weapon = new Knuckles()).identify();
+ (hero.belongings.armor = new ClothArmor()).identify();
+
+ new TaurcenBow().identify().collect();
+ new RangeBag().identify().collect();
+
+ } else {
+ (hero.belongings.weapon = new Knuckles()).identify();
+ (hero.belongings.armor = new ClothArmor()).identify();
+
+ Boomerang boomerang = new Boomerang(null);
+ boomerang.identify().collect();
+ EmpBola empbola = new EmpBola(3);
+ empbola.identify().collect();
+ new JumpH().collect();
+ }
+ new PotionOfMindVision().setKnown();
+ new ScrollOfRemoveCurse().setKnown();
+ }
+
+ private static void initPerformer(Hero hero) {
+
+ if (Dungeon.skins == 1) {
+ (hero.belongings.weapon = new GunA()).identify().upgrade(2);
+ (hero.belongings.armor = new VestArmor()).identify().upgrade(1);
+ new GoldAmmo().collect();
+ new WoodenAmmo().collect();
+ new BattleAmmo().collect();
+ AlienBag alienBag = new AlienBag();
+ (hero.belongings.misc1 = alienBag).identify();
+ hero.belongings.misc1.activate(hero);
+ new BShovel().collect();
+ new JumpP().collect();
+ } else if (Dungeon.skins == 2) {
+ hero.HT-=10;
+ hero.magicSkill+=3;
+ hero.evadeSkill+=5;
+ (hero.belongings.weapon = new EmptyPotion()).identify();
+ (hero.belongings.armor = new BaseArmor()).identify();
+ new CopyBall().collect();
+ new PotionOfMending().identify().collect();
+ new PotionOfHealing().identify().collect();
+ new JumpP().collect();
+ } else if (Dungeon.skins == 3) {
+
+ (hero.belongings.weapon = new Triangolo()).identify();
+ (hero.belongings.armor = new ClothArmor()).identify();
+
+ new Shovel().identify().collect();
+ new DanceLion().identify().collect();
+
+ } else {
+
+ (hero.belongings.weapon = new Triangolo()).identify();
+ (hero.belongings.armor = new ClothArmor()).identify();
+
+ new Shovel().identify().collect();
+ new ScrollOfLullaby().collect();
+ new JumpP().collect();
+
+ new FireBomb().collect();
+ new IceBomb().collect();
+ new StormBomb().collect();
+ new DungeonBomb().collect();
+ }
+
+ new DungeonBomb().collect();
+ new ScrollOfLullaby().setKnown();
+ new PotionOfPurity().setKnown();
+ }
+
+ private static void initSoldier(Hero hero) {
+ if (Dungeon.skins == 1) {
+ hero.STR += 2;
+ (hero.belongings.armor = new LeatherArmor()).identify().upgrade(3);
+ Dungeon.limitedDrops.strengthPotions.count += 2;
+
+ new AttackShoes().collect();
+ new MKbox().collect();
+
+ }else if (Dungeon.skins == 2) {
+ hero.HT+=5;
+ hero.STR += 6;
+ hero.magicSkill+=5;
+ hero.hitSkill-=10;
+ hero.evadeSkill-=35;
+ (hero.belongings.weapon = new GunC()).identify();
+ (hero.belongings.armor = new BaseArmor()).identify();
+ Dungeon.limitedDrops.strengthPotions.count += 6;
+ new MechPocket().collect();
+ new JumpS().collect();
+
+ } else if (Dungeon.skins == 3) {
+
+ (hero.belongings.weapon = new GunA()).identify();
+ (hero.belongings.armor = new VestArmor()).identify();
+
+ new HeavyAmmo().collect();
+ new GunOfSoldier().identify().collect();
+ new HealBag().identify().collect();
+
+ } else {
+
+ (hero.belongings.weapon = new Sling()).identify();
+ (hero.belongings.armor = new VestArmor()).identify();
+
+ new GunOfSoldier().identify().collect();
+
+ new JumpS().collect();
+ EscapeKnive knife = new EscapeKnive(3);
+ knife.identify().collect();
+ }
+
+ new ScrollOfRage().setKnown();
+ new PotionOfMending().setKnown();
+
+ hero.hitSkill = hero.hitSkill + 4;
+ hero.evadeSkill = hero.evadeSkill + 2;
+ }
+
+ private static void initFollower(Hero hero) {
+ if (Dungeon.skins == 1) {
+ (hero.belongings.weapon = new DiamondPickaxe()).identify();
+ (hero.belongings.armor = new LeatherArmor()).identify();
+ hero.STR += 4;
+ Dungeon.limitedDrops.strengthPotions.count += 4;
+ new JumpF().collect();
+ }else if (Dungeon.skins == 2) {
+ (hero.belongings.weapon = new Dagger()).upgrade(2).identify();
+ (hero.belongings.armor = new VestArmor()).identify();
+ Pylon pylon = new Pylon();
+ (hero.belongings.misc1 = pylon).identify();
+ hero.belongings.misc1.activate(hero);
+ new JumpF().collect();
+
+ } else if (Dungeon.skins == 3) {
+
+ (hero.belongings.weapon = new Rapier()).identify();
+ (hero.belongings.armor = new VestArmor()).identify();
+
+ new FaithSign().identify().collect();
+ Pylon pylon = new Pylon();
+ (hero.belongings.misc1 = pylon).identify();
+ hero.belongings.misc1.activate(hero);
+
+ hero.STR += 4;
+ Dungeon.limitedDrops.strengthPotions.count+=4;
+
+ } else {
+
+ (hero.belongings.weapon = new WoodenStaff()).identify();
+ (hero.belongings.armor = new ClothArmor()).identify();
+ new PotionOfHealing().identify().collect();
+ new FaithSign().identify().collect();
+ new JumpF().collect();
+ }
+
+ new ScrollOfTerror().setKnown();
+ new PotionOfHealing().setKnown();
+
+ }
+
+ public String title() {
+ return Messages.get(HeroClass.class, title);
+ }
+
+ public String title2() {
+ return Messages.get(HeroClass.class, title2);
+ }
+
+
+ public String spritesheet() {
+
+ switch (this) {
+ case WARRIOR:
+ return Assets.WARRIOR;
+ case MAGE:
+ return Assets.MAGE;
+ case ROGUE:
+ return Assets.ROGUE;
+ case HUNTRESS:
+ return Assets.HUNTRESS;
+ case PERFORMER:
+ return Assets.PERFORMER;
+ case SOLDIER:
+ return Assets.SOLDIER;
+ case FOLLOWER:
+ return Assets.FOLLOWER;
+ }
+
+ return null;
+ }
+
+ public String[] perks() {
+
+ switch (this) {
+ case WARRIOR:
+ return new String[]{
+ Messages.get(HeroClass.class, "warrior_desc_item"),
+ Messages.get(HeroClass.class, "warrior_desc_loadout"),
+ Messages.get(HeroClass.class, "warrior_desc_misc"),
+ };
+ case MAGE:
+ return new String[]{
+ Messages.get(HeroClass.class, "mage_desc_item"),
+ Messages.get(HeroClass.class, "mage_desc_loadout"),
+ Messages.get(HeroClass.class, "mage_desc_misc"),
+ };
+ case ROGUE:
+ return new String[]{
+ Messages.get(HeroClass.class, "rogue_desc_item"),
+ Messages.get(HeroClass.class, "rogue_desc_loadout"),
+ Messages.get(HeroClass.class, "rogue_desc_misc"),
+ };
+ case HUNTRESS:
+ return new String[]{
+ Messages.get(HeroClass.class, "huntress_desc_item"),
+ Messages.get(HeroClass.class, "huntress_desc_loadout"),
+ Messages.get(HeroClass.class, "huntress_desc_misc"),
+ };
+ case PERFORMER:
+ return new String[]{
+ Messages.get(HeroClass.class, "performer_desc_item"),
+ Messages.get(HeroClass.class, "performer_desc_loadout"),
+ Messages.get(HeroClass.class, "performer_desc_misc"),
+ };
+ case SOLDIER:
+ return new String[]{
+ Messages.get(HeroClass.class, "soldier_desc_item"),
+ Messages.get(HeroClass.class, "soldier_desc_loadout"),
+ Messages.get(HeroClass.class, "soldier_desc_misc"),
+ };
+ case FOLLOWER:
+ return new String[]{
+ Messages.get(HeroClass.class, "follower_desc_item"),
+ Messages.get(HeroClass.class, "follower_desc_loadout"),
+ Messages.get(HeroClass.class, "follower_desc_misc"),
+ };
+ }
+ return null;
+ }
+
+ private static final String CLASS = "class";
+
+ public void storeInBundle(Bundle bundle) {
+ bundle.put(CLASS, toString());
+ }
+
+ public static HeroClass restoreInBundle(Bundle bundle) {
+ String value = bundle.getString(CLASS);
+ return value.length() > 0 ? valueOf(value) : ROGUE;
+ }
+
+
+}
diff --git a/java/com/hmdzl/spspd/actors/hero/HeroSubClass.java b/java/com/hmdzl/spspd/actors/hero/HeroSubClass.java
new file mode 100644
index 00000000..a4835b5a
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/hero/HeroSubClass.java
@@ -0,0 +1,72 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.hero;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.watabou.utils.Bundle;
+
+public enum HeroSubClass {
+
+ NONE( null ),
+
+ GLADIATOR( "gladiator" ),
+ BERSERKER( "berserker" ),
+
+ WARLOCK( "warlock" ),
+ BATTLEMAGE( "battlemage" ),
+
+ ASSASSIN( "assassin" ),
+ FREERUNNER( "freerunner" ),
+
+ SNIPER( "sniper" ),
+ WARDEN( "warden" ),
+
+ SUPERSTAR( "superstar" ),
+ JOKER( "joker" ),
+
+ AGENT( "agent" ),
+ LEADER( "leader" ),
+
+ PASTOR("pastor"),
+ ARTISAN("artisan");
+
+ private String title;
+
+ HeroSubClass( String title ) {
+ this.title = title;
+ }
+
+ public String title() {
+ return Messages.get(this, title);
+ }
+
+ public String desc() {
+ return Messages.get(this, title+"_desc");
+ }
+
+ private static final String SUBCLASS = "subClass";
+
+ public void storeInBundle( Bundle bundle ) {
+ bundle.put( SUBCLASS, toString() );
+ }
+
+ public static HeroSubClass restoreInBundle( Bundle bundle ) {
+ String value = bundle.getString( SUBCLASS );
+ return valueOf( value );
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/Acidic.java b/java/com/hmdzl/spspd/actors/mobs/Acidic.java
new file mode 100644
index 00000000..8976d1cb
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/Acidic.java
@@ -0,0 +1,71 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.Badges;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.Blob;
+import com.hmdzl.spspd.actors.blobs.StenchGas;
+import com.hmdzl.spspd.sprites.AcidicSprite;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.watabou.utils.Random;
+
+public class Acidic extends Scorpio {
+
+ {
+ spriteClass = AcidicSprite.class;
+
+ properties.add(Property.BEAST);
+ properties.add(Property.DEMONIC);
+ }
+
+ @Override
+ public boolean act() {
+ GameScene.add(Blob.seed(pos, 30, StenchGas.class));
+ return super.act();
+ }
+
+ @Override
+ public int defenseProc(Char enemy, int damage) {
+
+ int dmg = Random.IntRange(0, damage/2);
+ if (dmg > 0) {
+ enemy.damage(dmg, this);
+ }
+
+ return super.defenseProc(enemy, damage);
+ }
+
+ @Override
+ public void die(Object cause) {
+ super.die(cause);
+ Badges.validateRare(this);
+ }
+
+ private static final HashSet> IMMUNITIES = new HashSet>();
+ static {
+ IMMUNITIES.add(StenchGas.class);
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/AdultDragonViolet.java b/java/com/hmdzl/spspd/actors/mobs/AdultDragonViolet.java
new file mode 100644
index 00000000..aebde0a3
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/AdultDragonViolet.java
@@ -0,0 +1,155 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.actors.buffs.Silent;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Poison;
+import com.hmdzl.spspd.items.BossRush;
+import com.hmdzl.spspd.items.weapon.enchantments.EnchantmentDark;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.mechanics.Ballistica;
+import com.hmdzl.spspd.sprites.AdultDragonVioletSprite;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.watabou.utils.Callback;
+import com.watabou.utils.Random;
+
+public class AdultDragonViolet extends Mob implements Callback{
+
+ private static final int JUMP_DELAY = 20;
+ private static final float TIME_TO_ZAP = 1f;
+
+ {
+ spriteClass = AdultDragonVioletSprite.class;
+ baseSpeed = 1.5f;
+
+ HP = HT = 8000;
+ EXP = 10;
+ evadeSkill = 40;
+
+ loot = new BossRush();
+ lootChance = 1f;
+
+ properties.add(Property.DRAGON);
+ properties.add(Property.BOSS);
+ }
+
+ private int timeToJump = JUMP_DELAY;
+
+
+ @Override
+ public int damageRoll() {
+ return Random.Int(60, 80);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 50;
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(20, 50);
+ }
+
+
+ @Override
+ public void die(Object cause) {
+
+ super.die(cause);
+
+ yell(Messages.get(this, "die"));
+
+ }
+
+ @Override
+ protected boolean canAttack(Char enemy) {
+ if (buff(Silent.class) != null){
+ return Level.adjacent(pos, enemy.pos) && (!isCharmedBy(enemy));
+ } else return new Ballistica( pos, enemy.pos, Ballistica.MAGIC_BOLT).collisionPos == enemy.pos;
+ }
+
+ @Override
+ protected boolean doAttack(Char enemy) {
+
+ if (Level.adjacent(pos, enemy.pos)) {
+
+ return super.doAttack(enemy);
+
+ } else {
+
+ boolean visible = Level.fieldOfView[pos]
+ || Level.fieldOfView[enemy.pos];
+ if (visible) {
+ ((AdultDragonVioletSprite) sprite).zap(enemy.pos);
+ } else {
+ zap();
+ }
+
+ return !visible;
+ }
+ }
+
+
+ private void zap() {
+ spend(TIME_TO_ZAP);
+
+
+ yell(Messages.get(this, "atk"));
+
+ if (hit(this, enemy, true)) {
+
+ int dmg = damageRoll();
+ enemy.damage(dmg, this);
+
+ Buff.affect(enemy,Poison.class).set(Poison.durationFactor(enemy));
+
+ } else {
+ enemy.sprite.showStatus(CharSprite.NEUTRAL, enemy.defenseVerb());
+ }
+
+ }
+
+ public void onZapComplete() {
+ zap();
+ next();
+ }
+
+ @Override
+ public void call() {
+ next();
+ }
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+ static {
+ RESISTANCES.add(ToxicGas.class);
+ RESISTANCES.add(Poison.class);
+ RESISTANCES.add(EnchantmentDark.class);
+
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/Albino.java b/java/com/hmdzl/spspd/actors/mobs/Albino.java
new file mode 100644
index 00000000..43b7b9c6
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/Albino.java
@@ -0,0 +1,72 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.Badges;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.items.food.meatfood.Meat;
+import com.hmdzl.spspd.sprites.AlbinoSprite;
+import com.watabou.utils.Random;
+import com.hmdzl.spspd.actors.blobs.Blob;
+import com.hmdzl.spspd.actors.blobs.CorruptGas;
+import com.hmdzl.spspd.actors.buffs.Amok;
+import com.hmdzl.spspd.actors.buffs.Terror;
+import com.hmdzl.spspd.actors.buffs.Vertigo;
+import com.hmdzl.spspd.scenes.GameScene;
+
+public class Albino extends Rat {
+
+ {
+ spriteClass = AlbinoSprite.class;
+
+ HP = HT = 10+(Dungeon.depth*Random.NormalIntRange(1, 3));
+
+ loot = new Meat();
+ lootChance = 1f;
+
+ properties.add(Property.BEAST);
+ properties.add(Property.DEMONIC);
+ }
+
+ @Override
+ public void die(Object cause) {
+ super.die(cause);
+ Badges.validateRare(this);
+ }
+
+ @Override
+ public boolean act() {
+ GameScene.add(Blob.seed(pos, 15, CorruptGas.class));
+ return super.act();
+ }
+
+ private static final HashSet> IMMUNITIES = new HashSet>();
+ static {
+ IMMUNITIES.add(Amok.class);
+ IMMUNITIES.add(Terror.class);
+ IMMUNITIES.add(CorruptGas.class);
+ IMMUNITIES.add(Vertigo.class);
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/AlbinoPiranha.java b/java/com/hmdzl/spspd/actors/mobs/AlbinoPiranha.java
new file mode 100644
index 00000000..2a66a6a3
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/AlbinoPiranha.java
@@ -0,0 +1,203 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.actors.buffs.Corruption;
+import com.hmdzl.spspd.items.food.vegetable.NutVegetable;
+import com.hmdzl.spspd.items.food.completefood.GoldenNut;
+import com.hmdzl.spspd.items.reward.CaveReward;
+import com.hmdzl.spspd.items.scrolls.ScrollOfSacrifice;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.Statistics;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.buffs.Burning;
+import com.hmdzl.spspd.actors.buffs.Frost;
+import com.hmdzl.spspd.actors.buffs.Paralysis;
+import com.hmdzl.spspd.actors.buffs.Roots;
+import com.hmdzl.spspd.items.ConchShell;
+import com.hmdzl.spspd.items.food.meatfood.Meat;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.sprites.AlbinoPiranhaSprite;
+import com.hmdzl.spspd.utils.GLog;
+import com.watabou.utils.Random;
+
+public class AlbinoPiranha extends Mob {
+
+ private static final String TXT_KILLCOUNT = "Albino Piranha Kill Count: %s";
+
+ {
+ spriteClass = AlbinoPiranhaSprite.class;
+
+ baseSpeed = 1f;
+
+ EXP = 5;
+
+ loot = new Meat();
+ lootChance = 0.1f;
+
+ properties.add(Property.BEAST);
+ }
+
+ public AlbinoPiranha() {
+ super();
+
+ HP = HT = 20 + Statistics.albinoPiranhasKilled*2;
+ evadeSkill = 40 + Statistics.albinoPiranhasKilled/5;
+ }
+
+ protected boolean checkwater(int cell){
+ return Level.water[cell];
+ }
+
+
+ @Override
+ protected boolean act() {
+
+ if (!Level.water[pos]) {
+ die(null);
+ return true;
+
+
+ } else {
+ // this causes pirahna to move away when a door is closed on them.
+ Dungeon.level.updateFieldOfView(this);
+ enemy = chooseEnemy();
+ if (state == this.HUNTING
+ && !(enemy.isAlive() && Level.fieldOfView[enemy.pos] && enemy.invisible <= 0)) {
+ state = this.WANDERING;
+ int oldPos = pos;
+ int i = 0;
+ do {
+ i++;
+ target = Dungeon.level.randomDestination();
+ if (i == 100)
+ return true;
+ } while (!getCloser(target));
+ moveSprite(oldPos, pos);
+ return true;
+ }
+
+ return super.act();
+ }
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(Statistics.albinoPiranhasKilled/2, 4 + Statistics.albinoPiranhasKilled);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 20 + Statistics.albinoPiranhasKilled;
+ }
+
+ @Override
+ public int drRoll() {
+ return Statistics.albinoPiranhasKilled;
+ }
+
+ @Override
+ public void die(Object cause) {
+
+ super.die(cause);
+
+ Statistics.albinoPiranhasKilled++;
+ GLog.w(Messages.get(Mob.class,"killcount",Statistics.albinoPiranhasKilled));
+
+
+ explodeDew(pos);
+ if(Random.Int(105-Math.min(Statistics.albinoPiranhasKilled,100))==0){
+ Dungeon.level.drop(new NutVegetable(), pos).sprite.drop();
+ }
+
+ if(Statistics.albinoPiranhasKilled == 25) {
+ Dungeon.limitedDrops.conchshell.drop();
+ Dungeon.level.drop(new ConchShell(), pos).sprite.drop();
+ }
+
+ if(Statistics.albinoPiranhasKilled == 50) {
+ Dungeon.level.drop(new ScrollOfSacrifice(), pos).sprite.drop();
+ }
+
+ if(Statistics.albinoPiranhasKilled == 100) {
+ Dungeon.level.drop(new CaveReward(), pos).sprite.drop();
+ }
+
+ if (Statistics.goldThievesKilled>99 && Statistics.skeletonsKilled>99
+ && Statistics.albinoPiranhasKilled == 100 && Statistics.archersKilled>99){
+ Dungeon.level.drop(new GoldenNut(), pos).sprite.drop();
+ }
+
+
+
+
+ }
+
+ @Override
+ public boolean reset() {
+ return true;
+ }
+
+ @Override
+ protected boolean getCloser(int target) {
+
+ if (rooted) {
+ return false;
+ }
+
+ int step = Dungeon.findPath(this, pos, target, Level.water,
+ Level.fieldOfView);
+ if (step != -1) {
+ move(step);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ protected boolean getFurther(int target) {
+ int step = Dungeon.flee(this, pos, target, Level.water,
+ Level.fieldOfView);
+ if (step != -1) {
+ move(step);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private static final HashSet> IMMUNITIES = new HashSet>();
+ static {
+ IMMUNITIES.add(Burning.class);
+ IMMUNITIES.add(Paralysis.class);
+ IMMUNITIES.add(ToxicGas.class);
+ IMMUNITIES.add(Roots.class);
+ IMMUNITIES.add(Frost.class);
+ IMMUNITIES.add(Corruption.class);
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/Assassin.java b/java/com/hmdzl/spspd/actors/mobs/Assassin.java
new file mode 100644
index 00000000..c95f91f6
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/Assassin.java
@@ -0,0 +1,130 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.Statistics;
+import com.hmdzl.spspd.actors.buffs.Locked;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.items.StoneOre;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.buffs.Poison;
+import com.hmdzl.spspd.items.weapon.enchantments.EnchantmentDark;
+import com.hmdzl.spspd.items.weapon.melee.special.TekkoKagi;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.mechanics.Ballistica;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.sprites.AssassinSprite;
+import com.hmdzl.spspd.utils.GLog;
+import com.watabou.utils.Random;
+
+public class Assassin extends Mob {
+
+ protected static final float SPAWN_DELAY = 2f;
+
+ {
+ spriteClass = AssassinSprite.class;
+ baseSpeed = 2f;
+
+ HP = HT = 80+(5*Random.NormalIntRange(2, 5));
+ EXP = 10;
+ maxLvl = 18;
+ evadeSkill = 15;
+
+ loot = new StoneOre();
+ lootChance = 0.2f;
+
+ properties.add(Property.HUMAN);
+
+ }
+
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(10, 23);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 25;
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(0, 5);
+ }
+ @Override
+ protected float attackDelay() {
+ return 0.75f;
+ }
+
+ @Override
+ public void die(Object cause) {
+
+ super.die(cause);
+ Statistics.assassinsKilled++;
+ GLog.w(Messages.get(Mob.class,"killcount", Statistics.assassinsKilled));
+
+ if (Statistics.assassinsKilled == 100){
+ Dungeon.level.drop(new TekkoKagi(), pos).sprite.drop();
+ }
+ }
+
+ @Override
+ protected boolean canAttack(Char enemy) {
+ if (buff(Locked.class) != null){
+ return Level.adjacent(pos, enemy.pos) && (!isCharmedBy(enemy));
+ } else
+ return new Ballistica( pos, enemy.pos, Ballistica.PROJECTILE).collisionPos == enemy.pos;
+ }
+
+ public static Assassin spawnAt(int pos) {
+ if (Level.passable[pos] && Actor.findChar(pos) == null) {
+
+ Assassin w = new Assassin();
+ 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));
+
+ return w;
+
+ } else {
+ return null;
+ }
+ }
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+ static {
+ RESISTANCES.add(ToxicGas.class);
+ RESISTANCES.add(Poison.class);
+ RESISTANCES.add(EnchantmentDark.class);
+
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/Bandit.java b/java/com/hmdzl/spspd/actors/mobs/Bandit.java
new file mode 100644
index 00000000..adb40e20
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/Bandit.java
@@ -0,0 +1,61 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.Badges;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.buffs.Blindness;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Cripple;
+import com.hmdzl.spspd.actors.buffs.Poison;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.sprites.BanditSprite;
+import com.watabou.utils.Random;
+
+public class Bandit extends Thief {
+
+ public Item item;
+
+ {
+ spriteClass = BanditSprite.class;
+
+ // 1 in 30 chance to be a crazy bandit, equates to overall 1/90 chance.
+ lootChance = 1f;
+
+ properties.add(Property.ELF);
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+
+ Buff.prolong(enemy, Blindness.class, Random.Int(5, 12));
+ Buff.affect(enemy, Poison.class).set(
+ Random.Int(5, 7) * Poison.durationFactor(enemy));
+ Buff.prolong(enemy, Cripple.class, Cripple.DURATION);
+ Dungeon.observe();
+
+ return damage;
+ }
+
+ @Override
+ public void die(Object cause) {
+ super.die(cause);
+ Badges.validateRare(this);
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/BanditKing.java b/java/com/hmdzl/spspd/actors/mobs/BanditKing.java
new file mode 100644
index 00000000..b00587b8
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/BanditKing.java
@@ -0,0 +1,85 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.CountDown;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.items.weapon.melee.special.Spork;
+import com.hmdzl.spspd.sprites.BanditKingSprite;
+import com.hmdzl.spspd.utils.GLog;
+import com.watabou.utils.Random;
+
+public class BanditKing extends Mob {
+
+ public Item item;
+
+ {
+ spriteClass = BanditKingSprite.class;
+ HP = HT = 300;
+ EXP = 10;
+ maxLvl = 25;
+ flying = true;
+
+ // 1 in 30 chance to be a crazy bandit, equates to overall 1/90 chance.
+ lootChance = 0.2f;
+ evadeSkill = 20; //20
+ if (Dungeon.depth<25){Dungeon.sporkAvail = false;}
+
+ properties.add(Property.ELF);
+ properties.add(Property.MINIBOSS);
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(10, 20);
+ }
+
+ @Override
+ public float speed() {
+ return 2f;
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+ if(enemy.buff(CountDown.class) == null){
+ Buff.affect(enemy, CountDown.class);
+ state = FLEEING;
+ }
+
+ return damage;
+ }
+
+ @Override
+ public void die(Object cause) {
+ super.die(cause);
+ if (Dungeon.depth<25){
+ yell(Messages.get(this, "die"));
+ GLog.n(Messages.get(this, "dis"));
+ if (!Dungeon.limitedDrops.spork.dropped()) {
+ Dungeon.level.drop(new Spork(), pos).sprite.drop();
+ Dungeon.limitedDrops.spork.drop();
+ Dungeon.sporkAvail = false;
+ yell(Messages.get(this, "spork"));
+ }
+ }
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/Bat.java b/java/com/hmdzl/spspd/actors/mobs/Bat.java
new file mode 100644
index 00000000..30801655
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/Bat.java
@@ -0,0 +1,103 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.items.food.meatfood.Meat;
+import com.hmdzl.spspd.items.potions.PotionOfMending;
+
+import com.hmdzl.spspd.sprites.BatSprite;
+import com.watabou.utils.Random;
+
+public class Bat extends Mob {
+
+ {
+ spriteClass = BatSprite.class;
+
+ HP = HT = 80+(adj(0)*Random.NormalIntRange(2, 5));
+ evadeSkill = 15+adj(0);
+ baseSpeed = 2f;
+
+ EXP = 9;
+ maxLvl = 25;
+
+ flying = true;
+
+ loot = new PotionOfMending();
+ lootChance = 0.1667f; // by default, see die()
+
+ lootOther = new Meat();
+ lootChanceOther = 0.5f; // by default, see die()
+
+ properties.add(Property.BEAST);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(15, 22+adj(0));
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 16+adj(0);
+ }
+
+ @Override
+ public int drRoll() {
+ return adj(0);
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+
+ int reg = Math.min(damage, HT - HP);
+
+ if (reg > 0) {
+ HP += reg;
+ sprite.emitter().burst(Speck.factory(Speck.HEALING), 1);
+ }
+
+ return damage;
+ }
+
+ @Override
+ public void die(Object cause) {
+ super.die(cause);
+ lootChance = 1f / 6 ;
+
+ }
+
+ @Override
+ protected Item createLoot() {
+ return super.createLoot();
+ }
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+ static {
+
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/Bestiary.java b/java/com/hmdzl/spspd/actors/mobs/Bestiary.java
new file mode 100644
index 00000000..01aed40c
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/Bestiary.java
@@ -0,0 +1,343 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.watabou.utils.Random;
+
+public class Bestiary {
+
+ public static Mob mob(int depth) {
+ @SuppressWarnings("unchecked")
+ Class extends Mob> cl = (Class extends Mob>) mobClass(depth);
+ try {
+ return cl.newInstance();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public static Mob mutable(int depth) {
+ @SuppressWarnings("unchecked")
+ Class extends Mob> cl = (Class extends Mob>) mobClass(depth);
+
+ if (Random.Int(30) == 0) {
+ if (cl == Rat.class) {
+ cl = Albino.class;
+ } else if (cl == Thief.class) {
+ cl = Bandit.class;
+ } else if (cl == Brute.class) {
+ cl = Shielded.class;
+ } else if (cl == Monk.class) {
+ cl = Senior.class;
+ } else if (cl == Scorpio.class) {
+ cl = Acidic.class;
+ }
+ }
+
+ try {
+ return cl.newInstance();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ private static Class> mobClass(int depth) {
+
+ float[] chances;
+ Class>[] classes;
+
+
+ switch (depth) {
+ case 1:
+ chances = new float[]{1, 1, 0.02f};
+ classes = new Class>[]{Rat.class, BrownBat.class,
+ RatBoss.class};
+ break;
+ case 2:
+ chances = new float[]{1, 1, 0.7f, 0.5f};
+ classes = new Class>[]{Rat.class, BrownBat.class,
+ DustElement.class, LiveMoss.class};
+ break;
+ case 3:
+ chances = new float[]{1, 1, 0.8f, 0.6f, 0.4f, 0.2f, 0.7f };
+ classes = new Class>[]{
+ Rat.class, BrownBat.class,
+ DustElement.class, LiveMoss.class,
+ Swarm.class, Crab.class,PatrolUAV.class};
+ break;
+ case 4:
+ chances = new float[]{1, 1, 0.9f, 0.7f, 0.5f, 0.3f, 0.02f, 0.02f,0.7f};
+ classes = new Class>[]{Rat.class, BrownBat.class,
+ DustElement.class, LiveMoss.class,
+ Swarm.class, Crab.class,
+ Gnoll.class, Thief.class,PatrolUAV.class};
+ break;
+ case 5:
+ if (Random.Int(3) == 1) {
+ chances = new float[]{ 1 };
+ classes = new Class>[]{Goo.class};
+ } else if (Random.Int(2) == 1) {
+ chances = new float[]{ 1 };
+ classes = new Class>[]{SewerHeart.class};
+ } else {
+ chances = new float[]{ 1 };
+ classes = new Class>[]{PlagueDoctor.class};
+ }
+ break;
+
+ case 6:
+ chances = new float[]{0.8f, 0.8f, 1, 1,0.5f};
+ classes = new Class>[]{Swarm.class, Crab.class,
+ Thief.class, Gnoll.class,PatrolUAV.class};
+ break;
+ case 7:
+ chances = new float[]{0.6f, 1, 1, 0.4f,0.2f};
+ classes = new Class>[]{Crab.class,
+ Thief.class, Gnoll.class,
+ Guard.class, Zombie.class};
+ break;
+ case 8:
+ chances = new float[]{1, 1, 0.5f, 0.4f, 0.3f,0.7f,0.5f};
+ classes = new Class>[]{Thief.class, Gnoll.class,
+ Guard.class, Assassin.class, TrollWarrior.class, Zombie.class,FireRabbit.class};
+ break;
+ case 9:
+ if (Dungeon.sporkAvail) {
+ chances = new float[]{1, 1, 0.1f,1};
+ classes = new Class>[]{Assassin.class, TrollWarrior.class, BanditKing.class, Zombie.class};
+ } else {
+ chances = new float[]{1, 1, 0.8f, 0.6f, 0.5f, 0.02f, 0.01f,1f,0.8f};
+ classes = new Class>[]{Thief.class, Gnoll.class,
+ Guard.class, Assassin.class, TrollWarrior.class,
+ Bat.class, Brute.class, Zombie.class,FireRabbit.class};
+ }
+ break;
+
+ case 10:
+ if (Random.Int(3) == 1){
+ chances = new float[]{ 1 };
+ classes = new Class>[]{Tengu.class};
+ }else if (Random.Int(2) == 1){
+ //}else{
+ chances = new float[]{ 1 };
+ classes = new Class>[]{PrisonWander.class};
+ }else{
+ chances = new float[] { 1 };
+ classes = new Class>[] { Tank.class };
+ }
+ break;
+
+ case 11:
+ chances = new float[] { 0.8f, 0.6f, 1, 0.7f, 0.5f,0.5f };
+ classes = new Class>[] { Assassin.class, TrollWarrior.class,
+ Bat.class, Skeleton.class,Brute.class,FireRabbit.class };
+ break;
+ case 12:
+ chances = new float[] { 1, 0.9f, 0.7f, 0.5f, 0.3f ,0.9f,1 };
+ classes = new Class>[] { Bat.class, Skeleton.class, Brute.class,
+ GnollShaman.class,Spinner.class,SandMob.class,BombBug.class };
+ break;
+ case 13:
+ chances = new float[] { 1, 1, 0.9f, 0.7f, 0.6f, 0.7f,0.4f, 0.02f,1 };
+ classes = new Class>[] { Bat.class, Skeleton.class, Brute.class,
+ GnollShaman.class,Spinner.class, BrokenRobot.class,SandMob.class,
+ FireElemental.class,BombBug.class };
+ break;
+ case 14:
+ chances = new float[] { 1, 1, 1, 0.9f,0.8f,0.6f,0.6f,0.04f, 0.02f,1 };
+ classes = new Class>[] { Bat.class, Skeleton.class, Brute.class,
+ GnollShaman.class,Spinner.class, BrokenRobot.class,SandMob.class,
+ FireElemental.class, Monk.class,BombBug.class};
+ break;
+
+ case 15:
+ if (Random.Int(3) ==1) {
+ chances = new float[]{ 1 };
+ classes = new Class>[] { Hybrid.class };
+ } else if (Random.Int(2) == 1){
+ chances = new float[]{ 1 };
+ classes = new Class>[] { DM300.class };
+ } else {
+ chances = new float[]{ 1 };
+ classes = new Class>[]{SpiderQueen.class};
+ }
+ break;
+
+ case 16:
+ chances = new float[] { 0.8f, 0.6f, 1, 1, 0.4f };
+ classes = new Class>[] { GnollShaman.class,BrokenRobot.class,
+ FireElemental.class, Warlock.class, Monk.class };
+ break;
+ case 17:
+ chances = new float[] { 1, 1, 0.8f, 0.4f,0.4f ,0.2f };
+ classes = new Class>[] { FireElemental.class, Warlock.class,Monk.class,
+ Golem.class,SpiderBot.class, Musketeer.class};
+ break;
+ case 18:
+ chances = new float[] { 1, 1, 1, 0.8f,0.8f, 0.6f, 0.2f,0.1f };
+ classes = new Class>[] { FireElemental.class, Warlock.class,Monk.class,
+ Golem.class, SpiderBot.class,Musketeer.class, DwarfLich.class,ManySkeleton.class };
+ break;
+ case 19:
+
+ chances = new float[] { 1, 1, 1, 1, 1,0.8f, 0.6f, 0.02f,0.3f };
+ classes = new Class>[] { FireElemental.class, Warlock.class,Monk.class,
+ Golem.class, SpiderBot.class,Musketeer.class, DwarfLich.class,
+ Succubus.class,ManySkeleton.class};
+ break;
+ case 20:
+ if (Random.Int(3) ==1) {
+ chances = new float[]{ 1 };
+ classes = new Class>[] { LichDancer.class };
+ } else if (Random.Int(2) == 1){
+ chances = new float[]{ 1 };
+ classes = new Class>[] { ElderAvatar.class };
+ } else {
+ chances = new float[] { 1 };
+ classes = new Class>[] { King.class };
+ }
+
+ break;
+
+ case 22:
+ chances = new float[] { 0.8f,0.8f, 1, 1, 1, 0.2f, 0.2f };
+ classes = new Class>[] {Musketeer.class, DwarfLich.class,
+ Succubus.class, Eye.class, DemonGoo.class, DemonFlower.class, Sufferer.class};
+ break;
+ case 23:
+ chances = new float[] { 1, 1, 1, 0.5f,0.5f, 0.5f,0.5f };
+ classes = new Class>[] { Succubus.class, Eye.class, DemonGoo.class,
+ Scorpio.class,ThiefImp.class , DemonFlower.class, Sufferer.class};
+ break;
+ case 24:
+ chances = new float[] { 1, 1, 1, 1, 1, 1, 1 };
+ classes = new Class>[] {Succubus.class, Eye.class, DemonGoo.class,
+ Scorpio.class,ThiefImp.class, DemonFlower.class, Sufferer.class
+ };
+ break;
+
+ case 25:
+ chances = new float[] { 1 };
+ classes = new Class>[] { Yog.class };
+ break;
+
+ case 27:
+ chances = new float[] { 1, 0.05f,0.1f };
+ classes = new Class>[] { GnollArcher.class, ForestProtector.class,Brute.class };
+ break;
+ case 28:
+ chances = new float[] { 1, 0.05f,0.1f };
+ classes = new Class>[] { MossySkeleton.class, GraveProtector.class,ManySkeleton.class};
+ break;
+ case 29:
+ chances = new float[] { 1, 0.05f,0.1f };
+ classes = new Class>[] { AlbinoPiranha.class, FishProtector.class,Crab.class };
+ break;
+ case 30:
+ chances = new float[] { 1, 0.05f,0.1f };
+ classes = new Class>[] { GoldThief.class, VaultProtector.class,Succubus.class};
+ break;
+
+ case 31:
+ chances = new float[] { 1, 0.1f };
+ classes = new Class>[] { BlueWraith.class, DwarfLich.class};
+ break;
+
+ case 32:
+ chances = new float[] { 1,0.05f };
+ classes = new Class>[] { Orc.class, GoldOrc.class};
+ break;
+ case 33:
+ chances = new float[] { 1, 0.2f };
+ classes = new Class>[] { FlyingProtector.class, FireElemental.class };
+ break;
+ case 35:
+ chances = new float[] {1, 1 };
+ classes = new Class>[] {GoldOrc.class, Fiend.class };
+ break;
+ case 36:
+ chances = new float[] {1};
+ classes = new Class>[] {TenguDen.class};
+ break;
+ case 41:
+ chances = new float[] {1};
+ classes = new Class>[] {BanditKing.class};
+ break;
+ case 45:
+ chances = new float[] {1 };
+ classes = new Class>[] {TestMob.class };
+ break;
+ case 71:
+ chances = new float[] {1};
+ classes = new Class>[] {Dragonking.class};
+ break;
+ case 85:
+ chances = new float[] {
+ 1,1,
+ 1,1,
+ 1,1,1,
+ 1,1,
+ 1,1,1,1,
+ 1,1,1,
+ 1,1,1,1,
+ 1,1,1,
+ 1,1,1,1,
+ 1,
+ 1,1,
+ 1,1};
+ classes = new Class>[] {
+ Rat.class, BrownBat.class,
+ DustElement.class, LiveMoss.class,
+ Swarm.class, Crab.class,PatrolUAV.class,
+ Thief.class, Gnoll.class,
+ Guard.class, Assassin.class, TrollWarrior.class, Zombie.class,
+ Bat.class, Skeleton.class, Brute.class,
+ GnollShaman.class,Spinner.class, BrokenRobot.class,SandMob.class,
+ FireElemental.class, Warlock.class,Monk.class,
+ Golem.class, SpiderBot.class,Musketeer.class, DwarfLich.class,
+ Succubus.class, Eye.class, DemonGoo.class,
+ Scorpio.class,ThiefImp.class, DemonFlower.class, Sufferer.class,
+ BlueWraith.class,
+ Orc.class,FlyingProtector.class,
+ GoldOrc.class, Fiend.class };
+ break;
+
+ default:
+ chances = new float[] { 1 };
+ classes = new Class>[] { Eye.class };
+ }
+
+
+
+ return classes[Random.chances(chances)];
+ }
+
+ public static boolean isUnique(Char mob) {
+ return mob instanceof Goo
+ || mob instanceof Tengu
+ || mob instanceof DM300
+ || mob instanceof King
+ || mob instanceof Yog.BurningFist
+ || mob instanceof Yog.RottingFist
+ || mob instanceof FetidRat
+ || mob instanceof GnollTrickster
+ || mob instanceof GreatCrab;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/BlueCat.java b/java/com/hmdzl/spspd/actors/mobs/BlueCat.java
new file mode 100644
index 00000000..316cb102
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/BlueCat.java
@@ -0,0 +1,172 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Terror;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.items.Amulet;
+import com.hmdzl.spspd.items.Generator;
+import com.hmdzl.spspd.items.Gold;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.items.artifacts.MasterThievesArmband;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.sprites.BanditKingSprite;
+import com.hmdzl.spspd.utils.GLog;
+import com.hmdzl.spspd.messages.Messages;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Random;
+
+public class BlueCat extends Mob {
+
+ protected static final String TXT_STOLE = "%s stole %s from you!";
+ protected static final String TXT_CARRIES = "\n\n%s is carrying a _%s_. Stolen obviously.";
+ protected static final String TXT_RATCHECK1 = "Spork is avail";
+ protected static final String TXT_RATCHECK2 = "Spork is not avail";
+
+ public Item item;
+
+ {
+ spriteClass = BanditKingSprite.class;
+
+ HP = HT = 20+(adj(0)*Random.NormalIntRange(3, 5));
+ evadeSkill = 8+adj(0);
+
+ EXP = 5;
+
+ loot = new MasterThievesArmband().identify();
+ lootChance = 0.01f;
+
+ lootOther = Generator.Category.BERRY;
+ lootChanceOther = 1f; // by default, see die()
+
+ FLEEING = new Fleeing();
+
+ properties.add(Property.ELF);
+ }
+
+ 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 int damageRoll() {
+ return Random.NormalIntRange(1, 7+adj(0));
+ }
+
+ @Override
+ protected float attackDelay() {
+ return 0.5f;
+ }
+
+ @Override
+ public void die(Object cause) {
+
+ super.die(cause);
+
+ if (item != null) {
+ Dungeon.level.drop(item, pos).sprite.drop();
+ }
+ }
+
+ @Override
+ protected Item createLoot() {
+ return new Gold(Random.NormalIntRange(100, 250));
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 120;
+ }
+
+ @Override
+ public int drRoll() {
+ return 3;
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+ if (item == null && enemy instanceof Hero && steal((Hero) enemy)) {
+ state = FLEEING;
+ }
+
+ return damage;
+ }
+
+ @Override
+ public int defenseProc(Char enemy, int damage) {
+ if (state == FLEEING) {
+ Dungeon.level.drop(new Gold(), pos).sprite.drop();
+ }
+
+ return damage;
+ }
+
+ protected boolean steal(Hero hero) {
+
+ Amulet item = hero.belongings.getItem(Amulet.class);
+ if (item != null) {
+
+ item.updateQuickslot();
+
+ GLog.w(Messages.get(BlueCat.class, "stole", item.name()) );
+
+ this.item = item;
+ item.detachAll(hero.belongings.backpack);
+
+
+ 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 class Fleeing extends Mob.Fleeing {
+ @Override
+ protected void nowhereToRun() {
+ if (buff(Terror.class) == null) {
+ sprite.showStatus(CharSprite.NEGATIVE, Messages.get(Mob.class, "rage"));
+ state = HUNTING;
+ } else {
+ super.nowhereToRun();
+ }
+ }
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/BlueWraith.java b/java/com/hmdzl/spspd/actors/mobs/BlueWraith.java
new file mode 100644
index 00000000..58734685
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/BlueWraith.java
@@ -0,0 +1,105 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import com.hmdzl.spspd.items.Generator;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Terror;
+import com.hmdzl.spspd.actors.buffs.Vertigo;
+import com.hmdzl.spspd.effects.particles.ShadowParticle;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.sprites.BlueWraithSprite;
+import com.watabou.noosa.tweeners.AlphaTweener;
+import com.watabou.utils.Random;
+
+public class BlueWraith extends Wraith {
+
+ {
+ spriteClass = BlueWraithSprite.class;
+
+ HP = HT = 250;
+ evadeSkill = 24;
+ baseSpeed = 2f;
+
+ EXP = 20;
+
+ loot = Generator.random(Generator.Category.SEED);
+ lootChance = 1.0f; // by default, see die()
+
+ properties.add(Property.UNDEAD);
+
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+ if (Random.Int(10) == 0) {
+ Buff.affect(enemy, Vertigo.class, Vertigo.duration(enemy));
+ Buff.affect(enemy, Terror.class, Terror.DURATION).object = enemy.id();
+ }
+
+ return damage;
+ }
+
+ @Override
+ public void adjustStats(int level) {
+ this.level = level;
+ evadeSkill = 24;
+ enemySeen = true;
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(20, 90);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 46;
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(10, 25);
+ }
+
+ @Override
+ protected boolean canAttack(Char enemy) {
+ return Dungeon.level.distance( pos, enemy.pos ) <= 2 ;
+ }
+
+ public static BlueWraith spawnAt(int pos) {
+
+ BlueWraith b = new BlueWraith();
+ b.adjustStats(Dungeon.depth);
+ b.pos = pos;
+ b.state = b.HUNTING;
+ GameScene.add(b, SPAWN_DELAY);
+
+ b.sprite.alpha(0);
+ b.sprite.parent.add(new AlphaTweener(b.sprite, 1, 0.5f));
+
+ b.sprite.emitter().burst(ShadowParticle.CURSE, 5);
+
+ return b;
+
+
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/BombBug.java b/java/com/hmdzl/spspd/actors/mobs/BombBug.java
new file mode 100644
index 00000000..12890c51
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/BombBug.java
@@ -0,0 +1,131 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Silent;
+import com.hmdzl.spspd.actors.buffs.StoneIce;
+import com.hmdzl.spspd.items.StoneOre;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.Assets;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.Generator;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.items.weapon.enchantments.EnchantmentDark;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.sprites.SkeletonSprite;
+
+import com.hmdzl.spspd.sprites.SpiderJumpSprite;
+import com.watabou.noosa.audio.Sample;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Random;
+
+public class BombBug extends Mob {
+
+ {
+ spriteClass = SpiderJumpSprite.class;
+
+ HP = HT = 80+(adj(0)*Random.NormalIntRange(2, 5));
+ evadeSkill = 15+adj(0);
+ baseSpeed = 1.5f;
+
+ EXP = 9;
+ maxLvl = 25;
+
+ loot = new StoneOre();
+ lootChance = 0.3f;
+
+ properties.add(Property.BEAST);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(15, 20+adj(0));
+ }
+
+
+ @Override
+ public void die(Object cause) {
+
+ super.die(cause);
+
+ for (int i = 0; i < Level.NEIGHBOURS8.length; i++) {
+ Char ch = findChar(pos + Level.NEIGHBOURS8[i]);
+ if (ch != null && ch.isAlive()) {
+ Buff.affect(ch,StoneIce.class).level(10);
+
+ }
+ }
+
+ if (Dungeon.visible[pos]) {
+ Sample.INSTANCE.play(Assets.SND_BLAST);
+ }
+
+
+ }
+
+
+ @Override
+ public int hitSkill(Char target) {
+ return 16+adj(0);
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(2, 5);
+ }
+
+ private static final HashSet> IMMUNITIES = new HashSet>();
+ static {
+ IMMUNITIES.add(EnchantmentDark.class);
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+
+ public static void spawnAround(int pos) {
+ for (int n : Level.NEIGHBOURS4) {
+ int cell = pos + n;
+ if (Level.passable[cell] && Actor.findChar(cell) == null) {
+ spawnAt(cell);
+ }
+ }
+ }
+
+ public static BombBug spawnAt(int pos) {
+ if (Level.passable[pos] && Actor.findChar(pos) == null) {
+
+ BombBug w = new BombBug();
+ w.pos = pos;
+ w.state = w.HUNTING;
+ GameScene.add(w, 1f);
+ return w;
+
+ } else {
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/mobs/BrokenRobot.java b/java/com/hmdzl/spspd/actors/mobs/BrokenRobot.java
new file mode 100644
index 00000000..50d977e8
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/BrokenRobot.java
@@ -0,0 +1,270 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.items.StoneOre;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.Assets;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.blobs.Blob;
+import com.hmdzl.spspd.actors.blobs.TarGas;
+import com.hmdzl.spspd.actors.buffs.Light;
+import com.hmdzl.spspd.actors.buffs.Terror;
+import com.hmdzl.spspd.effects.CellEmitter;
+import com.hmdzl.spspd.effects.particles.BlastParticle;
+import com.hmdzl.spspd.effects.particles.PurpleParticle;
+import com.hmdzl.spspd.effects.particles.SmokeParticle;
+import com.hmdzl.spspd.items.Heap;
+import com.hmdzl.spspd.items.scrolls.ScrollOfRecharging;
+import com.hmdzl.spspd.items.weapon.enchantments.EnchantmentDark;
+
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.levels.Terrain;
+import com.hmdzl.spspd.mechanics.Ballistica;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.sprites.BrokenRobotSprite;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.utils.GLog;
+
+import com.watabou.noosa.audio.Sample;
+import com.watabou.utils.Random;
+
+public class BrokenRobot extends Mob {
+
+ private static final String TXT_DEATHGAZE_KILLED = "%s's deathray killed you...";
+ private static final float SPAWN_DELAY = 2f;
+
+ {
+ spriteClass = BrokenRobotSprite.class;
+
+ HP = HT = 120+(adj(0)*Random.NormalIntRange(4, 7));
+ evadeSkill = 20+adj(1);
+ viewDistance = Light.DISTANCE;
+
+ EXP = 13;
+ maxLvl = 25;
+
+
+ lootOther = new StoneOre();
+ lootChanceOther = 0.25f;
+
+ loot = new ScrollOfRecharging();
+ lootChance = 0.25f; // by default, see die()
+
+ properties.add(Property.MECH);
+ }
+
+ private Ballistica beam;
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(0, 5);
+ }
+
+ @Override
+ public boolean act() {
+ GameScene.add(Blob.seed(pos,30, TarGas.class));
+ if(enemySeen){
+ switch (Random.Int(50)) {
+ case 1:
+ GLog.n(Messages.get(this,"explode") );
+ explode(pos);
+ if (HP<1){destroy();}
+ break;
+ }
+ }
+
+ return super.act();
+ }
+
+
+
+ @Override
+ protected boolean canAttack(Char enemy) {
+
+ beam = new Ballistica( pos, enemy.pos, Ballistica.STOP_TERRAIN);
+
+ return beam.subPath(1, beam.dist).contains(enemy.pos);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 20+adj(0);
+ }
+
+ @Override
+ protected float attackDelay() {
+ return 3f;
+ }
+
+ @Override
+ protected boolean doAttack(Char enemy) {
+
+ spend(attackDelay());
+
+ boolean rayVisible = false;
+
+ for (int i : beam.subPath(0, beam.dist)) {
+ if (Dungeon.visible[i]) {
+ rayVisible = true;
+ }
+ }
+
+ if (rayVisible) {
+ sprite.attack(beam.collisionPos);
+ return false;
+ } else {
+ attack(enemy);
+ return true;
+ }
+ }
+
+ @Override
+ public boolean attack(Char enemy) {
+
+ for (int pos : beam.subPath(1, beam.dist)) {
+
+ Char ch = Actor.findChar( pos );
+ if (ch == null) {
+ continue;
+ }
+
+ if (hit(this, ch, true)) {
+ ch.damage(Random.NormalIntRange(2, 8+adj(0)), this);
+
+ if (Dungeon.visible[pos]) {
+ ch.sprite.flash();
+ CellEmitter.center(pos).burst(PurpleParticle.BURST,
+ Random.IntRange(1, 2));
+ }
+
+ if (!ch.isAlive() && ch == Dungeon.hero) {
+ Dungeon.fail(Messages.format(ResultDescriptions.MOB));
+ //GLog.n(Messages.get(this, "kill"));
+ }
+ } else {
+ ch.sprite.showStatus(CharSprite.NEUTRAL, ch.defenseVerb());
+ }
+ }
+
+ return true;
+ }
+
+ public static void spawnAround(int pos) {
+ for (int n : Level.NEIGHBOURS4) {
+ int cell = pos + n;
+ if (Level.passable[cell] && Actor.findChar(cell) == null) {
+ spawnAt(cell);
+ }
+ }
+ }
+
+ public static BrokenRobot spawnAt(int pos) {
+
+ BrokenRobot b = new BrokenRobot();
+
+ b.pos = pos;
+ b.state = b.HUNTING;
+ GameScene.add(b, SPAWN_DELAY);
+
+ return b;
+
+ }
+
+
+ public void explode(int cell) {
+ // We're blowing up, so no need for a fuse anymore.
+
+ Sample.INSTANCE.play(Assets.SND_BLAST, 2);
+
+ if (Dungeon.visible[cell]) {
+ CellEmitter.center(cell).burst(BlastParticle.FACTORY, 30);
+ }
+
+ boolean terrainAffected = false;
+ for (int n : Level.NEIGHBOURS9) {
+ int c = cell + n;
+ if (c >= 0 && c < Level.getLength()) {
+ if (Dungeon.visible[c]) {
+ CellEmitter.get(c).burst(SmokeParticle.FACTORY, 4);
+ }
+
+ if (Level.flamable[c]) {
+ Level.set(c, Terrain.EMBERS);
+ GameScene.updateMap(c);
+ terrainAffected = true;
+ }
+
+ // destroys items / triggers bombs caught in the blast.
+ Heap heap = Dungeon.level.heaps.get(c);
+ if (heap != null)
+ heap.explode();
+
+ Char ch = Actor.findChar(c);
+ if (ch != null) {
+ // those not at the center of the blast take damage less
+ // consistently.
+ int minDamage = c == cell ? Dungeon.depth + 5 : 1;
+ int maxDamage = 10 + Dungeon.depth * 2;
+
+ int dmg = Random.NormalIntRange(minDamage, maxDamage)
+ - Math.max(ch.drRoll(),0);
+ if (dmg > 0) {
+ ch.damage(dmg, this);
+ }
+
+ if (ch == this && HP<1){
+ die(this);
+ }
+ }
+ }
+ }
+
+ if (terrainAffected) {
+ Dungeon.observe();
+ }
+ }
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+ static {
+ RESISTANCES.add(EnchantmentDark.class);
+
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+
+ private static final HashSet> IMMUNITIES = new HashSet>();
+ static {
+ IMMUNITIES.add(Terror.class);
+ IMMUNITIES.add(ToxicGas.class);
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/BrownBat.java b/java/com/hmdzl/spspd/actors/mobs/BrownBat.java
new file mode 100644
index 00000000..4cbd94e5
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/BrownBat.java
@@ -0,0 +1,83 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.Generator;
+import com.hmdzl.spspd.items.food.meatfood.Meat;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.BrownBatSprite;
+import com.hmdzl.spspd.utils.GLog;
+import com.watabou.utils.Random;
+
+public class BrownBat extends Mob {
+
+ {
+ spriteClass = BrownBatSprite.class;
+
+ HP = HT = 20;
+ evadeSkill = 1;
+ baseSpeed = 2f;
+
+ EXP = 1;
+ maxLvl = 6;
+
+ flying = true;
+
+ loot = new Meat();
+ lootChance = 0.5f; // by default, see die()
+
+ lootOther = Generator.Category.BERRY;
+ lootChanceOther = 0.05f; // by default, see die()
+
+ properties.add(Property.BEAST);
+
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(1, 4);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 5+Dungeon.depth;
+ }
+
+
+ @Override
+ public int drRoll() {
+ return 1;
+ }
+
+ @Override
+ public void die(Object cause) {
+ super.die(cause);
+
+ if (Random.Int(5) == 0) {
+ for (Mob mob : Dungeon.level.mobs.toArray(new Mob[0])) {
+ if (Random.Int(2) == 0 && enemy!=null){mob.beckon(enemy.pos);}
+ }
+ GLog.w(Messages.get(this,"die"));
+ }
+
+
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/Brute.java b/java/com/hmdzl/spspd/actors/mobs/Brute.java
new file mode 100644
index 00000000..a622dbee
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/Brute.java
@@ -0,0 +1,116 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.DefenceUp;
+import com.hmdzl.spspd.actors.buffs.Terror;
+import com.hmdzl.spspd.items.Gold;
+import com.hmdzl.spspd.items.Generator;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.BruteSprite;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.utils.GLog;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Random;
+
+public class Brute extends Mob {
+
+ private static final String TXT_ENRAGED = "%s becomes enraged!";
+
+ {
+ spriteClass = BruteSprite.class;
+
+ HP = HT = 120+(adj(0)*Random.NormalIntRange(4, 8));
+ evadeSkill = 15+adj(0);
+
+ EXP = 8;
+ maxLvl = 25;
+
+ loot = Gold.class;
+ lootChance = 0.5f;
+
+ lootOther = Generator.random(Generator.Category.RANGEWEAPON);
+ lootChanceOther = 0.5f; // by default, see die()
+
+ properties.add(Property.ORC);
+ }
+
+ private boolean enraged = false;
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ enraged = HP < HT / 4;
+ }
+
+ @Override
+ public int damageRoll() {
+ return enraged ? Random.NormalIntRange(25+adj(0), 60+adj(0)) : Random.NormalIntRange(10+adj(0), 35+adj(0));
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 20+adj(1);
+ }
+
+ @Override
+ protected float attackDelay() {
+ return 1.2f;
+ }
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(0, 10);
+ }
+
+ @Override
+ public void damage(int dmg, Object src) {
+ super.damage(dmg, src);
+
+ if (isAlive() && !enraged && HP < HT / 4) {
+ enraged = true;
+ Buff.affect(this,DefenceUp.class,5f).level(70);
+ spend(TICK);
+ if (Dungeon.visible[pos]) {
+ GLog.w(Messages.get(this, "enraged"));
+ sprite.showStatus(CharSprite.NEGATIVE, "enraged");
+ }
+ }
+ }
+
+ /*@Override
+ protected boolean canAttack(Char enemy) {if (buff(Locked.class) != null){
+ return Level.adjacent(pos, enemy.pos) && (!isCharmedBy(enemy));
+ } else
+ return Dungeon.level.distance( pos, enemy.pos ) <= 2 ;
+ } */
+
+ private static final HashSet> IMMUNITIES = new HashSet>();
+ static {
+ IMMUNITIES.add(Terror.class);
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/Crab.java b/java/com/hmdzl/spspd/actors/mobs/Crab.java
new file mode 100644
index 00000000..8a5afdc6
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/Crab.java
@@ -0,0 +1,58 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.food.meatfood.MysteryMeat;
+import com.hmdzl.spspd.sprites.CrabSprite;
+import com.watabou.utils.Random;
+
+public class Crab extends Mob {
+
+ {
+ spriteClass = CrabSprite.class;
+
+ HP = HT = 50+(adj(0)*Random.NormalIntRange(1, 3));
+ evadeSkill = 5+adj(1);
+ baseSpeed = 2f;
+
+ EXP = 3;
+ maxLvl = 9;
+
+ loot = new MysteryMeat();
+ lootChance = 0.5f;
+
+ properties.add(Property.BEAST);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(3, 6+adj(0));
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 12+adj(0);
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(0, 4);
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/CrabKing.java b/java/com/hmdzl/spspd/actors/mobs/CrabKing.java
new file mode 100644
index 00000000..8d0dd032
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/CrabKing.java
@@ -0,0 +1,173 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.Assets;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.buffs.Locked;
+import com.hmdzl.spspd.actors.buffs.Poison;
+import com.hmdzl.spspd.effects.CellEmitter;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.items.AdamantArmor;
+import com.hmdzl.spspd.items.Gold;
+import com.hmdzl.spspd.items.weapon.enchantments.EnchantmentDark;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.mechanics.Ballistica;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.sprites.CrabKingSprite;
+import com.hmdzl.spspd.utils.GLog;
+import com.hmdzl.spspd.messages.Messages;
+import com.watabou.noosa.audio.Sample;
+import com.watabou.utils.Random;
+
+public class CrabKing extends Mob {
+
+ private static final int JUMP_DELAY = 5;
+
+ {
+ spriteClass = CrabKingSprite.class;
+ baseSpeed = 2f;
+
+ HP = HT = 1300;
+ EXP = 20;
+ evadeSkill = 30;
+
+ properties.add(Property.BEAST);
+ properties.add(Property.BOSS);
+ }
+
+ private int timeToJump = JUMP_DELAY;
+
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(20, 50);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 35;
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(5, 10);
+ }
+
+ @Override
+ protected boolean act() {
+ boolean result = super.act();
+
+
+ if (HP < HT) {
+ sprite.emitter().burst( Speck.factory( Speck.HEALING ), 1 );
+ HP = HP + 10;
+ GLog.n(Messages.get(this,"heal"));
+ }
+ return result;
+ }
+
+ @Override
+ public void die(Object cause) {
+
+ super.die(cause);
+
+ GameScene.bossSlain();
+
+ Dungeon.level.drop(new Gold(Random.Int(1900, 4000)), pos).sprite.drop();
+ Dungeon.level.drop(new AdamantArmor(), pos).sprite.drop();
+ Dungeon.crabkingkilled=true;
+
+ yell(Messages.get(this,"die"));
+
+ }
+
+ @Override
+ protected boolean getCloser(int target) {
+ if (Level.fieldOfView[target]) {
+ jump();
+ return true;
+ } else {
+ return super.getCloser(target);
+ }
+ }
+
+ @Override
+ protected boolean canAttack(Char enemy) {
+ if (buff(Locked.class) != null){
+ return Level.adjacent(pos, enemy.pos) && (!isCharmedBy(enemy));
+ } else
+ return new Ballistica( pos, enemy.pos, Ballistica.PROJECTILE).collisionPos == enemy.pos;
+ }
+
+ @Override
+ protected boolean doAttack(Char enemy) {
+ timeToJump--;
+ if (timeToJump <= 0 && Level.adjacent(pos, enemy.pos)) {
+ jump();
+ return true;
+ } else {
+ return super.doAttack(enemy);
+ }
+ }
+
+ private void jump() {
+ timeToJump = JUMP_DELAY;
+
+ int newPos;
+ do {
+ newPos = Random.Int(Level.getLength());
+ } while (!Level.fieldOfView[newPos] || !Level.passable[newPos]
+ || Level.adjacent(newPos, enemy.pos)
+ || Actor.findChar(newPos) != null);
+
+ sprite.move(pos, newPos);
+ move(newPos);
+
+ if (Dungeon.visible[newPos]) {
+ CellEmitter.get(newPos).burst(Speck.factory(Speck.WOOL), 6);
+ Sample.INSTANCE.play(Assets.SND_PUFF);
+ }
+
+ spend(1 / speed());
+ }
+
+ @Override
+ public void notice() {
+ super.notice();
+ yell(Messages.get(this,"notice"));
+ }
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+ static {
+ RESISTANCES.add(ToxicGas.class);
+ RESISTANCES.add(Poison.class);
+ RESISTANCES.add(EnchantmentDark.class);
+
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/DM300.java b/java/com/hmdzl/spspd/actors/mobs/DM300.java
new file mode 100644
index 00000000..ba548f50
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/DM300.java
@@ -0,0 +1,443 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.Assets;
+import com.hmdzl.spspd.Badges;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.Badges.Badge;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.Blob;
+import com.hmdzl.spspd.actors.blobs.ConfusionGas;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Paralysis;
+import com.hmdzl.spspd.actors.buffs.Terror;
+import com.hmdzl.spspd.effects.CellEmitter;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.effects.particles.BlastParticle;
+import com.hmdzl.spspd.effects.particles.ElmoParticle;
+import com.hmdzl.spspd.effects.particles.SmokeParticle;
+import com.hmdzl.spspd.effects.particles.SparkParticle;
+import com.hmdzl.spspd.items.Generator;
+import com.hmdzl.spspd.items.Gold;
+import com.hmdzl.spspd.items.StoneOre;
+import com.hmdzl.spspd.items.TomeOfMastery;
+import com.hmdzl.spspd.items.artifacts.CapeOfThorns;
+import com.hmdzl.spspd.levels.CavesBossLevel;
+import com.hmdzl.spspd.levels.traps.LightningTrap;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.items.journalpages.Sokoban3;
+import com.hmdzl.spspd.items.keys.SkeletonKey;
+import com.hmdzl.spspd.items.weapon.enchantments.EnchantmentDark;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.levels.Terrain;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.sprites.DM300Sprite;
+import com.hmdzl.spspd.sprites.TowerSprite;
+import com.hmdzl.spspd.utils.GLog;
+
+import com.watabou.noosa.Camera;
+import com.watabou.noosa.audio.Sample;
+import com.watabou.utils.Callback;
+import com.watabou.utils.PathFinder;
+import com.watabou.utils.Random;
+
+public class DM300 extends Mob implements Callback {
+
+ private static final float TIME_TO_ZAP = 2f;
+
+ {
+ spriteClass = DM300Sprite.class;
+
+ HP = HT = 800;
+ EXP = 50;
+ evadeSkill = 24;
+
+ loot = new CapeOfThorns().identify();
+ lootChance = 0.2f;
+
+ lootOther = Generator.Category.NORNSTONE;
+ lootChanceOther = 1f;
+
+ properties.add(Property.MECH);
+ properties.add(Property.BOSS);
+ }
+
+ private int bossAlive = 0;
+ private int towerAlive = 0;
+
+ @Override
+ public int damageRoll() {
+
+ return Random.NormalIntRange(15, 19)*towerAlive;
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 35;
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(10, 10+(4*towerAlive));
+ }
+
+ public void spawnTower() {
+ Tower a = new Tower();
+ Tower b = new Tower();
+
+ do {
+ a.pos = pos + PathFinder.NEIGHBOURS8[Random.Int( 8 )];
+ b.pos = pos + PathFinder.NEIGHBOURS8[Random.Int( 8 )];
+ } while (!Dungeon.level.passable[a.pos] || !Dungeon.level.passable[b.pos] || a.pos == b.pos);
+
+ GameScene.add(a);
+ GameScene.add(b);
+ }
+
+ @Override
+ public boolean act() {
+
+ if (towerAlive < 1){
+ spawnTower();
+ towerAlive++;
+ }
+
+ GameScene.add(Blob.seed(pos, 30, ToxicGas.class));
+
+ return super.act();
+ }
+
+ @Override
+ public void move(int step) {
+ 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,"heal"));
+ }
+ }
+
+ int[] cells = { step - 1, step + 1, step - Level.getWidth(),
+ step + Level.getWidth(), step - 1 - Level.getWidth(),
+ step - 1 + Level.getWidth(), step + 1 - Level.getWidth(),
+ step + 1 + Level.getWidth() };
+ 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.water[cell]) {
+ GameScene.ripple(cell);
+ } else if (Dungeon.level.map[cell] == Terrain.EMPTY) {
+ Level.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 void die(Object cause) {
+
+ super.die(cause);
+
+ for (Mob mob : Dungeon.level.mobs) {
+
+ if (mob instanceof Tower){
+ bossAlive++;
+ }
+
+ }
+
+ if(bossAlive==0){
+
+ GameScene.bossSlain();
+ ((CavesBossLevel) Dungeon.level).unseal();
+ Dungeon.level.drop(new SkeletonKey(Dungeon.depth), pos).sprite.drop();
+ Badges.validateBossSlain();
+ }
+
+ Badges.Badge badgeToCheck = null;
+ switch (Dungeon.hero.heroClass) {
+ case WARRIOR:
+ badgeToCheck = Badge.MASTERY_WARRIOR;
+ break;
+ case MAGE:
+ badgeToCheck = Badge.MASTERY_MAGE;
+ break;
+ case ROGUE:
+ badgeToCheck = Badge.MASTERY_ROGUE;
+ break;
+ case HUNTRESS:
+ badgeToCheck = Badge.MASTERY_HUNTRESS;
+ break;
+ case PERFORMER:
+ badgeToCheck = Badge.MASTERY_PERFORMER;
+ break;
+ case SOLDIER:
+ badgeToCheck = Badge.MASTERY_SOLDIER;
+ break;
+ case FOLLOWER:
+ badgeToCheck = Badge.MASTERY_FOLLOWER;
+ break;
+ }
+
+
+ Dungeon.level.drop(new Sokoban3(), pos).sprite.drop();
+ Dungeon.level.drop(new TomeOfMastery(), pos).sprite.drop();
+
+ yell(Messages.get(this,"die"));
+ }
+
+ @Override
+ public void notice() {
+ super.notice();
+ yell(Messages.get(this, "notice"));
+ }
+
+ @Override
+ public void call() {
+ next();
+ }
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+ static {
+ RESISTANCES.add(EnchantmentDark.class);
+
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+
+ private static final HashSet> IMMUNITIES = new HashSet>();
+ static {
+ IMMUNITIES.add(ToxicGas.class);
+ IMMUNITIES.add(Terror.class);
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+
+public static class Tower extends Mob implements Callback {
+
+ {
+ spriteClass = TowerSprite.class;
+
+ HP = HT = 500+(Dungeon.depth*Random.NormalIntRange(2, 5));
+ evadeSkill = 0;
+
+ EXP = 25;
+
+ hostile = false;
+ state = PASSIVE;
+
+ loot = new StoneOre();
+ lootChance = 1f;
+
+ properties.add(Property.MECH);
+ properties.add(Property.BOSS);
+ }
+
+ @Override
+ public void beckon(int cell) {
+ // Do nothing
+ }
+
+ private int bossAlive = 0;
+
+ @Override
+ public int damageRoll() {
+ return 0;
+ }
+
+ @Override
+ public void damage(int dmg, Object src) {
+
+ for (Mob mob : Dungeon.level.mobs) {
+ mob.beckon(Dungeon.hero.pos);
+ }
+
+ GLog.w(Messages.get(this,"alert"));
+ CellEmitter.center(pos).start(
+ Speck.factory(Speck.SCREAM), 0.3f, 3);
+ Sample.INSTANCE.play(Assets.SND_CHALLENGE);
+
+ super.damage(dmg, src);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 0;
+ }
+
+ @Override
+ public int drRoll() {
+ return 0;
+ }
+
+ @Override
+ protected boolean act() {
+
+ switch (Random.Int(4)) {
+ case 1:
+ for (Mob mob : Dungeon.level.mobs) {
+ if (mob instanceof Tower && mob != this) {
+ mob.sprite.centerEmitter().burst(SparkParticle.FACTORY, 3);
+ mob.sprite.flash();
+ }
+ }
+ break;
+ case 2:
+ if (Dungeon.level.mobs.size()<10){
+ BrokenRobot.spawnAround(pos);
+ GLog.n(Messages.get(this,"robots"));
+ }
+ break;
+ }
+
+ return super.act();
+ }
+
+ @Override
+ public void call() {
+ next();
+ }
+
+ public void explode(int cell) {
+ // We're blowing up, so no need for a fuse anymore.
+
+ Sample.INSTANCE.play(Assets.SND_BLAST, 2);
+
+ if (Dungeon.visible[cell]) {
+ CellEmitter.center(cell).burst(BlastParticle.FACTORY, 30);
+ }
+
+ boolean terrainAffected = false;
+ for (int n : Level.NEIGHBOURS8) {
+ int c = cell + n;
+ if (c >= 0 && c < Level.getLength()) {
+ if (Dungeon.visible[c]) {
+ CellEmitter.get(c).burst(SmokeParticle.FACTORY, 4);
+ }
+
+ if (Level.flamable[c]) {
+ Level.set(c, Terrain.EMBERS);
+ GameScene.updateMap(c);
+ terrainAffected = true;
+ }
+
+ Char ch = Actor.findChar(c);
+ if (ch != null) {
+ // those not at the center of the blast take damage less
+ // consistently.
+ int minDamage = c == cell ? Dungeon.depth + 5 : 1;
+ int maxDamage = 10 + Dungeon.depth * 2;
+
+ int dmg = Random.NormalIntRange(minDamage, maxDamage)
+ - Math.max(ch.drRoll(),0);
+ if (dmg > 0) {
+ ch.damage(dmg, this);
+ }
+ }
+ }
+ }
+
+ if (terrainAffected) {
+ Dungeon.observe();
+ }
+ }
+
+
+ @Override
+ public void add(Buff buff) {
+ }
+
+ @Override
+ public void die(Object cause) {
+
+ super.die(cause);
+
+ explode(pos);
+
+ for (Mob mob : Dungeon.level.mobs) {
+
+ if (mob instanceof Tower || mob instanceof DM300){
+ bossAlive++;
+ }
+
+ }
+
+ if(bossAlive==0){
+
+ GameScene.bossSlain();
+ ((CavesBossLevel) Dungeon.level).unseal();
+ Dungeon.level.drop(new SkeletonKey(Dungeon.depth), pos).sprite.drop();
+ Dungeon.level.drop(new Gold(Random.Int(3000, 6000)), pos).sprite.drop();
+
+ Badges.validateBossSlain();
+ }
+ explodeDew(pos);
+ }
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+ static {
+ RESISTANCES.add(EnchantmentDark.class);
+
+ RESISTANCES.add(LightningTrap.Electricity.class);
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+
+ private static final HashSet> IMMUNITIES = new HashSet>();
+ static {
+ IMMUNITIES.add(ToxicGas.class);
+ IMMUNITIES.add(Terror.class);
+ IMMUNITIES.add(ConfusionGas.class);
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+
+
+}
+
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/DemonFlower.java b/java/com/hmdzl/spspd/actors/mobs/DemonFlower.java
new file mode 100644
index 00000000..ffe90d29
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/DemonFlower.java
@@ -0,0 +1,148 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.actors.buffs.ArmorBreak;
+import com.hmdzl.spspd.actors.buffs.AttackDown;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Burning;
+import com.hmdzl.spspd.actors.buffs.DefenceUp;
+import com.hmdzl.spspd.actors.buffs.GrowSeed;
+import com.hmdzl.spspd.actors.buffs.Silent;
+import com.hmdzl.spspd.items.Generator;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.buffs.Poison;
+import com.hmdzl.spspd.items.weapon.enchantments.EnchantmentDark;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.sprites.DemonflowerSprite;
+import com.hmdzl.spspd.utils.GLog;
+import com.watabou.utils.Random;
+
+public class DemonFlower extends Mob {
+
+ private static final int DEBUFF_DELAY = 6;
+
+ {
+ spriteClass = DemonflowerSprite.class;
+
+ HP = HT = 450;
+ EXP = 25;
+ maxLvl = 35;
+ evadeSkill = 5;
+
+ properties.add(Property.PLANT);
+ properties.add(Property.DEMONIC);
+
+ loot = Generator.Category.SEED;
+ lootChance = 0.5f;
+
+ }
+
+ private int addDebuff = DEBUFF_DELAY;
+
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(26, 37);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 35+adj(1);
+ }
+
+ @Override
+ protected float attackDelay() {
+ return 0.33f;
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(0, 5);
+ }
+
+ @Override
+ protected boolean doAttack(Char enemy) {
+ addDebuff--;
+ if (addDebuff <= 0 && Level.adjacent(pos, enemy.pos) && (buff(Silent.class) == null)) {
+ debuffadd();
+ return true;
+ } else {
+ return super.doAttack(enemy);
+ }
+ }
+
+ @Override
+ public int defenseProc(Char enemy, int damage) {
+
+ int dmg = damage;
+ if (dmg < HT/9 && buff(DefenceUp.class) == null) {
+ Buff.affect(this,DefenceUp.class,3f).level(dmg);
+ }
+
+ return super.defenseProc(enemy, damage);
+ }
+
+ private void debuffadd() {
+ addDebuff = DEBUFF_DELAY;
+
+ int pos = enemy.pos;
+ Char ch;
+ if ((ch = Actor.findChar(pos)) != null) {
+ Buff.prolong(ch, AttackDown.class,5f).level(30);
+ Buff.prolong(ch, ArmorBreak.class,5f).level(30);
+ }
+ GLog.n(Messages.get(this,"debuff"));
+
+ spend(1f);
+ }
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+ private static final HashSet> WEAKNESS = new HashSet>();
+ private static final HashSet> IMMUNITIES = new HashSet>();
+ static {
+ WEAKNESS.add(Burning.class);
+
+ RESISTANCES.add(ToxicGas.class);
+ RESISTANCES.add(Poison.class);
+ RESISTANCES.add(EnchantmentDark.class);
+
+ IMMUNITIES.add(GrowSeed.class);
+
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+
+ @Override
+ public HashSet> weakness() {
+ return WEAKNESS;
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/DemonGoo.java b/java/com/hmdzl/spspd/actors/mobs/DemonGoo.java
new file mode 100644
index 00000000..cfdf9c16
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/DemonGoo.java
@@ -0,0 +1,213 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Burning;
+import com.hmdzl.spspd.actors.buffs.Light;
+import com.hmdzl.spspd.actors.buffs.Ooze;
+import com.hmdzl.spspd.actors.buffs.Poison;
+import com.hmdzl.spspd.actors.buffs.Roots;
+import com.hmdzl.spspd.effects.Pushing;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.items.StoneOre;
+import com.hmdzl.spspd.items.weapon.enchantments.EnchantmentDark;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.levels.Terrain;
+import com.hmdzl.spspd.levels.features.Door;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.sprites.DemonGooSprite;
+import com.hmdzl.spspd.utils.GLog;
+import com.hmdzl.spspd.messages.Messages;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Random;
+
+public class DemonGoo extends Mob {
+
+protected static final float SPAWN_DELAY = 2f;
+
+private int demonGooGeneration = 0;
+
+private static final String DEMONGOOGENERATION = "demonGooGeneration";
+
+ {
+ HP = HT = 300+(adj(0)*Random.NormalIntRange(4, 7));
+ EXP = 10;
+ maxLvl = 35;
+ evadeSkill = 10+adj(1);
+ //10
+ spriteClass = DemonGooSprite.class;
+ baseSpeed = 2f;
+ viewDistance = Light.DISTANCE;
+
+ loot = new StoneOre();
+ lootChance = 1f;
+
+ properties.add(Property.ELEMENT);
+ properties.add(Property.DEMONIC);
+ }
+
+ private static final float SPLIT_DELAY = 1f;
+
+ @Override
+ protected boolean act() {
+ boolean result = super.act();
+
+ if (Level.water[pos] && HP < HT) {
+ sprite.emitter().burst( Speck.factory( Speck.HEALING ), 1 );
+ HP++;
+ } else if(Level.water[pos] && HP == HT && HT < 200){
+ sprite.emitter().burst( Speck.factory( Speck.HEALING ), 1 );
+ HT=HT+5;
+ HP=HT;
+ }
+ return result;
+ }
+
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(30+adj(1), 60+adj(1));
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 35+adj(1);
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(10, 15);
+ //10
+ }
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(DEMONGOOGENERATION, demonGooGeneration);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ demonGooGeneration = bundle.getInt(DEMONGOOGENERATION);
+ }
+
+ @Override
+ public int defenseProc(Char enemy, int damage) {
+
+ if (HP >= damage + 2) {
+ ArrayList candidates = new ArrayList();
+ boolean[] passable = Level.passable;
+
+ int[] neighbours = { pos + 1, pos - 1, pos + Level.getWidth(),
+ pos - Level.getWidth() };
+ for (int n : neighbours) {
+ if (passable[n] && Actor.findChar(n) == null) {
+ candidates.add(n);
+ }
+ }
+
+ if (candidates.size() > 0) {
+ GLog.n(Messages.get(this, "divide"));
+ DemonGoo clone = split();
+ clone.HP = (HP - damage) / 2;
+ clone.pos = Random.element(candidates);
+ clone.state = clone.HUNTING;
+
+ if (Dungeon.level.map[clone.pos] == Terrain.DOOR) {
+ Door.enter(clone.pos);
+ }
+
+ GameScene.add(clone, SPLIT_DELAY);
+ Actor.addDelayed(new Pushing(clone, pos, clone.pos), -1);
+
+ HP -= clone.HP;
+ }
+ }
+
+ return damage;
+ }
+
+
+ private DemonGoo split() {
+ DemonGoo clone = new DemonGoo();
+ clone.demonGooGeneration = demonGooGeneration + 1;
+ if (buff(Burning.class) != null) {
+ Buff.affect(clone, Burning.class).reignite(clone);
+ }
+ if (buff(Poison.class) != null) {
+ Buff.affect(clone, Poison.class).set(2);
+ }
+ return clone;
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+ if (Random.Int(3) == 0) {
+ Buff.affect(enemy, Ooze.class);
+ enemy.sprite.burst(0x000000, 5);
+ }
+ return damage;
+ }
+
+ @Override
+ public void notice() {
+ super.notice();
+ //yell(Messages.get(this, "notice"));
+ }
+
+ @Override
+ public void die(Object cause) {
+
+ super.die(cause);
+ //yell(Messages.get(this, "die"));
+ }
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+ static {
+ RESISTANCES.add(ToxicGas.class);
+ RESISTANCES.add(EnchantmentDark.class);
+
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+
+ private static final HashSet> IMMUNITIES = new HashSet>();
+
+ static {
+ IMMUNITIES.add(Roots.class);
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+
+
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/Dragonking.java b/java/com/hmdzl/spspd/actors/mobs/Dragonking.java
new file mode 100644
index 00000000..67b68fab
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/Dragonking.java
@@ -0,0 +1,98 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.Blob;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.buffs.Poison;
+import com.hmdzl.spspd.items.keys.SkeletonKey;
+import com.hmdzl.spspd.items.weapon.enchantments.EnchantmentDark;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.sprites.DragonkingSprite;
+import com.watabou.utils.Random;
+import com.hmdzl.spspd.actors.blobs.ShockWeb;
+
+
+public class Dragonking extends Mob {
+ {
+ spriteClass = DragonkingSprite.class;
+ baseSpeed = 1f;
+
+ HP = HT = 100;
+ EXP = 1;
+ evadeSkill = 0;
+
+ properties.add(Property.DRAGON);
+ properties.add(Property.BOSS);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(0, 1);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 1;
+ }
+
+ @Override
+ public int drRoll() {
+ return 0;
+ }
+
+ @Override
+ public void die(Object cause) {
+
+ super.die(cause);
+ GameScene.bossSlain();
+ Dungeon.level.drop(new SkeletonKey(Dungeon.depth), pos).sprite.drop();
+ UGoo.spawnAt(pos);
+
+ }
+
+ @Override
+ public void move(int step) {
+ GameScene.add(Blob.seed(pos, Random.Int(5, 7), ShockWeb.class));
+ super.move(step);
+ }
+
+ @Override
+ protected boolean doAttack(Char enemy) {
+
+ return super.doAttack(enemy);
+
+ }
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+ static {
+ RESISTANCES.add(ToxicGas.class);
+ RESISTANCES.add(Poison.class);
+ RESISTANCES.add(EnchantmentDark.class);
+
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/DustElement.java b/java/com/hmdzl/spspd/actors/mobs/DustElement.java
new file mode 100644
index 00000000..87ad37d4
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/DustElement.java
@@ -0,0 +1,73 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import com.hmdzl.spspd.actors.buffs.Blindness;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.items.Generator;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.sprites.DustElementSprite;
+import com.hmdzl.spspd.utils.GLog;
+import com.watabou.utils.Random;
+
+public class DustElement extends Mob {
+
+ {
+ spriteClass = DustElementSprite.class;
+
+ HP = HT = 35+(Dungeon.depth*Random.NormalIntRange(1, 3));
+ evadeSkill = 4+(Math.round((Dungeon.depth)/2));
+
+ EXP = 2;
+ maxLvl = 8;
+
+ loot = Generator.random(Generator.Category.SEED);
+ lootChance = 0.5f;
+
+ properties.add(Property.ELEMENT);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(2, 5+(Dungeon.depth));
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 11+(Dungeon.depth);
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+ if (Random.Int(10) == 0) {
+ Buff.prolong(enemy, Blindness.class, Random.Int(3, 10));
+ GLog.w(Messages.get(this,"blind"));
+ Dungeon.observe();
+ }
+
+ return damage;
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(0, 2);
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/DwarfLich.java b/java/com/hmdzl/spspd/actors/mobs/DwarfLich.java
new file mode 100644
index 00000000..0c6f4859
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/DwarfLich.java
@@ -0,0 +1,123 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Poison;
+import com.hmdzl.spspd.items.food.fruit.Blackberry;
+import com.hmdzl.spspd.items.potions.PotionOfHealing;
+
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.mechanics.Ballistica;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.sprites.DwarfLichSprite;
+import com.watabou.utils.Random;
+
+public class DwarfLich extends Mob {
+
+ private static final float SPAWN_DELAY = 2f;
+
+ {
+ spriteClass = DwarfLichSprite.class;
+
+ HP = HT = 120+(adj(0)*Random.NormalIntRange(7, 5));
+ evadeSkill = 24+adj(1);
+
+ EXP = 14;
+ maxLvl = 30;
+
+ loot = new PotionOfHealing();
+ lootChance = 0.3f;
+
+ lootOther = new Blackberry();
+ lootChanceOther = 0.3f;
+
+ properties.add(Property.UNDEAD);
+ properties.add(Property.DWARF);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(20, 32);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 36+adj(1);
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(5, 15);
+ }
+
+ @Override
+ protected boolean canAttack(Char enemy) {
+ Ballistica attack = new Ballistica( pos, enemy.pos, Ballistica.MAGIC_BOLT);
+ return !Level.adjacent( pos, enemy.pos ) && attack.collisionPos == enemy.pos;
+ }
+
+ @Override
+ protected boolean getCloser(int target) {
+ if (state == HUNTING) {
+ return enemySeen && getFurther(target);
+ } else {
+ return super.getCloser(target);
+ }
+ }
+ @Override
+ public void die(Object cause) {
+ RedWraith.spawnAt(this.pos);
+ super.die(cause);
+ }
+
+ public static void spawnAround(int pos) {
+ for (int n : Level.NEIGHBOURS4) {
+ int cell = pos + n;
+ if (Level.passable[cell] && Actor.findChar(cell) == null) {
+ spawnAt(cell);
+ }
+ }
+ }
+
+ public static DwarfLich spawnAt(int pos) {
+
+ DwarfLich d = new DwarfLich();
+
+ d.pos = pos;
+ d.state = d.HUNTING;
+ GameScene.add(d, SPAWN_DELAY);
+
+ return d;
+
+ }
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+ static {
+
+ RESISTANCES.add(Poison.class);
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/ElderAvatar.java b/java/com/hmdzl/spspd/actors/mobs/ElderAvatar.java
new file mode 100644
index 00000000..600a19a5
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/ElderAvatar.java
@@ -0,0 +1,775 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.Badges;
+import com.hmdzl.spspd.Challenges;
+import com.hmdzl.spspd.actors.blobs.DarkGas;
+import com.hmdzl.spspd.actors.blobs.ElectriShock;
+import com.hmdzl.spspd.actors.buffs.Amok;
+import com.hmdzl.spspd.actors.buffs.ArmorBreak;
+import com.hmdzl.spspd.actors.buffs.AttackDown;
+import com.hmdzl.spspd.actors.buffs.Blindness;
+import com.hmdzl.spspd.actors.buffs.Burning;
+import com.hmdzl.spspd.actors.buffs.Charm;
+import com.hmdzl.spspd.actors.buffs.Chill;
+import com.hmdzl.spspd.actors.buffs.Disarm;
+import com.hmdzl.spspd.actors.buffs.Frost;
+import com.hmdzl.spspd.actors.buffs.GlassShield;
+import com.hmdzl.spspd.actors.buffs.GrowSeed;
+import com.hmdzl.spspd.actors.buffs.ShieldArmor;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.items.DolyaSlate;
+import com.hmdzl.spspd.items.Generator;
+import com.hmdzl.spspd.items.Gold;
+import com.hmdzl.spspd.items.KindOfArmor;
+import com.hmdzl.spspd.items.StoneOre;
+import com.hmdzl.spspd.items.armor.normalarmor.NormalArmor;
+import com.hmdzl.spspd.items.armor.normalarmor.RubberArmor;
+import com.hmdzl.spspd.items.armor.normalarmor.WoodenArmor;
+import com.hmdzl.spspd.items.artifacts.AlienBag;
+import com.hmdzl.spspd.items.bombs.DangerousBomb;
+import com.hmdzl.spspd.items.keys.SkeletonKey;
+import com.hmdzl.spspd.levels.Terrain;
+import com.hmdzl.spspd.mechanics.Ballistica;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.Assets;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Paralysis;
+import com.hmdzl.spspd.actors.buffs.Vertigo;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.items.journalpages.Sokoban4;
+import com.hmdzl.spspd.items.wands.WandOfDisintegration;
+import com.hmdzl.spspd.levels.CityBossLevel;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.sprites.ElderAvatarSprite;
+import com.hmdzl.spspd.sprites.GolemSprite;
+import com.hmdzl.spspd.sprites.MonkSprite;
+import com.hmdzl.spspd.sprites.MusketeerSprite;
+import com.hmdzl.spspd.sprites.ObeliskSprite;
+import com.hmdzl.spspd.sprites.WarlockSprite;
+import com.hmdzl.spspd.utils.GLog;
+import com.watabou.noosa.audio.Sample;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Random;
+
+public class ElderAvatar extends Mob {
+
+ {
+ spriteClass = ElderAvatarSprite.class;
+
+ HP = HT = 600;
+ EXP = 50;
+ evadeSkill = 25;
+ baseSpeed = 1f;
+
+ loot = new AlienBag().identify();
+ lootChance = 0.2f;
+
+ lootOther = Generator.Category.GUNWEAPON;
+ lootChanceOther = 1f;
+
+ properties.add(Property.ALIEN);
+ properties.add(Property.BOSS);
+ }
+
+ private int orbAlive = 0;
+ private int waves = 0;
+ public static int breaks = 0;
+
+ private static final String WAVES = "waves";
+ private static final String BREAKS = "breaks";
+ private static final String ORBALIVE = "orbAlive";
+
+ @Override
+ public void storeInBundle( Bundle bundle ) {
+ super.storeInBundle(bundle);
+ bundle.put( WAVES, waves );
+ bundle.put( BREAKS, breaks );
+ bundle.put( ORBALIVE, orbAlive );
+ }
+
+ @Override
+ public void restoreFromBundle( Bundle bundle ) {
+ super.restoreFromBundle(bundle);
+ waves = bundle.getInt( WAVES );
+ breaks = bundle.getInt( BREAKS );
+ orbAlive = bundle.getInt( ORBALIVE );
+ }
+
+
+ public void spawnObe() {
+ Obelisk a = new Obelisk();
+
+ a.pos = Terrain.EMPTY_WELL;
+ do {
+ a.pos = Random.Int(Dungeon.level.randomRespawnCellMob());
+ } while (Dungeon.level.map[a.pos] != Terrain.EMPTY_WELL
+ || Actor.findChar(a.pos) != null);
+ GameScene.add(a);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Dungeon.isChallenged(Challenges.TEST_TIME) ? Random.NormalIntRange(0, 1) : Random.NormalIntRange(25, 40);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 58;
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(8, 12);
+ }
+
+ @Override
+ protected boolean canAttack(Char enemy) {
+ if (HP > 49) return Dungeon.level.distance(pos, enemy.pos) <= 3;
+ else return Dungeon.level.distance(pos, enemy.pos) <= 0;
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+ if (Random.Int(5) == 0) {
+ new DangerousBomb().explode(enemy.pos);
+ }
+ if (Random.Int(8) == 0) {
+ Buff.affect(enemy, Charm.class, Charm.durationFactor(enemy)
+ * Random.IntRange(3, 5)).object = id();
+ enemy.sprite.centerEmitter().start(Speck.factory(Speck.HEART),
+ 0.2f, 5);
+ Sample.INSTANCE.play(Assets.SND_CHARMS);
+ }
+ Hero hero = Dungeon.hero;
+ KindOfArmor armor = hero.belongings.armor;
+ if (Random.Int(10) == 0) {
+ if (armor != null && !(armor instanceof WoodenArmor || armor instanceof RubberArmor || armor instanceof NormalArmor)
+ && !armor.cursed) {
+ hero.belongings.armor = null;
+ Dungeon.level.drop(armor, hero.pos).sprite.drop();
+ GLog.w(Messages.get(this, "disarm"));
+ }
+ }
+ return damage;
+ }
+
+ public boolean checkObelisk() {
+
+ int obeliskAlive = 0;
+ if (Dungeon.level.mobs != null) {
+ for (Mob mob : Dungeon.level.mobs) {
+ if (mob instanceof Obelisk && mob.HP > 10) {
+ obeliskAlive++;
+ }
+ }
+ }
+ if (obeliskAlive > 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void damage(int dmg, Object src) {
+ if (dmg > this.HP && checkObelisk()) {
+ dmg = Random.Int(this.HP);
+ //Buff.affect(this,ShieldArmor.class).level(100);
+ }
+ super.damage(dmg, src);
+ }
+
+ @Override
+ protected boolean act() {
+
+ if (orbAlive < 1) {
+ spawnObe();
+ orbAlive++;
+
+ return true;
+ }
+
+ if (HP < 50 && waves == 0 && breaks == 0) {
+ summonHunter(pos);
+ waves++;
+ Buff.affect(this,ShieldArmor.class).level(100);
+ sprite.centerEmitter().start(Speck.factory(Speck.SCREAM), 0.4f, 2);
+ Sample.INSTANCE.play(Assets.SND_CHALLENGE);
+ return true;
+ }
+
+ if (HP < 50 && waves == 1 && breaks == 1) {
+ summonWarlock(pos);
+ waves++;
+ Buff.affect(this,ShieldArmor.class).level(100);
+ sprite.centerEmitter().start(Speck.factory(Speck.SCREAM), 0.4f, 2);
+ Sample.INSTANCE.play(Assets.SND_CHALLENGE);
+ return true;
+ }
+
+ if (HP < 50 && waves == 2 && breaks == 2) {
+ summonMonk(pos);
+ waves++;
+ Buff.affect(this,ShieldArmor.class).level(100);
+ sprite.centerEmitter().start(Speck.factory(Speck.SCREAM), 0.4f, 2);
+ Sample.INSTANCE.play(Assets.SND_CHALLENGE);
+ return true;
+ }
+
+ if (HP < 50 && waves == 3 && breaks == 3) {
+ summonMech(pos);
+ waves++;
+ Buff.affect(this,ShieldArmor.class).level(100);
+ sprite.centerEmitter().start(Speck.factory(Speck.SCREAM), 0.4f, 2);
+ Sample.INSTANCE.play(Assets.SND_CHALLENGE);
+ return true;
+ }
+
+ return super.act();
+ }
+
+ private void summonHunter(int pos) {
+ TheHunter.spawnAround(pos);
+ }
+
+ private void summonWarlock(int pos) {
+ TheWarlock.spawnAround(pos);
+ }
+
+ private void summonMonk(int pos) {
+ TheMonk.spawnAround(pos);
+ }
+
+ private void summonMech(int pos) {
+ TheMech.spawnAround(pos);
+ }
+
+ @Override
+ public void die(Object cause) {
+
+ yell(Messages.get(this, "died"));
+
+ GameScene.bossSlain();
+ ((CityBossLevel) Dungeon.level).unseal();
+ if (!Dungeon.limitedDrops.journal.dropped()) {
+ Dungeon.level.drop(new DolyaSlate(), pos).sprite.drop();
+ Dungeon.limitedDrops.journal.drop();
+ }
+ Dungeon.level.drop(new Sokoban4(), pos).sprite.drop();
+
+ Dungeon.level.drop(new SkeletonKey(Dungeon.depth), pos).sprite.drop();
+ Dungeon.level.drop(new Gold(Random.Int(4900, 10000)), pos).sprite.drop();
+
+ Badges.validateBossSlain();
+
+ super.die(cause);
+ }
+
+ @Override
+ public void notice() {
+ super.notice();
+ yell(Messages.get(this, "notice"));
+ }
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+
+ static {
+ RESISTANCES.add(ToxicGas.class);
+ RESISTANCES.add(Amok.class);
+ RESISTANCES.add(Vertigo.class);
+
+ RESISTANCES.add(WandOfDisintegration.class);
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+
+ private static final HashSet> IMMUNITIES = new HashSet>();
+
+ static {
+ IMMUNITIES.add(Paralysis.class);
+ IMMUNITIES.add(Charm.class);
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+
+ public static class TheHunter extends Mob {
+
+ {
+ spriteClass = MusketeerSprite.class;
+
+ HP = HT = 100;
+ evadeSkill = 15;
+ EXP = 0;
+ baseSpeed = 3f;
+ viewDistance = 6;
+ state = WANDERING;
+ properties.add(Property.ALIEN);
+ properties.add(Property.BOSS);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(20, 35);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 60;
+ }
+
+ @Override
+ protected boolean canAttack(Char enemy) {
+ if (buff(Disarm.class) != null){
+ return false;
+ } else
+ return new Ballistica( pos, enemy.pos, Ballistica.PROJECTILE).collisionPos == enemy.pos;
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+ Buff.affect(this, Disarm.class,5f);
+ Buff.affect(enemy,ArmorBreak.class,3f).level(30);
+ return damage;
+ }
+
+ @Override
+ public void damage(int dmg, Object src) {
+ super.damage(dmg, src);
+ if (src instanceof ToxicGas) {
+ ((ToxicGas) src).clear(pos);
+ }
+ }
+
+ @Override
+ public void die(Object cause) {
+ super.die(cause);
+ }
+
+ @Override
+ public int drRoll() {
+ return 5;
+ }
+
+ public static void spawnAround(int pos) {
+ for (int n : Level.NEIGHBOURS4) {
+ int cell = pos + n;
+ if (Level.passable[cell] && Actor.findChar(cell) == null) {
+ spawnAt(cell);
+ }
+ }
+ }
+
+ public static TheHunter spawnAt(int pos) {
+
+ TheHunter d = new TheHunter();
+
+ d.pos = pos;
+ d.state = d.HUNTING;
+ GameScene.add(d, 2f);
+
+ return d;
+
+ }
+
+ private static final HashSet> IMMUNITIES = new HashSet>();
+
+ static {
+ IMMUNITIES.add(Charm.class);
+ IMMUNITIES.add(Amok.class);
+ IMMUNITIES.add(Paralysis.class);
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+ }
+
+ public static class TheWarlock extends Mob {
+ {
+ spriteClass = WarlockSprite.class;
+
+ HP = HT = 150;
+ evadeSkill = 15;
+ EXP = 0;
+ state = WANDERING;
+ properties.add(Property.ALIEN);
+ properties.add(Property.BOSS);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(25, 45);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 60;
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+ Buff.prolong(enemy,Vertigo.class,3f);
+ Buff.prolong(enemy,AttackDown.class,3f).level(20);
+ return damage;
+ }
+
+ @Override
+ public void damage(int dmg, Object src) {
+ dmg =(int)(dmg/2);
+ super.damage(dmg, src);
+ }
+
+ @Override
+ public void die(Object cause) {
+ super.die(cause);
+ }
+
+ @Override
+ public int drRoll() {
+ return 5;
+ }
+
+ public static void spawnAround(int pos) {
+ for (int n : Level.NEIGHBOURS4) {
+ int cell = pos + n;
+ if (Level.passable[cell] && Actor.findChar(cell) == null) {
+ spawnAt(cell);
+ }
+ }
+ }
+
+ public static TheWarlock spawnAt(int pos) {
+
+ TheWarlock d = new TheWarlock();
+
+ d.pos = pos;
+ d.state = d.HUNTING;
+ GameScene.add(d, 2f);
+
+ return d;
+
+ }
+
+ private static final HashSet> IMMUNITIES = new HashSet>();
+
+ static {
+ IMMUNITIES.add(Charm.class);
+ IMMUNITIES.add(Amok.class);
+ IMMUNITIES.add(Paralysis.class);
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+ }
+
+ public static class TheMonk extends Mob {
+
+ {
+ spriteClass = MonkSprite.class;
+
+ HP = HT = 100;
+ evadeSkill = 30;
+ EXP = 0;
+ baseSpeed = 2f;
+ viewDistance = 5;
+ state = WANDERING;
+ properties.add(Property.ALIEN);
+ properties.add(Property.BOSS);
+ }
+
+ @Override
+ protected float attackDelay() {
+ return 0.5f;
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(15, 30);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 60;
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+ if (Random.Int(6) == 0) {
+ Buff.affect(this,GlassShield.class).turns(1);
+ }
+ Buff.prolong(enemy,Blindness.class,3f);
+ return damage;
+ }
+
+ @Override
+ public void damage(int dmg, Object src) {
+ super.damage(dmg, src);
+ if (src instanceof ToxicGas) {
+ ((ToxicGas) src).clear(pos);
+ }
+ }
+
+ @Override
+ public void die(Object cause) {
+ super.die(cause);
+ }
+
+ @Override
+ public int drRoll() {
+ return 5;
+ }
+
+ public static void spawnAround(int pos) {
+ for (int n : Level.NEIGHBOURS4) {
+ int cell = pos + n;
+ if (Level.passable[cell] && Actor.findChar(cell) == null) {
+ spawnAt(cell);
+ }
+ }
+ }
+
+ public static TheMonk spawnAt(int pos) {
+
+ TheMonk d = new TheMonk();
+
+ d.pos = pos;
+ d.state = d.HUNTING;
+ GameScene.add(d, 2f);
+
+ return d;
+
+ }
+
+ private static final HashSet> IMMUNITIES = new HashSet>();
+
+ static {
+ IMMUNITIES.add(Charm.class);
+ IMMUNITIES.add(Amok.class);
+ IMMUNITIES.add(Paralysis.class);
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+ }
+
+ public static class TheMech extends Mob {
+
+ {
+ spriteClass = GolemSprite.class;
+
+ HP = HT = 200;
+ evadeSkill = 15;
+ EXP = 0;
+ state = WANDERING;
+ baseSpeed = 0.5f;
+ properties.add(Property.ALIEN);
+ properties.add(Property.MECH);
+ properties.add(Property.BOSS);
+ }
+ private int addshield = 0;
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(45, 70);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 30;
+ }
+
+ @Override
+ protected boolean act() {
+
+ if (addshield < 1) {
+ Buff.affect(this,ShieldArmor.class).level(100);
+ addshield++;
+ return true;
+ }
+ return super.act();
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+ Buff.affect(enemy, Burning.class).reignite(enemy);
+ return damage;
+ }
+
+ @Override
+ public void damage(int dmg, Object src) {
+ super.damage(dmg, src);
+ }
+
+ @Override
+ public void die(Object cause) {
+ super.die(cause);
+ }
+
+ @Override
+ public int drRoll() {
+ return 10;
+ }
+
+ public static void spawnAround(int pos) {
+ for (int n : Level.NEIGHBOURS4) {
+ int cell = pos + n;
+ if (Level.passable[cell] && Actor.findChar(cell) == null) {
+ spawnAt(cell);
+ }
+ }
+ }
+
+ public static TheMech spawnAt(int pos) {
+
+ TheMech d = new TheMech();
+
+ d.pos = pos;
+ d.state = d.HUNTING;
+ GameScene.add(d, 2f);
+
+ return d;
+
+ }
+
+ private static final HashSet> IMMUNITIES = new HashSet>();
+
+ static {
+ IMMUNITIES.add(Burning.class);
+ IMMUNITIES.add(Frost.class);
+ IMMUNITIES.add(Chill.class);
+ IMMUNITIES.add(ElectriShock.class);
+ IMMUNITIES.add(ToxicGas.class);
+ IMMUNITIES.add(DarkGas.class);
+ IMMUNITIES.add(GrowSeed.class);
+ IMMUNITIES.add(Charm.class);
+ IMMUNITIES.add(Amok.class);
+ IMMUNITIES.add(Paralysis.class);
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+ }
+
+ public static class Obelisk extends Mob {
+
+ {
+ spriteClass = ObeliskSprite.class;
+
+ HP = HT = 1000;
+ evadeSkill = 0;
+
+ EXP = 10;
+
+ hostile = false;
+ state = PASSIVE;
+
+ loot = new StoneOre();
+ lootChance = 0.05f;
+
+ properties.add(Property.UNKNOW);
+ properties.add(Property.BOSS);
+ }
+
+ @Override
+ public void beckon(int cell) {
+ // Do nothing
+ }
+
+ @Override
+ public void add(Buff buff) {
+ }
+
+ @Override
+ public int damageRoll() {
+ return 0;
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 0;
+ }
+
+ @Override
+ public int drRoll() {
+ return 0;
+ }
+
+ @Override
+ protected boolean act() {
+
+ if (3 - ElderAvatar.breaks > 4 * HP / HT) {
+ ElderAvatar.breaks++;
+ for (Mob mob : Dungeon.level.mobs) {
+ if (mob instanceof ElderAvatar) {
+ mob.HP = 600;
+ }
+ }
+ return true;
+ }
+ return super.act();
+ }
+
+ public boolean checkElder() {
+
+ int elderAlive = 0;
+ if (Dungeon.level.mobs != null) {
+ for (Mob mob : Dungeon.level.mobs) {
+ if (mob instanceof ElderAvatar && mob.HP > 20) {
+ elderAlive++;
+ }
+ }
+ }
+ if (elderAlive > 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void damage(int dmg, Object src) {
+ if (checkElder()) {
+ yell(Messages.get(this, "impossible"));
+ } else {
+ super.damage(dmg, src);
+ }
+ }
+
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/Eye.java b/java/com/hmdzl/spspd/actors/mobs/Eye.java
new file mode 100644
index 00000000..98a95fd1
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/Eye.java
@@ -0,0 +1,200 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Light;
+import com.hmdzl.spspd.actors.buffs.Terror;
+import com.hmdzl.spspd.effects.CellEmitter;
+import com.hmdzl.spspd.effects.particles.PurpleParticle;
+import com.hmdzl.spspd.items.food.meatfood.MysteryMeat;
+import com.hmdzl.spspd.items.potions.PotionOfHealing;
+import com.hmdzl.spspd.items.wands.WandOfDisintegration;
+import com.hmdzl.spspd.items.weapon.enchantments.EnchantmentDark;
+
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.mechanics.Ballistica;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.sprites.EyeSprite;
+
+import com.watabou.noosa.tweeners.AlphaTweener;
+import com.watabou.utils.Random;
+
+public class Eye extends Mob {
+
+ private static final String TXT_DEATHGAZE_KILLED = "%s's deathgaze killed you...";
+ protected static final float SPAWN_DELAY = 2f;
+
+ {
+ spriteClass = EyeSprite.class;
+
+ HP = HT = 200+(adj(0)*Random.NormalIntRange(4, 7));
+ evadeSkill = 20+adj(1);
+ viewDistance = Light.DISTANCE;
+
+ EXP = 15;
+ maxLvl = 35;
+
+ flying = true;
+
+ loot = new PotionOfHealing();
+ lootChance = 0.1f;
+
+ lootOther = new MysteryMeat();
+ lootChanceOther = 0.5f; // by default, see die()
+
+ properties.add(Property.DEMONIC);
+ }
+
+ private Ballistica beam;
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(10, 20);
+ }
+
+ private int hitCell;
+
+ @Override
+ protected boolean canAttack(Char enemy) {
+
+ beam = new Ballistica( pos, enemy.pos, Ballistica.STOP_TERRAIN);
+
+ return beam.subPath(1, beam.dist).contains(enemy.pos);
+ }
+
+
+ @Override
+ public int hitSkill(Char target) {
+ return 30+adj(0);
+ }
+
+ @Override
+ protected float attackDelay() {
+ return 1.6f;
+ }
+
+ @Override
+ protected boolean doAttack(Char enemy) {
+
+ spend(attackDelay());
+
+ boolean rayVisible = false;
+
+ for (int i : beam.subPath(0, beam.dist)) {
+ if (Dungeon.visible[i]) {
+ rayVisible = true;
+ }
+ }
+
+ if (rayVisible) {
+ sprite.attack(beam.collisionPos);
+ return false;
+ } else {
+ attack(enemy);
+ return true;
+ }
+ }
+
+ @Override
+ public boolean attack(Char enemy) {
+
+ for (int pos : beam.subPath(1, beam.dist)) {
+
+ Char ch = Actor.findChar( pos );
+ if (ch == null) {
+ continue;
+ }
+
+ if (hit(this, ch, true)) {
+ ch.damage(Random.NormalIntRange(14, 20+adj(0)), this);
+
+ if (Dungeon.visible[pos]) {
+ ch.sprite.flash();
+ CellEmitter.center(pos).burst(PurpleParticle.BURST,
+ Random.IntRange(1, 2));
+ }
+
+ if (!ch.isAlive() && ch == Dungeon.hero) {
+ Dungeon.fail(Messages.format(ResultDescriptions.MOB));
+ //GLog.n(Messages.get(this, "kill"));
+ }
+ } else {
+ ch.sprite.showStatus(CharSprite.NEUTRAL, ch.defenseVerb());
+ }
+ }
+
+ return true;
+ }
+
+
+ public static void spawnAroundChance(int pos) {
+ for (int n : Level.NEIGHBOURS4) {
+ int cell = pos + n;
+ if (Level.passable[cell] && Actor.findChar(cell) == null && Random.Float()<0.50f) {
+ spawnAt(cell);
+ }
+ }
+ }
+
+ public static Eye spawnAt(int pos) {
+ if (Level.passable[pos] && Actor.findChar(pos) == null) {
+
+ Eye e = new Eye();
+ e.pos = pos;
+ e.state = e.HUNTING;
+ GameScene.add(e, SPAWN_DELAY);
+
+ e.sprite.alpha(0);
+ e.sprite.parent.add(new AlphaTweener(e.sprite, 1, 0.5f));
+
+ return e;
+
+ } else {
+ return null;
+ }
+ }
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+ static {
+ RESISTANCES.add(WandOfDisintegration.class);
+ RESISTANCES.add(EnchantmentDark.class);
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+
+ private static final HashSet> IMMUNITIES = new HashSet>();
+ static {
+ IMMUNITIES.add(Terror.class);
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/FetidRat.java b/java/com/hmdzl/spspd/actors/mobs/FetidRat.java
new file mode 100644
index 00000000..d2bd95a3
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/FetidRat.java
@@ -0,0 +1,93 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.actors.mobs.npcs.Ghost;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.Blob;
+import com.hmdzl.spspd.actors.blobs.StenchGas;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Ooze;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.sprites.FetidRatSprite;
+
+import com.watabou.utils.Random;
+
+ public class FetidRat extends Rat {
+
+ {
+ //name = "fetidrat";
+ spriteClass = FetidRatSprite.class;
+
+ HP = HT = 45;
+ evadeSkill = 5;
+
+ EXP = 4;
+
+ state = WANDERING;
+
+ properties.add(Property.BEAST);
+ properties.add(Property.MINIBOSS);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 12;
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(0, 2);
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+ if (Random.Int(3) == 0) {
+ Buff.affect(enemy, Ooze.class);
+ }
+
+ return damage;
+ }
+
+ @Override
+ public int defenseProc(Char enemy, int damage) {
+
+ GameScene.add(Blob.seed(pos, 20, StenchGas.class));
+
+ return super.defenseProc(enemy, damage);
+ }
+
+ @Override
+ public void die(Object cause) {
+ super.die(cause);
+
+ Ghost.Quest.process();
+ }
+
+ private static final HashSet> IMMUNITIES = new HashSet>();
+ static {
+ IMMUNITIES.add(StenchGas.class);
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+ }
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/mobs/Fiend.java b/java/com/hmdzl/spspd/actors/mobs/Fiend.java
new file mode 100644
index 00000000..84342950
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/Fiend.java
@@ -0,0 +1,167 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import com.hmdzl.spspd.actors.buffs.Silent;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Weakness;
+import com.hmdzl.spspd.items.Generator;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.mechanics.Ballistica;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.sprites.FiendSprite;
+
+import com.watabou.utils.Callback;
+import com.watabou.utils.Random;
+
+public class Fiend extends Mob implements Callback {
+
+ private static final float TIME_TO_ZAP = 2f;
+
+ private static final String TXT_SHADOWBOLT_KILLED = "%s's shadow bolt killed you...";
+
+ private static final float SPAWN_DELAY = 6f;
+
+ {
+ spriteClass = FiendSprite.class;
+ baseSpeed = 1.5f;
+ viewDistance = 4;
+ HP = HT = 80+(Dungeon.depth*Random.NormalIntRange(2, 5));
+ evadeSkill = 2;
+
+ EXP = 20;
+
+ loot = Generator.Category.SCROLL;
+ lootChance = 0.15f;
+
+ properties.add(Property.DEMONIC);
+ properties.add(Property.ELEMENT);
+
+ }
+
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(Dungeon.depth/2, Dungeon.depth);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 50;
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(5, 10);
+ }
+
+ @Override
+ protected boolean canAttack(Char enemy) { if (buff(Silent.class) != null){
+ return Level.adjacent(pos, enemy.pos) && (!isCharmedBy(enemy));
+ } else
+ return new Ballistica( pos, enemy.pos, Ballistica.MAGIC_BOLT).collisionPos == enemy.pos;
+ }
+
+ @Override
+ protected boolean doAttack(Char enemy) {
+
+ if (Level.adjacent(pos, enemy.pos)) {
+
+ return super.doAttack(enemy);
+
+ } else {
+
+ boolean visible = Level.fieldOfView[pos]
+ || Level.fieldOfView[enemy.pos];
+ if (visible) {
+ ((FiendSprite) sprite).zap(enemy.pos);
+ } else {
+ zap();
+ }
+
+ return !visible;
+ }
+ }
+
+ private void zap() {
+ spend(TIME_TO_ZAP);
+
+ if (hit(this, enemy, true)) {
+ if (enemy == Dungeon.hero && Random.Int(5) == 0) {
+ Buff.prolong(enemy, Weakness.class, Weakness.duration(enemy));
+ }
+
+ int dmg = Random.Int(20, 45);
+ enemy.damage(dmg, this);
+
+ if (!enemy.isAlive() && enemy == Dungeon.hero) {
+ Dungeon.fail( Messages.format(ResultDescriptions.MOB));
+ //GLog.n(Messages.get(this, "kill"));
+ }
+ } else {
+ enemy.sprite.showStatus(CharSprite.NEUTRAL, enemy.defenseVerb());
+ }
+ }
+
+ public void onZapComplete() {
+ zap();
+ next();
+ }
+
+ @Override
+ public void call() {
+ next();
+ }
+
+ public static void spawnAround(int pos) {
+ for (int n : Level.NEIGHBOURS4) {
+ int cell = pos + n;
+ if (Level.passable[cell] && Actor.findChar(cell) == null) {
+ spawnAt(cell);
+ }
+ }
+ }
+
+ public static void spawnAroundChance(int pos) {
+ for (int n : Level.NEIGHBOURS4) {
+ int cell = pos + n;
+ if (Level.passable[cell] && Actor.findChar(cell) == null && Random.Float() < 0.75f) {
+ spawnAt(cell);
+ }
+ }
+ }
+
+ public static Fiend spawnAt(int pos) {
+
+ Fiend b = new Fiend();
+
+ b.pos = pos;
+ b.state = b.HUNTING;
+ GameScene.add(b, SPAWN_DELAY);
+
+ return b;
+
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/FireElemental.java b/java/com/hmdzl/spspd/actors/mobs/FireElemental.java
new file mode 100644
index 00000000..a13aa6c0
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/FireElemental.java
@@ -0,0 +1,115 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.Fire;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Burning;
+import com.hmdzl.spspd.actors.buffs.Chill;
+import com.hmdzl.spspd.actors.buffs.Frost;
+import com.hmdzl.spspd.effects.Speck;
+import com.hmdzl.spspd.items.wands.WandOfFirebolt;
+import com.hmdzl.spspd.items.potions.PotionOfLiquidFlame;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.sprites.FireElementalSprite;
+import com.watabou.utils.Random;
+
+public class FireElemental extends Mob {
+
+ {
+ spriteClass = FireElementalSprite.class;
+
+ HP = HT = 120+(adj(0)*Random.NormalIntRange(4, 7));
+ evadeSkill = 20+adj(0);
+
+ EXP = 15;
+ maxLvl = 30;
+
+ flying = true;
+
+ loot = new PotionOfLiquidFlame();
+ lootChance = 0.1f;
+
+ lootOther = new WandOfFirebolt();
+ lootChanceOther = 0.02f; // by default, see die()
+
+ properties.add(Property.ELEMENT);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(16, 20+adj(1));
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 25+adj(1);
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(0, 5);
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+ if (Random.Int(2) == 0) {
+ Buff.affect(enemy, Burning.class).reignite(enemy);
+ }
+
+ return damage;
+ }
+
+ @Override
+ protected boolean canAttack(Char enemy) {
+ return Dungeon.level.distance( pos, enemy.pos ) <= 2 ;
+ }
+
+ @Override
+ public void add(Buff buff) {
+ if (buff instanceof Burning) {
+ if (HP < HT) {
+ HP++;
+ sprite.emitter().burst(Speck.factory(Speck.HEALING), 1);
+ }
+ } else if (buff instanceof Frost || buff instanceof Chill) {
+ if (Level.water[this.pos])
+ damage(Random.NormalIntRange(HT / 2, HT), buff);
+ else
+ damage(Random.NormalIntRange(1, HT * 2 / 3), buff);
+ } else {
+ super.add(buff);
+ }
+ }
+
+ private static final HashSet> IMMUNITIES = new HashSet>();
+ static {
+ IMMUNITIES.add(Burning.class);
+ IMMUNITIES.add(Fire.class);
+ IMMUNITIES.add(WandOfFirebolt.class);
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/FireRabbit.java b/java/com/hmdzl/spspd/actors/mobs/FireRabbit.java
new file mode 100644
index 00000000..f4591ee5
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/FireRabbit.java
@@ -0,0 +1,98 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.Fire;
+import com.hmdzl.spspd.actors.buffs.ArmorBreak;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Burning;
+import com.hmdzl.spspd.actors.buffs.Locked;
+import com.hmdzl.spspd.items.wands.WandOfFirebolt;
+import com.hmdzl.spspd.items.potions.PotionOfLiquidFlame;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.sprites.FireRabbitSprite;
+import com.watabou.utils.Random;
+
+public class FireRabbit extends Mob {
+
+ {
+ spriteClass = FireRabbitSprite.class;
+
+ HP = HT = 80+(adj(0)*Random.NormalIntRange(3, 5));
+ evadeSkill = 8+adj(0);
+
+ EXP = 5;
+ maxLvl = 20;
+
+ loot = new PotionOfLiquidFlame();
+ lootChance = 0.1f;
+
+ properties.add(Property.ORC);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(6, 8+adj(0));
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 12;
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(5, 10);
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+ if (Random.Int(3) == 0) {
+ Buff.affect(enemy, Burning.class).reignite(enemy);
+ yell( Messages.get(this, "yell") );
+ }
+ if (Dungeon.level.distance( pos, enemy.pos ) == 3){
+ damage = 0;
+ Buff.affect(enemy, ArmorBreak.class,5f).level(20);
+ }
+ return damage;
+ }
+
+ @Override
+ protected boolean canAttack(Char enemy) {
+ return Dungeon.level.distance( pos, enemy.pos ) <= 3 ;
+ }
+
+
+ private static final HashSet> IMMUNITIES = new HashSet>();
+ static {
+ IMMUNITIES.add(Locked.class);
+ IMMUNITIES.add(Burning.class);
+ IMMUNITIES.add(Fire.class);
+ IMMUNITIES.add(WandOfFirebolt.class);
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/FishProtector.java b/java/com/hmdzl/spspd/actors/mobs/FishProtector.java
new file mode 100644
index 00000000..17ffb9ae
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/FishProtector.java
@@ -0,0 +1,146 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Invisibility;
+import com.hmdzl.spspd.actors.buffs.Silent;
+import com.hmdzl.spspd.effects.particles.SparkParticle;
+import com.hmdzl.spspd.items.VioletDewdrop;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.levels.traps.LightningTrap;
+import com.hmdzl.spspd.mechanics.Ballistica;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.sprites.FishProtectorSprite;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.watabou.noosa.Camera;
+import com.watabou.utils.Callback;
+import com.watabou.utils.Random;
+
+public class FishProtector extends Mob implements Callback {
+
+ private static final float TIME_TO_ZAP = 2f;
+
+ private static final String TXT_LIGHTNING_KILLED = "%s's lightning bolt killed you...";
+
+ {
+ spriteClass = FishProtectorSprite.class;
+
+ EXP = 1;
+ state = HUNTING;
+ flying = true;
+
+ HP = HT = 300;
+ evadeSkill = 25;
+
+ loot = new VioletDewdrop();
+ lootChance = 1f;
+
+ properties.add(Property.ELEMENT);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(12, 20);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 25;
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(0, 15);
+ }
+
+
+ @Override
+ protected boolean canAttack(Char enemy) { if (buff(Silent.class) != null){
+ return Level.adjacent(pos, enemy.pos) && (!isCharmedBy(enemy));
+ } else
+ return new Ballistica( pos, enemy.pos, Ballistica.MAGIC_BOLT).collisionPos == enemy.pos;
+ }
+
+ @Override
+ protected boolean doAttack(Char enemy) {
+
+ if (Level.distance(pos, enemy.pos) <= 1) {
+
+ return super.doAttack(enemy);
+
+ } else {
+
+ boolean visible = Level.fieldOfView[pos]
+ || Level.fieldOfView[enemy.pos];
+ if (visible) {
+ ((FishProtectorSprite) sprite).zap(enemy.pos);
+ }
+
+ spend(TIME_TO_ZAP);
+
+ if (hit(this, enemy, true)) {
+ int dmg = Random.Int(25, 60);
+ if (Level.water[enemy.pos] && !enemy.flying) {
+ dmg *= 1.5f;
+ }
+ enemy.damage(dmg, this);
+
+ enemy.sprite.centerEmitter().burst(SparkParticle.FACTORY, 3);
+ enemy.sprite.flash();
+
+ if (enemy == Dungeon.hero) {
+
+ Camera.main.shake(2, 0.3f);
+
+ if (!enemy.isAlive()) {
+ Dungeon.fail( Messages.format(ResultDescriptions.MOB) );
+ //GLog.n(Messages.get(this, "zap_kill"));
+ }
+ }
+ } else {
+ enemy.sprite
+ .showStatus(CharSprite.NEUTRAL, enemy.defenseVerb());
+ }
+
+ return !visible;
+ }
+ }
+
+ @Override
+ public void call() {
+ next();
+ }
+
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+ static {
+ RESISTANCES.add(LightningTrap.Electricity.class);
+ RESISTANCES.add(Invisibility.class);
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/FlyingProtector.java b/java/com/hmdzl/spspd/actors/mobs/FlyingProtector.java
new file mode 100644
index 00000000..e4b34487
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/FlyingProtector.java
@@ -0,0 +1,152 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.actors.buffs.Silent;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.effects.particles.SparkParticle;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.levels.traps.LightningTrap;
+import com.hmdzl.spspd.mechanics.Ballistica;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.sprites.FlyingProtectorSprite;
+
+import com.watabou.noosa.Camera;
+import com.watabou.utils.Callback;
+import com.watabou.utils.Random;
+
+public class FlyingProtector extends Mob implements Callback {
+
+ private static final float TIME_TO_ZAP = 2f;
+
+ private static final float SPAWN_DELAY = 0.2f;
+
+
+ private static final String TXT_LIGHTNING_KILLED = "%s's lightning bolt killed you...";
+
+ {
+ spriteClass = FlyingProtectorSprite.class;
+
+ EXP = 5;
+ state = HUNTING;
+ flying = true;
+
+ HP = HT = 50 + Dungeon.depth * 4;
+ evadeSkill = 4 + Dungeon.depth * 1;
+
+ properties.add(Property.ELEMENT);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(20, 30);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return (int) ((9 + Dungeon.depth));
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(0, Dungeon.depth);
+ }
+
+ @Override
+ protected boolean canAttack(Char enemy) { if (buff(Silent.class) != null){
+ return Level.adjacent(pos, enemy.pos) && (!isCharmedBy(enemy));
+ } else
+ return new Ballistica( pos, enemy.pos, Ballistica.MAGIC_BOLT).collisionPos == enemy.pos;
+ }
+
+ @Override
+ protected boolean doAttack(Char enemy) {
+
+ if (Level.distance(pos, enemy.pos) <= 1) {
+
+ return super.doAttack(enemy);
+
+ } else {
+
+ boolean visible = Level.fieldOfView[pos]
+ || Level.fieldOfView[enemy.pos];
+ if (visible) {
+ ((FlyingProtectorSprite) sprite).zap(enemy.pos);
+ }
+
+ spend(TIME_TO_ZAP);
+
+ if (hit(this, enemy, true)) {
+ int dmg = Random.Int(25, 40);
+ if (Level.water[enemy.pos] && !enemy.flying) {
+ dmg *= 1.5f;
+ }
+ enemy.damage(dmg, this);
+
+ enemy.sprite.centerEmitter().burst(SparkParticle.FACTORY, 3);
+ enemy.sprite.flash();
+
+ if (enemy == Dungeon.hero) {
+
+ Camera.main.shake(2, 0.3f);
+
+ if (!enemy.isAlive()) {
+ Dungeon.fail( Messages.format(ResultDescriptions.MOB) );
+ //GLog.n(Messages.get(this, "kill"));
+ }
+ }
+ } else {
+ enemy.sprite
+ .showStatus(CharSprite.NEUTRAL, enemy.defenseVerb());
+ }
+
+ return !visible;
+ }
+ }
+
+ public static FlyingProtector spawnAt(int pos) {
+
+ FlyingProtector b = new FlyingProtector();
+
+ b.pos = pos;
+ b.state = b.HUNTING;
+ GameScene.add(b, SPAWN_DELAY);
+ return b;
+ }
+
+ @Override
+ public void call() {
+ next();
+ }
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+ static {
+ RESISTANCES.add(LightningTrap.Electricity.class);
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/ForestProtector.java b/java/com/hmdzl/spspd/actors/mobs/ForestProtector.java
new file mode 100644
index 00000000..d846e340
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/ForestProtector.java
@@ -0,0 +1,144 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.actors.buffs.Silent;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.Statistics;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.effects.particles.SparkParticle;
+import com.hmdzl.spspd.items.VioletDewdrop;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.levels.traps.LightningTrap;
+import com.hmdzl.spspd.mechanics.Ballistica;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.sprites.ForestProtectorSprite;
+
+import com.watabou.noosa.Camera;
+import com.watabou.utils.Callback;
+import com.watabou.utils.Random;
+
+public class ForestProtector extends Mob implements Callback {
+
+ private static final float TIME_TO_ZAP = 2f;
+
+ private static final String TXT_LIGHTNING_KILLED = "%s's lightning bolt killed you...";
+
+ {
+ spriteClass = ForestProtectorSprite.class;
+
+
+ EXP = 1;
+ state = HUNTING;
+ flying = true;
+
+ HP = HT = 250;
+ evadeSkill = 10;
+
+ loot = new VioletDewdrop();
+ lootChance = 1f;
+
+ properties.add(Property.ELEMENT);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(5, 10);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 16;
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(0, 5);
+ }
+
+ @Override
+ protected boolean canAttack(Char enemy) { if (buff(Silent.class) != null){
+ return Level.adjacent(pos, enemy.pos) && (!isCharmedBy(enemy));
+ } else
+ return new Ballistica( pos, enemy.pos, Ballistica.MAGIC_BOLT).collisionPos == enemy.pos;
+ }
+
+ @Override
+ protected boolean doAttack(Char enemy) {
+
+ if (Level.distance(pos, enemy.pos) <= 1) {
+
+ return super.doAttack(enemy);
+
+ } else {
+
+ boolean visible = Level.fieldOfView[pos]
+ || Level.fieldOfView[enemy.pos];
+ if (visible) {
+ ((ForestProtectorSprite) sprite).zap(enemy.pos);
+ }
+
+ spend(TIME_TO_ZAP);
+
+ if (hit(this, enemy, true)) {
+ int dmg = Random.Int(5+Math.round(Statistics.archersKilled/10), 10+Math.round(Statistics.archersKilled/5));
+ if (Level.water[enemy.pos] && !enemy.flying) {
+ dmg *= 1.5f;
+ }
+ enemy.damage(dmg, this);
+
+ enemy.sprite.centerEmitter().burst(SparkParticle.FACTORY, 3);
+ enemy.sprite.flash();
+
+ if (enemy == Dungeon.hero) {
+
+ Camera.main.shake(2, 0.3f);
+
+ if (!enemy.isAlive()) {
+ Dungeon.fail(Messages.format(ResultDescriptions.MOB));
+ //GLog.n(Messages.get(this, "kill"));
+ }
+ }
+ } else {
+ enemy.sprite
+ .showStatus(CharSprite.NEUTRAL, enemy.defenseVerb());
+ }
+
+ return !visible;
+ }
+ }
+
+ @Override
+ public void call() {
+ next();
+ }
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+ static {
+ RESISTANCES.add(LightningTrap.Electricity.class);
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/Gnoll.java b/java/com/hmdzl/spspd/actors/mobs/Gnoll.java
new file mode 100644
index 00000000..86f90540
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/Gnoll.java
@@ -0,0 +1,73 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.buffs.Locked;
+import com.hmdzl.spspd.items.Generator;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.Gold;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.sprites.GnollSprite;
+import com.watabou.utils.Random;
+
+public class Gnoll extends Mob {
+
+ {
+ spriteClass = GnollSprite.class;
+
+ HP = HT = 70+(adj(0)*Random.NormalIntRange(3, 7));
+ evadeSkill = 9+adj(1);
+
+
+ EXP = 10;
+ maxLvl = 18;
+
+ loot = Gold.class;
+ lootChance = 0.5f;
+
+ lootOther = Generator.random(Generator.Category.RANGEWEAPON);
+ lootChanceOther = 0.5f; // by default, see die()
+
+ properties.add(Property.ORC);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(10+adj(0), 20+adj(0));
+ }
+
+
+ @Override
+ protected boolean canAttack(Char enemy) {if (buff(Locked.class) != null){
+ return Level.adjacent(pos, enemy.pos) && (!isCharmedBy(enemy));
+ } else
+ return Dungeon.level.distance( pos, enemy.pos ) <= 2 ;
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 12+adj(0);
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(5, 8);
+ }
+
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/GnollArcher.java b/java/com/hmdzl/spspd/actors/mobs/GnollArcher.java
new file mode 100644
index 00000000..789cf9d6
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/GnollArcher.java
@@ -0,0 +1,129 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.Statistics;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Locked;
+import com.hmdzl.spspd.items.TreasureMap;
+import com.hmdzl.spspd.items.challengelists.SewerChallenge;
+import com.hmdzl.spspd.items.food.completefood.GoldenNut;
+import com.hmdzl.spspd.items.reward.SewerReward;
+import com.hmdzl.spspd.items.scrolls.ScrollOfSacrifice;
+import com.hmdzl.spspd.items.weapon.missiles.ForestDart;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.mechanics.Ballistica;
+import com.hmdzl.spspd.sprites.GnollArcherSprite;
+import com.hmdzl.spspd.utils.GLog;
+
+import com.hmdzl.spspd.messages.Messages;
+import com.watabou.utils.Random;
+
+public class GnollArcher extends Mob {
+
+ private static final String TXT_KILLCOUNT = "Gnoll Archer Kill Count: %s";
+ {
+ //name = "gnollarcher";
+ spriteClass = GnollArcherSprite.class;
+
+ HP = HT = 25 + Statistics.archersKilled;
+ evadeSkill = 5;
+
+ EXP = 1;
+
+ baseSpeed = 0.9f;
+
+ state = WANDERING;
+
+ properties.add(Property.ORC);
+
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 30;
+ }
+
+ @Override
+ protected boolean canAttack(Char enemy) {
+ Ballistica attack = new Ballistica( pos, enemy.pos, Ballistica.PROJECTILE);
+ if (buff(Locked.class) != null){
+ return Level.adjacent(pos, enemy.pos) && (!isCharmedBy(enemy));
+ } else
+
+ return !Level.adjacent(pos, enemy.pos) && attack.collisionPos == enemy.pos;
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(1+Math.round(Statistics.archersKilled/10), 8+Math.round(Statistics.archersKilled/5));
+ }
+
+ @Override
+ public int drRoll() {
+ return 0;
+ }
+
+ @Override
+ protected boolean getCloser(int target) {
+ if (Level.adjacent(pos, enemy.pos)) {
+ return getFurther(target);
+ } else {
+ return super.getCloser(target);
+ }
+ }
+
+ @Override
+ public void die(Object cause) {
+ super.die(cause);
+ if (Dungeon.depth > 25) {
+ Dungeon.level.drop(new ForestDart(3), pos).sprite.drop();
+ }
+
+ Statistics.archersKilled++;
+ GLog.w(Messages.get(Mob.class, "killcount", Statistics.archersKilled));
+
+
+ if (!Dungeon.limitedDrops.sewerkey.dropped() && Dungeon.depth < 27) {
+ Dungeon.limitedDrops.sewerkey.drop();
+ Dungeon.level.drop(new SewerChallenge(), pos).sprite.drop();
+ explodeDew(pos);
+ } else {
+ explodeDew(pos);
+ }
+
+ if (Statistics.archersKilled == 25) {
+ Dungeon.limitedDrops.treasuremap.drop();
+ Dungeon.level.drop(new TreasureMap(), pos).sprite.drop();
+ }
+
+ if (Statistics.archersKilled == 50) {
+ Dungeon.level.drop(new ScrollOfSacrifice(), pos).sprite.drop();
+ }
+
+ if (Statistics.archersKilled == 100) {
+ Dungeon.level.drop(new SewerReward(), pos).sprite.drop();
+ }
+
+ if (Statistics.goldThievesKilled > 99 && Statistics.skeletonsKilled > 99
+ && Statistics.albinoPiranhasKilled > 99 && Statistics.archersKilled == 100 ) {
+ Dungeon.level.drop(new GoldenNut(), pos).sprite.drop();
+ }
+ }
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/mobs/GnollKing.java b/java/com/hmdzl/spspd/actors/mobs/GnollKing.java
new file mode 100644
index 00000000..28363e58
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/GnollKing.java
@@ -0,0 +1,337 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.items.quest.GnollClothes;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.items.Gold;
+import com.hmdzl.spspd.sprites.GnollKingSprite;
+import com.hmdzl.spspd.sprites.GnollKeeperSprite;
+import com.hmdzl.spspd.items.AdamantRing;
+import com.hmdzl.spspd.actors.buffs.Burning;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.actors.Actor;
+import com.hmdzl.spspd.actors.blobs.Blob;
+import com.hmdzl.spspd.actors.blobs.CorruptGas;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Cripple;
+import com.hmdzl.spspd.actors.buffs.Roots;
+import com.hmdzl.spspd.actors.buffs.Weakness;
+import com.hmdzl.spspd.actors.buffs.Amok;
+import com.hmdzl.spspd.actors.buffs.Bleeding;
+import com.hmdzl.spspd.actors.buffs.Charm;
+import com.hmdzl.spspd.actors.buffs.Poison;
+import com.hmdzl.spspd.actors.buffs.Sleep;
+import com.hmdzl.spspd.actors.buffs.Terror;
+import com.hmdzl.spspd.actors.buffs.Vertigo;
+import com.hmdzl.spspd.actors.buffs.Paralysis;
+import com.hmdzl.spspd.actors.blobs.ToxicGas;
+import com.hmdzl.spspd.items.scrolls.ScrollOfPsionicBlast;
+import com.hmdzl.spspd.items.weapon.enchantments.EnchantmentDark;
+import com.hmdzl.spspd.levels.Level;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Random;
+
+public class GnollKing extends Mob {
+
+ protected int breaks = 0;
+
+ {
+ spriteClass = GnollKingSprite.class;
+
+ HP = HT = 1000;
+ evadeSkill = 0;
+
+ EXP = 30;
+
+ baseSpeed = 0.75f;
+
+ loot = new GnollClothes();
+ lootChance = 1f;
+
+ FLEEING = new Fleeing();
+
+ properties.add(Property.ORC);
+ properties.add(Property.BOSS);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(15,25);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 100;
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(0, 5);
+ }
+
+ @Override
+ public float speed() {
+ if (breaks == 1) return 4*super.speed();
+ else return super.speed();
+ }
+
+
+ @Override
+ public boolean act() {
+
+ if( 3 - breaks > 4 * HP / HT ) {
+ breaks++;
+ yell(Messages.get(this,"angry"));
+ return true;
+ }
+
+ if (breaks == 1){
+ state = FLEEING;
+ }
+
+ if (breaks == 2){
+ state = HUNTING;
+ }
+
+ if (breaks > 0){
+ int newPos = -1;
+ for (int i = 0; i < 10; i++) {
+ newPos = Dungeon.level.randomRespawnCellMob();
+ if (newPos != -1) {
+ break;
+ }
+ }
+ if (Dungeon.level.mobs.size()<4){
+ GnollKeeper.spawnAroundChance(newPos);
+ }
+ }
+ return super.act();
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+
+ if (breaks == 0){
+ if (Random.Int(2) == 0) {
+ if(enemy == Dungeon.hero){
+ Buff.prolong(enemy, Cripple.class, 3 );
+ }
+ }
+ }
+
+
+ if (breaks == 2){
+ if (Random.Int(2) == 0) {
+ if(enemy == Dungeon.hero){
+ Buff.prolong(enemy, Roots.class, 3 );
+ }
+ }
+ }
+
+ if (breaks == 3){
+ if (Random.Int(2) == 0) {
+ if(enemy == Dungeon.hero){
+ Buff.prolong(enemy, Weakness.class, 3);
+ }
+ }
+ }
+
+ return damage;
+ }
+
+ @Override
+ public int defenseProc(Char enemy, int damage) {
+
+ int dmg = Random.IntRange(0, 20);
+
+ if (breaks == 3){
+ if (dmg > 0 || (Random.Int(3) == 0 )) {
+ enemy.damage(dmg, this);
+ }
+ }
+ return super.defenseProc(enemy, damage);
+ }
+
+ @Override
+ public void damage(int dmg, Object src) {
+
+ dmg = Random.Int(10,20);
+
+ if (breaks == 2){
+ if (dmg > 15){
+ GameScene.add(Blob.seed(pos, 30, CorruptGas.class));
+ }
+ }
+ super.damage(dmg, src);
+ }
+
+ @Override
+ protected boolean canAttack(Char enemy) {
+
+ if (breaks == 2){
+ return Dungeon.level.distance( pos, enemy.pos ) <= 2 ;}
+ else return Dungeon.level.distance( pos, enemy.pos ) <= 1;
+ }
+
+ @Override
+ public void die(Object cause) {
+
+ super.die(cause);
+
+ GameScene.bossSlain();
+ Dungeon.level.drop(new AdamantRing(), pos).sprite.drop();
+ Dungeon.level.drop(new Gold(Random.Int(1000, 1500)), pos).sprite.drop();
+
+
+ Dungeon.gnollkingkilled=true;
+
+ yell(Messages.get(this,"die"));
+
+ }
+
+ @Override
+ public void notice() {
+ super.notice();
+ yell(Messages.get(this,"notice"));
+ }
+
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+ private static final HashSet> IMMUNITIES = new HashSet>();
+ static {
+ RESISTANCES.add(ToxicGas.class);
+ RESISTANCES.add(Poison.class);
+ RESISTANCES.add(EnchantmentDark.class);
+ IMMUNITIES.add(EnchantmentDark.class);
+ IMMUNITIES.add(Terror.class);
+ IMMUNITIES.add(Amok.class);
+ IMMUNITIES.add(Charm.class);
+ IMMUNITIES.add(Sleep.class);
+ IMMUNITIES.add(Burning.class);
+ IMMUNITIES.add(ToxicGas.class);
+ IMMUNITIES.add(ScrollOfPsionicBlast.class);
+ IMMUNITIES.add(Vertigo.class);
+ IMMUNITIES.add(Paralysis.class);
+ IMMUNITIES.add(Bleeding.class);
+ IMMUNITIES.add(CorruptGas.class);
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+
+ private static final String BREAKS = "breaks";
+
+ @Override
+ public void storeInBundle( Bundle bundle ) {
+ super.storeInBundle(bundle);
+ bundle.put( BREAKS, breaks );
+ }
+
+ @Override
+ public void restoreFromBundle( Bundle bundle ) {
+ super.restoreFromBundle(bundle);
+ breaks = bundle.getInt( BREAKS );
+ }
+ public static class GnollKeeper extends Mob {
+
+ private static final float SPAWN_DELAY = 10f;
+
+ {
+ //name = "Gnoll Keeper";
+ spriteClass = GnollKeeperSprite.class;
+
+ HP = HT = 5;
+ evadeSkill = 10;
+
+ EXP = 0;
+
+ state = WANDERING;
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 36;
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(0, 0);
+ }
+
+ @Override
+ public int drRoll() {
+ return 1;
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+ yell(Messages.get(this ,"safe"));
+ return damage;
+ }
+
+ @Override
+ public boolean act() {
+
+ return super.act();
+ }
+
+ public static void spawnAround(int pos) {
+ for (int n : Level.NEIGHBOURS4) {
+ int cell = pos + n;
+ if (Level.passable[cell] && Actor.findChar(cell) == null) {
+ spawnAt(cell);
+ }
+ }
+ }
+
+ public static void spawnAroundChance(int pos) {
+ for (int n : Level.NEIGHBOURS4) {
+ int cell = pos + n;
+ if (Level.passable[cell] && Actor.findChar(cell) == null && Random.Float() < 0.75f) {
+ spawnAt(cell);
+ }
+ }
+ }
+
+ public static GnollKeeper spawnAt(int pos) {
+
+ GnollKeeper g1 = new GnollKeeper();
+
+ g1.pos = pos;
+ g1.state = g1.HUNTING;
+ GameScene.add(g1, SPAWN_DELAY);
+
+ return g1;
+
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/mobs/GnollShaman.java b/java/com/hmdzl/spspd/actors/mobs/GnollShaman.java
new file mode 100644
index 00000000..ef9e1f90
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/GnollShaman.java
@@ -0,0 +1,145 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.actors.buffs.Silent;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.ResultDescriptions;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.effects.particles.SparkParticle;
+import com.hmdzl.spspd.items.Generator;
+import com.hmdzl.spspd.items.wands.WandOfLightning;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.levels.traps.LightningTrap;
+import com.hmdzl.spspd.mechanics.Ballistica;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.sprites.ShamanSprite;
+
+import com.watabou.noosa.Camera;
+import com.watabou.utils.Callback;
+import com.watabou.utils.Random;
+
+public class GnollShaman extends Mob implements Callback {
+
+ private static final float TIME_TO_ZAP = 2f;
+
+ private static final String TXT_LIGHTNING_KILLED = "%s's lightning bolt killed you...";
+
+ {
+ spriteClass = ShamanSprite.class;
+
+ HP = HT = 80+(adj(0)*Random.NormalIntRange(2, 5));
+ evadeSkill = 15+adj(0);
+
+ EXP = 10;
+ maxLvl = 25;
+
+ loot = Generator.Category.SCROLL;
+ lootChance = 0.15f;
+
+ lootOther = new WandOfLightning();
+ lootChanceOther = 0.02f;
+
+ properties.add(Property.ORC);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(14, 20+adj(0));
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 16+adj(0);
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(0, 4);
+ }
+
+ @Override
+ protected boolean canAttack(Char enemy) { if (buff(Silent.class) != null){
+ return Level.adjacent(pos, enemy.pos) && (!isCharmedBy(enemy));
+ } else
+ return new Ballistica( pos, enemy.pos, Ballistica.MAGIC_BOLT).collisionPos == enemy.pos;
+ }
+
+ @Override
+ protected boolean doAttack(Char enemy) {
+
+ if (Level.distance(pos, enemy.pos) <= 1) {
+
+ return super.doAttack(enemy);
+
+ } else {
+
+ boolean visible = Level.fieldOfView[pos]
+ || Level.fieldOfView[enemy.pos];
+ if (visible) {
+ ((ShamanSprite) sprite).zap(enemy.pos);
+ }
+
+ spend(TIME_TO_ZAP);
+
+ if (hit(this, enemy, true)) {
+ int dmg = Random.Int(2+adj(0), 12+adj(3));
+ if (Level.water[enemy.pos] && !enemy.flying) {
+ dmg *= 1.5f;
+ }
+ enemy.damage(dmg, this);
+
+ enemy.sprite.centerEmitter().burst(SparkParticle.FACTORY, 3);
+ enemy.sprite.flash();
+
+ if (enemy == Dungeon.hero) {
+
+ Camera.main.shake(2, 0.3f);
+
+ if (!enemy.isAlive()) {
+ Dungeon.fail( Messages.format(ResultDescriptions.MOB));
+ //GLog.n(Messages.get(this, "zap_kill"));
+ }
+ }
+ } else {
+ enemy.sprite
+ .showStatus(CharSprite.NEUTRAL, enemy.defenseVerb());
+ }
+
+ return !visible;
+ }
+ }
+
+ @Override
+ public void call() {
+ next();
+ }
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+ static {
+ RESISTANCES.add(LightningTrap.Electricity.class);
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/GnollTrickster.java b/java/com/hmdzl/spspd/actors/mobs/GnollTrickster.java
new file mode 100644
index 00000000..2e11f5d4
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/GnollTrickster.java
@@ -0,0 +1,127 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import com.hmdzl.spspd.actors.buffs.Locked;
+import com.hmdzl.spspd.actors.mobs.npcs.Ghost;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.Blob;
+import com.hmdzl.spspd.actors.blobs.Fire;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Burning;
+import com.hmdzl.spspd.actors.buffs.Poison;
+import com.hmdzl.spspd.items.Generator;
+import com.hmdzl.spspd.items.weapon.missiles.PoisonDart;
+import com.hmdzl.spspd.levels.Level;
+import com.hmdzl.spspd.mechanics.Ballistica;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.sprites.GnollTricksterSprite;
+
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Random;
+
+ public class GnollTrickster extends Gnoll {
+ {
+ //name = "gnolltrickster";
+ spriteClass = GnollTricksterSprite.class;
+
+ HP = HT = 60;
+ evadeSkill = 5;
+
+ EXP = 5;
+
+ state = WANDERING;
+
+ loot = Generator.random(PoisonDart.class);
+ lootChance = 1f;
+
+ properties.add(Property.ORC);
+ properties.add(Property.MINIBOSS);
+ }
+
+ private int combo = 0;
+
+ @Override
+ public int hitSkill(Char target) {
+ return 16;
+ }
+
+ @Override
+ protected boolean canAttack(Char enemy) {
+ Ballistica attack = new Ballistica( pos, enemy.pos, Ballistica.PROJECTILE);
+ if (buff(Locked.class) != null){
+ return Level.adjacent(pos, enemy.pos) && (!isCharmedBy(enemy));
+ } else
+ return !Level.adjacent( pos, enemy.pos ) && attack.collisionPos == enemy.pos;
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+ // The gnoll's attacks get more severe the more the player lets it
+ // hit them
+ combo++;
+ int effect = Random.Int(4) + combo;
+
+ if (effect > 2) {
+
+ if (effect >= 6 && enemy.buff(Burning.class) == null) {
+
+ if (Level.flamable[enemy.pos])
+ GameScene.add(Blob.seed(enemy.pos, 4, Fire.class));
+ Buff.affect(enemy, Burning.class).reignite(enemy);
+
+ } else
+ Buff.affect(enemy, Poison.class).set(
+ (effect - 2) * Poison.durationFactor(enemy));
+
+ }
+ return damage;
+ }
+
+ @Override
+ protected boolean getCloser(int target) {
+ combo = 0; // if he's moving, he isn't attacking, reset combo.
+ if (Level.adjacent(pos, enemy.pos)) {
+ return getFurther(target);
+ } else {
+ return super.getCloser(target);
+ }
+ }
+
+ @Override
+ public void die(Object cause) {
+ super.die(cause);
+
+ Ghost.Quest.process();
+ }
+
+ private static final String COMBO = "combo";
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(COMBO, combo);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ combo = bundle.getInt(COMBO);
+ }
+
+ }
\ No newline at end of file
diff --git a/java/com/hmdzl/spspd/actors/mobs/GoldCollector.java b/java/com/hmdzl/spspd/actors/mobs/GoldCollector.java
new file mode 100644
index 00000000..0167c275
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/GoldCollector.java
@@ -0,0 +1,71 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Buff;
+import com.hmdzl.spspd.actors.buffs.Taunt;
+import com.hmdzl.spspd.sprites.RatSprite;
+
+public class GoldCollector extends Mob {
+
+ {
+ spriteClass = RatSprite.class;
+
+ HP = HT = Dungeon.gold;
+ evadeSkill = Dungeon.gold;
+ baseSpeed = 3f;
+ flying = true;
+
+ state = WANDERING;
+
+ properties.add(Property.BOSS);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Dungeon.gold;
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return Dungeon.gold;
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+ if (enemy.buff(Taunt.class)== null && enemy == Dungeon.hero) {
+ Buff.affect(enemy, Taunt.class);
+ Dungeon.gold=0;
+ damage = 0;
+ this.damage(this.HT*2,this);
+ return damage;
+ } else return damage;
+ }
+
+ @Override
+ public int drRoll() {
+ return Dungeon.gold;
+ }
+
+ @Override
+ public void add( Buff buff ) {
+ //in other words, can't be directly affected by buffs/debuffs.
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/GoldOrc.java b/java/com/hmdzl/spspd/actors/mobs/GoldOrc.java
new file mode 100644
index 00000000..6fc7e545
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/GoldOrc.java
@@ -0,0 +1,98 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Amok;
+import com.hmdzl.spspd.actors.blobs.Blob;
+import com.hmdzl.spspd.actors.blobs.CorruptGas;
+import com.hmdzl.spspd.actors.buffs.Terror;
+import com.hmdzl.spspd.actors.buffs.Vertigo;
+import com.hmdzl.spspd.sprites.GoldOrcSprite;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.watabou.utils.Random;
+
+public class GoldOrc extends Mob {
+
+ {
+ spriteClass = GoldOrcSprite.class;
+ state = SLEEPING;
+
+ HP = HT = 500;
+ evadeSkill = 35;
+
+ EXP = 25;
+
+ properties.add(Property.ORC);
+ properties.add(Property.DEMONIC);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(55, 115);
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 55;
+ }
+
+ @Override
+ protected float attackDelay() {
+ return 1.5f;
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(16, 32);
+ }
+
+ @Override
+ public void damage(int dmg, Object src) {
+ if (dmg > HT/8){
+ GameScene.add(Blob.seed(pos, 30, CorruptGas.class));
+ }
+ super.damage(dmg, src);
+ }
+
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+ static {
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+
+ private static final HashSet> IMMUNITIES = new HashSet>();
+ static {
+ IMMUNITIES.add(Amok.class);
+ IMMUNITIES.add(Terror.class);
+ IMMUNITIES.add(CorruptGas.class);
+ IMMUNITIES.add(Vertigo.class);
+
+ }
+
+ @Override
+ public HashSet> immunities() {
+ return IMMUNITIES;
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/GoldThief.java b/java/com/hmdzl/spspd/actors/mobs/GoldThief.java
new file mode 100644
index 00000000..bda7c078
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/GoldThief.java
@@ -0,0 +1,182 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import com.hmdzl.spspd.items.challengelists.CityChallenge;
+import com.hmdzl.spspd.items.food.completefood.GoldenNut;
+import com.hmdzl.spspd.items.reward.CityReward;
+import com.hmdzl.spspd.items.scrolls.ScrollOfSacrifice;
+import com.hmdzl.spspd.messages.Messages;
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.Statistics;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.buffs.Terror;
+import com.hmdzl.spspd.actors.hero.Hero;
+import com.hmdzl.spspd.items.AncientCoin;
+import com.hmdzl.spspd.items.Gold;
+import com.hmdzl.spspd.items.Item;
+import com.hmdzl.spspd.sprites.CharSprite;
+import com.hmdzl.spspd.sprites.GoldThiefSprite;
+import com.hmdzl.spspd.utils.GLog;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.Random;
+
+public class GoldThief extends Mob {
+
+ protected static final String TXT_STOLE = "%s stole %s gold from you!";
+ private static final String TXT_KILLCOUNT = "Gold Thief Kill Count: %s";
+
+ public Item item;
+
+ {
+ spriteClass = GoldThiefSprite.class;
+
+ HP = HT = 100+Statistics.goldThievesKilled;
+ evadeSkill = 26;
+
+ EXP = 1;
+
+ FLEEING = new Fleeing();
+
+ properties.add(Property.ELF);
+ }
+
+ private int goldtodrop = 0;
+
+ private static final String GOLDTODROP = "goldtodrop";
+
+ @Override
+ public void storeInBundle(Bundle bundle) {
+ super.storeInBundle(bundle);
+ bundle.put(GOLDTODROP, goldtodrop);
+ }
+
+ @Override
+ public void restoreFromBundle(Bundle bundle) {
+ super.restoreFromBundle(bundle);
+ goldtodrop = bundle.getInt(GOLDTODROP);
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(20, 30+Statistics.goldThievesKilled/2);
+ }
+
+ @Override
+ protected float attackDelay() {
+ return 0.75f;
+ }
+
+ @Override
+ public void die(Object cause) {
+
+ super.die(cause);
+ Statistics.goldThievesKilled++;
+ GLog.w(Messages.get(Mob.class,"killcount",Statistics.goldThievesKilled));
+
+
+ if (item != null) {
+ Dungeon.level.drop(item, pos).sprite.drop();
+ }
+
+ if (!Dungeon.limitedDrops.citykey.dropped() && Dungeon.depth<27) {
+ Dungeon.limitedDrops.citykey.drop();
+ Dungeon.level.drop(new CityChallenge(), pos).sprite.drop();
+ explodeDew(pos);
+ } else {
+ explodeDew(pos);
+ }
+
+ if(Statistics.goldThievesKilled == 25) {
+ Dungeon.limitedDrops.ancientcoin.drop();
+ Dungeon.level.drop(new AncientCoin(), pos).sprite.drop();
+ }
+
+ if(Statistics.goldThievesKilled == 50) {
+ Dungeon.level.drop(new ScrollOfSacrifice(), pos).sprite.drop();
+ }
+
+ if(Statistics.goldThievesKilled == 100) {
+ Dungeon.level.drop(new CityReward(), pos).sprite.drop();
+ }
+
+ if (Statistics.goldThievesKilled == 100 && Statistics.skeletonsKilled>99
+ && Statistics.albinoPiranhasKilled>99 && Statistics.archersKilled>99){
+ Dungeon.level.drop(new GoldenNut(), pos).sprite.drop();
+ }
+
+ }
+
+ @Override
+ protected Item createLoot() {
+ return new Gold(Random.NormalIntRange(goldtodrop+50, goldtodrop+100));
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 40;
+ }
+
+ @Override
+ public int drRoll() {
+ return 13+Math.round((Statistics.goldThievesKilled+1/10)+1);
+ }
+
+ @Override
+ public int attackProc(Char enemy, int damage) {
+ if (item == null && enemy instanceof Hero && steal((Hero) enemy)) {
+ state = FLEEING;
+ }
+
+ return damage;
+ }
+
+ @Override
+ public int defenseProc(Char enemy, int damage) {
+ if (state == FLEEING) {
+ Dungeon.level.drop(new Gold(), pos).sprite.drop();
+ }
+
+ return damage;
+ }
+
+ protected boolean steal(Hero hero) {
+
+ Gold gold = new Gold(Random.Int(100, 300));
+ if (gold.quantity() > 0) {
+ goldtodrop = Math.min((gold.quantity()+100),Dungeon.gold);
+ Dungeon.gold -= goldtodrop;
+ GLog.w(Messages.get(GoldThief.class, "stole", gold.quantity()));
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private class Fleeing extends Mob.Fleeing {
+ @Override
+ protected void nowhereToRun() {
+ if (buff(Terror.class) == null) {
+ sprite.showStatus(CharSprite.NEGATIVE, Messages.get(Mob.class, "rage"));
+ state = HUNTING;
+ } else {
+ super.nowhereToRun();
+ }
+ }
+ }
+}
diff --git a/java/com/hmdzl/spspd/actors/mobs/Golem.java b/java/com/hmdzl/spspd/actors/mobs/Golem.java
new file mode 100644
index 00000000..c1a6ffae
--- /dev/null
+++ b/java/com/hmdzl/spspd/actors/mobs/Golem.java
@@ -0,0 +1,124 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2014 Oleg Dolya
+ *
+ * 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.hmdzl.spspd.actors.mobs;
+
+import java.util.HashSet;
+
+import com.hmdzl.spspd.Dungeon;
+import com.hmdzl.spspd.items.StoneOre;
+import com.hmdzl.spspd.items.Generator;
+import com.hmdzl.spspd.actors.Char;
+import com.hmdzl.spspd.actors.blobs.Blob;
+import com.hmdzl.spspd.actors.blobs.TarGas;
+import com.hmdzl.spspd.actors.buffs.Amok;
+import com.hmdzl.spspd.actors.buffs.Tar;
+import com.hmdzl.spspd.actors.buffs.Sleep;
+import com.hmdzl.spspd.actors.buffs.Terror;
+import com.hmdzl.spspd.actors.mobs.npcs.Imp;
+import com.hmdzl.spspd.scenes.GameScene;
+import com.hmdzl.spspd.sprites.GolemSprite;
+
+import com.watabou.utils.Random;
+
+public class Golem extends Mob {
+
+ {
+ spriteClass = GolemSprite.class;
+
+ HP = HT = 180+(adj(0)*Random.NormalIntRange(4, 7));
+ evadeSkill = 18+adj(1);
+
+ EXP = 15;
+ maxLvl = 30;
+
+ loot = new StoneOre();
+ lootChance = 0.5f;
+
+ properties.add(Property.MECH);
+ }
+
+ @Override
+ public boolean act() {
+ //GameScene.add(Blob.seed(pos, 30, TarGas.class));
+ return super.act();
+ }
+
+ @Override
+ public int damageRoll() {
+ return Random.NormalIntRange(20+adj(0), 60+adj(1));
+ }
+
+ @Override
+ public int hitSkill(Char target) {
+ return 28+adj(1);
+ }
+
+ @Override
+ protected float attackDelay() {
+ return 1.5f;
+ }
+
+ @Override
+ public int drRoll() {
+ return Random.NormalIntRange(10, 15);
+ }
+
+ @Override
+ public void damage(int dmg, Object src) {
+ if (dmg > HT/8){
+ GameScene.add(Blob.seed(pos, 30, TarGas.class));
+ }
+ super.damage(dmg, src);
+ }
+
+ @Override
+ public void die(Object cause) {
+
+ Imp.Quest.process(this);
+ if (Dungeon.limitedDrops.nornstones.count<6
+ && Random.Int(6)<3
+ ){
+ Dungeon.level.drop(Generator.random(Generator.Category.NORNSTONE), pos).sprite.drop();
+ Dungeon.limitedDrops.nornstones.count++;
+ }
+ super.die(cause);
+ }
+
+ private static final HashSet> RESISTANCES = new HashSet>();
+ static {
+ }
+
+ @Override
+ public HashSet> resistances() {
+ return RESISTANCES;
+ }
+
+ private static final HashSet