Added transporter containment and scanner (wip)

Refactored MovingEntity to support transporter
Added ITransporterCore API
This commit is contained in:
Unknown 2018-04-03 22:41:07 +02:00 committed by unknown
parent 07b23d9de7
commit 7a567a8722
23 changed files with 2044 additions and 1075 deletions

View file

@ -71,11 +71,13 @@ import cr0s.warpdrive.block.hull.ItemBlockHullSlab;
import cr0s.warpdrive.block.movement.BlockLift;
import cr0s.warpdrive.block.movement.BlockShipController;
import cr0s.warpdrive.block.movement.BlockShipCore;
import cr0s.warpdrive.block.movement.BlockTransporter;
import cr0s.warpdrive.block.movement.BlockTransporterCore;
import cr0s.warpdrive.block.movement.BlockTransporterContainment;
import cr0s.warpdrive.block.movement.BlockTransporterScanner;
import cr0s.warpdrive.block.movement.TileEntityLift;
import cr0s.warpdrive.block.movement.TileEntityShipController;
import cr0s.warpdrive.block.movement.TileEntityShipCore;
import cr0s.warpdrive.block.movement.TileEntityTransporter;
import cr0s.warpdrive.block.movement.TileEntityTransporterCore;
import cr0s.warpdrive.block.breathing.BlockAir;
import cr0s.warpdrive.block.passive.BlockBedrockGlass;
import cr0s.warpdrive.block.passive.BlockDecorative;
@ -206,7 +208,9 @@ public class WarpDrive {
public static Block blockShipScanner;
public static Block blockCloakingCore;
public static Block blockCloakingCoil;
public static Block blockTransporter;
public static Block blockTransporterCore;
public static Block blockTransporterContainment;
public static Block blockTransporterScanner;
public static Block blockIC2reactorLaserMonitor;
public static Block blockEnanReactorCore;
public static Block blockEnanReactorLaser;
@ -464,11 +468,21 @@ public class WarpDrive {
GameRegistry.registerBlock(blockCloakingCoil, ItemBlockAbstractBase.class, "blockCloakingCoil");
// TRANSPORTER
blockTransporter = new BlockTransporter();
// TRANSPORTER CORE
blockTransporterCore = new BlockTransporterCore();
GameRegistry.registerBlock(blockTransporter, ItemBlockAbstractBase.class, "blockTransporter");
GameRegistry.registerTileEntity(TileEntityTransporter.class, MODID + ":blockTransporter");
GameRegistry.registerBlock(blockTransporterCore, ItemBlockAbstractBase.class, "blockTransporterCore");
GameRegistry.registerTileEntity(TileEntityTransporterCore.class, MODID + ":blockTransporterCore");
// TRANSPORTER CONTAINMENT
blockTransporterContainment = new BlockTransporterContainment();
GameRegistry.registerBlock(blockTransporterContainment, ItemBlockAbstractBase.class, "blockTransporterContainment");
// TRANSPORTER SCANNER
blockTransporterScanner = new BlockTransporterScanner();
GameRegistry.registerBlock(blockTransporterScanner, ItemBlockAbstractBase.class, "blockTransporterScanner");
// IC2 REACTOR LASER MONITOR
if (WarpDriveConfig.isIndustrialCraft2Loaded) {
@ -850,7 +864,8 @@ public class WarpDrive {
mapping.remap(Item.getItemFromBlock(blockTransportBeacon));
break;
case "WarpDrive:transporter":
mapping.remap(Item.getItemFromBlock(blockTransporter));
case "WarpDrive:blockTransporter":
mapping.remap(Item.getItemFromBlock(blockTransporterCore));
break;
case "WarpDrive:warpCore":
mapping.remap(Item.getItemFromBlock(blockShipCore));
@ -944,7 +959,8 @@ public class WarpDrive {
mapping.remap(blockTransportBeacon);
break;
case "WarpDrive:transporter":
mapping.remap(blockTransporter);
case "WarpDrive:blockTransporter":
mapping.remap(blockTransporterCore);
break;
case "WarpDrive:warpCore":
mapping.remap(blockShipCore);

View file

@ -0,0 +1,24 @@
package cr0s.warpdrive.api.computer;
import cr0s.warpdrive.api.IBeamFrequency;
public interface ITransporterCore extends IEnergy, IBeamFrequency {
Object[] transporterName(final Object[] arguments);
Object[] enable(final Object[] arguments);
Object[] state();
Object[] remoteLocation(final Object[] arguments);
Object[] lock(final Object[] arguments);
Object[] energyFactor(final Object[] arguments);
Object[] getLockStrength();
Object[] getEnergyRequired();
Object[] energize(final Object[] arguments);
}

View file

@ -0,0 +1,57 @@
package cr0s.warpdrive.block.movement;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import cr0s.warpdrive.block.BlockAbstractBase;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IIconRegister;
import net.minecraft.util.IIcon;
import net.minecraft.world.IBlockAccess;
import net.minecraftforge.common.util.ForgeDirection;
public class BlockTransporterContainment extends BlockAbstractBase {
@SideOnly(Side.CLIENT)
private IIcon[] iconBuffer;
public BlockTransporterContainment() {
super(Material.iron);
setBlockName("warpdrive.movement.transporter_containment");
setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.5F, 1.0F);
}
@SideOnly(Side.CLIENT)
@Override
public void registerBlockIcons(final IIconRegister iconRegister) {
iconBuffer = new IIcon[3];
// Solid textures
iconBuffer[0] = iconRegister.registerIcon("warpdrive:movement/transporter_containment-bottom");
iconBuffer[1] = iconRegister.registerIcon("warpdrive:movement/transporter_containment-top");
iconBuffer[2] = iconRegister.registerIcon("warpdrive:movement/transporter_containment-side");
}
@Override
public boolean isOpaqueCube() {
return false;
}
@Override
public boolean isNormalCube() {
return false;
}
@Override
public boolean isSideSolid(final IBlockAccess blockAccess, final int x, final int y, final int z, final ForgeDirection side) {
return side == ForgeDirection.DOWN;
}
@SideOnly(Side.CLIENT)
@Override
public IIcon getIcon(int side, int metadata) {
if (side == 0 || side == 1) {
return iconBuffer[side];
}
return iconBuffer[2];
}
}

View file

@ -13,40 +13,40 @@ import net.minecraft.world.World;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class BlockTransporter extends BlockAbstractContainer {
public class BlockTransporterCore extends BlockAbstractContainer {
@SideOnly(Side.CLIENT)
private IIcon[] iconBuffer;
public BlockTransporter() {
public BlockTransporterCore() {
super(Material.iron);
setBlockName("warpdrive.movement.Transporter");
setBlockName("warpdrive.movement.transporter_core");
}
@Override
public TileEntity createNewTileEntity(final World world, final int metadata) {
return new TileEntityTransporter();
return new TileEntityTransporterCore();
}
@SideOnly(Side.CLIENT)
@Override
public void registerBlockIcons(final IIconRegister iconRegister) {
iconBuffer = new IIcon[4];
// Solid textures
iconBuffer[0] = iconRegister.registerIcon("warpdrive:movement/transporter-bottom");
iconBuffer[1] = iconRegister.registerIcon("warpdrive:movement/transporter-top");
iconBuffer[2] = iconRegister.registerIcon("warpdrive:movement/transporter-side_inactive");
iconBuffer[3] = iconRegister.registerIcon("warpdrive:movement/transporter-side_active");
iconBuffer = new IIcon[5];
iconBuffer[0] = iconRegister.registerIcon("warpdrive:movement/transporter_core-bottom_top");
iconBuffer[1] = iconRegister.registerIcon("warpdrive:movement/transporter_core-side_invalid");
iconBuffer[2] = iconRegister.registerIcon("warpdrive:movement/transporter_core-side_offline");
iconBuffer[3] = iconRegister.registerIcon("warpdrive:movement/transporter_core-side_low_power");
iconBuffer[4] = iconRegister.registerIcon("warpdrive:movement/transporter_core-side_online");
}
@SideOnly(Side.CLIENT)
@Override
public IIcon getIcon(int side, int metadata) {
if (side == 0 || side == 1) {
return iconBuffer[side];
return iconBuffer[0];
}
return iconBuffer[metadata == 0 ? 2 : 3];
return iconBuffer[(metadata % 4) + 1];
}
@Override
@ -58,8 +58,8 @@ public class BlockTransporter extends BlockAbstractContainer {
if (entityPlayer.getHeldItem() == null) {
final TileEntity tileEntity = world.getTileEntity(x, y, z);
if (tileEntity instanceof TileEntityTransporter) {
Commons.addChatMessage(entityPlayer, ((TileEntityTransporter) tileEntity).getStatus());
if (tileEntity instanceof TileEntityTransporterCore) {
Commons.addChatMessage(entityPlayer, ((TileEntityTransporterCore) tileEntity).getStatus());
return true;
}
}

View file

@ -0,0 +1,95 @@
package cr0s.warpdrive.block.movement;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import cr0s.warpdrive.block.BlockAbstractBase;
import cr0s.warpdrive.data.VectorI;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IIconRegister;
import net.minecraft.util.IIcon;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
public class BlockTransporterScanner extends BlockAbstractBase {
@SideOnly(Side.CLIENT)
private IIcon[] iconBuffer;
public BlockTransporterScanner() {
super(Material.iron);
setBlockName("warpdrive.movement.transporter_scanner");
setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.5F, 1.0F);
setLightOpacity(255);
}
@SideOnly(Side.CLIENT)
@Override
public void registerBlockIcons(final IIconRegister iconRegister) {
iconBuffer = new IIcon[4];
// Solid textures
iconBuffer[0] = iconRegister.registerIcon("warpdrive:movement/transporter_scanner-bottom");
iconBuffer[1] = iconRegister.registerIcon("warpdrive:movement/transporter_scanner-side");
iconBuffer[2] = iconRegister.registerIcon("warpdrive:movement/transporter_scanner-top_offline");
iconBuffer[3] = iconRegister.registerIcon("warpdrive:movement/transporter_scanner-top_online");
}
@Override
public boolean isOpaqueCube() {
return false;
}
@Override
public boolean isNormalCube() {
return false;
}
@Override
public boolean isSideSolid(final IBlockAccess blockAccess, final int x, final int y, final int z, final ForgeDirection side) {
return side == ForgeDirection.DOWN;
}
@Override
public int getLightValue(final IBlockAccess blockAccess, final int x, final int y, final int z) {
final int metadata = blockAccess.getBlockMetadata(x, y, z);
return metadata == 0 ? 0 : 6;
}
@SideOnly(Side.CLIENT)
@Override
public IIcon getIcon(int side, int metadata) {
if (side == 0) {
return iconBuffer[0];
}
if (side != 1) {
return iconBuffer[1];
}
return iconBuffer[metadata == 0 ? 2 : 3];
}
public boolean isValid(final World worldObj, final VectorI vScanner) {
boolean isScannerPosition = true;
for (int x = vScanner.x - 1; x <= vScanner.x + 1; x++) {
for (int z = vScanner.z - 1; z <= vScanner.z + 1; z++) {
// check base block is containment or scanner in checker pattern
final Block blockBase = worldObj.getBlock(x, vScanner.y, z);
if ( !(blockBase instanceof BlockTransporterContainment)
&& (!isScannerPosition || !(blockBase instanceof BlockTransporterScanner)) ) {
return false;
}
isScannerPosition = !isScannerPosition;
// check 2 above blocks are air
if (!worldObj.isAirBlock(x, vScanner.y + 1, z)) {
return false;
}
if (!worldObj.isAirBlock(x, vScanner.y + 2, z)) {
return false;
}
}
}
return true;
}
}

View file

@ -1,893 +0,0 @@
package cr0s.warpdrive.block.movement;
import cr0s.warpdrive.Commons;
import cr0s.warpdrive.WarpDrive;
import cr0s.warpdrive.api.IBeamFrequency;
import cr0s.warpdrive.block.TileEntityAbstractEnergy;
import cr0s.warpdrive.block.forcefield.BlockForceField;
import cr0s.warpdrive.block.forcefield.TileEntityForceField;
import cr0s.warpdrive.block.passive.BlockTransportBeacon;
import cr0s.warpdrive.config.Dictionary;
import cr0s.warpdrive.config.WarpDriveConfig;
import cr0s.warpdrive.data.EnumComponentType;
import cr0s.warpdrive.data.EnumTransporterState;
import cr0s.warpdrive.data.ForceFieldSetup;
import cr0s.warpdrive.data.Vector3;
import cr0s.warpdrive.data.VectorI;
import cr0s.warpdrive.network.PacketHandler;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.peripheral.IComputerAccess;
import li.cil.oc.api.machine.Arguments;
import li.cil.oc.api.machine.Callback;
import li.cil.oc.api.machine.Context;
import java.lang.ref.WeakReference;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.client.particle.EntityFX;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionEffect;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.StatCollector;
import cpw.mods.fml.common.Optional;
import net.minecraftforge.common.util.ForgeDirection;
public class TileEntityTransporter extends TileEntityAbstractEnergy implements IBeamFrequency {
// persistent properties
private int beamFrequency = -1;
private boolean isEnabled = true;
private boolean isLockRequested = false;
private boolean isEnergizeRequested = false;
private VectorI vSource_relative = new VectorI();
private VectorI vDestination_relative = new VectorI();
private double energyFactor = 1.0D;
private double lockStrengthActual = 0.0D;
private int tickCooldown = 0;
private EnumTransporterState transporterState = EnumTransporterState.DISABLED;
// computed properties
private boolean isConnected = false;
private int energyCostForTransfer = 0;
private double lockStrengthOptimal = -1.0D;
private double lockStrengthSpeed = 0.0D;
private boolean isJammed = false;
private VectorI vSource_absolute = new VectorI();
private VectorI vDestination_absolute = new VectorI();
private WeakReference<Entity> weakEntity = null;
private Vector3 v3EntityPosition = null;
private int tickEnergizing = 0;
public TileEntityTransporter() {
super();
IC2_sinkTier = 2;
IC2_sourceTier = 2;
peripheralName = "warpdriveTransporter";
addMethods(new String[] {
"beamFrequency",
"enable",
"source",
"destination",
"lock",
"energyFactor",
"getLockStrength",
"getEnergyRequired",
"energize",
"upgrades"
});
setUpgradeMaxCount(EnumComponentType.ENDER_CRYSTAL, WarpDriveConfig.TRANSPORTER_RANGE_UPGRADE_MAX_QUANTITY);
setUpgradeMaxCount(EnumComponentType.CAPACITIVE_CRYSTAL, WarpDriveConfig.TRANSPORTER_ENERGY_STORED_UPGRADE_MAX_QUANTITY);
setUpgradeMaxCount(EnumComponentType.EMERALD_CRYSTAL, WarpDriveConfig.TRANSPORTER_LOCKING_UPGRADE_MAX_QUANTITY);
}
@Override
protected void onFirstUpdateTick() {
super.onFirstUpdateTick();
updateParameters();
}
@Override
public void updateEntity() {
super.updateEntity();
if (worldObj.isRemote) {
return;
}
// frequency status
isConnected = beamFrequency > 0 && beamFrequency <= IBeamFrequency.BEAM_FREQUENCY_MAX;
// always cooldown
if (tickCooldown > 0) {
tickCooldown--;
} else {
tickCooldown = 0;
}
// consume power and apply general lock strength increase and decay
boolean isPowered;
if (!isEnabled) {
transporterState = EnumTransporterState.DISABLED;
isPowered = false;
// (lock strength is cleared in state machine)
} else {
// energy consumption
final int energyRequired = getEnergyRequired(transporterState);
if (energyRequired > 0) {
isPowered = energy_consume(energyRequired, false);
if (!isPowered) {
transporterState = EnumTransporterState.IDLE;
}
} else {
isPowered = true;
}
// lock strength always decays
lockStrengthActual = Math.max(0.0D, lockStrengthActual * WarpDriveConfig.TRANSPORTER_LOCKING_STRENGTH_FACTOR_PER_TICK);
// lock strength is capped at optimal, increasing when powered
// a slight overshoot is added to force convergence
if ( isPowered
&& ( transporterState == EnumTransporterState.ACQUIRING
|| transporterState == EnumTransporterState.ENERGIZING ) ) {
final double overshoot = 0.01D;
lockStrengthActual = Math.min(lockStrengthOptimal,
lockStrengthActual + lockStrengthSpeed * (lockStrengthOptimal - lockStrengthActual + overshoot));
}
}
// state feedback
final boolean isActive = isEnabled && isConnected && isPowered;
updateMetadata(isActive ? 1 : 0);
if (isActive && isLockRequested && isJammed) {
PacketHandler.sendSpawnParticlePacket(worldObj, "jammed", (byte) 5, new Vector3(this).translate(0.5F),
new Vector3(0.0D, 0.0D, 0.0D),
1.0F, 1.0F, 1.0F,
1.0F, 1.0F, 1.0F,
32);
}
// execute state transitions
switch (transporterState) {
case DISABLED:
isLockRequested = false;
isEnergizeRequested = false;
lockStrengthActual = 0.0D;
if (isActive) {
transporterState = EnumTransporterState.IDLE;
}
break;
case IDLE:
if (isLockRequested) {
// initial validation before starting acquisition
updateParameters();
if (!isJammed) {
transporterState = EnumTransporterState.ACQUIRING;
} else {
tickCooldown = WarpDriveConfig.TRANSPORTER_JAMMED_COOLDOWN_TICKS;
}
}
break;
case ACQUIRING:
if (!isLockRequested) {
transporterState = EnumTransporterState.IDLE;
} else if (isEnergizeRequested) {
// final validation in case environment has changed
updateParameters();
if (isJammed) {
tickCooldown += WarpDriveConfig.TRANSPORTER_JAMMED_COOLDOWN_TICKS;
transporterState = EnumTransporterState.IDLE;
} else {
// reset entity to grab
weakEntity = null;
v3EntityPosition = null;
// consume energy
final int energyRequired = getEnergyRequired(transporterState);
if (energy_consume(energyRequired, false)) {
tickEnergizing = WarpDriveConfig.TRANSPORTER_TRANSFER_WARMUP_TICKS;
transporterState = EnumTransporterState.ENERGIZING;
}
}
}
break;
case ENERGIZING:
// get entity
updateEntityToTransfer();
if (weakEntity == null) {
transporterState = EnumTransporterState.ACQUIRING;
isEnergizeRequested = false;
tickCooldown = WarpDriveConfig.TRANSPORTER_TRANSFER_COOLDOWN_TICKS;
lockStrengthActual = Math.max(0.0D, lockStrengthActual - WarpDriveConfig.TRANSPORTER_TRANSFER_LOCKING_LOST);
break;
}
final Entity entity = weakEntity.get();
if (entity == null) {
// bad state
WarpDrive.logger.info(String.format("%s Entity went missing, retrying next tick...",
this));
break;
}
// warm-up
if (tickEnergizing > 0) {
tickEnergizing--;
break;
}
// check lock strength
if ( lockStrengthActual < 1.0D
&& worldObj.rand.nextDouble() > lockStrengthActual ) {
if (WarpDriveConfig.LOGGING_TRANSPORTER) {
WarpDrive.logger.info(String.format("%s Insufficient lock strength %.3f", this, lockStrengthActual));
}
applyTeleportationDamages(false, entity, lockStrengthActual);
tickCooldown = WarpDriveConfig.TRANSPORTER_TRANSFER_COOLDOWN_TICKS;
break;
}
// teleport
final Vector3 v3Target = new Vector3(
vDestination_absolute.x + entity.posX - vSource_absolute.x,
vDestination_absolute.y + entity.posY - vSource_absolute.y,
vDestination_absolute.z + entity.posZ - vSource_absolute.z);
if (WarpDriveConfig.LOGGING_TRANSPORTER) {
WarpDrive.logger.info(String.format("%s Teleporting entity %s to %s",
this, entity, v3Target));
}
Commons.moveEntity(entity, worldObj, v3Target);
applyTeleportationDamages(false, entity, lockStrengthActual);
tickCooldown = WarpDriveConfig.TRANSPORTER_TRANSFER_COOLDOWN_TICKS;
lockStrengthActual = Math.max(0.0D, lockStrengthActual - WarpDriveConfig.TRANSPORTER_TRANSFER_LOCKING_LOST);
break;
default:
transporterState = EnumTransporterState.DISABLED;
break;
}
// client effects
if ( lockStrengthActual > 0.0F
|| tickEnergizing > 0
|| tickCooldown > 0 ) {
final Entity entity = weakEntity == null ? null : weakEntity.get();
PacketHandler.sendTransporterEffectPacket(worldObj, vSource_absolute, vDestination_absolute, lockStrengthActual,
entity, v3EntityPosition,
tickEnergizing, tickCooldown, 64);
}
}
@Override
public String getStatusHeader() {
return super.getStatusHeader()
+ "\n" + StatCollector.translateToLocalFormatted("warpdrive.transporter.status",
vSource_absolute.x, vSource_absolute.y, vSource_absolute.z,
vDestination_absolute.x, vDestination_absolute.y, vDestination_absolute.z);
}
@Override
public int getBeamFrequency() {
return beamFrequency;
}
@Override
public void setBeamFrequency(final int beamFrequency) {
this.beamFrequency = beamFrequency;
}
private class FocusValues {
public int countRangeUpgrades;
public double strength;
public double speed;
}
private void updateParameters() {
isJammed = false;
// check connection
if (!isConnected) {
isJammed = true;
return;
}
// check minimum range
if (vSource_relative.subtract(vDestination_relative).getMagnitudeSquared() < 2) {
isJammed = true;
return;
}
// compute absolute coordinates
vSource_absolute = new VectorI(this).translate(EnumFacing.UP).translate(vSource_relative);
vDestination_absolute = new VectorI(this).translate(EnumFacing.UP).translate(vDestination_relative);
// compute range as max distance between transporter, source and destination
final int rangeSource2 = vSource_relative.getMagnitudeSquared();
final int rangeDestination2 = vDestination_relative.getMagnitudeSquared();
final int rangeDelta2 = vSource_relative.subtract(vDestination_relative).getMagnitudeSquared();
final int rangeActual = (int) Math.ceil(Math.sqrt(Math.max(rangeSource2, Math.max(rangeDestination2, rangeDelta2))));
// compute energy cost from range
energyCostForTransfer = (int) Math.ceil(Math.max(0, Commons.interpolate(
0,
WarpDriveConfig.TRANSPORTER_TRANSFER_ENERGY_AT_MIN_RANGE,
WarpDriveConfig.TRANSPORTER_RANGE_BASE_BLOCKS,
WarpDriveConfig.TRANSPORTER_TRANSFER_ENERGY_AT_MAX_RANGE,
rangeActual)));
// compute focalization bonuses
final FocusValues focusValuesSource = getFocusValueAtCoordinates(vSource_absolute);
final FocusValues focusValuesDestination = getFocusValueAtCoordinates(vDestination_absolute);
final double focusBoost = energyFactor
* WarpDriveConfig.TRANSPORTER_LOCKING_STRENGTH_BONUS_AT_MAX_ENERGY_FACTOR
/ WarpDriveConfig.TRANSPORTER_TRANSFER_ENERGY_FACTOR_MAX;
lockStrengthOptimal = (focusValuesSource.strength + focusValuesDestination.strength) / 2.0D + focusBoost;
lockStrengthSpeed = (focusValuesSource.speed + focusValuesDestination.speed) / 2.0D
/ WarpDriveConfig.TRANSPORTER_LOCKING_SPEED_OPTIMAL_TICKS;
final int rangeMax = WarpDriveConfig.TRANSPORTER_RANGE_BASE_BLOCKS
+ WarpDriveConfig.TRANSPORTER_RANGE_UPGRADE_BLOCKS * focusValuesSource.countRangeUpgrades
+ WarpDriveConfig.TRANSPORTER_RANGE_UPGRADE_BLOCKS * focusValuesDestination.countRangeUpgrades;
if (WarpDriveConfig.LOGGING_TRANSPORTER) {
WarpDrive.logger.info(String.format("Transporter parameters at (%d %d %d) are range (actual %d max %d) lockStrength (optimal %.3f speed %.3f)",
xCoord, yCoord, zCoord,
rangeActual, rangeMax,
lockStrengthOptimal, lockStrengthSpeed));
}
if (rangeActual > rangeMax) {
isJammed = true;
return;
}
isJammed |= isJammedTrajectory(vSource_absolute);
isJammed |= isJammedTrajectory(vDestination_absolute);
}
private FocusValues getFocusValueAtCoordinates(final VectorI vAbsolute) {
// scan the area
int countBeacons = 0;
int countTransporters = 0;
int sumRangeUpgrades = 0;
int sumFocusUpgrades = 0;
final int xMin = vAbsolute.x - WarpDriveConfig.TRANSPORTER_FOCUS_SEARCH_RADIUS_BLOCKS;
final int xMax = vAbsolute.x + WarpDriveConfig.TRANSPORTER_FOCUS_SEARCH_RADIUS_BLOCKS;
final int yMin = vAbsolute.y - WarpDriveConfig.TRANSPORTER_FOCUS_SEARCH_RADIUS_BLOCKS;
final int yMax = vAbsolute.y + WarpDriveConfig.TRANSPORTER_FOCUS_SEARCH_RADIUS_BLOCKS;
final int zMin = vAbsolute.z - WarpDriveConfig.TRANSPORTER_FOCUS_SEARCH_RADIUS_BLOCKS;
final int zMax = vAbsolute.z + WarpDriveConfig.TRANSPORTER_FOCUS_SEARCH_RADIUS_BLOCKS;
for (int x = xMin; x <= xMax; x++) {
for (int y = yMin; y <= yMax; y++) {
if (y < 0 || y > 254) {
continue;
}
for (int z = zMin; z <= zMax; z++) {
final Block block = worldObj.getBlock(x, y, z);
if (block instanceof BlockTransportBeacon) {
// count active beacons
final boolean isActive = worldObj.getBlockMetadata(x, y, z) == 0;
if (isActive) {
countBeacons++;
}
} else if (block instanceof BlockTransporter) {
// count active transporters
final TileEntity tileEntity = worldObj.getTileEntity(x, y, z);
if (tileEntity instanceof TileEntityTransporter) {
countTransporters++;
// remember upgrades
sumRangeUpgrades += ((TileEntityTransporter) tileEntity).getUpgradeCount(EnumComponentType.ENDER_CRYSTAL);
sumFocusUpgrades += ((TileEntityTransporter) tileEntity).getUpgradeCount(EnumComponentType.EMERALD_CRYSTAL);
}
}
}
}
}
// compute values
final FocusValues result = new FocusValues();
if (countTransporters > 0) {
final int countFocusUpgrades = sumFocusUpgrades / countTransporters;
result.countRangeUpgrades = sumRangeUpgrades / countTransporters;
result.speed = WarpDriveConfig.TRANSPORTER_LOCKING_SPEED_AT_TRANSPORTER + countFocusUpgrades * WarpDriveConfig.TRANSPORTER_LOCKING_STRENGTH_UPGRADE;
result.strength = WarpDriveConfig.TRANSPORTER_LOCKING_STRENGTH_AT_TRANSPORTER + countFocusUpgrades * WarpDriveConfig.TRANSPORTER_LOCKING_SPEED_UPGRADE;
} else if (countBeacons > 0) {
result.countRangeUpgrades = 0;
result.speed = WarpDriveConfig.TRANSPORTER_LOCKING_SPEED_AT_FOCUS;
result.strength = WarpDriveConfig.TRANSPORTER_LOCKING_STRENGTH_AT_FOCUS;
} else {
result.countRangeUpgrades = 0;
result.speed = WarpDriveConfig.TRANSPORTER_LOCKING_SPEED_IN_WILDERNESS;
result.strength = WarpDriveConfig.TRANSPORTER_LOCKING_STRENGTH_IN_WILDERNESS;
}
if (WarpDriveConfig.LOGGING_TRANSPORTER) {
WarpDrive.logger.info(String.format("Transporter getFocusValueAtCoordinates %s gives range %d speed %.3f strength %.3f",
vAbsolute, result.countRangeUpgrades, result.speed, result.strength));
}
return result;
}
private boolean isJammedTrajectory(final VectorI vAbsolute) {
final VectorI vPath = vAbsolute.clone().translateBack(new VectorI(this));
final int length = (int) Math.ceil(3 * Math.sqrt(vPath.getMagnitudeSquared()));
final Vector3 v3Delta = new Vector3(vPath.x / (double) length, vPath.y / (double) length, vPath.z / (double) length);
// scan along given trajectory
final Vector3 v3Current = new Vector3(this).translate(0.5D);
final VectorI vCurrent = new VectorI(this);
final VectorI vPrevious = vCurrent.clone();
for (int step = 0; step < length; step++) {
v3Current.translate(v3Delta);
vCurrent.x = (int) Math.round(v3Current.x);
vCurrent.y = (int) Math.round(v3Current.y);
vCurrent.z = (int) Math.round(v3Current.z);
// skip repeating coordinates
if (vCurrent.equals(vPrevious)) {
continue;
}
if (isJammedCoordinate(vCurrent)) return true;
// remember this coordinates
vPrevious.x = vCurrent.x;
vPrevious.y = vCurrent.y;
vPrevious.z = vCurrent.z;
}
return false;
}
private boolean isJammedCoordinate(final VectorI vCurrent) {
// check block blacklist for blinking
final Block block = vCurrent.getBlock(worldObj);
if (Dictionary.BLOCKS_NOBLINK.contains(block)) {
return true;
}
// allow passing through force fields with same beam frequency
if (block instanceof BlockForceField) {
final TileEntity tileEntity = vCurrent.getTileEntity(worldObj);
if (tileEntity instanceof TileEntityForceField) {
final ForceFieldSetup forceFieldSetup = ((TileEntityForceField) tileEntity).getForceFieldSetup();
if (forceFieldSetup == null) {
// projector not loaded yet, consider it jammed by default
WarpDrive.logger.warn(String.format("%s projector not loaded at %s", this, tileEntity));
return true;
}
if (forceFieldSetup.beamFrequency != beamFrequency) {
// jammed by invalid beam frequency
if (WarpDriveConfig.LOGGING_TRANSPORTER) {
WarpDrive.logger.info(String.format("%s signal jammed by %s", this, tileEntity));
}
return true;
}
}
}
return false;
}
private int getEnergyRequired(final EnumTransporterState transporterState) {
switch (transporterState) {
case DISABLED:
return 0;
case IDLE:
return 0;
case ACQUIRING:
return (int) Math.ceil(WarpDriveConfig.TRANSPORTER_ACQUIRING_ENERGY_FACTOR * energyCostForTransfer * energyFactor);
case ENERGIZING:
return (int) Math.ceil(energyCostForTransfer * energyFactor);
default:
return 0;
}
}
private void applyTeleportationDamages(final boolean isPreTeleportation, final Entity entity, final double strength) {
// skip invulnerable
if ( entity.isDead
|| entity.isEntityInvulnerable() ) {
return;
}
// add bonus if transport was successful
final double strengthToUse = isPreTeleportation ? strength : Math.random() * WarpDriveConfig.TRANSPORTER_TRANSFER_SUCCESS_LOCK_BONUS + strength;
final double strengthSafe = 0.95D;
final double strengthMaxDamage = 0.65D;
final double strengthNoDamage = 0.10D;
if (strengthToUse > strengthSafe) {
return;
}
final double damageNormalized = (strengthSafe - strengthToUse) / (strengthSafe - strengthMaxDamage);
final double damageMax = isPreTeleportation ? WarpDriveConfig.TRANSPORTER_TRANSFER_FAILURE_MAX_DAMAGE : WarpDriveConfig.TRANSPORTER_TRANSFER_SUCCESS_MAX_DAMAGE ;
// final double damageAmount = Commons.clamp(1.0D, 1000.0D, Math.pow(10.0D, 10.0D * damageNormalized));
final double damageAmount = Commons.clamp(1.0D, 1000.0D, damageMax * damageNormalized);
if (WarpDriveConfig.LOGGING_TRANSPORTER) {
WarpDrive.logger.info(String.format("%s Applying teleportation damages %s transport with %.3f strength, %.2f damage towards %s",
this,
isPreTeleportation ? "pre" : "post",
strengthToUse,
damageAmount,
entity));
}
if (entity instanceof EntityLivingBase) {
entity.attackEntityFrom(WarpDrive.damageTeleportation, (float) damageAmount);
final boolean isCreative = (entity instanceof EntityPlayer) && ((EntityPlayer) entity).capabilities.isCreativeMode;
if (!isCreative) {
if (isPreTeleportation) {
// add 1s nausea
((EntityLivingBase) entity).addPotionEffect(new PotionEffect(Potion.confusion.id, 20, 0, true));
} else {
// add 5s poison
((EntityLivingBase) entity).addPotionEffect(new PotionEffect(Potion.poison.id, 5 * 20, 0, true));
}
}
} else if (strengthToUse > strengthNoDamage) {
// add lava blade at location
final VectorI vPosition = new VectorI(entity);
if (worldObj.isAirBlock(vPosition.x, vPosition.y, vPosition.z)) {
worldObj.setBlock(vPosition.x, vPosition.y, vPosition.z, Blocks.flowing_lava, 6, 2);
}
}
}
private void updateEntityToTransfer() {
// validate existing entity
if (weakEntity != null) {
final Entity entity = weakEntity.get();
if ( entity == null
|| entity.isDead ) {
// no longer valid => search a new one, no energy lost
weakEntity = null;
v3EntityPosition = null;
} else {
final double tolerance2 = WarpDriveConfig.TRANSPORTER_ENTITY_MOVEMENT_TOLERANCE_BLOCKS
* WarpDriveConfig.TRANSPORTER_ENTITY_MOVEMENT_TOLERANCE_BLOCKS;
final double distance2 = v3EntityPosition.distanceTo_square(entity);
if (distance2 > tolerance2) {
// entity moved too much => damage existing one, grab another, lose energy
final double strength = Math.sqrt(distance2) / Math.sqrt(tolerance2) / 2.0D;
applyTeleportationDamages(true, entity, strength);
weakEntity = null;
v3EntityPosition = null;
transporterState = EnumTransporterState.ACQUIRING;
}
}
}
// grab another entity on first tick or if bad things happened
if (weakEntity == null) {
final Entity entityClosest = getClosestEntityAtSource();
if (entityClosest == null) {
return;
}
weakEntity = new WeakReference<>(entityClosest);
v3EntityPosition = new Vector3(entityClosest);
}
}
private Entity getClosestEntityAtSource() {
final AxisAlignedBB aabb = AxisAlignedBB.getBoundingBox(
vSource_absolute.x - WarpDriveConfig.TRANSPORTER_ENTITY_GRAB_RADIUS_BLOCKS,
vSource_absolute.y - 1.0D,
vSource_absolute.z - WarpDriveConfig.TRANSPORTER_ENTITY_GRAB_RADIUS_BLOCKS,
vSource_absolute.x + WarpDriveConfig.TRANSPORTER_ENTITY_GRAB_RADIUS_BLOCKS + 1.0D,
vSource_absolute.y + 2.0D,
vSource_absolute.z + WarpDriveConfig.TRANSPORTER_ENTITY_GRAB_RADIUS_BLOCKS + 1.0D);
Entity entityClosest = null;
double rangeClosest2 = Integer.MAX_VALUE;
final List entities = worldObj.getEntitiesWithinAABBExcludingEntity(null, aabb);
for (final Object object : entities) {
if (!(object instanceof Entity)) {
continue;
}
final Entity entity = (Entity) object;
// skip particle effects
if (entity instanceof EntityFX) {
continue;
}
// skip blacklisted ids
final String entityId = EntityList.getEntityString(entity);
if (Dictionary.ENTITIES_LEFTBEHIND.contains(entityId)) {
if (WarpDriveConfig.LOGGING_TRANSPORTER) {
WarpDrive.logger.info(String.format("Entity is not valid for transportation (id %s) %s",
entityId, entity));
}
continue;
}
// keep closest one
final double range2 = vSource_absolute.distance2To(entity);
if (range2 < rangeClosest2) {
rangeClosest2 = range2;
entityClosest = (Entity) object;
}
}
return entityClosest;
}
@Override
public int energy_getMaxStorage() {
final int energyUpgrades = getUpgradeCount(EnumComponentType.CAPACITIVE_CRYSTAL);
return WarpDriveConfig.TRANSPORTER_MAX_ENERGY_STORED + energyUpgrades * WarpDriveConfig.TRANSPORTER_ENERGY_STORED_UPGRADE_BONUS;
}
@Override
public boolean energy_canInput(final ForgeDirection from) {
return from != ForgeDirection.UP;
}
@Override
public void writeToNBT(final NBTTagCompound tagCompound) {
super.writeToNBT(tagCompound);
tagCompound.setInteger(IBeamFrequency.BEAM_FREQUENCY_TAG, beamFrequency);
tagCompound.setBoolean("isEnabled", isEnabled);
tagCompound.setBoolean("isLockRequested", isLockRequested);
tagCompound.setBoolean("isEnergizeRequested", isEnergizeRequested);
tagCompound.setTag("source", vSource_relative.writeToNBT(new NBTTagCompound()));
tagCompound.setTag("destination", vDestination_relative.writeToNBT(new NBTTagCompound()));
tagCompound.setDouble("energyFactor", energyFactor);
tagCompound.setDouble("lockStrengthActual", lockStrengthActual);
tagCompound.setInteger("tickCooldown", tickCooldown);
tagCompound.setString("state", transporterState.toString());
}
@Override
public void readFromNBT(final NBTTagCompound tagCompound) {
super.readFromNBT(tagCompound);
beamFrequency = tagCompound.getInteger(IBeamFrequency.BEAM_FREQUENCY_TAG);
isEnabled = tagCompound.getBoolean("isEnabled");
isLockRequested = tagCompound.getBoolean("isLockRequested");
isEnergizeRequested = tagCompound.getBoolean("isEnergizeRequested");
final NBTBase tagSource = tagCompound.getTag("source");
if (tagSource instanceof NBTTagCompound) {
vSource_relative.readFromNBT((NBTTagCompound) tagSource);
}
final NBTBase tagDestination = tagCompound.getTag("destination");
if (tagDestination instanceof NBTTagCompound) {
vDestination_relative.readFromNBT((NBTTagCompound) tagDestination);
}
energyFactor = tagCompound.getDouble("energyFactor");
lockStrengthActual = tagCompound.getDouble("lockStrengthActual");
tickCooldown = tagCompound.getInteger("tickCooldown");
try {
transporterState = EnumTransporterState.valueOf(tagCompound.getString("state"));
} catch (IllegalArgumentException exception) {
transporterState = EnumTransporterState.DISABLED;
}
}
// Common OC/CC methods
public Boolean[] enable(Object[] arguments) {
if (arguments.length == 1) {
isEnabled = Commons.toBool(arguments[0]);
markDirty();
}
return new Boolean[] { isEnabled };
}
public Integer[] source(final Object[] arguments) {
final VectorI vNew = getVectorI(vSource_relative, arguments);
if (!vNew.equals(vSource_relative)) {
isLockRequested = false;
isEnergizeRequested = false;
vSource_relative = vNew;
}
return new Integer[] { vSource_relative.x, vSource_relative.y, vSource_relative.z };
}
public Integer[] destination(final Object[] arguments) {
final VectorI vNew = getVectorI(vDestination_relative, arguments);
if (!vNew.equals(vDestination_relative)) {
isLockRequested = false;
isEnergizeRequested = false;
vDestination_relative = vNew;
}
return new Integer[] { vDestination_relative.x, vDestination_relative.y, vDestination_relative.z };
}
private VectorI getVectorI(final VectorI vDefault, final Object[] arguments) {
final VectorI vResult = vDefault.clone();
try {
if (arguments.length == 3) {
vResult.x = Commons.toInt(arguments[0]);
vResult.y = Commons.toInt(arguments[1]);
vResult.z = Commons.toInt(arguments[2]);
} else if (arguments.length == 1) {
vResult.x = 0;
vResult.y = 0;
vResult.z = 0;
}
} catch (NumberFormatException e) {
// ignore
}
return vResult;
}
private Boolean[] lock(final Object[] arguments) {
if (arguments.length == 1) {
isLockRequested = Commons.toBool(arguments[0]);
markDirty();
}
return new Boolean[] { isLockRequested };
}
private Double[] energyFactor(final Object[] arguments) {
try {
if (arguments.length >= 1) {
energyFactor = Commons.clamp(1, WarpDriveConfig.TRANSPORTER_TRANSFER_ENERGY_FACTOR_MAX, Commons.toDouble(arguments[0]));
}
} catch (NumberFormatException exception) {
// ignore
}
return new Double[] { energyFactor };
}
private Double[] getLockStrength() {
return new Double[] { lockStrengthActual };
}
private Integer[] getEnergyRequired() {
return new Integer[] { getEnergyRequired(EnumTransporterState.ENERGIZING) };
}
private Boolean[] energize(final Object[] arguments) {
if (arguments.length == 1) {
isEnergizeRequested = Commons.toBool(arguments[0]);
markDirty();
}
return new Boolean[] { isEnergizeRequested };
}
// OpenComputers callback methods
@Callback
@Optional.Method(modid = "OpenComputers")
public Object[] beamFrequency(Context context, Arguments arguments) {
if (arguments.count() == 1) {
setBeamFrequency(arguments.checkInteger(0));
}
return new Integer[] { beamFrequency };
}
@Callback
@Optional.Method(modid = "OpenComputers")
public Object[] enable(Context context, Arguments arguments) {
return enable(argumentsOCtoCC(arguments));
}
@Callback
@Optional.Method(modid = "OpenComputers")
public Object[] source(Context context, Arguments arguments) {
return source(argumentsOCtoCC(arguments));
}
@Callback
@Optional.Method(modid = "OpenComputers")
public Object[] destination(Context context, Arguments arguments) {
return destination(argumentsOCtoCC(arguments));
}
@Callback
@Optional.Method(modid = "OpenComputers")
public Object[] lock(Context context, Arguments arguments) {
return lock(argumentsOCtoCC(arguments));
}
@Callback
@Optional.Method(modid = "OpenComputers")
public Object[] energyFactor(Context context, Arguments arguments) {
return energyFactor(argumentsOCtoCC(arguments));
}
@Callback
@Optional.Method(modid = "OpenComputers")
public Object[] getLockStrength(Context context, Arguments arguments) {
return getLockStrength();
}
@Callback
@Optional.Method(modid = "OpenComputers")
public Object[] getEnergyRequired(Context context, Arguments arguments) {
return getEnergyRequired();
}
@Callback
@Optional.Method(modid = "OpenComputers")
public Object[] energize(Context context, Arguments arguments) {
return energize(argumentsOCtoCC(arguments));
}
// ComputerCraft IPeripheral methods
@Override
@Optional.Method(modid = "ComputerCraft")
public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) {
final String methodName = getMethodName(method);
switch (methodName) {
case "beamFrequency":
if (arguments.length == 1) {
setBeamFrequency(Commons.toInt(arguments[0]));
}
return new Integer[] { beamFrequency };
case "enable":
return enable(arguments);
case "source":
return source(arguments);
case "destination":
return destination(arguments);
case "lock":
return lock(arguments);
case "energyFactor":
return energyFactor(arguments);
case "getLockStrength":
return getLockStrength();
case "getEnergyRequired":
return getEnergyRequired();
case "energize":
return energize(arguments);
}
return super.callMethod(computer, context, method, arguments);
}
@Override
public String toString() {
return String.format("%s Beam \'%d\' @ %s (%d %d %d)",
getClass().getSimpleName(),
beamFrequency,
worldObj == null ? "~NULL~" : worldObj.provider.getDimensionName(),
xCoord, yCoord, zCoord);
}
}

File diff suppressed because it is too large Load diff

View file

@ -174,7 +174,7 @@ public class Recipes {
'p', ItemComponent.getItemStack(EnumComponentType.POWER_INTERFACE)));
// Transporter
GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(WarpDrive.blockTransporter), false, "iii", "ptc", "iii",
GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(WarpDrive.blockTransporterCore), false, "iii", "ptc", "iii",
'i', Items.iron_ingot,
't', ItemComponent.getItemStack(EnumComponentType.ENDER_CRYSTAL),
'c', ItemComponent.getItemStack(EnumComponentType.COMPUTER_INTERFACE),
@ -348,7 +348,7 @@ public class Recipes {
'w', "logWood",
'm', WarpDrive.blockMiningLaser }));
GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(WarpDrive.blockTransporter), false, new Object[] { "ece", "imi", "iei",
GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(WarpDrive.blockTransporterCore), false, new Object[] { "ece", "imi", "iei",
'e', Items.ender_pearl,
'c', circuit,
'i', ironPlate,
@ -491,7 +491,7 @@ public class Recipes {
'm', WarpDrive.blockMiningLaser,
's', WarpDriveConfig.getModItemStack("IC2", "itemToolChainsaw", -1) }));
GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(WarpDrive.blockTransporter), false, new Object[] { "aea", "ctc", "ama",
GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(WarpDrive.blockTransporterCore), false, new Object[] { "aea", "ctc", "ama",
'a', advancedAlloy,
'e', Items.ender_pearl,
'c', "circuitAdvanced",
@ -1269,15 +1269,25 @@ public class Recipes {
'a', Items.diamond_axe,
'g', "paneGlassColorless"));
// Transporter is non-functional => no recipe
/*
GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(WarpDrive.blockTransporter), false, "aea", "ctc", "ama",
'a', advancedAlloy,
'e', Items.ender_pearl,
'c', "circuitAdvanced",
'm', advancedMachine,
't', WarpDriveConfig.getModItemStack("IC2", "blockMachine2", 0) )); // Teleporter
/**/
// Transporter containment is 1 HV Machine casing, 2 Ender crystal, gives 2
GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(WarpDrive.blockTransporterContainment, 2), false, " e ", " m ", " e ",
'm', itemStackMachineCasings[2],
'e', ItemComponent.getItemStack(EnumComponentType.ENDER_CRYSTAL)));
// Transporter core is 1 HV Machine casing, 1 Emerald crystal, 1 Capacitive crystal, 1 Diamond crystal, 1 Power interface, 1 Computer interface
GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(WarpDrive.blockTransporterCore), false, " E ", "pmd", " c ",
'm', itemStackMachineCasings[2],
'c', ItemComponent.getItemStack(EnumComponentType.COMPUTER_INTERFACE),
'd', ItemComponent.getItemStack(EnumComponentType.DIAMOND_CRYSTAL),
'E', ItemComponent.getItemStack(EnumComponentType.EMERALD_CRYSTAL),
'p', ItemComponent.getItemStack(EnumComponentType.POWER_INTERFACE)));
// Transporter scanner is 1 HV Machine casing, 1 Emerald crystal, 3 Capacitive crystal, 2 Ender crystal
GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(WarpDrive.blockTransporterScanner), false, " E ", "eme", "CCC",
'm', itemStackMachineCasings[2],
'e', ItemComponent.getItemStack(EnumComponentType.ENDER_CRYSTAL),
'E', ItemComponent.getItemStack(EnumComponentType.EMERALD_CRYSTAL),
'C', ItemComponent.getItemStack(EnumComponentType.CAPACITIVE_CRYSTAL)));
// IC2 needs to be loaded for the following 2 recipes
if (WarpDriveConfig.isIndustrialCraft2Loaded) {
@ -1358,7 +1368,7 @@ public class Recipes {
't', oreEmeraldOrTitaniumPlate,
'i', oreEmeraldOrReinforcedIridiumPlate,
'c', itemStackGoldIngotOrCoil,
'm', itemStackMachineCasings[3] ));
'm', itemStackMachineCasings[3] ));
// Enantiomorphic reactor core is 1 EV Machine casing, 4 Capacitive crystal, 1 Computer interface, 1 Power interface, 2 Lenses
GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(WarpDrive.blockEnanReactorCore), false, "CpC", "lml", "CcC",

View file

@ -359,6 +359,10 @@ public class WarpDriveConfig {
public static int TRANSPORTER_MAX_ENERGY_STORED = 2000000;
public static int TRANSPORTER_ENERGY_STORED_UPGRADE_BONUS = TRANSPORTER_MAX_ENERGY_STORED / 2;
public static int TRANSPORTER_ENERGY_STORED_UPGRADE_MAX_QUANTITY = 8;
public static int TRANSPORTER_UPDATE_PARAMETERS_TICKS = 1 * 20;
public static int TRANSPORTER_SCANNER_GRAB_XZ_BLOCKS = 8;
public static int TRANSPORTER_SCANNER_GRAB_Y_BELOW_BLOCKS = 3;
public static int TRANSPORTER_SCANNER_GRAB_Y_ABOVE_BLOCKS = 1;
public static int TRANSPORTER_RANGE_BASE_BLOCKS = 128;
public static int TRANSPORTER_RANGE_UPGRADE_BLOCKS = 16;
public static int TRANSPORTER_RANGE_UPGRADE_MAX_QUANTITY = 8;
@ -372,12 +376,11 @@ public class WarpDriveConfig {
public static int TRANSPORTER_TRANSFER_SUCCESS_MAX_DAMAGE = 100;
public static double TRANSPORTER_TRANSFER_LOCKING_LOST = 0.5D;
public static int TRANSPORTER_TRANSFER_WARMUP_TICKS = 3 * 20;
public static int TRANSPORTER_TRANSFER_RELEASE_TICKS = 2 * 20;
public static int TRANSPORTER_TRANSFER_COOLDOWN_TICKS = 10 * 20;
public static double TRANSPORTER_ENTITY_MOVEMENT_TOLERANCE_BLOCKS = 1.0D;
public static int TRANSPORTER_ENTITY_GRAB_RADIUS_BLOCKS = 2;
public static int TRANSPORTER_FOCUS_SEARCH_RADIUS_BLOCKS = 2;
public static double TRANSPORTER_LOCKING_STRENGTH_FACTOR_PER_TICK = 0.999D; // natural decay
public static double TRANSPORTER_LOCKING_STRENGTH_FACTOR_PER_TICK = Math.pow(0.01D, 1.0D / 300.0D); // natural decay down to 1% over 300 ticks
public static double TRANSPORTER_LOCKING_STRENGTH_IN_WILDERNESS = 0.25D;
public static double TRANSPORTER_LOCKING_STRENGTH_AT_FOCUS = 0.5D;
public static double TRANSPORTER_LOCKING_STRENGTH_AT_TRANSPORTER = 1.0D;

View file

@ -1,5 +1,6 @@
package cr0s.warpdrive.data;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.ChunkCoordIntPair;
@ -19,12 +20,19 @@ public class GlobalPosition {
this.z = z;
}
public GlobalPosition(TileEntity tileEntity) {
public GlobalPosition(final TileEntity tileEntity) {
this(tileEntity.getWorldObj().provider.dimensionId, tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord);
}
public GlobalPosition(final Entity entity) {
this(entity.worldObj.provider.dimensionId,
(int) Math.floor(entity.posX),
(int) Math.floor(entity.posY),
(int) Math.floor(entity.posZ));
}
public WorldServer getWorldServerIfLoaded() {
WorldServer world = DimensionManager.getWorld(dimensionId);
final WorldServer world = DimensionManager.getWorld(dimensionId);
// skip unloaded worlds
if (world == null) {
return null;
@ -52,11 +60,29 @@ public class GlobalPosition {
return getWorldServerIfLoaded() != null;
}
public CelestialObject getCelestialObject(final boolean isRemote) {
return CelestialObjectManager.get(isRemote, dimensionId, x, z);
}
public Vector3 getUniversalCoordinates(final boolean isRemote) {
CelestialObject celestialObject = CelestialObjectManager.get(isRemote, dimensionId, x, z);
final CelestialObject celestialObject = CelestialObjectManager.get(isRemote, dimensionId, x, z);
return StarMapRegistry.getUniversalCoordinates(celestialObject, x, y, z);
}
public VectorI getVectorI() {
return new VectorI(x, y, z);
}
public double distance2To(final Entity entity) {
if (entity.worldObj.provider.dimensionId != dimensionId) {
return Double.MAX_VALUE;
}
final double newX = entity.posX - x;
final double newY = entity.posY - y;
final double newZ = entity.posZ - z;
return newX * newX + newY * newY + newZ * newZ;
}
public GlobalPosition(final NBTTagCompound tagCompound) {
dimensionId = tagCompound.getInteger("dimensionId");
x = tagCompound.getInteger("x");
@ -76,6 +102,22 @@ public class GlobalPosition {
&& x == tileEntity.xCoord && y == tileEntity.yCoord && z == tileEntity.zCoord;
}
@Override
public boolean equals(final Object object) {
if (object instanceof GlobalPosition) {
GlobalPosition globalPosition = (GlobalPosition) object;
return (dimensionId == globalPosition.dimensionId) && (x == globalPosition.x) && (y == globalPosition.y) && (z == globalPosition.z);
} else if (object instanceof VectorI) {
VectorI vector = (VectorI) object;
return (x == vector.x) && (y == vector.y) && (z == vector.z);
} else if (object instanceof TileEntity) {
TileEntity tileEntity = (TileEntity) object;
return (dimensionId == tileEntity.getWorldObj().provider.dimensionId) && (x == tileEntity.xCoord) && (y == tileEntity.yCoord) && (z == tileEntity.zCoord);
}
return false;
}
@Override
public int hashCode() {
return dimensionId << 24 + (x >> 10) << 12 + y << 10 + (z >> 10);

View file

@ -8,36 +8,49 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
public class MovingEntity {
private final WeakReference<Entity> weakEntity;
public final double originalX;
public final double originalY;
public final double originalZ;
public MovingEntity(final Entity entity) {
weakEntity = new WeakReference<>(entity);
originalX = entity.posX;
originalY = entity.posY;
originalZ = entity.posZ;
}
public Entity getEntity() {
return weakEntity.get();
}
public boolean isUnlimited() {
final Entity entity = getEntity();
if (!(entity instanceof EntityPlayer)) {
return false;
}
final String playerName = ((EntityPlayer) entity).getDisplayName();
for (final String unlimitedName : WarpDriveConfig.SHIP_VOLUME_UNLIMITED_PLAYERNAMES) {
if (unlimitedName.equals(playerName)) {
return true;
}
}
return false;
}
public static final MovingEntity INVALID = new MovingEntity(null);
private final WeakReference<Entity> weakEntity;
public final Vector3 v3OriginalPosition;
public MovingEntity(final Entity entity) {
if (entity == null) {
weakEntity = new WeakReference<>(null);
v3OriginalPosition = new Vector3(0, -100, 0);
} else {
weakEntity = new WeakReference<>(entity);
v3OriginalPosition = new Vector3(entity);
}
}
public Entity getEntity() {
return weakEntity.get();
}
public boolean isUnlimited() {
final Entity entity = getEntity();
if (!(entity instanceof EntityPlayer)) {
return false;
}
final String playerName = ((EntityPlayer) entity).getDisplayName();
for (final String unlimitedName : WarpDriveConfig.SHIP_VOLUME_UNLIMITED_PLAYERNAMES) {
if (unlimitedName.equals(playerName)) {
return true;
}
}
return false;
}
public double getDistanceMoved_square() {
final Entity entity = getEntity();
if (entity == null) {
return Double.MAX_VALUE;
}
return v3OriginalPosition.distanceTo_square(entity);
}
}

View file

@ -12,6 +12,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
import net.minecraft.block.Block;
@ -95,6 +96,25 @@ public class StarMapRegistry {
// not found => ignore it
}
public StarMapRegistryItem getByUUID(final EnumStarMapEntryType enumStarMapEntryType, final UUID uuid) {
for (final Integer dimensionId : registry.keySet()) {
final CopyOnWriteArraySet<StarMapRegistryItem> setStarMapRegistryItems = registry.get(dimensionId);
if (setStarMapRegistryItems == null) {
continue;
}
for (final StarMapRegistryItem starMapRegistryItem : setStarMapRegistryItems) {
if ( enumStarMapEntryType == null
|| starMapRegistryItem.type == enumStarMapEntryType ) {
if (starMapRegistryItem.uuid.equals(uuid)) {
return starMapRegistryItem;
}
}
}
}
return null;
}
public String find(final String nameShip) {
final int MAX_LENGTH = 2000;
final StringBuilder resultMatch = new StringBuilder();

View file

@ -29,7 +29,8 @@ public class StarMapRegistryItem extends GlobalPosition {
STAR(4, "star"), // a star
STRUCTURE(5, "structure"), // a structure from WorldGeneration (moon, asteroid field, etc.)
WARP_ECHO(6, "warp_echo"), // remains of a warp
ACCELERATOR(7, "accelerator"); // an accelerator setup
ACCELERATOR(7, "accelerator"), // an accelerator setup
TRANSPORTER(8, "transporter"); // a transporter room
private final int id;
private final String name;

View file

@ -1083,17 +1083,14 @@ public class JumpSequencer extends AbstractSequencer {
continue;
}
final double oldEntityX = movingEntity.originalX;
final double oldEntityY = movingEntity.originalY;
final double oldEntityZ = movingEntity.originalZ;
Vec3 target = transformation.apply(oldEntityX, oldEntityY, oldEntityZ);
final Vec3 target = transformation.apply(movingEntity.v3OriginalPosition.x, movingEntity.v3OriginalPosition.y, movingEntity.v3OriginalPosition.z);
final double newEntityX = target.xCoord;
final double newEntityY = target.yCoord;
final double newEntityZ = target.zCoord;
if (WarpDriveConfig.LOGGING_JUMP) {
WarpDrive.logger.info(String.format("Entity moving: (%.2f %.2f %.2f) -> (%.2f %.2f %.2f) entity %s",
oldEntityX, oldEntityY, oldEntityZ,
movingEntity.v3OriginalPosition.x, movingEntity.v3OriginalPosition.y, movingEntity.v3OriginalPosition.z,
newEntityX, newEntityY, newEntityZ, entity.toString()));
}
@ -1357,16 +1354,16 @@ public class JumpSequencer extends AbstractSequencer {
if (WarpDriveConfig.LOGGING_JUMP) {
WarpDrive.logger.info(String.format("Entity restoring position at (%f %f %f)",
movingEntity.originalX, movingEntity.originalY, movingEntity.originalZ));
movingEntity.v3OriginalPosition.x, movingEntity.v3OriginalPosition.y, movingEntity.v3OriginalPosition.z));
}
// Update position
if (entity instanceof EntityPlayerMP) {
final EntityPlayerMP player = (EntityPlayerMP) entity;
player.setPositionAndUpdate(movingEntity.originalX, movingEntity.originalY, movingEntity.originalZ);
player.setPositionAndUpdate(movingEntity.v3OriginalPosition.x, movingEntity.v3OriginalPosition.y, movingEntity.v3OriginalPosition.z);
} else {
entity.setPosition(movingEntity.originalX, movingEntity.originalY, movingEntity.originalZ);
entity.setPosition(movingEntity.v3OriginalPosition.x, movingEntity.v3OriginalPosition.y, movingEntity.v3OriginalPosition.z);
}
}
}

View file

@ -3,6 +3,8 @@ package cr0s.warpdrive.network;
import cr0s.warpdrive.Commons;
import cr0s.warpdrive.WarpDrive;
import cr0s.warpdrive.config.WarpDriveConfig;
import cr0s.warpdrive.data.GlobalPosition;
import cr0s.warpdrive.data.MovingEntity;
import cr0s.warpdrive.data.Vector3;
import cr0s.warpdrive.data.VectorI;
import cr0s.warpdrive.render.EntityFXBeam;
@ -26,15 +28,16 @@ import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraftforge.common.util.ForgeDirection;
import java.util.ArrayList;
import java.util.Collection;
public class MessageTransporterEffect implements IMessage, IMessageHandler<MessageTransporterEffect, IMessage> {
private final int ENTITY_ID_NONE = 0;
private VectorI vSource;
private VectorI vDestination;
private boolean isTransporterRoom;
private GlobalPosition globalPosition;
private ArrayList<Integer> idEntities;
private ArrayList<Vector3> v3EntityPositions;
private double lockStrength;
private int idEntity;
private Vector3 v3EntityPosition;
private int tickEnergizing;
private int tickCooldown;
@ -42,56 +45,79 @@ public class MessageTransporterEffect implements IMessage, IMessageHandler<Messa
// required on receiving side
}
public MessageTransporterEffect(final VectorI vSource, final VectorI vDestination, final double lockStrength,
final Entity entity, final Vector3 v3EntityPosition,
final int tickEnergizing, final int tickCooldown) {
this.vSource = vSource;
this.vDestination = vDestination;
public MessageTransporterEffect(final boolean isTransporterRoom, final GlobalPosition globalPosition,
final Collection<MovingEntity> movingEntities,
final double lockStrength, final int tickEnergizing, final int tickCooldown) {
this.isTransporterRoom = isTransporterRoom;
this.globalPosition = globalPosition;
if ( movingEntities == null
|| movingEntities.isEmpty() ) {
this.idEntities = null;
this.v3EntityPositions = null;
} else {
idEntities = new ArrayList<>(movingEntities.size());
v3EntityPositions = new ArrayList<>(movingEntities.size());
for (final MovingEntity movingEntity : movingEntities) {
final Entity entity = movingEntity.getEntity();
if (entity != null) {
idEntities.add(entity.getEntityId());
v3EntityPositions.add(movingEntity.v3OriginalPosition);
}
}
}
this.lockStrength = lockStrength;
this.idEntity = entity == null ? ENTITY_ID_NONE : entity.getEntityId();
this.v3EntityPosition = v3EntityPosition;
this.tickEnergizing = tickEnergizing;
this.tickCooldown = tickCooldown;
}
@Override
public void fromBytes(final ByteBuf buffer) {
int x = buffer.readInt();
int y = buffer.readInt();
int z = buffer.readInt();
vSource = new VectorI(x, y, z);
isTransporterRoom = buffer.readBoolean();
x = buffer.readInt();
y = buffer.readInt();
z = buffer.readInt();
vDestination = new VectorI(x, y, z);
final short dimensionId = buffer.readShort();
final int x = buffer.readInt();
final int y = buffer.readInt();
final int z = buffer.readInt();
globalPosition = new GlobalPosition(dimensionId, x, y, z);
final int countEntities = buffer.readByte();
idEntities = new ArrayList<>(countEntities);
v3EntityPositions = new ArrayList<>(countEntities);
for (int indexEntity = 0; indexEntity < countEntities; indexEntity++) {
final int idEntity = buffer.readInt();
idEntities.add(idEntity);
final double xEntity = buffer.readDouble();
final double yEntity = buffer.readDouble();
final double zEntity = buffer.readDouble();
v3EntityPositions.add(new Vector3(xEntity, yEntity, zEntity));
}
lockStrength = buffer.readFloat();
idEntity = buffer.readInt();
final double xEntity = buffer.readDouble();
final double yEntity = buffer.readDouble();
final double zEntity = buffer.readDouble();
v3EntityPosition = new Vector3(xEntity, yEntity, zEntity);
tickEnergizing = buffer.readShort();
tickCooldown = buffer.readShort();
}
@Override
public void toBytes(ByteBuf buffer) {
buffer.writeInt(vSource.x);
buffer.writeInt(vSource.y);
buffer.writeInt(vSource.z);
buffer.writeInt(vDestination.x);
buffer.writeInt(vDestination.y);
buffer.writeInt(vDestination.z);
buffer.writeBoolean(isTransporterRoom);
buffer.writeShort(globalPosition.dimensionId);
buffer.writeInt(globalPosition.x);
buffer.writeInt(globalPosition.y);
buffer.writeInt(globalPosition.z);
final int countEntities = idEntities == null ? 0 : idEntities.size();
buffer.writeByte(countEntities);
for (int indexEntity = 0; indexEntity < countEntities; indexEntity++) {
buffer.writeInt(idEntities.get(indexEntity));
final Vector3 v3EntityPosition = v3EntityPositions.get(indexEntity);
buffer.writeDouble(v3EntityPosition.x);
buffer.writeDouble(v3EntityPosition.y);
buffer.writeDouble(v3EntityPosition.z);
}
buffer.writeFloat((float) lockStrength);
buffer.writeInt(idEntity);
buffer.writeDouble(v3EntityPosition == null ? 0.0D : v3EntityPosition.x);
buffer.writeDouble(v3EntityPosition == null ? -1000.0D : v3EntityPosition.y);
buffer.writeDouble(v3EntityPosition == null ? 0.0D : v3EntityPosition.z);
buffer.writeShort(tickEnergizing);
buffer.writeShort(tickCooldown);
}
@ -105,50 +131,36 @@ public class MessageTransporterEffect implements IMessage, IMessageHandler<Messa
final EntityPlayer player = Minecraft.getMinecraft().thePlayer;
// handle source
if (vSource.distance2To(player) <= maxRenderDistance_squared) {
if (globalPosition.distance2To(player) <= maxRenderDistance_squared) {
handleAtSource(world);
}
// handle target
if (vDestination.distance2To(player) <= maxRenderDistance_squared) {
handleAtDestination(world);
}
}
private void handleAtSource(final World world) {
// add flying particles in area of effect
spawnParticlesInArea(world, vSource, false,
0.4F, 0.7F, 0.9F,
0.10F, 0.15F, 0.10F);
// get actual entity
final Entity entity = idEntity == ENTITY_ID_NONE ? null : world.getEntityByID(idEntity);
// energizing
// @TODO cylinder fade in + shower
if (entity != null) {
final Vector3 v3Position = new Vector3(entity);
final Vector3 v3Target = v3Position.clone().translate(ForgeDirection.UP, entity.height);
EntityFX effect = new EntityFXBeam(world, v3Position, v3Target,
0.6F + 0.1F * world.rand.nextFloat(),
0.6F + 0.15F * world.rand.nextFloat(),
0.8F + 0.10F * world.rand.nextFloat(),
20, 0);
FMLClientHandler.instance().getClient().effectRenderer.addEffect(effect);
// add flying particles in area of effect when in the wild
if (!isTransporterRoom) {
spawnParticlesInArea(world, globalPosition.getVectorI(), false,
0.4F, 0.7F, 0.9F,
0.10F, 0.15F, 0.10F);
}
// cooldown
// @TODO cylinder fade out
}
private void handleAtDestination(final World world) {
// add flying particles in area of effect
spawnParticlesInArea(world, vDestination, true,
0.4F, 0.9F, 0.7F,
0.10F, 0.10F, 0.15F);
// energizing
// @TODO cylinder fade in + shower
// get actual entity
for (int indexEntity = 0; indexEntity < idEntities.size(); indexEntity++) {
final Entity entity = world.getEntityByID(idEntities.get(indexEntity));
// energizing
// @TODO cylinder fade in + shower
if (entity != null) {
final Vector3 v3Position = new Vector3(entity);
final Vector3 v3Target = v3Position.clone().translate(ForgeDirection.UP, entity.height);
final EntityFX effect = new EntityFXBeam(world, v3Position, v3Target,
0.6F + 0.1F * world.rand.nextFloat(),
0.6F + 0.15F * world.rand.nextFloat(),
0.8F + 0.10F * world.rand.nextFloat(),
20, 0);
FMLClientHandler.instance().getClient().effectRenderer.addEffect(effect);
}
}
// cooldown
// @TODO cylinder fade out
@ -221,10 +233,10 @@ public class MessageTransporterEffect implements IMessage, IMessageHandler<Messa
}
if (WarpDriveConfig.LOGGING_EFFECTS) {
WarpDrive.logger.info("Received transporter effect from %s to %s with %.3f lockStrength towards entity with id %d at %s, energizing in %d ticks, cooldown for %d ticks",
messageSpawnParticle.vSource, messageSpawnParticle.vDestination, messageSpawnParticle.lockStrength,
messageSpawnParticle.idEntity, messageSpawnParticle.v3EntityPosition,
messageSpawnParticle.tickEnergizing, messageSpawnParticle.tickCooldown);
WarpDrive.logger.info("Received transporter effect isTransporterRoom %s at %s towards %d entities, with %.3f lockStrength, energizing in %d ticks, cooldown for %d ticks",
messageSpawnParticle.isTransporterRoom, messageSpawnParticle.globalPosition,
messageSpawnParticle.idEntities.size(),
messageSpawnParticle.lockStrength, messageSpawnParticle.tickEnergizing, messageSpawnParticle.tickCooldown);
}
messageSpawnParticle.handle(Minecraft.getMinecraft().theWorld);

View file

@ -4,10 +4,12 @@ import cr0s.warpdrive.WarpDrive;
import cr0s.warpdrive.config.WarpDriveConfig;
import cr0s.warpdrive.data.CelestialObject;
import cr0s.warpdrive.data.CloakedArea;
import cr0s.warpdrive.data.GlobalPosition;
import cr0s.warpdrive.data.MovingEntity;
import cr0s.warpdrive.data.Vector3;
import cr0s.warpdrive.data.VectorI;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import net.minecraft.entity.Entity;
@ -115,27 +117,31 @@ public class PacketHandler {
}
// Transporter effect sent to client side
public static void sendTransporterEffectPacket(final World world, final VectorI vSource, final VectorI vDestination, final double lockStrength,
final Entity entity, final Vector3 v3EntityPosition,
final int tickEnergizing, final int tickCooldown, final int radius) {
public static void sendTransporterEffectPacket(final World world, final GlobalPosition globalPositionLocal, final GlobalPosition globalPositionRemote, final double lockStrength,
final Collection<MovingEntity> movingEntitiesLocal, final Collection<MovingEntity> movingEntitiesRemote,
final int tickEnergizing, final int tickCooldown, final int radius) {
assert(!world.isRemote);
final MessageTransporterEffect messageTransporterEffect = new MessageTransporterEffect(vSource, vDestination, lockStrength,
entity, v3EntityPosition,
tickEnergizing, tickCooldown);
final MessageTransporterEffect messageTransporterEffectLocal = new MessageTransporterEffect(
true, globalPositionLocal, movingEntitiesLocal,
lockStrength, tickEnergizing, tickCooldown);
final MessageTransporterEffect messageTransporterEffectRemote = new MessageTransporterEffect(
false, globalPositionRemote, movingEntitiesRemote,
lockStrength, tickEnergizing, tickCooldown);
// check both ends to send packet
final List<EntityPlayerMP> playerEntityList = MinecraftServer.getServer().getConfigurationManager().playerEntityList;
final int dimensionId = world.provider.dimensionId;
final int radius_square = radius * radius;
for (int index = 0; index < playerEntityList.size(); index++) {
final EntityPlayerMP entityPlayerMP = playerEntityList.get(index);
if (entityPlayerMP.dimension == dimensionId) {
if ( vSource.distance2To(entityPlayerMP) < radius_square
|| vDestination.distance2To(entityPlayerMP) < radius_square ) {
simpleNetworkManager.sendTo(messageTransporterEffect, entityPlayerMP);
}
if ( globalPositionLocal != null
&& globalPositionLocal.distance2To(entityPlayerMP) < radius_square ) {
simpleNetworkManager.sendTo(messageTransporterEffectLocal, entityPlayerMP);
}
if ( globalPositionRemote != null
&& globalPositionRemote.distance2To(entityPlayerMP) < radius_square ) {
simpleNetworkManager.sendTo(messageTransporterEffectRemote, entityPlayerMP);
}
}
}

View file

@ -297,7 +297,9 @@ tile.warpdrive.movement.ShipCore.name=Raumschiff Kern
tile.warpdrive.movement.ShipCore.tooltip=Definiert dein Schiff relativ zur Steuerung. Schließe eine Energiequelle an, um den Kern zu laden.\nSollte horizontal neben der Steuerung plaziert werden.
tile.warpdrive.movement.ShipCore.bounding_box.disabled=Bounding box display have been disabled.
tile.warpdrive.movement.ShipCore.bounding_box.enabled=Bounding box display is now enabled. Only you can see it.\nSneak right-click the Ship core again to disable it.
tile.warpdrive.movement.Transporter.name=Transporter
tile.warpdrive.movement.transporter_containment.name=Transporter Containment
tile.warpdrive.movement.transporter_core.name=Transporter Core
tile.warpdrive.movement.transporter_scanner.name=Transporter Scanner
tile.warpdrive.weapon.LaserCamera.name=Laser und Kamera
tile.warpdrive.weapon.WeaponController.name=Waffen Steuerung

View file

@ -294,7 +294,9 @@ tile.warpdrive.movement.ShipCore.name=Ship Core
tile.warpdrive.movement.ShipCore.tooltip=Defines your ship center relative to the controller. Connecting an energy source will charge the core.\nShall be placed horizontally directly next to the Ship controller.
tile.warpdrive.movement.ShipCore.bounding_box.disabled=Bounding box display have been disabled.
tile.warpdrive.movement.ShipCore.bounding_box.enabled=Bounding box display is now enabled. Only you can see it.\nSneak right-click the Ship core again to disable it.
tile.warpdrive.movement.Transporter.name=Transporter
tile.warpdrive.movement.transporter_containment.name=Transporter Containment
tile.warpdrive.movement.transporter_core.name=Transporter Core
tile.warpdrive.movement.transporter_scanner.name=Transporter Scanner
tile.warpdrive.weapon.LaserCamera.name=Laser + Camera
tile.warpdrive.weapon.WeaponController.name=Weapon Controller

View file

@ -292,7 +292,9 @@ tile.warpdrive.movement.ShipController.name=Controlleur de vaisseau
tile.warpdrive.movement.ShipController.tooltip=Défini l'avant du vaisseau par rapport au coeur. Attache un ordinateur pour ouvrir l'interface utilisateur.\nDoit être placé horizontalement directement à coté du Coeur de vaisseau.
tile.warpdrive.movement.ShipCore.name=Coeur de vaisseau
tile.warpdrive.movement.ShipCore.tooltip=Défini le centre du vaisseau par rapport au controlleur. Connecte une source d'énergie pour charger le coeur\nDoit être placé horizontalement directement à coté du Controlleur de vaisseau.
tile.warpdrive.movement.Transporter.name=Transporteur
tile.warpdrive.movement.transporter_containment.name=Confinement de transporteur
tile.warpdrive.movement.transporter_core.name=Cœur de transporteur
tile.warpdrive.movement.transporter_scanner.name=Scanneur de transporteur
tile.warpdrive.weapon.LaserCamera.name=Laser + Caméra
tile.warpdrive.weapon.WeaponController.name=Controlleur d'armement

View file

@ -294,7 +294,9 @@ tile.warpdrive.movement.ShipCore.name=Schip-Kern
tile.warpdrive.movement.ShipCore.tooltip=Definieert uw schips-middelpunt ten opzichte van ships-bestuurder. Sluit een stroombron aan om de kern op te laden.\nMoet horizontaal naast een Schips-bestuurder worden geplaatst.
tile.warpdrive.movement.ShipCore.bounding_box.disabled=Bounding box display have been disabled.
tile.warpdrive.movement.ShipCore.bounding_box.enabled=Bounding box display is now enabled. Only you can see it.\nSneak right-click the Ship core again to disable it.
tile.warpdrive.movement.Transporter.name=Transporteur
tile.warpdrive.movement.transporter_containment.name=Transporter Containment
tile.warpdrive.movement.transporter_core.name=Transporter Core
tile.warpdrive.movement.transporter_scanner.name=Transporter Scanner
tile.warpdrive.weapon.LaserCamera.name=Laser met Camera
tile.warpdrive.weapon.WeaponController.name=Wapens-Bestuurder

View file

@ -292,7 +292,9 @@ tile.warpdrive.movement.ShipController.name=Контроллер корабля
tile.warpdrive.movement.ShipController.tooltip=Defines your ship front relative to the core. Attach a computer to open the user interface.\nShall be placed horizontally directly next to the Ship core.
tile.warpdrive.movement.ShipCore.name=Ядро корабля
tile.warpdrive.movement.ShipCore.tooltip=Defines your ship center relative to the controller. Connecting an energy source will charge the core.\nShall be placed horizontally directly next to the Ship controller.
tile.warpdrive.movement.Transporter.name=Транспортер
tile.warpdrive.movement.transporter_containment.name=Transporter Containment
tile.warpdrive.movement.transporter_core.name=Транспортер
tile.warpdrive.movement.transporter_scanner.name=Transporter Scanner
tile.warpdrive.weapon.LaserCamera.name=Камера с прикрепленным лазером
tile.warpdrive.weapon.WeaponController.name=Контроллер оружия

View file

@ -294,7 +294,9 @@ tile.warpdrive.movement.ShipCore.name=飞船核心
tile.warpdrive.movement.ShipCore.tooltip=相对于控制器以设定飞船中心.连接供能设备充能.\n必须水平紧贴控制器才能连接.
tile.warpdrive.movement.ShipCore.bounding_box.disabled=边界显示已禁用.
tile.warpdrive.movement.ShipCore.bounding_box.enabled=边界显示启用. 只有你可见.\n再次潜行右击核心可关闭.
tile.warpdrive.movement.Transporter.name=传送台
tile.warpdrive.movement.transporter_containment.name=Transporter Containment
tile.warpdrive.movement.transporter_core.name=传送台
tile.warpdrive.movement.transporter_scanner.name=Transporter Scanner
tile.warpdrive.weapon.LaserCamera.name=激光+相机
tile.warpdrive.weapon.WeaponController.name=武器控制器

View file

@ -210,7 +210,9 @@ tile.warpdrive.forcefield.relay3.tooltip=支持在其網絡內共享最多1個
tile.warpdrive.movement.Lift.name=升降機
tile.warpdrive.movement.ShipController.name=船艦制禦器
tile.warpdrive.movement.ShipCore.name=波動核心
tile.warpdrive.movement.Transporter.name=運輸
tile.warpdrive.movement.transporter_containment.name=Transporter Containment
tile.warpdrive.movement.transporter_core.name=運輸
tile.warpdrive.movement.transporter_scanner.name=Transporter Scanner
tile.warpdrive.weapon.LaserCamera.name=鐳射&攝像機
tile.warpdrive.weapon.WeaponController.name=火控系統