Generating an EARTHQUAKE o.O

Discussion in 'Plugin Development' started by thehutch, Dec 30, 2011.

  1. Offline

    thehutch

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Basically I am trying to create a "Earthquake" by simply getting all the blocks around a player and then randomly destroying them whilst also injuring players within the radius of the caster.

    Also if possible whilst the earthquake is happening there will be World effects like tnt effects

    Here is the current code which atm does completely nothing but I have been messing around with some stuff, I am just a little stuck on it:

    Code:java
    1.  
    2. public class Earthquake {
    3.  
    4. private int damage;
    5. private float mana;
    6. private float radius;
    7.  
    8. public Earthquake(int damage, float radius, float mana, Player p) {
    9. this.damage = damage;
    10. this.radius = radius;
    11. this.mana = mana;
    12. this.initiateEarthquake(p);
    13. }
    14.  
    15. public void initiateEarthquake(Player p) {
    16.  
    17. double locX = p.getLocation().getX();
    18. double locY = p.getLocation().getY();
    19. double locZ = p.getLocation().getZ();
    20.  
    21. Location startloc = new Location(p.getWorld(), locX, locY, locZ);
    22. Location end = new Location(p.getWorld(), locX+radius, locY+radius, locZ+radius);
    23.  
    24. }
    25.  
    26. private void HeroToThere(Location start, Location end, Player caster) {
    27.  
    28. double locX = caster.getLocation().getX();
    29. double locY = caster.getLocation().getY();
    30. double locZ = caster.getLocation().getZ();
    31.  
    32. HashSet<Block> blocks = new HashSet<Block>();
    33. Random rand = new Random();
    34.  
    35. for(int x=(int)locX ; x<this.radius ; x++) {
    36. for(int y=(int)locY ; y<this.radius ; y++) {
    37. for(int z=(int)locZ ; z<this.radius ; z++) {
    38. blocks.add(caster.getWorld().getBlockAt(x, y, z));
    39. }
    40. }
    41. }
    42.  
    43. }
    44.  
    45. private void checkForPlayers(Location start, Location end, Player caster) {
    46.  
    47. double locX = caster.getLocation().getX();
    48. double locY = caster.getLocation().getY();
    49. double locZ = caster.getLocation().getZ();
    50.  
    51. List<Entity> entities = caster.getNearbyEntities(locX, locY, locZ);
    52. int amount = 0;
    53.  
    54. for(Entity e : entities) {
    55. if (start.distanceSquared(end) > start.distanceSquared(e.getLocation())) {
    56. e.remove();
    57. amount++;
    58. }
    59. }
    60. caster.sendMessage(ChatColor.RED + "You killed " + amount + " entities");
    61. }
    62. }

    This post has been edited 1 time. It was last edited by thehutch Dec 30, 2011.
  2. Offline

    ItsHarry

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Okay, so what's the problem?
  3. Offline

    thehutch

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    I am stuck I have no idea on how to do the damage part to players and also the block destroying and the slow generating of the sphere around the player of world effects
  4. Offline

    ItsHarry

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    In that case, you should change the question to "How do destroy blocks around the player?" instead
  5. Offline

    thehutch

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    there is more to destroying blocks in this spell

    This post has been edited 3 times. It was last edited by thehutch Dec 30, 2011.
  6. Offline

    thehutch

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    any ideas ?
  7. Offline

    nkrecklow

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    This would create a drop of the block and remove the block.
    Code:
    public void explodeBlock(Block b) {
        Material m = b.getType();
        World w = b.getWorld();
        w.dropItemNaturally(m, 1);
        b.setType(Material.AIR);
    }
    This is the same, but it has a 0-5 chance of dropping its block, all are destroyed though.
    Code:
    public void explodeBlock(Block b) {
        World w = b.getWorld();
        Random r = new Random();
        if (r.nextInt(6) == 1) {
              Material m = b.getType();
              w.dropItemNaturally(m, 1);
        }
        b.setType(Material.AIR);
    }
    This could get nearby entities and damage them depending on distance.
    I'm also sure there's a much better way to do this using a equation.
    Code:
    for (Entity e : p.getNearbyEntities(5, 5, 5)) {
         if (e instanceof Player) {
              double d = e.getLocation().distance(p.getLocation());
              if (d <= 3 && d > 0) {
                        d = 16.0; // 8 hearts damage
              } else if (d > 3 && d <= 5) {
                        d = 10.0; // 5 hearts damage
              } else if (d == 0) {
                        d = 20.0; // 10 hearts damage
              }
              Player n = (Player) e;
              n.damage(d.intValue());
         }
    }

    This post has been edited 4 times. It was last edited by steaks4uce Dec 30, 2011.
  8. Offline

    thehutch

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    @steaks4uce

    hmm thanks for this it will come in handy although how could I put this in a delay so it doesn't just destroy them instantly?

    Also what about the world effects?
  9. Offline

    nkrecklow

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    You would need to make a list of all blocks being destoryed, then do something like this.
    This would pause one second, then destroy the block, and move on to the next in the list.
    Code:
    for (Block b : blocks) { // Given the list is called "blocks"
        plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
            public void run() {
                explodeBlock(b); // Explode using earlier methods
            }
        }, 10L); // Divide by 20 to get in seconds (this is 1/2 second)
    }

    This post has been edited 2 times. It was last edited by steaks4uce Dec 30, 2011.
  10. Offline

    nkrecklow

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Now, this would cause extreme lag, it creates a "tnt" effect for every block.
    Code:
    for (Block b : blocks) {
        World w = b.getWorld();
        w.createExplosion(b.getLocation(), 0); // Creates a explosion with no damage
    }
    This is a smoke effect that wouldn't cause nearly as much, but isn't as exciting.
    Code:
    for (Block b : blocks) {
        World w = b.getWorld();
        w.playEffect(b.getLocation(), Effect.SMOKE, 0); // Little smoke effect
    }

    This post has been edited 2 times. It was last edited by steaks4uce Dec 30, 2011.
  11. Offline

    nkrecklow

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    And I would integrate them, like this.
    Code:
    void explodeBlock(Block b) {
        World w = b.getWorld();
        Random r = new Random();
        if (r.nextInt(6) == 1) {
              Material m = b.getType();
              w.dropItemNaturally(m, 1);
        }
        b.setType(Material.AIR);
        w.playEffect(b.getLocation(), Effect.SMOKE, 0);
    }
    Code:
    for (Block b : blocks) { // Given the list is called "blocks"
        plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
            public void run() {
                explodeBlock(b); // Explode using earlier methods
            }
        }, 10L); // Divide by 20 to get in seconds (this is 1/2 second)
    }

    This post has been edited 1 time. It was last edited by steaks4uce Dec 30, 2011.
  12. Offline

    thehutch

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    I am trying to think of a way to make that dimished damage for greater distance any ideas? This is what I have:

    ((Player) e).setHealth((int) (((Player) e).getHealth() - damage % dist));
  13. Offline

    bergerkiller

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    @thehutch since I haven't seen it yet, I recommend using some Random in it too. You simply check the surface (using getHighestBlockAt) and randomly pick an x/z value to destroy a block. It's a lot better than busting holes into the ground. :)

    EDIT

    Misread, but maybe picking an x/z is a bit more versatile than using Randoms as a boolean to break a block or not.

    Also,
    The % is not a percentage, use / there. The % is basically a 'remainder return' (modulus) operator.
    Code:
    int a = 5 % 3; //2
    int b = 4 % 3; //3
    int c = 6 % 3; //0
    int d = 8 % 6 //2

    This post has been edited 5 times. It was last edited by bergerkiller Dec 31, 2011.
  14. Offline

    thehutch

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    @bergerkiller

    I know what % means :D thats why I used it, I am just simply trying to find the best way to a dimished damage based on how far you are away from the centre. The way I did was basically the greater the player is from the centre the smaller the remainder so less damage :p If you know any better way (more efficient) or more accurate way of doing this then please tell me.
  15. Offline

    bergerkiller

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    @thehutch well actually not, right now you simply divide the damage value by the distance from the explosion and take the remainder of that. If the damage is 3 and the distance is 0.5, this would return 0.

    Why not use a divide calculation there? Or multiple epicentres?
    Code:
    public double getDamageFactor(double distance) {
        if (distance < 2) return 2.0;
        return 4.0 / distance;
    }
    For example. You could add additional factors or offsets in it too.

    This post has been edited 1 time. It was last edited by bergerkiller Dec 31, 2011.
  16. Offline

    thehutch

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    @bergerkiller

    Ok well this is what I have so far if your wondering :

    Code:java
    1.  
    Code:java
    1.  
    2. public class Earthquake {
    3.  
    4. private int damage;
    5. private int density;
    6. private int skillLevel;
    7. private float mana;
    8. private float radius;
    9. private float coolDown;
    10.  
    11. public Earthquake(int damage, float radius, float mana, Player p,
    12. int skillLevel, float coolDown, int density) {
    13. this.damage = damage;
    14. this.skillLevel = skillLevel;
    15. this.radius = radius;
    16. this.mana = mana;
    17. this.coolDown = coolDown;
    18. this.density = density;
    19.  
    20. this.initiateEarthquake(p);
    21. }
    22.  
    23. public void initiateEarthquake(Player p) {
    24.  
    25. double locX = p.getLocation().getX();
    26. double locY = p.getLocation().getY();
    27. double locZ = p.getLocation().getZ();
    28.  
    29. Location startloc = new Location(p.getWorld(), locX, locY, locZ);
    30. Location end = new Location(p.getWorld(), locX+radius, locY+radius, locZ+radius);
    31.  
    32.  
    33.  
    34. }
    35.  
    36. private double getDamageFactor(double dist) {
    37. return (double)dist / damage;
    38. }
    39.  
    40. private void destroyBlocks(Block b) {
    41. World w = b.getWorld();
    42. Random r = new Random();
    43. if (r.nextInt(6) == 1 ) {
    44. w.dropItemNaturally(b.getLocation(), new ItemStack(1));
    45. b.setType(Material.AIR);
    46. }
    47. w.playEffect(b.getLocation(), Effect.SMOKE, density);
    48. }
    49.  
    50. private void HeroToThere(Location start, Location end, Player caster) {
    51.  
    52. double locX = caster.getLocation().getX();
    53. double locY = caster.getLocation().getY();
    54. double locZ = caster.getLocation().getZ();
    55.  
    56. HashSet<Block> blocks = new HashSet<Block>();
    57. Random rand = new Random();
    58.  
    59. for(int x=(int)locX ; x<this.radius ; x++) {
    60. for(int y=(int)locY ; y<this.radius ; y++) {
    61. for(int z=(int)locZ ; z<this.radius ; z++) {
    62. blocks.add(caster.getWorld().getBlockAt(x, y, z));
    63. }
    64. }
    65. }
    66. }
    67.  
    68. private void checkForPlayers(Location start, Location end, Player caster) {
    69.  
    70. double locX = caster.getLocation().getX();
    71. double locY = caster.getLocation().getY();
    72. double locZ = caster.getLocation().getZ();
    73.  
    74. List<LivingEntity> le = caster.getWorld().getLivingEntities();
    75.  
    76. for(LivingEntity e : le) {
    77. if (start.distance(end) > start.distance(e.getLocation())) {
    78. e.setHealth((int)(e.getHealth() - this.getDamageFactor(start.distance(e.getLocation()))));
    79. }
    80. }
    81. }
    82. }
    83. [LEFT][/LEFT]


    This post has been edited 2 times. It was last edited by thehutch Dec 31, 2011.
  17. Offline

    bergerkiller

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    @thehutch
    Code:
    private double getDamageFactor(double dist) {
            return (double)dist / damage;
    }
    That can't be right..so the further away the player, the more damage? Shouldn't it be the other way around?

    This post has been edited 1 time. It was last edited by bergerkiller Dec 31, 2011.
  18. Offline

    thehutch

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    So I think I got everything but the expanding circle/box shape around the player? any ideas on how to do this? Since I know you did that crazy chunk stuff where depending on which way you were looking was which chunks loaded first :D
  19. Offline

    bergerkiller

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    You mean like a block tsunami? You could start off making a single function which moves all top-blocks one up in a rectangular pattern, increasing the radius every x times. This way you will see a wave of blocks rising up.
  20. Offline

    thehutch

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    You know of any fancy equations which could do so?
  21. Offline

    bergerkiller

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    @thehutch
    Um I don't have time to write something just now, but I can give some tips:
    - Make one function to raise a block region one up (Block from, Block to, int height)
    - Call this function 4 times (or more) to raise all the blocks.

    But, I guess a circular effect is a lot nicer, for that you'll need to use cosinus/sinus:
    Code:
    public void raiseRadius(Block middle, double radius) {
        Set<Block> toRaise = new HashSet<Block>();
        //go around the circle and find all blocks
        double accuracy = 0.1 * Math.PI;
        int dx, dz;
        for (double d = 0; d < 2 * Math.PI; d += accuracy) {
            dx = (int) (radius * Math.cos(d));
            dz = (int) (radius * Math.sin(d));
            toRaise.add(middle.getRelative(dx, 0, dz);
        }
        raise(toRaise);
    
    }
    public void raise(Set<Block> blocks) {
        for (Block block : blocks) {
            block.getRelative(BlockFace.UP).setTypeAndData(block.getType(), block.getData());
        block.setTypeId(0);
        }
    }
    Something like that. Accuracy needs to be calculated as well, based on the radius used.
  22. Offline

    thehutch

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    @bergerkiller

    Any idea on how to get a random block from the HashSet? there is no get(); for Sets.
    Could I use a List<Block> instead? Which is fastest?

    This post has been edited 1 time. It was last edited by thehutch Dec 31, 2011.
  23. Offline

    bergerkiller

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    @thehutch A set is needed, since the loop before it could return the same block twice. And those functions will move ALL blocks in the set one up, that's the idea. The idea is a circular ripple that moves from the middle outwards (radius becomes larger and larger)
  24. Offline

    thehutch

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Ok 2 things :D first is does this look right then?

    Code:
    class Earthquake {
    
        private int damage;
        private int density;
        private int skillLevel;
        private float mana;
        private float radius;
        private float coolDown;
        private long tickSpeed;
    
        public Earthquake(int damage, float radius, float mana, Player p,
                          int skillLevel, float coolDown, int density,
                          long tickSpeed) {
    
            this.damage = damage;
            this.skillLevel = skillLevel;
            this.radius = radius;
            this.mana = mana;
            this.coolDown = coolDown;
            this.density = density;
            this.tickSpeed = tickSpeed;
    
            this.initiateEarthquake(p);
        }
    
        public void initiateEarthquake(final Player p) {
    
            double locX = p.getLocation().getX();
            double locY = p.getLocation().getY();
            double locZ = p.getLocation().getZ();
    
            Location startloc = new Location(p.getWorld(), locX, locY, locZ);
            // Location end = new Location(p.getWorld(), locX + radius, locY +
            // radius, locZ + radius);
    
            Bukkit.getScheduler().scheduleSyncRepeatingTask(PluginMain.p, new Runnable() {
    
                public void run() {
                    checkForPlayers(p.getLocation(), p);
                }
            }, 20L, tickSpeed);
            HereToThere(p);
    
        }
    
        /**
         * Returns how much damage the player with take depending on how far they
         * are from the centre
         * @param dist
         * @return double
         */
        private double getDamageFactor(double dist) {
            return (double) damage / dist;
        }
    
        private void explodeBlock(Block b) {
            World w = b.getWorld();
            Random r = new Random();
            if (r.nextInt(6) == 1) {
                Material m = b.getType();
                w.dropItemNaturally(b.getLocation(), new ItemStack(m, 1));
            }
            b.setType(Material.AIR);
            w.playEffect(b.getLocation(), Effect.SMOKE, 0);
        }
    
        /**
         *
         * @param caster
         */
        private void HereToThere(Player caster) {
    
            double locX = caster.getLocation().getX();
            double locY = caster.getLocation().getY();
            double locZ = caster.getLocation().getZ();
    
            Set<Block> blocks = new HashSet<Block>();
    
            this.addBlocks(blocks, caster.getLocation().add(locX, locY-1, locZ).getBlock());
    
            Random rand = new Random();
            int destruction = (int)(Math.PI * (Math.pow(radius, 2))) / 2;
            while(destruction !=0) {
    
                for(final Block b : blocks) {
                    Bukkit.getScheduler().scheduleSyncRepeatingTask(PluginMain.p, new Runnable() {
    
                        public void run() {
                            explodeBlock(b);
                        }
                    }, 0, 10L);
                }
                destruction--;
            }
    
            while (damage != 0) {
                for (final Block b : blocks) {
                    Bukkit.getServer().getScheduler()
                            .scheduleSyncDelayedTask(PluginMain.p, new Runnable() {
                                public void run() {
                                    explodeBlock(b);
                                }
                            }, 100L);
                }
                damage--;
            }
        }
    
    
        private Set<Block> addBlocks(Set<Block> blocks, Block centre) {
    
            double accuracy = 0.1 * Math.PI;
            int dx, dy;
    
            for(double d=0 ; d<2*Math.PI ; d+=accuracy) {
                dx = (int)(radius * Math.cos(d));
                dy = (int)(radius * Math.sin(d));
                blocks.add(centre.getRelative(dx,0,dy));
            }
            raise(blocks);
            return blocks;
        }
    
        private void raise(Set<Block> blocks) {
            for (Block block : blocks) {
                block.getRelative(BlockFace.UP).setType(block.getType());
                block.getRelative(BlockFace.UP).setData(block.getData());
            block.setTypeId(0);
            }
        }
    
        private void checkForPlayers(Location start, Player caster) {
    
            List<LivingEntity> le = caster.getWorld().getLivingEntities();
    
            for (LivingEntity e : le) {
                if (radius > start.distance(e.getLocation())) {
                    e.setHealth((int) (e.getHealth() - this.getDamageFactor(start
                            .distance(e.getLocation()))));
                }
            }
        }
    }
    And secondly would you like to join my team who are creating this plugin, we would very much appreciated with your maths skills :D
  25. Offline

    bergerkiller

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    @thehutch neh sorry, got more than enough to do already :)
    I just like to throw in my knowledge now and then...

    It looks fine to me, but do test everything correctly, place it under a command or something. When you perform it, a scheduled sync task should update your animation (it is a block animation basically). What needs to happen, is that you update the blocks. But, I'll go ahead and make a function for ya. I feel like it :)

    The function will show a circular ripple extending from under the player.
  26. Offline

    bergerkiller

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    theguynextdoor likes this.
  27. Offline

    thehutch

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    Thank you very much :D Also I edited it a little since I saw you made it in your TrainCarts plugin :D

    Also how do I run it? Do I called the "makeEarthquake" class?
  28. Offline

    bergerkiller

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)

    This post has been edited 1 time. It was last edited by bergerkiller Dec 31, 2011.
  29. Offline

    Tomaz

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
  30. Offline

    thehutch

    dev.bukkit.org profile:
    CFUSERNAME
    My Plugins (CFCOUNT)
    @bergerkiller

    I seem to be having a problem starting the Earthquake, I have it linked upto a playerInteract event and I have debug messages running through and they are all hit but nothing happens :( This is how I call it like you said:

    Code:
                Block epicentre = p.getLocation().add(p.getLocation().getX(), p.getLocation().getY() - 1, p.getLocation().getZ()).getBlock();
                Earthquake e = new Earthquake(epicentre, 10);
                e.makeEarthquake(epicentre, c.getInt("Spells.Earthquake.radius"));
    

Share This Page