001/*
002 * Trident - A Multithreaded Server Alternative
003 * Copyright 2014 The TridentSDK Team
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package net.tridentsdk.server.entity.block;
019
020import net.tridentsdk.base.Block;
021import net.tridentsdk.base.Position;
022import net.tridentsdk.base.Substance;
023import net.tridentsdk.effect.sound.SoundEffectType;
024import net.tridentsdk.entity.block.PrimeTNT;
025import net.tridentsdk.entity.types.EntityType;
026import net.tridentsdk.event.entity.EntityExplodeEvent;
027import net.tridentsdk.server.data.RecordBuilder;
028import net.tridentsdk.server.event.EventProcessor;
029import net.tridentsdk.server.packets.play.out.PacketPlayOutExplosion;
030import net.tridentsdk.server.packets.play.out.PacketPlayOutSoundEffect;
031import net.tridentsdk.server.player.TridentPlayer;
032import net.tridentsdk.server.world.TridentChunk;
033import net.tridentsdk.util.Vector;
034
035import java.util.UUID;
036import java.util.concurrent.atomic.AtomicInteger;
037
038public class TridentPrimeTNT extends TridentFallingBlock implements PrimeTNT {
039    private volatile int fuse = 80; // 4 seconds by default
040    private volatile int radius = 4; // Sphere with 4 blocks radius
041
042    private volatile AtomicInteger countDown = new AtomicInteger(fuse);
043
044    public TridentPrimeTNT(UUID id, Position spawnLocation) {
045        super(id, spawnLocation);
046    }
047
048    @Override
049    protected void doTick() {
050        if (countDown.get() == 0) {
051            EntityExplodeEvent event = EventProcessor.fire(new EntityExplodeEvent(this, radius));
052            if (event.isIgnored()) {
053                return;
054            }
055
056            Position p = position();
057            int radius = this.radius; // Prevent the value from changing within operation
058
059            int minX = (int) (p.x() - radius);
060            int maxX = (int) (p.x() + radius);
061            int minY = (int) (p.y() - radius);
062            int maxY = (int) (p.y() + radius);
063            int minZ = (int) (p.z() - radius);
064            int maxZ = (int) (p.z() + radius);
065
066            RecordBuilder[] records = new RecordBuilder[(int) Math.pow(radius * 2, 3)];
067            int recordIdx = 0;
068
069            for (int i = minX; i < maxX; i++) {
070                for (int j = minY; j < maxY; j++) {
071                    for (int k = minZ; k < maxZ; k++) {
072                        Block block = p.world().blockAt(new Position(p.world(), i, j, k));
073                        ((TridentChunk) p.world().chunkAt(i / 16, k / 16, false))
074                                .setAt(i, j, k, Substance.AIR, (byte) 0, (byte) 0, (byte) 0);
075                        records[recordIdx] = new RecordBuilder()
076                                .setX((byte) i)
077                                .setY((byte) j)
078                                .setZ((byte) k)
079                                .setData(block.meta())
080                                .setBlockId(block.substance().id());
081                        recordIdx++;
082                    }
083                }
084            }
085
086            PacketPlayOutExplosion explosion = new PacketPlayOutExplosion();
087            explosion.set("loc", p)
088                    .set("recordCount", records.length)
089                    .set("records", records)
090                    .set("velocity", new Vector(radius, radius, radius));
091
092            PacketPlayOutSoundEffect sound = new PacketPlayOutSoundEffect();
093            sound.set("sound", SoundEffectType.RANDOM_EXPLODE).set("loc", p).set("volume", 50).set("pitch", 20);
094
095            TridentPlayer.sendFiltered(explosion, player -> player.world().equals(world()));
096            TridentPlayer.sendFiltered(sound, player -> player.world().equals(world()));
097        }
098
099        countDown.decrementAndGet();
100    }
101
102    @Override
103    public int fuse() {
104        return fuse;
105    }
106
107    @Override
108    public int radius() {
109        return radius;
110    }
111
112    @Override
113    public void setRadius(int radius) {
114        this.radius = radius;
115    }
116
117    @Override
118    public void setFuse(int ticks) {
119        this.fuse = ticks;
120        this.countDown.set(ticks);
121    }
122
123    @Override
124    public EntityType type() {
125        return EntityType.PRIMED_TNT;
126    }
127}