/* * Copyright 2016 MovingBlocks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.terasology.logic.health; import org.terasology.audio.AudioManager; import org.terasology.audio.StaticSound; import org.terasology.audio.events.PlaySoundEvent; import org.terasology.entitySystem.entity.EntityBuilder; import org.terasology.entitySystem.entity.EntityManager; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.event.ReceiveEvent; import org.terasology.entitySystem.systems.BaseComponentSystem; import org.terasology.entitySystem.systems.RegisterMode; import org.terasology.entitySystem.systems.RegisterSystem; import org.terasology.logic.characters.events.AttackEvent; import org.terasology.logic.location.LocationComponent; import org.terasology.logic.particles.BlockParticleEffectComponent; import org.terasology.math.geom.Vector3f; import org.terasology.registry.In; import org.terasology.utilities.random.FastRandom; import org.terasology.utilities.random.Random; import org.terasology.world.block.Block; import org.terasology.world.block.BlockComponent; import org.terasology.world.block.entity.damage.BlockDamageModifierComponent; import org.terasology.world.block.family.BlockFamily; import org.terasology.world.block.regions.ActAsBlockComponent; import org.terasology.world.block.sounds.BlockSounds; /** * This system is responsible for giving blocks health when they are attacked and damaging them instead of destroying them. */ @RegisterSystem public class BlockDamageAuthoritySystem extends BaseComponentSystem { private static final float BLOCK_REGEN_SECONDS = 4.0f; @In private EntityManager entityManager; @In private AudioManager audioManager; private Random random = new FastRandom(); @ReceiveEvent public void beforeDamaged(BeforeDamagedEvent event, EntityRef blockEntity, BlockComponent blockComp) { if (!blockComp.getBlock().isDestructible()) { event.consume(); } } @ReceiveEvent public void beforeDamaged(BeforeDamagedEvent event, EntityRef blockEntity, ActAsBlockComponent blockComp) { if (blockComp.block != null && !blockComp.block.getArchetypeBlock().isDestructible()) { event.consume(); } } @ReceiveEvent(components = {BlockDamagedComponent.class}) public void onRepaired(FullHealthEvent event, EntityRef entity) { entity.removeComponent(BlockDamagedComponent.class); } @ReceiveEvent public void onDamaged(OnDamagedEvent event, EntityRef entity, BlockComponent blockComponent, LocationComponent locComp) { onDamagedCommon(event, blockComponent.getBlock().getBlockFamily(), locComp.getWorldPosition(), entity); if (!entity.hasComponent(BlockDamagedComponent.class)) { entity.addComponent(new BlockDamagedComponent()); } } @ReceiveEvent public void onDamaged(OnDamagedEvent event, EntityRef entity, ActAsBlockComponent blockComponent, LocationComponent locComp) { if (blockComponent.block != null) { onDamagedCommon(event, blockComponent.block, locComp.getWorldPosition(), entity); } } public void onDamagedCommon(OnDamagedEvent event, BlockFamily blockFamily, Vector3f location, EntityRef entityRef) { BlockDamageModifierComponent blockDamageSettings = event.getType().getComponent(BlockDamageModifierComponent.class); boolean skipDamageEffects = false; if (blockDamageSettings != null) { skipDamageEffects = blockDamageSettings.skipPerBlockEffects; } if (!skipDamageEffects) { onPlayBlockDamageCommon(blockFamily, location, entityRef); } } private void onPlayBlockDamageCommon(BlockFamily family, Vector3f location, EntityRef entityRef) { EntityBuilder builder = entityManager.newBuilder("engine:defaultBlockParticles"); builder.getComponent(LocationComponent.class).setWorldPosition(location); builder.getComponent(BlockParticleEffectComponent.class).blockType = family.getURI().toString(); builder.build(); if (family.getArchetypeBlock().isDebrisOnDestroy()) { EntityBuilder dustBuilder = entityManager.newBuilder("engine:dustEffect"); dustBuilder.getComponent(LocationComponent.class).setWorldPosition(location); dustBuilder.build(); } BlockSounds sounds = family.getArchetypeBlock().getSounds(); if (!sounds.getDigSounds().isEmpty()) { StaticSound sound = random.nextItem(sounds.getDigSounds()); entityRef.send(new PlaySoundEvent(sound, 1f)); } } @ReceiveEvent(netFilter = RegisterMode.AUTHORITY) public void beforeDamage(BeforeDamagedEvent event, EntityRef entity, BlockComponent blockComp) { beforeDamageCommon(event, blockComp.getBlock()); } @ReceiveEvent(netFilter = RegisterMode.AUTHORITY) public void beforeDamage(BeforeDamagedEvent event, EntityRef entity, ActAsBlockComponent blockComp) { if (blockComp.block != null) { beforeDamageCommon(event, blockComp.block.getArchetypeBlock()); } } private void beforeDamageCommon(BeforeDamagedEvent event, Block block) { if (event.getDamageType() != null) { BlockDamageModifierComponent blockDamage = event.getDamageType().getComponent(BlockDamageModifierComponent.class); if (blockDamage != null) { BlockFamily blockFamily = block.getBlockFamily(); for (String category : blockFamily.getCategories()) { if (blockDamage.materialDamageMultiplier.containsKey(category)) { event.multiply(blockDamage.materialDamageMultiplier.get(category)); } } } } } @ReceiveEvent(netFilter = RegisterMode.AUTHORITY) public void onAttackHealthlessBlock(AttackEvent event, EntityRef targetEntity, BlockComponent blockComponent) { if (!targetEntity.hasComponent(HealthComponent.class)) { HealthAuthoritySystem.damageEntity(event, targetEntity); } } @ReceiveEvent(netFilter = RegisterMode.AUTHORITY) public void onAttackHealthlessActAsBlock(AttackEvent event, EntityRef targetEntity, ActAsBlockComponent actAsBlockComponent) { if (!targetEntity.hasComponent(HealthComponent.class)) { HealthAuthoritySystem.damageEntity(event, targetEntity); } } @ReceiveEvent public void beforeDamagedEnsureHealthPresent(BeforeDamagedEvent event, EntityRef blockEntity, BlockComponent blockComponent) { if (!blockEntity.hasComponent(HealthComponent.class)) { Block type = blockComponent.getBlock(); if (blockComponent != null) { if (type.isDestructible()) { HealthComponent healthComponent = new HealthComponent(type.getHardness(), type.getHardness() / BLOCK_REGEN_SECONDS, 1.0f); healthComponent.destroyEntityOnNoHealth = true; blockEntity.addComponent(healthComponent); } } } } }