Merge pull request #2483 from DangerousMilk/Meteorite-Tweaks

Meteor Improvements
This commit is contained in:
HbmMods 2025-10-23 11:55:37 +02:00 committed by GitHub
commit b3aa9ab637
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 204 additions and 93 deletions

View File

@ -1,5 +1,6 @@
package com.hbm.entity.projectile;
import com.hbm.blocks.ModBlocks;
import com.hbm.config.WorldConfig;
import com.hbm.explosion.ExplosionLarge;
import com.hbm.main.MainRegistry;
@ -7,24 +8,97 @@ import com.hbm.world.feature.Meteorite;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import com.hbm.sound.AudioWrapper;
import java.util.ArrayList;
import java.util.List;
public class EntityMeteor extends Entity {
public boolean safe = false;
private AudioWrapper audioFly;
public EntityMeteor(World p_i1582_1_) {
super(p_i1582_1_);
this.ignoreFrustumCheck = true;
this.isImmuneToFire = true;
this.setSize(4F, 4F);
if(worldObj.isRemote) this.audioFly = MainRegistry.proxy.getLoopedSound("hbm:entity.meteoriteFallingLoop", 0, 0, 0, 1F, 100F, 0.9F + this.rand.nextFloat() * 0.2F, 0);
}
public List<int[]> getBlocksInRadius(World world, int x, int y, int z, int radius) {
List<int[]> foundBlocks = new ArrayList<>();
int rSq = radius * radius;
for (int dx = -radius; dx <= radius; dx++) {
for (int dy = -radius; dy <= radius; dy++) {
for (int dz = -radius; dz <= radius; dz++) {
// Check if point (dx, dy, dz) lies inside the sphere
if (dx * dx + dy * dy + dz * dz <= rSq) {
foundBlocks.add(new int[]{x + dx, y + dy, z + dz});
}
}
}
}
return foundBlocks;
}
public void damageOrDestroyBlock(World world, int blockX, int blockY, int blockZ)
{
if(safe) return;
// Get current block info
Block block = world.getBlock(blockX, blockY, blockZ);
if (block == null) return;
float hardness = block.getBlockHardness(world, blockX, blockY, blockZ);
// Check if the block is weak and can be destroyed
if (block == Blocks.leaves || block == Blocks.log || (hardness >= 0 && hardness <= 0.3F)) {
// Destroy the block
world.setBlockToAir(blockX, blockY, blockZ);
}
else {
// Found solid block
if(hardness < 0 || hardness > 5F) return;
if(rand.nextInt(6) == 1){
// Turn blocks into damaged variants
if(block == Blocks.dirt) {
world.setBlock(blockX, blockY, blockZ, ModBlocks.dirt_dead);
}
else if(block == Blocks.sand) {
if(rand.nextInt(2) == 1) {
world.setBlock(blockX, blockY, blockZ, Blocks.sandstone);
}
else {
world.setBlock(blockX, blockY, blockZ, Blocks.glass);
}
}
else if(block == Blocks.stone) {
world.setBlock(blockX, blockY, blockZ, Blocks.cobblestone);
}
else if(block == Blocks.grass) {
world.setBlock(blockX, blockY, blockZ, ModBlocks.waste_earth);
}
}
}
}
public void clearMeteorPath(World world, int x, int y, int z) {
for (int[] blockPos : getBlocksInRadius(world, x, y, z, 5))
{
damageOrDestroyBlock(worldObj, blockPos[0], blockPos[1], blockPos[2]);
}
}
@Override
public void onUpdate() {
if(!worldObj.isRemote && !WorldConfig.enableMeteorStrikes) {
this.setDead();
return;
@ -37,23 +111,59 @@ public class EntityMeteor extends Entity {
this.motionY -= 0.03;
if(motionY < -2.5)
motionY = -2.5;
this.moveEntity(motionX, motionY, motionZ);
if(!this.worldObj.isRemote && this.onGround && this.posY < 260) {
worldObj.createExplosion(this, this.posX, this.posY, this.posZ, 5 + rand.nextFloat(), !safe);
if(WorldConfig.enableMeteorTails) {
ExplosionLarge.spawnParticles(worldObj, posX, posY + 5, posZ, 75);
ExplosionLarge.spawnParticles(worldObj, posX + 5, posY, posZ, 75);
ExplosionLarge.spawnParticles(worldObj, posX - 5, posY, posZ, 75);
ExplosionLarge.spawnParticles(worldObj, posX, posY, posZ + 5, 75);
ExplosionLarge.spawnParticles(worldObj, posX, posY, posZ - 5, 75);
if(!this.worldObj.isRemote && this.posY < 260) {
clearMeteorPath(worldObj, (int)this.posX, (int)this.posY, (int)this.posZ);
if(this.onGround) {
worldObj.createExplosion(this, this.posX, this.posY, this.posZ, 5 + rand.nextFloat(), !safe);
if(WorldConfig.enableMeteorTails) {
ExplosionLarge.spawnRubble(worldObj, this.posX, this.posY, this.posZ, 25);
ExplosionLarge.spawnParticles(worldObj, posX, posY + 5, posZ, 75);
ExplosionLarge.spawnParticles(worldObj, posX + 5, posY, posZ, 75);
ExplosionLarge.spawnParticles(worldObj, posX - 5, posY, posZ, 75);
ExplosionLarge.spawnParticles(worldObj, posX, posY, posZ + 5, 75);
ExplosionLarge.spawnParticles(worldObj, posX, posY, posZ - 5, 75);
}
// Bury the meteor into the ground
int spawnPosX = (int) (Math.round(this.posX - 0.5D) + (safe ? 0 : (this.motionZ * 4)));
int spawnPosY = (int) Math.round(this.posY - (safe ? 0 : 4));
int spawnPosZ = (int) (Math.round(this.posZ - 0.5D) + (safe ? 0 : (this.motionZ * 4)));
(new Meteorite()).generate(worldObj, rand, spawnPosX, spawnPosY, spawnPosZ, safe, true, true);
clearMeteorPath(worldObj, spawnPosX, spawnPosY, spawnPosZ);
this.worldObj.playSoundEffect(this.posX, this.posY, this.posZ, "hbm:entity.oldExplosion", 10000.0F, 0.5F + this.rand.nextFloat() * 0.1F);
this.setDead();
}
}
// Sound
if(worldObj.isRemote){
if(this.isDead) {
if(this.audioFly != null) this.audioFly.stopSound();
}
(new Meteorite()).generate(worldObj, rand, (int) Math.round(this.posX - 0.5D), (int) Math.round(this.posY - 0.5D), (int) Math.round(this.posZ - 0.5D), safe, true, true);
this.worldObj.playSoundEffect(this.posX, this.posY, this.posZ, "hbm:entity.oldExplosion", 10000.0F, 0.5F + this.rand.nextFloat() * 0.1F);
this.setDead();
if(this.audioFly.isPlaying()) {
// Update sound
this.audioFly.keepAlive();
this.audioFly.updateVolume(1F);
this.audioFly.updatePosition((int)this.posX, (int)this.posY, (int)this.posZ);
}
else
{
// Start playing the sound
EntityPlayer player = Minecraft.getMinecraft().thePlayer;
double distance = player.getDistanceSq(this.posX, this.posY, this.posZ);
if (distance < 110 * 110) {
this.audioFly.startSound();
}
}
}
if(WorldConfig.enableMeteorTails && worldObj.isRemote) {

View File

@ -33,12 +33,12 @@ import net.minecraft.world.World;
import net.minecraftforge.event.ForgeEventFactory;
public class BossSpawnHandler {
//because some dimwit keeps resetting the world rand
private static final Random meteorRand = new Random();
public static void rollTheDice(World world) {
/*
* Spawns every 3 hours with a 33% chance if
* - the player is 3 blocks below the surface
@ -46,117 +46,117 @@ public class BossSpawnHandler {
* - the player has either crafted or placed an ore acidizer before
*/
if(MobConfig.enableMaskman) {
if(world.getTotalWorldTime() % MobConfig.maskmanDelay == 0) {
if(world.rand.nextInt(MobConfig.maskmanChance) == 0 && !world.playerEntities.isEmpty() && world.provider.isSurfaceWorld()) { //33% chance only if there is a player online
EntityPlayer player = (EntityPlayer) world.playerEntities.get(world.rand.nextInt(world.playerEntities.size())); //choose a random player
int id = Item.getIdFromItem(Item.getItemFromBlock(ModBlocks.machine_crystallizer));
StatBase statCraft = StatList.objectCraftStats[id];
StatBase statPlace = StatList.objectUseStats[id];
if(!(player instanceof EntityPlayerMP)) return;
EntityPlayerMP playerMP = (EntityPlayerMP) player;
boolean acidizerStat = !GeneralConfig.enableStatReRegistering || (statCraft != null && playerMP.func_147099_x().writeStat(statCraft) > 0)|| (statPlace != null && playerMP.func_147099_x().writeStat(statPlace) > 0);
if(acidizerStat && ContaminationUtil.getRads(player) >= MobConfig.maskmanMinRad && (world.getHeightValue((int)player.posX, (int)player.posZ) > player.posY + 3 || !MobConfig.maskmanUnderground)) { //if the player has more than 50 RAD and is underground
player.addChatComponentMessage(new ChatComponentText("The mask man is about to claim another victim.").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.RED)));
double spawnX = player.posX + world.rand.nextGaussian() * 20;
double spawnZ = player.posZ + world.rand.nextGaussian() * 20;
double spawnY = world.getHeightValue((int)spawnX, (int)spawnZ);
trySpawn(world, (float)spawnX, (float)spawnY, (float)spawnZ, new EntityMaskMan(world));
}
}
}
}
if(MobConfig.enableRaids) {
if(world.getTotalWorldTime() % MobConfig.raidDelay == 0) {
if(world.rand.nextInt(MobConfig.raidChance) == 0 && !world.playerEntities.isEmpty() && world.provider.isSurfaceWorld()) {
EntityPlayer player = (EntityPlayer) world.playerEntities.get(world.rand.nextInt(world.playerEntities.size()));
if(player.getEntityData().getCompoundTag(player.PERSISTED_NBT_TAG).getLong("fbiMark") < world.getTotalWorldTime()) {
player.addChatComponentMessage(new ChatComponentText("FBI, OPEN UP!").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.RED)));
Vec3 vec = Vec3.createVectorHelper(MobConfig.raidAttackDistance, 0, 0);
vec.rotateAroundY((float)(Math.PI * 2) * world.rand.nextFloat());
for(int i = 0; i < MobConfig.raidAmount; i++) {
double spawnX = player.posX + vec.xCoord + world.rand.nextGaussian() * 5;
double spawnZ = player.posZ + vec.zCoord + world.rand.nextGaussian() * 5;
double spawnY = world.getHeightValue((int)spawnX, (int)spawnZ);
trySpawn(world, (float)spawnX, (float)spawnY, (float)spawnZ, new EntityFBI(world));
}
for(int i = 0; i < MobConfig.raidDrones; i++) {
double spawnX = player.posX + vec.xCoord + world.rand.nextGaussian() * 5;
double spawnZ = player.posZ + vec.zCoord + world.rand.nextGaussian() * 5;
double spawnY = world.getHeightValue((int)spawnX, (int)spawnZ);
trySpawn(world, (float)spawnX, (float)spawnY + 10, (float)spawnZ, new EntityFBIDrone(world));
}
}
}
}
}
if(MobConfig.enableElementals) {
if(world.getTotalWorldTime() % MobConfig.elementalDelay == 0) {
if(world.rand.nextInt(MobConfig.elementalChance) == 0 && !world.playerEntities.isEmpty() && world.provider.isSurfaceWorld()) {
EntityPlayer player = (EntityPlayer) world.playerEntities.get(world.rand.nextInt(world.playerEntities.size()));
if(player.getEntityData().getCompoundTag(player.PERSISTED_NBT_TAG).getBoolean("radMark")) {
player.addChatComponentMessage(new ChatComponentText("You hear a faint clicking...").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.YELLOW)));
player.getEntityData().getCompoundTag(player.PERSISTED_NBT_TAG).setBoolean("radMark", false);
Vec3 vec = Vec3.createVectorHelper(MobConfig.raidAttackDistance, 0, 0);
for(int i = 0; i < MobConfig.elementalAmount; i++) {
vec.rotateAroundY((float)(Math.PI * 2) * world.rand.nextFloat());
double spawnX = player.posX + vec.xCoord + world.rand.nextGaussian();
double spawnZ = player.posZ + vec.zCoord + world.rand.nextGaussian();
double spawnY = world.getHeightValue((int)spawnX, (int)spawnZ);
EntityRADBeast rad = new EntityRADBeast(world);
if(i == 0)
rad.makeLeader();
trySpawn(world, (float)spawnX, (float)spawnY, (float)spawnZ, rad);
}
}
}
}
}
if(WorldConfig.enableMeteorStrikes && !world.isRemote) {
meteorUpdate(world);
}
if(world.getTotalWorldTime() % 20 == 0) {
if(world.rand.nextInt(5) == 0 && !world.playerEntities.isEmpty() && world.provider.isSurfaceWorld()) {
EntityPlayer player = (EntityPlayer) world.playerEntities.get(world.rand.nextInt(world.playerEntities.size()));
if(HbmLivingProps.getDigamma(player) > 0) {
Vec3 vec = Vec3.createVectorHelper(75, 0, 0);
vec.rotateAroundY((float)(Math.PI * 2) * world.rand.nextFloat());
@ -168,14 +168,14 @@ public class BossSpawnHandler {
}
}
}
private static void trySpawn(World world, float x, float y, float z, EntityLiving e) {
e.setLocationAndAngles(x, y, z, world.rand.nextFloat() * 360.0F, 0.0F);
Result canSpawn = ForgeEventFactory.canEntitySpawn(e, world, x, y, z);
if (canSpawn == Result.ALLOW || canSpawn == Result.DEFAULT) {
world.spawnEntityInWorld(e);
ForgeEventFactory.doSpecialSpawn(e, world, x, y, z);
e.onSpawnWithEgg(null);
@ -183,32 +183,32 @@ public class BossSpawnHandler {
}
public static void markFBI(EntityPlayer player) {
if(!player.worldObj.isRemote)
player.getEntityData().getCompoundTag(player.PERSISTED_NBT_TAG).setLong("fbiMark", player.worldObj.getTotalWorldTime() + 20 * 60 * 20);
}
public static int meteorShower = 0;
private static void meteorUpdate(World world) {
if(meteorRand.nextInt(meteorShower > 0 ? WorldConfig.meteorShowerChance : WorldConfig.meteorStrikeChance) == 0) {
if(!world.playerEntities.isEmpty()) {
EntityPlayer p = (EntityPlayer)world.playerEntities.get(meteorRand.nextInt(world.playerEntities.size()));
if(p != null && p.dimension == 0) {
boolean repell = false;
boolean strike = true;
for(int i = 0; i < 4; i++) {
ItemStack armor = p.getCurrentArmor(i);
if(armor != null && ArmorModHandler.hasMods(armor)) {
for(int j = 0; j < 8; j++) {
ItemStack mod = ArmorModHandler.pryMods(armor)[j];
if(mod != null) {
if(mod.getItem() == ModItems.protection_charm) repell = true;
if(mod.getItem() == ModItems.meteor_charm) strike = false;
@ -216,19 +216,19 @@ public class BossSpawnHandler {
}
}
}
if(strike)
spawnMeteorAtPlayer(p, repell);
}
}
}
if(meteorShower > 0) {
meteorShower--;
if(meteorShower == 0 && GeneralConfig.enableDebugMode)
MainRegistry.logger.info("Ended meteor shower.");
}
if(meteorRand.nextInt(WorldConfig.meteorStrikeChance * 100) == 0 && WorldConfig.enableMeteorShowers) {
meteorShower = (int)(WorldConfig.meteorShowerDuration * 0.75 + WorldConfig.meteorShowerDuration * 0.25 * meteorRand.nextFloat());
@ -236,12 +236,12 @@ public class BossSpawnHandler {
MainRegistry.logger.info("Started meteor shower! Duration: " + meteorShower);
}
}
public static void spawnMeteorAtPlayer(EntityPlayer player, boolean repell) {
EntityMeteor meteor = new EntityMeteor(player.worldObj);
meteor.setPositionAndRotation(player.posX + meteorRand.nextInt(201) - 100, 384, player.posZ + meteorRand.nextInt(201) - 100, 0, 0);
Vec3 vec;
if(repell) {
vec = Vec3.createVectorHelper(meteor.posX - player.posX, 0, meteor.posZ - player.posZ).normalize();
@ -253,7 +253,7 @@ public class BossSpawnHandler {
vec = Vec3.createVectorHelper(meteorRand.nextDouble() - 0.5D, 0, 0);
vec.rotateAroundY((float) (Math.PI * meteorRand.nextDouble()));
}
meteor.motionX = vec.xCoord;
meteor.motionY = -2.5;
meteor.motionZ = vec.zCoord;

View File

@ -23,19 +23,19 @@ import net.minecraft.world.World;
@Spaghetti("why")
public class Meteorite {
public static boolean safeMode = false;
public void generate(World world, Random rand, int x, int y, int z, boolean safe, boolean allowSpecials, boolean damagingImpact) {
safeMode = safe;
if(replacables.isEmpty()) {
generateReplacables();
}
if(damagingImpact) {
List<Entity> list = (List<Entity>) world.getEntitiesWithinAABBExcludingEntity(null, AxisAlignedBB.getBoundingBox(x - 7.5, y - 7.5, z - 7.5, x + 7.5, y + 7.5, z + 7.5));
for(Entity e : list) {
e.attackEntityFrom(ModDamageSource.meteorite, 1000);
}
@ -693,21 +693,21 @@ public class Meteorite {
for(EnumMeteorType num : EnumMeteorType.values()) ores.add(DictFrame.fromOne(ModBlocks.ore_meteor, num));
return ores;
}
private void setBlock(World world, int x, int y, int z, Block b, int meta, int flag) {
Block target = world.getBlock(x, y, z);
if(safeMode) {
if(!target.isReplaceable(world, x, y, z) && !replacables.contains(target)) return;
if(!target.isReplaceable(world, x, y, z) && !replacables.contains(target)) return;
}
float hardness = target.getBlockHardness(world, x, y, z);
if(hardness != -1 && hardness < 10_000)
world.setBlock(x, y, z, b, meta, flag);
}
public static HashSet<Block> replacables = new HashSet();
public static void generateReplacables() {
replacables.add(ModBlocks.block_meteor);
replacables.add(ModBlocks.block_meteor_broken);

View File

@ -73,7 +73,7 @@
"block.assemblerStart": {"category": "block", "sounds": [{"name": "block/assemblerStart", "stream": false}]},
"block.assemblerStop": {"category": "block", "sounds": [{"name": "block/assemblerStop", "stream": false}]},
"block.assemblerCut": {"category": "block", "sounds": [{"name": "block/assemblerCut", "stream": false}]},
"door.TransitionSealOpen": {"category": "block", "sounds": [{"name": "block/door/transition_seal_open", "stream": true}]},
"door.wghStart": {"category": "block", "sounds": [{"name": "block/door/wgh_start", "stream": true}]},
"door.wghStop": {"category": "block", "sounds": [{"name": "block/door/wgh_stop", "stream": true}]},
@ -225,13 +225,13 @@
"weapon.explosionSmallFar": {"category": "player", "sounds": ["weapon/explosionSmallFar1", "weapon/explosionSmallFar2"]},
"weapon.explosionTiny": {"category": "player", "sounds": ["weapon/explosionTiny1", "weapon/explosionTiny2"]},
"weapon.hkShoot": {"category": "player", "sounds": [{"name": "weapon/hkShoot", "stream": false}]},
"weapon.dFlash": {"category": "player", "sounds": [{"name": "weapon/dFlash", "stream": false}]},
"weapon.reloadTurret": {"category": "player", "sounds": [{"name": "weapon/reloadTurret", "stream": false}]},
"weapon.switchmode1": {"category": "player", "sounds": [{"name": "weapon/switchmode1", "stream": false}]},
"weapon.switchmode2": {"category": "player", "sounds": [{"name": "weapon/switchmode2", "stream": false}]},
"weapon.fire.blackPowder": {"category": "player", "sounds": ["weapon/fire/blackPowder"]},
"weapon.fire.flameLoop": {"category": "player", "sounds": ["weapon/fire/flameLoop"]},
"weapon.fire.lockon": {"category": "player", "sounds": ["weapon/fire/lockon"]},
@ -262,7 +262,7 @@
"weapon.fire.stab": {"category": "player", "sounds": ["weapon/fire/stab1", "weapon/fire/stab2"]},
"weapon.fire.grenade": {"category": "player", "sounds": ["weapon/fire/grenade"]},
"weapon.fire.amat": {"category": "player", "sounds": ["weapon/fire/amat"]},
"weapon.reload.boltClose": {"category": "player", "sounds": ["weapon/reload/boltClose"]},
"weapon.reload.boltOpen": {"category": "player", "sounds": ["weapon/reload/boltOpen"]},
"weapon.reload.closeClick": {"category": "player", "sounds": ["weapon/reload/closeClick"]},
@ -293,7 +293,7 @@
"weapon.reload.screw": {"category": "player", "sounds": ["weapon/reload/screw"]},
"weapon.foley.gunWhack": {"category": "player", "sounds": ["weapon/foley/gunWhack", "weapon/foley/gunWhack2"]},
"turret.chekhov_fire": {"category": "block", "sounds": [{"name": "turret/chekhov_fire", "stream": false}]},
"turret.jeremy_fire": {"category": "block", "sounds": ["turret/jeremy_fire1", "turret/jeremy_fire2", "turret/jeremy_fire3", "turret/jeremy_fire4", "turret/jeremy_fire5"]},
"turret.jeremy_reload": {"category": "block", "sounds": [{"name": "turret/jeremy_reload", "stream": false}]},
@ -328,21 +328,22 @@
"entity.siegeIdle": {"category": "hostile", "sounds": ["entity/siegeIdle1"]},
"entity.siegeHurt": {"category": "hostile", "sounds": ["entity/siegeHurt1", "entity/siegeHurt2"]},
"entity.siegeDeath": {"category": "hostile", "sounds": ["entity/siegeDeath1", "entity/siegeDeath2", "entity/siegeDeath3"]},
"step.metal": {"category": "player", "sounds": [{"name": "footsteps/metal", "stream": false}]},
"entity.meteoriteFallingLoop": {"category": "block", "sounds": [{"name": "entity/meteoriteFallingLoop", "stream": false}]},
"step.metal": {"category": "player", "sounds": [{"name": "footsteps/metal", "stream": false}]},
"step.iron_jump": {"category": "player", "sounds": [{"name": "footsteps/iron_jump", "stream": false}]},
"step.iron_land": {"category": "player", "sounds": [{"name": "footsteps/iron_land", "stream": false}]},
"step.iron": {"category": "player", "sounds": ["footsteps/iron1", "footsteps/iron2", "footsteps/iron3", "footsteps/iron4"]},
"step.metalBlock": {"category": "block", "sounds": ["footsteps/metalStep1", "footsteps/metalStep2", "footsteps/metalStep3", "footsteps/metalStep4"]},
"step.powered": {"category": "player", "sounds": ["footsteps/powered1", "footsteps/powered2", "footsteps/powered3"]},
"player.vomit": {"category": "player", "sounds": [{"name": "player/vomit", "stream": false}]},
"player.cough": {"category": "player", "sounds": ["player/cough1", "player/cough2", "player/cough3", "player/cough4"]},
"player.gulp": {"category": "player", "sounds": ["player/gulp1", "player/gulp2", "player/gulp3", "player/gulp4"]},
"player.groan": {"category": "player", "sounds": ["player/groan1", "player/groan2", "player/groan3"]},
"potatos.random": {"category": "player", "sounds": ["potatos/randResponse0", "potatos/randResponse1", "potatos/randResponse2", "potatos/randResponse3", "potatos/randResponse4", "potatos/randResponse5", "potatos/randResponse6", "potatos/randResponse7"]},
"alarm.amsSiren": {"category": "record", "sounds": [{"name": "alarm/amsSiren", "stream": false}]},
"alarm.apcLoop": {"category": "record", "sounds": [{"name": "alarm/apcLoop", "stream": false}]},
"alarm.apcPass": {"category": "record", "sounds": [{"name": "alarm/apcPass", "stream": false}]},