mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-19 12:17:17 -04:00
applying weapon bonus damage to robot player for properly calculated damage on swing; applying tool durability reduction on attack, too; simulating a click for swing and use now via raytracing, falling back to simple use when that fails (basically like player click block vs player click air), which means stuff like using bone meal now also properly works; better feedback on what happened when a tool was used; added callback to query current tool's durability; building list of pre-break items earlier to allow detecting items generated in other callbacks than harvest (e.g. for redstone in motion blocks)
This commit is contained in:
parent
942027d957
commit
bade1b5dc9
@ -83,7 +83,7 @@ object Config {
|
|||||||
var callOnItemUseFirst = false
|
var callOnItemUseFirst = false
|
||||||
var allowActivateBlocks = true
|
var allowActivateBlocks = true
|
||||||
var canAttackPlayers = false
|
var canAttackPlayers = false
|
||||||
var itemDamageChance = 0.05
|
var itemDamageRate = 0.05
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
|
@ -93,7 +93,13 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with Buffer with Power
|
|||||||
|
|
||||||
override def validate() {
|
override def validate() {
|
||||||
super.validate()
|
super.validate()
|
||||||
if (isClient) {
|
if (isServer) {
|
||||||
|
items(0) match {
|
||||||
|
case Some(item) => player_.getAttributeMap.applyAttributeModifiers(item.getAttributeModifiers)
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
ClientPacketSender.sendRotatableStateRequest(this)
|
ClientPacketSender.sendRotatableStateRequest(this)
|
||||||
ClientPacketSender.sendScreenBufferRequest(this)
|
ClientPacketSender.sendScreenBufferRequest(this)
|
||||||
ClientPacketSender.sendRobotSelectedSlotRequest(this)
|
ClientPacketSender.sendRobotSelectedSlotRequest(this)
|
||||||
@ -198,8 +204,18 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with Buffer with Power
|
|||||||
case _ => false // Invalid slot.
|
case _ => false // Invalid slot.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override protected def onItemRemoved(slot: Int, item: ItemStack) {
|
||||||
|
super.onItemRemoved(slot, item)
|
||||||
|
if (slot == 0) {
|
||||||
|
player_.getAttributeMap.removeAttributeModifiers(item.getAttributeModifiers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override protected def onItemAdded(slot: Int, item: ItemStack) {
|
override protected def onItemAdded(slot: Int, item: ItemStack) {
|
||||||
if (slot > 0 && slot < 3) {
|
if (slot == 0) {
|
||||||
|
player_.getAttributeMap.applyAttributeModifiers(item.getAttributeModifiers)
|
||||||
|
}
|
||||||
|
else if (slot == 1 || slot == 2) {
|
||||||
super.onItemAdded(slot, item)
|
super.onItemAdded(slot, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,11 @@ package li.cil.oc.server.component
|
|||||||
import li.cil.oc.api.network.{LuaCallback, Arguments, Context}
|
import li.cil.oc.api.network.{LuaCallback, Arguments, Context}
|
||||||
import li.cil.oc.common.tileentity
|
import li.cil.oc.common.tileentity
|
||||||
import li.cil.oc.server.{PacketSender => ServerPacketSender}
|
import li.cil.oc.server.{PacketSender => ServerPacketSender}
|
||||||
|
import li.cil.oc.util.ActivationType
|
||||||
import net.minecraft.block.{BlockFluid, Block}
|
import net.minecraft.block.{BlockFluid, Block}
|
||||||
import net.minecraft.entity.item.EntityItem
|
import net.minecraft.entity.item.EntityItem
|
||||||
import net.minecraft.item.{ItemStack, ItemBlock}
|
import net.minecraft.item.{ItemStack, ItemBlock}
|
||||||
|
import net.minecraft.util.{EnumMovingObjectType, Vec3}
|
||||||
import net.minecraftforge.common.ForgeDirection
|
import net.minecraftforge.common.ForgeDirection
|
||||||
import net.minecraftforge.fluids.FluidRegistry
|
import net.minecraftforge.fluids.FluidRegistry
|
||||||
import scala.Some
|
import scala.Some
|
||||||
@ -40,7 +42,7 @@ class Robot(val robot: tileentity.Robot) extends Computer(robot) {
|
|||||||
ServerPacketSender.sendRobotSelectedSlotState(robot)
|
ServerPacketSender.sendRobotSelectedSlotState(robot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result(selectedSlot)
|
result(selectedSlot + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback("count")
|
@LuaCallback("count")
|
||||||
@ -200,32 +202,91 @@ class Robot(val robot: tileentity.Robot) extends Computer(robot) {
|
|||||||
@LuaCallback("swing")
|
@LuaCallback("swing")
|
||||||
def swing(context: Context, args: Arguments): Array[AnyRef] = {
|
def swing(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
// Swing the equipped tool (left click).
|
// Swing the equipped tool (left click).
|
||||||
val lookSide = checkSideForAction(args, 0)
|
val facing = checkSideForAction(args, 0)
|
||||||
val side = if (args.isInteger(1)) checkSide(args, 1) else lookSide
|
val side = if (args.isInteger(1)) checkSide(args, 1) else facing
|
||||||
if (side.getOpposite == lookSide) {
|
if (side.getOpposite == facing) {
|
||||||
throw new IllegalArgumentException("invalid side")
|
throw new IllegalArgumentException("invalid side")
|
||||||
}
|
}
|
||||||
val player = robot.player(lookSide)
|
val sneaky = args.isBoolean(2) && args.checkBoolean(2)
|
||||||
val (bx, by, bz) = (x + lookSide.offsetX, y + lookSide.offsetY, z + lookSide.offsetZ)
|
val player = robot.player(facing)
|
||||||
result(player.clickBlock(bx, by, bz, side.getOpposite.ordinal))
|
Option(simulateClick(facing, side, 0.49)) match {
|
||||||
//robot.player().attackTargetEntityWithCurrentItem(entity)
|
case Some(hit) =>
|
||||||
|
player.setSneaking(sneaky)
|
||||||
|
val what = hit.typeOfHit match {
|
||||||
|
case EnumMovingObjectType.ENTITY =>
|
||||||
|
player.attackTargetEntityWithCurrentItem(hit.entityHit)
|
||||||
|
result(true, "entity")
|
||||||
|
case EnumMovingObjectType.TILE =>
|
||||||
|
val broke = player.clickBlock(hit.blockX, hit.blockY, hit.blockZ, hit.sideHit)
|
||||||
|
result(broke, "block")
|
||||||
|
}
|
||||||
|
player.setSneaking(false)
|
||||||
|
what
|
||||||
|
case _ =>
|
||||||
|
player.closestLivingEntity(facing) match {
|
||||||
|
case Some(entity) =>
|
||||||
|
player.attackTargetEntityWithCurrentItem(entity)
|
||||||
|
result(true, "entity")
|
||||||
|
case _ =>
|
||||||
|
result(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback("use")
|
@LuaCallback("use")
|
||||||
def use(context: Context, args: Arguments): Array[AnyRef] = {
|
def use(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
val lookSide = checkSideForAction(args, 0)
|
val facing = checkSideForAction(args, 0)
|
||||||
val side = if (args.isInteger(1)) checkSide(args, 1) else lookSide
|
val side = if (args.isInteger(1)) checkSide(args, 1) else facing
|
||||||
if (side.getOpposite == lookSide) {
|
if (side.getOpposite == facing) {
|
||||||
throw new IllegalArgumentException("invalid side")
|
throw new IllegalArgumentException("invalid side")
|
||||||
}
|
}
|
||||||
val sneaky = args.isBoolean(2) && args.checkBoolean(2)
|
val sneaky = args.isBoolean(2) && args.checkBoolean(2)
|
||||||
val player = robot.player(lookSide)
|
val player = robot.player(facing)
|
||||||
player.setSneaking(sneaky)
|
Option(simulateClick(facing, side, 0.51)) match {
|
||||||
val (bx, by, bz) = (x + lookSide.offsetX, y + lookSide.offsetY, z + lookSide.offsetZ)
|
case Some(hit) =>
|
||||||
val (hx, hy, hz) = (0.5f + side.offsetX * 0.5f, 0.5f + side.offsetY * 0.5f, 0.5f + side.offsetZ * 0.5f)
|
player.setSneaking(sneaky)
|
||||||
val ok = player.activateBlockOrUseItem(bx, by, bz, side.getOpposite.ordinal, hx, hy, hz)
|
val what = hit.typeOfHit match {
|
||||||
player.setSneaking(false)
|
case EnumMovingObjectType.ENTITY =>
|
||||||
result(ok)
|
// TODO Is there any practical use for this? Most of the stuff related to this is still 'obfuscated'...
|
||||||
|
result(false, "entity")
|
||||||
|
case EnumMovingObjectType.TILE =>
|
||||||
|
val (hx, hy, hz) = (
|
||||||
|
(hit.hitVec.xCoord - hit.blockX).toFloat,
|
||||||
|
(hit.hitVec.yCoord - hit.blockY).toFloat,
|
||||||
|
(hit.hitVec.zCoord - hit.blockZ).toFloat)
|
||||||
|
player.activateBlockOrUseItem(hit.blockX, hit.blockY, hit.blockZ, hit.sideHit, hx, hy, hz) match {
|
||||||
|
case ActivationType.BlockActivated => result(true, "block_activated")
|
||||||
|
case ActivationType.ItemPlaced => result(true, "item_placed")
|
||||||
|
case ActivationType.ItemUsed => result(true, "item_used")
|
||||||
|
case _ => result(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
player.setSneaking(false)
|
||||||
|
what
|
||||||
|
case _ =>
|
||||||
|
if (player.useEquippedItem()) result(true, "item_used")
|
||||||
|
else result(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@LuaCallback("durability")
|
||||||
|
def durability(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
|
Option(robot.getStackInSlot(0)) match {
|
||||||
|
case Some(item) =>
|
||||||
|
if (item.isItemStackDamageable) {
|
||||||
|
result(item.getMaxDamage - item.getItemDamage)
|
||||||
|
}
|
||||||
|
else result(Unit, "tool cannot be damaged")
|
||||||
|
case _ => result(Unit, "no tool equipped")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def simulateClick(facing: ForgeDirection, side: ForgeDirection, range: Double) = {
|
||||||
|
val (bx, by, bz) = (x + facing.offsetX, y + facing.offsetY, z + facing.offsetZ)
|
||||||
|
val (hx, hy, hz) = (0.5 + side.offsetX * range, 0.5 + side.offsetY * range, 0.5 + side.offsetZ * range)
|
||||||
|
val origin = Vec3.createVectorHelper(x + 0.5, y + 0.5, z + 0.5)
|
||||||
|
val target = Vec3.createVectorHelper(bx + hx, by + hy, bz + hz)
|
||||||
|
world.clip(origin, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
5
li/cil/oc/util/ActivationType.scala
Normal file
5
li/cil/oc/util/ActivationType.scala
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package li.cil.oc.util
|
||||||
|
|
||||||
|
object ActivationType extends Enumeration {
|
||||||
|
val None, ItemUsed, ItemPlaced, BlockActivated = Value
|
||||||
|
}
|
@ -66,12 +66,7 @@ class RobotPlayer(val robot: Robot) extends FakePlayer(robot.world, "OpenCompute
|
|||||||
|
|
||||||
def entitiesOnSide[Type <: Entity : ClassTag](side: ForgeDirection) = {
|
def entitiesOnSide[Type <: Entity : ClassTag](side: ForgeDirection) = {
|
||||||
val (bx, by, bz) = (robot.x + side.offsetX, robot.y + side.offsetY, robot.z + side.offsetZ)
|
val (bx, by, bz) = (robot.x + side.offsetX, robot.y + side.offsetY, robot.z + side.offsetZ)
|
||||||
val id = world.getBlockId(bx, by, bz)
|
entitiesInBlock[Type](bx, by, bz)
|
||||||
val block = Block.blocksList(id)
|
|
||||||
if (id == 0 || block == null || block.isAirBlock(world, bx, by, bz)) {
|
|
||||||
entitiesInBlock[Type](bx, by, bz)
|
|
||||||
}
|
|
||||||
else Iterable.empty
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def entitiesInBlock[Type <: Entity : ClassTag](x: Int, y: Int, z: Int) = {
|
def entitiesInBlock[Type <: Entity : ClassTag](x: Int, y: Int, z: Int) = {
|
||||||
@ -81,14 +76,20 @@ class RobotPlayer(val robot: Robot) extends FakePlayer(robot.world, "OpenCompute
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
// TODO override def canAttackWithItem = super.canAttackWithItem
|
override def attackTargetEntityWithCurrentItem(entity: Entity) {
|
||||||
|
val stack = getCurrentEquippedItem
|
||||||
|
val oldDamage = getCurrentEquippedItem.getItemDamage
|
||||||
|
super.attackTargetEntityWithCurrentItem(entity)
|
||||||
|
if (stack.stackSize > 0 && stack.isItemStackDamageable && getRNG.nextDouble() >= Config.itemDamageRate) {
|
||||||
|
val addedDamage = ((stack.getItemDamage - oldDamage) * Config.itemDamageRate).toInt
|
||||||
|
stack.setItemDamage(oldDamage + addedDamage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO override def attackTargetEntityWithCurrentItem(par1Entity: Entity)
|
def activateBlockOrUseItem(x: Int, y: Int, z: Int, side: Int, hitX: Float, hitY: Float, hitZ: Float): ActivationType.Value = {
|
||||||
|
|
||||||
def activateBlockOrUseItem(x: Int, y: Int, z: Int, side: Int, hitX: Float, hitY: Float, hitZ: Float): Boolean = {
|
|
||||||
val event = ForgeEventFactory.onPlayerInteract(this, Action.RIGHT_CLICK_BLOCK, x, y, z, side)
|
val event = ForgeEventFactory.onPlayerInteract(this, Action.RIGHT_CLICK_BLOCK, x, y, z, side)
|
||||||
if (event.isCanceled) {
|
if (event.isCanceled || event.useBlock == Event.Result.DENY) {
|
||||||
return false
|
return ActivationType.None
|
||||||
}
|
}
|
||||||
|
|
||||||
val stack = inventory.getCurrentItem
|
val stack = inventory.getCurrentItem
|
||||||
@ -97,7 +98,7 @@ class RobotPlayer(val robot: Robot) extends FakePlayer(robot.world, "OpenCompute
|
|||||||
if (item != null && item.onItemUseFirst(stack, this, world, x, y, z, side, hitX, hitY, hitZ)) {
|
if (item != null && item.onItemUseFirst(stack, this, world, x, y, z, side, hitX, hitY, hitZ)) {
|
||||||
if (stack.stackSize <= 0) ForgeEventFactory.onPlayerDestroyItem(this, stack)
|
if (stack.stackSize <= 0) ForgeEventFactory.onPlayerDestroyItem(this, stack)
|
||||||
if (stack.stackSize <= 0) inventory.setInventorySlotContents(0, null)
|
if (stack.stackSize <= 0) inventory.setInventorySlotContents(0, null)
|
||||||
return true
|
return ActivationType.ItemUsed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,17 +106,36 @@ class RobotPlayer(val robot: Robot) extends FakePlayer(robot.world, "OpenCompute
|
|||||||
val block = Block.blocksList(blockId)
|
val block = Block.blocksList(blockId)
|
||||||
val canActivate = block != null && Config.allowActivateBlocks
|
val canActivate = block != null && Config.allowActivateBlocks
|
||||||
val shouldActivate = canActivate && (!isSneaking || (item == null || item.shouldPassSneakingClickToBlock(world, x, y, z)))
|
val shouldActivate = canActivate && (!isSneaking || (item == null || item.shouldPassSneakingClickToBlock(world, x, y, z)))
|
||||||
val activated = shouldActivate && (event.useBlock == Event.Result.DENY ||
|
if (shouldActivate && block.onBlockActivated(world, x, y, z, this, side, hitX, hitY, hitZ)) {
|
||||||
block.onBlockActivated(world, x, y, z, this, side, hitX, hitY, hitZ))
|
return ActivationType.BlockActivated
|
||||||
|
}
|
||||||
|
|
||||||
activated || (stack != null && ({
|
if (stack != null) {
|
||||||
val direction = ForgeDirection.getOrientation(side).getOpposite
|
val didPlace = stack.tryPlaceItemIntoWorld(this, world, x, y, z, side, hitX, hitY, hitZ)
|
||||||
val (onX, onY, onZ) = (x + direction.offsetX, y + direction.offsetY, z + direction.offsetZ)
|
|
||||||
val result = stack.tryPlaceItemIntoWorld(this, world, onX, onY, onZ, side, hitX, hitY, hitZ)
|
|
||||||
if (stack.stackSize <= 0) ForgeEventFactory.onPlayerDestroyItem(this, stack)
|
if (stack.stackSize <= 0) ForgeEventFactory.onPlayerDestroyItem(this, stack)
|
||||||
if (stack.stackSize <= 0) inventory.setInventorySlotContents(0, null)
|
if (stack.stackSize <= 0) inventory.setInventorySlotContents(0, null)
|
||||||
result
|
if (didPlace) {
|
||||||
} || stack.getMaxItemUseDuration <= 0 && {
|
return ActivationType.ItemPlaced
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tryUseItem(stack)) {
|
||||||
|
return ActivationType.ItemUsed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActivationType.None
|
||||||
|
}
|
||||||
|
|
||||||
|
def useEquippedItem() = {
|
||||||
|
val event = ForgeEventFactory.onPlayerInteract(this, Action.RIGHT_CLICK_AIR, 0, 0, 0, -1)
|
||||||
|
if (!event.isCanceled && event.useItem != Event.Result.DENY) {
|
||||||
|
tryUseItem(getCurrentEquippedItem)
|
||||||
|
}
|
||||||
|
else false
|
||||||
|
}
|
||||||
|
|
||||||
|
private def tryUseItem(stack: ItemStack) =
|
||||||
|
stack != null && stack.stackSize > 0 && stack.getMaxItemUseDuration <= 0 && {
|
||||||
val oldSize = stack.stackSize
|
val oldSize = stack.stackSize
|
||||||
val oldDamage = stack.getItemDamage
|
val oldDamage = stack.getItemDamage
|
||||||
val newStack = stack.useItemRightClick(world, this)
|
val newStack = stack.useItemRightClick(world, this)
|
||||||
@ -126,8 +146,7 @@ class RobotPlayer(val robot: Robot) extends FakePlayer(robot.world, "OpenCompute
|
|||||||
else inventory.setInventorySlotContents(0, null)
|
else inventory.setInventorySlotContents(0, null)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}))
|
}
|
||||||
}
|
|
||||||
|
|
||||||
def placeBlock(stack: ItemStack, x: Int, y: Int, z: Int, side: Int, hitX: Float, hitY: Float, hitZ: Float): Boolean = {
|
def placeBlock(stack: ItemStack, x: Int, y: Int, z: Int, side: Int, hitX: Float, hitY: Float, hitZ: Float): Boolean = {
|
||||||
val event = ForgeEventFactory.onPlayerInteract(this, Action.RIGHT_CLICK_BLOCK, x, y, z, side)
|
val event = ForgeEventFactory.onPlayerInteract(this, Action.RIGHT_CLICK_BLOCK, x, y, z, side)
|
||||||
@ -184,16 +203,17 @@ class RobotPlayer(val robot: Robot) extends FakePlayer(robot.world, "OpenCompute
|
|||||||
if (stack.stackSize == 0) {
|
if (stack.stackSize == 0) {
|
||||||
destroyCurrentEquippedItem()
|
destroyCurrentEquippedItem()
|
||||||
}
|
}
|
||||||
else if (stack.isItemStackDamageable && getRNG.nextDouble() >= Config.itemDamageChance) {
|
else if (stack.isItemStackDamageable && getRNG.nextDouble() >= Config.itemDamageRate) {
|
||||||
stack.setItemDamage(oldDamage)
|
val addedDamage = ((stack.getItemDamage - oldDamage) * Config.itemDamageRate).toInt
|
||||||
|
stack.setItemDamage(oldDamage + addedDamage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val itemsBefore = entitiesInBlock[EntityItem](x, y, z)
|
||||||
block.onBlockHarvested(world, x, y, z, metadata, this)
|
block.onBlockHarvested(world, x, y, z, metadata, this)
|
||||||
if (block.removeBlockByPlayer(world, this, x, y, z)) {
|
if (block.removeBlockByPlayer(world, this, x, y, z)) {
|
||||||
block.onBlockDestroyedByPlayer(world, x, y, z, metadata)
|
block.onBlockDestroyedByPlayer(world, x, y, z, metadata)
|
||||||
if (block.canHarvestBlock(this, metadata)) {
|
if (block.canHarvestBlock(this, metadata)) {
|
||||||
val itemsBefore = entitiesInBlock[EntityItem](x, y, z)
|
|
||||||
block.harvestBlock(world, this, x, y, z, metadata)
|
block.harvestBlock(world, this, x, y, z, metadata)
|
||||||
val itemsAfter = entitiesInBlock[EntityItem](x, y, z)
|
val itemsAfter = entitiesInBlock[EntityItem](x, y, z)
|
||||||
val itemsDropped = itemsAfter -- itemsBefore
|
val itemsDropped = itemsAfter -- itemsBefore
|
||||||
|
Loading…
x
Reference in New Issue
Block a user