diff --git a/common/net/minecraft/src/buildcraft/core/EntityLaser.java b/common/net/minecraft/src/buildcraft/core/EntityLaser.java index 0cb838fc..cb60ae8a 100644 --- a/common/net/minecraft/src/buildcraft/core/EntityLaser.java +++ b/common/net/minecraft/src/buildcraft/core/EntityLaser.java @@ -1,199 +1,199 @@ -/** - * Copyright (c) SpaceToad, 2011 - * http://www.mod-buildcraft.com - * - * BuildCraft is distributed under the terms of the Minecraft Mod Public - * License 1.0, or MMPL. Please check the contents of the license located in - * http://www.mod-buildcraft.com/MMPL-1.0.txt - */ - -package net.minecraft.src.buildcraft.core; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -import net.minecraft.src.Entity; -import net.minecraft.src.NBTTagCompound; -import net.minecraft.src.World; -import net.minecraft.src.buildcraft.api.APIProxy; -import net.minecraft.src.buildcraft.api.Position; -import net.minecraft.src.forge.ISpawnHandler; - -public class EntityLaser extends Entity implements ISpawnHandler { - - protected Position head, tail; - - protected double renderSize = 0; - protected double angleY = 0; - protected double angleZ = 0; - protected String texture; - - double lastY; - - public EntityLaser(World world) { - - super(world); - } - - public EntityLaser(World world, Position head, Position tail) { - - super(world); - - this.head = head; - this.tail = tail; - - init(); - } - - protected void init() { - - preventEntitySpawning = false; - noClip = true; - isImmuneToFire = true; - - setPosition(head.x, head.y, head.z); - setSize(10, 10); - - dataWatcher.addObject(8 , Integer.valueOf(encodeDouble(head.x))); - dataWatcher.addObject(9 , Integer.valueOf(encodeDouble(head.y))); - dataWatcher.addObject(10, Integer.valueOf(encodeDouble(head.z))); - dataWatcher.addObject(11, Integer.valueOf(encodeDouble(tail.x))); - dataWatcher.addObject(12, Integer.valueOf(encodeDouble(tail.y))); - dataWatcher.addObject(13, Integer.valueOf(encodeDouble(tail.z))); - - dataWatcher.addObject(14, Byte.valueOf((byte) 0)); - - lastY = head.y; - } - - @Override - public void writeSpawnData(DataOutputStream data) throws IOException { - - data.writeDouble(head.x); - data.writeDouble(head.y); - data.writeDouble(head.z); - data.writeDouble(tail.x); - data.writeDouble(tail.y); - data.writeDouble(tail.z); - } - - @Override - public void readSpawnData(DataInputStream data) throws IOException { - - head = new Position(data.readDouble(), data.readDouble(), data.readDouble()); - tail = new Position(data.readDouble(), data.readDouble(), data.readDouble()); - init(); - } - - @Override - public void onUpdate() { - - if (head == null || tail == null) - return; - - if (APIProxy.isClient(worldObj)) { - updateData(); - } - - boundingBox.minX = Math.min(head.x, tail.x); - boundingBox.minY = Math.min(head.y, tail.y); - boundingBox.minZ = Math.min(head.z, tail.z); - - boundingBox.maxX = Math.max(head.x, tail.x); - boundingBox.maxY = Math.max(head.y, tail.y); - boundingBox.maxZ = Math.max(head.z, tail.z); - - if (!APIProxy.isClient(worldObj)) { - - boundingBox.minX--; - boundingBox.minY--; - boundingBox.minZ--; - - boundingBox.maxX++; - boundingBox.maxY++; - boundingBox.maxZ++; - } - - double dx = head.x - tail.x; - double dy = head.y - tail.y; - double dz = head.z - tail.z; - - renderSize = Math.sqrt(dx * dx + dy * dy + dz * dz); - angleZ = 360 - (Math.atan2(dz, dx) * 180.0 / Math.PI + 180.0); - dx = Math.sqrt(renderSize * renderSize - dy * dy); - angleY = -Math.atan2(dy, dx) * 180 / Math.PI; - } - - protected void updateData() { - - head.x = decodeDouble(dataWatcher.getWatchableObjectInt(8)); - head.y = decodeDouble(dataWatcher.getWatchableObjectInt(9)); - head.z = decodeDouble(dataWatcher.getWatchableObjectInt(10)); - tail.x = decodeDouble(dataWatcher.getWatchableObjectInt(11)); - tail.y = decodeDouble(dataWatcher.getWatchableObjectInt(12)); - tail.z = decodeDouble(dataWatcher.getWatchableObjectInt(13)); - } - - @Override - public void setPosition(double x, double y, double z) { - - posX = x; - posY = y; - posZ = z; - } - - public void setPositions(Position head, Position tail) { - - this.head = head; - this.tail = tail; - - setPosition(head.x, head.y, head.z); - - dataWatcher.updateObject(8 , Integer.valueOf(encodeDouble(head.x))); - dataWatcher.updateObject(9 , Integer.valueOf(encodeDouble(head.y))); - dataWatcher.updateObject(10, Integer.valueOf(encodeDouble(head.z))); - dataWatcher.updateObject(11, Integer.valueOf(encodeDouble(tail.x))); - dataWatcher.updateObject(12, Integer.valueOf(encodeDouble(tail.y))); - dataWatcher.updateObject(13, Integer.valueOf(encodeDouble(tail.z))); - } - - public void show() { - dataWatcher.updateObject(14, Byte.valueOf((byte) 1)); - } - - public void hide() { - dataWatcher.updateObject(14, Byte.valueOf((byte) 0)); - } - - public boolean isVisible() { - return dataWatcher.getWatchableObjectByte(14) == 0 ? false : true; - } - - public void setTexture(String texture) { - this.texture = texture; - } - - public String getTexture() { - return texture; - } - - private int encodeDouble(double d) { - return (int) (d * 8000); - } - - private double decodeDouble(int i) { - return (i / 8000D); - } - - @Override - protected void entityInit() { - } - - @Override - protected void readEntityFromNBT(NBTTagCompound nbttagcompound) { - } - - @Override - protected void writeEntityToNBT(NBTTagCompound nbttagcompound) {} -} +/** + * Copyright (c) SpaceToad, 2011 + * http://www.mod-buildcraft.com + * + * BuildCraft is distributed under the terms of the Minecraft Mod Public + * License 1.0, or MMPL. Please check the contents of the license located in + * http://www.mod-buildcraft.com/MMPL-1.0.txt + */ + +package net.minecraft.src.buildcraft.core; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.minecraft.src.Entity; +import net.minecraft.src.NBTTagCompound; +import net.minecraft.src.World; +import net.minecraft.src.buildcraft.api.APIProxy; +import net.minecraft.src.buildcraft.api.Position; +import net.minecraft.src.forge.ISpawnHandler; + +public class EntityLaser extends Entity implements ISpawnHandler { + + protected Position head, tail; + + protected double renderSize = 0; + protected double angleY = 0; + protected double angleZ = 0; + protected String texture; + + public EntityLaser(World world) { + + super(world); + } + + public EntityLaser(World world, Position head, Position tail) { + + super(world); + + this.head = head; + this.tail = tail; + + setPosition(head.x, head.y, head.z); + + init(); + } + + protected void init() { + + preventEntitySpawning = false; + noClip = true; + isImmuneToFire = true; + + setPosition(head.x, head.y, head.z); + setSize(10, 10); + + dataWatcher.addObject(8 , Integer.valueOf(encodeDouble(head.x))); + dataWatcher.addObject(9 , Integer.valueOf(encodeDouble(head.y))); + dataWatcher.addObject(10, Integer.valueOf(encodeDouble(head.z))); + dataWatcher.addObject(11, Integer.valueOf(encodeDouble(tail.x))); + dataWatcher.addObject(12, Integer.valueOf(encodeDouble(tail.y))); + dataWatcher.addObject(13, Integer.valueOf(encodeDouble(tail.z))); + + dataWatcher.addObject(14, Byte.valueOf((byte) 0)); + } + + @Override + public void writeSpawnData(DataOutputStream data) throws IOException { + + data.writeDouble(head.x); + data.writeDouble(head.y); + data.writeDouble(head.z); + data.writeDouble(tail.x); + data.writeDouble(tail.y); + data.writeDouble(tail.z); + } + + @Override + public void readSpawnData(DataInputStream data) throws IOException { + + head = new Position(data.readDouble(), data.readDouble(), data.readDouble()); + tail = new Position(data.readDouble(), data.readDouble(), data.readDouble()); + init(); + } + + @Override + public void onUpdate() { + + if (head == null || tail == null) + return; + + if (APIProxy.isClient(worldObj)) { + updateData(); + } + + boundingBox.minX = Math.min(head.x, tail.x); + boundingBox.minY = Math.min(head.y, tail.y); + boundingBox.minZ = Math.min(head.z, tail.z); + + boundingBox.maxX = Math.max(head.x, tail.x); + boundingBox.maxY = Math.max(head.y, tail.y); + boundingBox.maxZ = Math.max(head.z, tail.z); + + boundingBox.minX--; + boundingBox.minY--; + boundingBox.minZ--; + + boundingBox.maxX++; + boundingBox.maxY++; + boundingBox.maxZ++; + + double dx = head.x - tail.x; + double dy = head.y - tail.y; + double dz = head.z - tail.z; + + renderSize = Math.sqrt(dx * dx + dy * dy + dz * dz); + angleZ = 360 - (Math.atan2(dz, dx) * 180.0 / Math.PI + 180.0); + dx = Math.sqrt(renderSize * renderSize - dy * dy); + angleY = -Math.atan2(dy, dx) * 180 / Math.PI; + } + + protected void updateData() { + + head.x = decodeDouble(dataWatcher.getWatchableObjectInt(8)); + head.y = decodeDouble(dataWatcher.getWatchableObjectInt(9)); + head.z = decodeDouble(dataWatcher.getWatchableObjectInt(10)); + tail.x = decodeDouble(dataWatcher.getWatchableObjectInt(11)); + tail.y = decodeDouble(dataWatcher.getWatchableObjectInt(12)); + tail.z = decodeDouble(dataWatcher.getWatchableObjectInt(13)); + } + + @Override + public void setPosition(double x, double y, double z) { + + if (x == 0) + new Exception().printStackTrace(); + + System.out.println(new Position(x, y, z)); + + posX = x; + posY = y; + posZ = z; + } + + public void setPositions(Position head, Position tail) { + + this.head = head; + this.tail = tail; + + setPosition(head.x, head.y, head.z); + + dataWatcher.updateObject(8 , Integer.valueOf(encodeDouble(head.x))); + dataWatcher.updateObject(9 , Integer.valueOf(encodeDouble(head.y))); + dataWatcher.updateObject(10, Integer.valueOf(encodeDouble(head.z))); + dataWatcher.updateObject(11, Integer.valueOf(encodeDouble(tail.x))); + dataWatcher.updateObject(12, Integer.valueOf(encodeDouble(tail.y))); + dataWatcher.updateObject(13, Integer.valueOf(encodeDouble(tail.z))); + } + + public void show() { + dataWatcher.updateObject(14, Byte.valueOf((byte) 1)); + } + + public void hide() { + dataWatcher.updateObject(14, Byte.valueOf((byte) 0)); + } + + public boolean isVisible() { + return dataWatcher.getWatchableObjectByte(14) == 0 ? false : true; + } + + public void setTexture(String texture) { + this.texture = texture; + } + + public String getTexture() { + return texture; + } + + private int encodeDouble(double d) { + return (int) (d * 8000); + } + + private double decodeDouble(int i) { + return (i / 8000D); + } + + @Override + protected void entityInit() { + } + + @Override + protected void readEntityFromNBT(NBTTagCompound nbttagcompound) { + } + + @Override + protected void writeEntityToNBT(NBTTagCompound nbttagcompound) {} +} diff --git a/common/net/minecraft/src/buildcraft/silicon/TileLaser.java b/common/net/minecraft/src/buildcraft/silicon/TileLaser.java index 5bdbb96c..1bb4e8c0 100644 --- a/common/net/minecraft/src/buildcraft/silicon/TileLaser.java +++ b/common/net/minecraft/src/buildcraft/silicon/TileLaser.java @@ -1,236 +1,243 @@ -/** - * Copyright (c) SpaceToad, 2011 - * http://www.mod-buildcraft.com - * - * BuildCraft is distributed under the terms of the Minecraft Mod Public - * License 1.0, or MMPL. Please check the contents of the license located in - * http://www.mod-buildcraft.com/MMPL-1.0.txt - */ - -package net.minecraft.src.buildcraft.silicon; - -import java.util.LinkedList; - -import net.minecraft.src.NBTTagCompound; -import net.minecraft.src.TileEntity; -import net.minecraft.src.buildcraft.api.APIProxy; -import net.minecraft.src.buildcraft.api.IPowerReceptor; -import net.minecraft.src.buildcraft.api.Orientations; -import net.minecraft.src.buildcraft.api.Position; -import net.minecraft.src.buildcraft.api.PowerFramework; -import net.minecraft.src.buildcraft.api.PowerProvider; -import net.minecraft.src.buildcraft.api.SafeTimeTracker; -import net.minecraft.src.buildcraft.core.BlockIndex; -import net.minecraft.src.buildcraft.core.EntityEnergyLaser; -import net.minecraft.src.buildcraft.factory.TileAssemblyTable; - -public class TileLaser extends TileEntity implements IPowerReceptor { - - private EntityEnergyLaser laser = null; - - private final SafeTimeTracker laserTickTracker = new SafeTimeTracker(); - private final SafeTimeTracker searchTracker = new SafeTimeTracker(); - - private TileAssemblyTable assemblyTable; - - private PowerProvider powerProvider; - - private int nextLaserUpdate = 10; - private int nextLaserSearch = 200; - - public TileLaser() { - powerProvider = PowerFramework.currentFramework.createPowerProvider(); - powerProvider.configure(20, 25, 25, 25, 1000); - } - - @Override - public void updateEntity() { - if (powerProvider.energyStored == 0) { - if (laser != null) { - deleteLaser(); - } - - return; - } - - if (searchTracker.markTimeIfDelay(worldObj, nextLaserSearch)) { - aim(); - nextLaserSearch = 190 + worldObj.rand.nextInt(20); - } - - if (assemblyTable != null && (assemblyTable.isInvalid() || assemblyTable.currentRecipe == null)) { - deleteLaser(); - } - - if (laser != null && laserTickTracker.markTimeIfDelay(worldObj, nextLaserUpdate)) { - setLaserPosition(); - nextLaserUpdate = 5 + worldObj.rand.nextInt(10); - } - - if (assemblyTable != null) { - float p = powerProvider.useEnergy(0, 4, true); - laser.pushPower(p); - assemblyTable.receiveLaserEnergy(p); - } - } - - private void deleteLaser() { - if (laser != null) { - laser.setDead(); - laser = null; - assemblyTable = null; - } - } - - public void aim() { - - if (APIProxy.isClient(worldObj)) - return; - - int meta = worldObj.getBlockMetadata(xCoord, yCoord, zCoord); - - int minX = xCoord - 5; - int minY = yCoord - 5; - int minZ = zCoord - 5; - int maxX = xCoord + 5; - int maxY = yCoord + 5; - int maxZ = zCoord + 5; - - switch (Orientations.values()[meta]) { - case XNeg: - maxX = xCoord; - break; - case XPos: - minX = xCoord; - break; - case YNeg: - maxY = yCoord; - break; - case YPos: - minY = yCoord; - break; - case ZNeg: - maxZ = zCoord; - break; - case ZPos: - minZ = zCoord; - break; - } - - LinkedList targets = new LinkedList(); - - for (int x = minX; x <= maxX; ++x) { - for (int y = minY; y <= maxY; ++y) { - for (int z = minZ; z <= maxZ; ++z) { - TileEntity tile = worldObj.getBlockTileEntity(x, y, z); - if (tile instanceof TileAssemblyTable) { - TileAssemblyTable table = (TileAssemblyTable) tile; - - if (table.currentRecipe != null) { - targets.add(new BlockIndex(x, y, z)); - } - } - } - } - } - - if (targets.size() == 0) { - return; - } - - BlockIndex b = targets.get(worldObj.rand.nextInt(targets.size())); - assemblyTable = (TileAssemblyTable) worldObj.getBlockTileEntity(b.i, b.j, b.k); - - if (laser == null) { - laser = new EntityEnergyLaser(worldObj, new Position(xCoord, yCoord, zCoord), new Position(xCoord, yCoord, zCoord)); - setLaserPosition(); - worldObj.spawnEntityInWorld(laser); - laser.show(); - } else { - setLaserPosition(); - } - } - - private void setLaserPosition() { - int meta = worldObj.getBlockMetadata(xCoord, yCoord, zCoord); - double px = 0, py = 0, pz = 0; - - switch (Orientations.values()[meta]) { - case XNeg: - px = -0.3; - break; - case XPos: - px = 0.3; - break; - case YNeg: - py = -0.3; - break; - case YPos: - py = 0.3; - break; - case ZNeg: - pz = -0.3; - break; - case ZPos: - pz = 0.3; - break; - } - - Position head = new Position(xCoord + 0.5 + px, yCoord + 0.5 + py, zCoord + 0.5 + pz); - Position tail = new Position( - assemblyTable.xCoord + 0.475 + (worldObj.rand.nextFloat() - 0.5) / 5F, - assemblyTable.yCoord + 9F / 16F, - assemblyTable.zCoord + 0.475 + (worldObj.rand.nextFloat() - 0.5) / 5F); - - laser.setPositions(head, tail); - } - - @Override - public void setPowerProvider(PowerProvider provider) { - powerProvider = provider; - - } - - @Override - public PowerProvider getPowerProvider() { - return powerProvider; - } - - @Override - public void doWork() { - // TODO Auto-generated method stub - - } - - @Override - public int powerRequest() { - if (powerProvider.energyStored < 200 || laser != null) { - return 25; - } else { - return 0; - } - } - - @Override - public void readFromNBT(NBTTagCompound nbttagcompound) { - super.readFromNBT(nbttagcompound); - - PowerFramework.currentFramework.loadPowerProvider(this, nbttagcompound); - powerProvider.configure(20, 25, 25, 25, 1000); - } - - @Override - public void writeToNBT(NBTTagCompound nbttagcompound) { - super.writeToNBT(nbttagcompound); - - PowerFramework.currentFramework.savePowerProvider(this, nbttagcompound); - } - - @Override - public void invalidate() { - super.invalidate(); - - deleteLaser(); - } - -} +/** + * Copyright (c) SpaceToad, 2011 + * http://www.mod-buildcraft.com + * + * BuildCraft is distributed under the terms of the Minecraft Mod Public + * License 1.0, or MMPL. Please check the contents of the license located in + * http://www.mod-buildcraft.com/MMPL-1.0.txt + */ + +package net.minecraft.src.buildcraft.silicon; + +import java.util.LinkedList; + +import net.minecraft.src.NBTTagCompound; +import net.minecraft.src.TileEntity; +import net.minecraft.src.buildcraft.api.APIProxy; +import net.minecraft.src.buildcraft.api.IPowerReceptor; +import net.minecraft.src.buildcraft.api.Orientations; +import net.minecraft.src.buildcraft.api.Position; +import net.minecraft.src.buildcraft.api.PowerFramework; +import net.minecraft.src.buildcraft.api.PowerProvider; +import net.minecraft.src.buildcraft.api.SafeTimeTracker; +import net.minecraft.src.buildcraft.core.BlockIndex; +import net.minecraft.src.buildcraft.core.EntityEnergyLaser; +import net.minecraft.src.buildcraft.factory.TileAssemblyTable; + +public class TileLaser extends TileEntity implements IPowerReceptor { + + private EntityEnergyLaser laser = null; + + private final SafeTimeTracker laserTickTracker = new SafeTimeTracker(); + private final SafeTimeTracker searchTracker = new SafeTimeTracker(); + + private TileAssemblyTable assemblyTable; + + private PowerProvider powerProvider; + + private int nextLaserUpdate = 10; + private int nextLaserSearch = 200; + + public TileLaser() { + powerProvider = PowerFramework.currentFramework.createPowerProvider(); + powerProvider.configure(20, 25, 25, 25, 1000); + } + + @Override + public void updateEntity() { + + if (powerProvider.energyStored == 0) { + + if (laser != null) { + deleteLaser(); + } + + return; + } + + if (searchTracker.markTimeIfDelay(worldObj, nextLaserSearch)) { + aim(); + nextLaserSearch = 190 + worldObj.rand.nextInt(20); + } + + if (assemblyTable != null && (assemblyTable.isInvalid() || assemblyTable.currentRecipe == null)) { + deleteLaser(); + } + + if (laser != null && laserTickTracker.markTimeIfDelay(worldObj, nextLaserUpdate)) { + setLaserPosition(); + nextLaserUpdate = 5 + worldObj.rand.nextInt(10); + } + + if (assemblyTable != null) { + float p = powerProvider.useEnergy(0, 4, true); + laser.pushPower(p); + assemblyTable.receiveLaserEnergy(p); + } + } + + private void deleteLaser() { + + if (laser != null) { + laser.setDead(); + laser = null; + assemblyTable = null; + } + } + + public void aim() { + + if (APIProxy.isClient(worldObj)) + return; + + int meta = worldObj.getBlockMetadata(xCoord, yCoord, zCoord); + + int minX = xCoord - 5; + int minY = yCoord - 5; + int minZ = zCoord - 5; + int maxX = xCoord + 5; + int maxY = yCoord + 5; + int maxZ = zCoord + 5; + + switch (Orientations.values()[meta]) { + case XNeg: + maxX = xCoord; + break; + case XPos: + minX = xCoord; + break; + case YNeg: + maxY = yCoord; + break; + case YPos: + minY = yCoord; + break; + case ZNeg: + maxZ = zCoord; + break; + case ZPos: + minZ = zCoord; + break; + } + + LinkedList targets = new LinkedList(); + + for (int x = minX; x <= maxX; ++x) { + for (int y = minY; y <= maxY; ++y) { + for (int z = minZ; z <= maxZ; ++z) { + TileEntity tile = worldObj.getBlockTileEntity(x, y, z); + if (tile instanceof TileAssemblyTable) { + TileAssemblyTable table = (TileAssemblyTable) tile; + + if (table.currentRecipe != null) { + targets.add(new BlockIndex(x, y, z)); + } + } + } + } + } + + if (targets.size() == 0) { + return; + } + + BlockIndex b = targets.get(worldObj.rand.nextInt(targets.size())); + assemblyTable = (TileAssemblyTable) worldObj.getBlockTileEntity(b.i, b.j, b.k); + + if (laser == null) { + + laser = new EntityEnergyLaser(worldObj, new Position(xCoord, yCoord, zCoord), new Position(xCoord, yCoord, zCoord)); + setLaserPosition(); + worldObj.spawnEntityInWorld(laser); + laser.show(); + + } else { + setLaserPosition(); + } + } + + private void setLaserPosition() { + + int meta = worldObj.getBlockMetadata(xCoord, yCoord, zCoord); + double px = 0, py = 0, pz = 0; + + switch (Orientations.values()[meta]) { + + case XNeg: + px = -0.3; + break; + case XPos: + px = 0.3; + break; + case YNeg: + py = -0.3; + break; + case YPos: + py = 0.3; + break; + case ZNeg: + pz = -0.3; + break; + case ZPos: + pz = 0.3; + break; + } + + Position head = new Position(xCoord + 0.5 + px, yCoord + 0.5 + py, zCoord + 0.5 + pz); + Position tail = new Position( + assemblyTable.xCoord + 0.475 + (worldObj.rand.nextFloat() - 0.5) / 5F, + assemblyTable.yCoord + 9F / 16F, + assemblyTable.zCoord + 0.475 + (worldObj.rand.nextFloat() - 0.5) / 5F); + + laser.setPositions(head, tail); + } + + @Override + public void setPowerProvider(PowerProvider provider) { + powerProvider = provider; + + } + + @Override + public PowerProvider getPowerProvider() { + return powerProvider; + } + + @Override + public void doWork() { + // TODO Auto-generated method stub + + } + + @Override + public int powerRequest() { + if (powerProvider.energyStored < 200 || laser != null) { + return 25; + } else { + return 0; + } + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + PowerFramework.currentFramework.loadPowerProvider(this, nbttagcompound); + powerProvider.configure(20, 25, 25, 25, 1000); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + PowerFramework.currentFramework.savePowerProvider(this, nbttagcompound); + } + + @Override + public void invalidate() { + super.invalidate(); + + deleteLaser(); + } + +}