mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-18 03:36:47 -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 allowActivateBlocks = true
|
||||
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() {
|
||||
super.validate()
|
||||
if (isClient) {
|
||||
if (isServer) {
|
||||
items(0) match {
|
||||
case Some(item) => player_.getAttributeMap.applyAttributeModifiers(item.getAttributeModifiers)
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
else {
|
||||
ClientPacketSender.sendRotatableStateRequest(this)
|
||||
ClientPacketSender.sendScreenBufferRequest(this)
|
||||
ClientPacketSender.sendRobotSelectedSlotRequest(this)
|
||||
@ -198,8 +204,18 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with Buffer with Power
|
||||
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) {
|
||||
if (slot > 0 && slot < 3) {
|
||||
if (slot == 0) {
|
||||
player_.getAttributeMap.applyAttributeModifiers(item.getAttributeModifiers)
|
||||
}
|
||||
else if (slot == 1 || slot == 2) {
|
||||
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.common.tileentity
|
||||
import li.cil.oc.server.{PacketSender => ServerPacketSender}
|
||||
import li.cil.oc.util.ActivationType
|
||||
import net.minecraft.block.{BlockFluid, Block}
|
||||
import net.minecraft.entity.item.EntityItem
|
||||
import net.minecraft.item.{ItemStack, ItemBlock}
|
||||
import net.minecraft.util.{EnumMovingObjectType, Vec3}
|
||||
import net.minecraftforge.common.ForgeDirection
|
||||
import net.minecraftforge.fluids.FluidRegistry
|
||||
import scala.Some
|
||||
@ -40,7 +42,7 @@ class Robot(val robot: tileentity.Robot) extends Computer(robot) {
|
||||
ServerPacketSender.sendRobotSelectedSlotState(robot)
|
||||
}
|
||||
}
|
||||
result(selectedSlot)
|
||||
result(selectedSlot + 1)
|
||||
}
|
||||
|
||||
@LuaCallback("count")
|
||||
@ -200,32 +202,91 @@ class Robot(val robot: tileentity.Robot) extends Computer(robot) {
|
||||
@LuaCallback("swing")
|
||||
def swing(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
// Swing the equipped tool (left click).
|
||||
val lookSide = checkSideForAction(args, 0)
|
||||
val side = if (args.isInteger(1)) checkSide(args, 1) else lookSide
|
||||
if (side.getOpposite == lookSide) {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
val side = if (args.isInteger(1)) checkSide(args, 1) else facing
|
||||
if (side.getOpposite == facing) {
|
||||
throw new IllegalArgumentException("invalid side")
|
||||
}
|
||||
val player = robot.player(lookSide)
|
||||
val (bx, by, bz) = (x + lookSide.offsetX, y + lookSide.offsetY, z + lookSide.offsetZ)
|
||||
result(player.clickBlock(bx, by, bz, side.getOpposite.ordinal))
|
||||
//robot.player().attackTargetEntityWithCurrentItem(entity)
|
||||
val sneaky = args.isBoolean(2) && args.checkBoolean(2)
|
||||
val player = robot.player(facing)
|
||||
Option(simulateClick(facing, side, 0.49)) match {
|
||||
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")
|
||||
def use(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val lookSide = checkSideForAction(args, 0)
|
||||
val side = if (args.isInteger(1)) checkSide(args, 1) else lookSide
|
||||
if (side.getOpposite == lookSide) {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
val side = if (args.isInteger(1)) checkSide(args, 1) else facing
|
||||
if (side.getOpposite == facing) {
|
||||
throw new IllegalArgumentException("invalid side")
|
||||
}
|
||||
val sneaky = args.isBoolean(2) && args.checkBoolean(2)
|
||||
val player = robot.player(lookSide)
|
||||
player.setSneaking(sneaky)
|
||||
val (bx, by, bz) = (x + lookSide.offsetX, y + lookSide.offsetY, z + lookSide.offsetZ)
|
||||
val (hx, hy, hz) = (0.5f + side.offsetX * 0.5f, 0.5f + side.offsetY * 0.5f, 0.5f + side.offsetZ * 0.5f)
|
||||
val ok = player.activateBlockOrUseItem(bx, by, bz, side.getOpposite.ordinal, hx, hy, hz)
|
||||
player.setSneaking(false)
|
||||
result(ok)
|
||||
val player = robot.player(facing)
|
||||
Option(simulateClick(facing, side, 0.51)) match {
|
||||
case Some(hit) =>
|
||||
player.setSneaking(sneaky)
|
||||
val what = hit.typeOfHit match {
|
||||
case EnumMovingObjectType.ENTITY =>
|
||||
// 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) = {
|
||||
val (bx, by, bz) = (robot.x + side.offsetX, robot.y + side.offsetY, robot.z + side.offsetZ)
|
||||
val id = world.getBlockId(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
|
||||
entitiesInBlock[Type](bx, by, bz)
|
||||
}
|
||||
|
||||
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): Boolean = {
|
||||
def activateBlockOrUseItem(x: Int, y: Int, z: Int, side: Int, hitX: Float, hitY: Float, hitZ: Float): ActivationType.Value = {
|
||||
val event = ForgeEventFactory.onPlayerInteract(this, Action.RIGHT_CLICK_BLOCK, x, y, z, side)
|
||||
if (event.isCanceled) {
|
||||
return false
|
||||
if (event.isCanceled || event.useBlock == Event.Result.DENY) {
|
||||
return ActivationType.None
|
||||
}
|
||||
|
||||
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 (stack.stackSize <= 0) ForgeEventFactory.onPlayerDestroyItem(this, stack)
|
||||
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 canActivate = block != null && Config.allowActivateBlocks
|
||||
val shouldActivate = canActivate && (!isSneaking || (item == null || item.shouldPassSneakingClickToBlock(world, x, y, z)))
|
||||
val activated = shouldActivate && (event.useBlock == Event.Result.DENY ||
|
||||
block.onBlockActivated(world, x, y, z, this, side, hitX, hitY, hitZ))
|
||||
if (shouldActivate && block.onBlockActivated(world, x, y, z, this, side, hitX, hitY, hitZ)) {
|
||||
return ActivationType.BlockActivated
|
||||
}
|
||||
|
||||
activated || (stack != null && ({
|
||||
val direction = ForgeDirection.getOrientation(side).getOpposite
|
||||
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 != null) {
|
||||
val didPlace = stack.tryPlaceItemIntoWorld(this, world, x, y, z, side, hitX, hitY, hitZ)
|
||||
if (stack.stackSize <= 0) ForgeEventFactory.onPlayerDestroyItem(this, stack)
|
||||
if (stack.stackSize <= 0) inventory.setInventorySlotContents(0, null)
|
||||
result
|
||||
} || stack.getMaxItemUseDuration <= 0 && {
|
||||
if (didPlace) {
|
||||
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 oldDamage = stack.getItemDamage
|
||||
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)
|
||||
true
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@ -184,16 +203,17 @@ class RobotPlayer(val robot: Robot) extends FakePlayer(robot.world, "OpenCompute
|
||||
if (stack.stackSize == 0) {
|
||||
destroyCurrentEquippedItem()
|
||||
}
|
||||
else if (stack.isItemStackDamageable && getRNG.nextDouble() >= Config.itemDamageChance) {
|
||||
stack.setItemDamage(oldDamage)
|
||||
else if (stack.isItemStackDamageable && getRNG.nextDouble() >= Config.itemDamageRate) {
|
||||
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)
|
||||
if (block.removeBlockByPlayer(world, this, x, y, z)) {
|
||||
block.onBlockDestroyedByPlayer(world, x, y, z, metadata)
|
||||
if (block.canHarvestBlock(this, metadata)) {
|
||||
val itemsBefore = entitiesInBlock[EntityItem](x, y, z)
|
||||
block.harvestBlock(world, this, x, y, z, metadata)
|
||||
val itemsAfter = entitiesInBlock[EntityItem](x, y, z)
|
||||
val itemsDropped = itemsAfter -- itemsBefore
|
||||
|
Loading…
x
Reference in New Issue
Block a user