diff --git a/common/src/main/scala/net/psforever/objects/EquipmentSlot.scala b/common/src/main/scala/net/psforever/objects/EquipmentSlot.scala
index 7cb698b1b..816c1ec16 100644
--- a/common/src/main/scala/net/psforever/objects/EquipmentSlot.scala
+++ b/common/src/main/scala/net/psforever/objects/EquipmentSlot.scala
@@ -21,12 +21,26 @@ class EquipmentSlot {
Size
}
+ /**
+ * Determine what `Equipment` is stowed in the given position.
+ * @return the `Equipment` in this slot
+ */
def Equipment : Option[Equipment] = tool
+ /**
+ * Attempt to stow an item at the given position.
+ * @param assignEquipment the change in `Equipment` for this slot
+ * @return the `Equipment` in this slot
+ */
def Equipment_=(assignEquipment : Equipment) : Option[Equipment] = {
Equipment = Some(assignEquipment)
}
+ /**
+ * Attempt to stow an item at the given position.
+ * @param assignEquipment the change in `Equipment` for this slot
+ * @return the `Equipment` in this slot
+ */
def Equipment_=(assignEquipment : Option[Equipment]) : Option[Equipment] = {
if(assignEquipment.isDefined) { //if new equipment is defined, don't put it in the slot if the slot is being used
if(tool.isEmpty && EquipmentSize.isEqual(size, assignEquipment.get.Size)) {
diff --git a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala
index 4f3df693c..34976c0c2 100644
--- a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala
+++ b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala
@@ -1117,10 +1117,12 @@ object GlobalDefinitions {
val
flail_targeting_laser = SimpleItemDefinition(SItem.flail_targeting_laser)
flail_targeting_laser.Packet = new CommandDetonaterConverter
+ flail_targeting_laser.Tile = InventoryTile.Tile33
val
command_detonater = SimpleItemDefinition(SItem.command_detonater)
command_detonater.Packet = new CommandDetonaterConverter
+ command_detonater.Tile = InventoryTile.Tile33
val
ace = ConstructionItemDefinition(CItem.Unit.ace)
diff --git a/common/src/main/scala/net/psforever/objects/inventory/GridInventory.scala b/common/src/main/scala/net/psforever/objects/inventory/GridInventory.scala
index 8307cea26..b513ea553 100644
--- a/common/src/main/scala/net/psforever/objects/inventory/GridInventory.scala
+++ b/common/src/main/scala/net/psforever/objects/inventory/GridInventory.scala
@@ -116,12 +116,7 @@ class GridInventory {
}
/**
- * Test whether a given piece of `Equipment` would collide with any stowed content in the inventory.
- *
- * If there are fewer items stored in the inventory than there are cells required to represent the testing item,
- * test the collision by iterating through the list of items.
- * If there are more items, check that each cell that would be used for the testing items tile does not collide.
- * The "testing item" in this case has already been transformed into its tile dimensions.
+ * Test whether a given piece of `Equipment` would collide with any stowed content in the inventory.
* @param start the cell index to test this `Equipment` for insertion
* @param w the width of the `Equipment` to be tested
* @param h the height of the `Equipment` to be tested
@@ -132,8 +127,33 @@ class GridInventory {
Success(List.empty[Int])
}
else {
- def check : (Int,Int,Int) => Try[List[Int]] = if(items.size < w * h) { CheckCollisionsAsList } else { CheckCollisionsAsGrid }
- check(start, w, h)
+ CheckCollisionsVar(start, w, h) match {
+ case Success(list) =>
+ Success(list.map({ f => f.obj.GUID.guid }))
+ case Failure(ex) =>
+ Failure(ex)
+ }
+ }
+ }
+
+ /**
+ * Test whether a given piece of `Equipment` would collide with any stowed content in the inventory.
+ *
+ * If there are fewer items stored in the inventory than there are cells required to represent the testing item,
+ * test the collision by iterating through the list of items.
+ * If there are more items, check that each cell that would be used for the testing items tile does not collide.
+ * The "testing item" in this case has already been transformed into its tile dimensions.
+ * @param start the cell index to test this `Equipment` for insertion
+ * @param w the width of the `Equipment` to be tested
+ * @param h the height of the `Equipment` to be tested
+ * @return a `List` of existing items that an item of this scale would overlap if inserted
+ */
+ def CheckCollisionsVar(start : Int, w : Int, h : Int) : Try[List[InventoryItem]] = {
+ if(items.size < w * h) {
+ CheckCollisionsAsList(start, w, h)
+ }
+ else {
+ CheckCollisionsAsGrid(start, w, h)
}
}
@@ -145,10 +165,10 @@ class GridInventory {
* @param start the cell index to test this `Equipment` for insertion
* @param w the width of the `Equipment` to be tested
* @param h the height of the `Equipment` to be tested
- * @return a `List` of GUID values for all existing contents that this item would overlap if inserted
+ * @return a `List` of existing items that an item of this scale would overlap if inserted
* @throws IndexOutOfBoundsException if the region extends outside of the grid boundaries
*/
- def CheckCollisionsAsList(start : Int, w : Int, h : Int) : Try[List[Int]] = {
+ def CheckCollisionsAsList(start : Int, w : Int, h : Int) : Try[List[InventoryItem]] = {
val actualSlot = start - offset
val startx : Int = actualSlot % width
val starty : Int = actualSlot / width
@@ -159,7 +179,7 @@ class GridInventory {
Failure(new IndexOutOfBoundsException(s"requested region escapes the $bounds edge of the grid inventory - $startx, $starty; $w x $h"))
}
else {
- val collisions : mutable.Set[Int] = mutable.Set[Int]()
+ val collisions : mutable.Set[InventoryItem] = mutable.Set[InventoryItem]()
items.values.foreach({ item : InventoryItem =>
val actualItemStart : Int = item.start - offset
val itemx : Int = actualItemStart % width
@@ -168,7 +188,7 @@ class GridInventory {
val clipsOnX : Boolean = if(itemx < startx) { itemx + tile.width > startx } else { itemx <= startw }
val clipsOnY : Boolean = if(itemy < starty) { itemy + tile.height > starty } else { itemy <= starth }
if(clipsOnX && clipsOnY) {
- collisions += item.GUID.guid
+ collisions += item
}
})
Success(collisions.toList)
@@ -183,10 +203,10 @@ class GridInventory {
* @param start the cell index to test this `Equipment` for insertion
* @param w the width of the `Equipment` to be tested
* @param h the height of the `Equipment` to be tested
- * @return a `List` of GUID values for all existing contents that this item would overlap if inserted
+ * @return a `List` of existing items that an item of this scale would overlap if inserted
* @throws IndexOutOfBoundsException if the region extends outside of the grid boundaries
*/
- def CheckCollisionsAsGrid(start : Int, w : Int, h : Int) : Try[List[Int]] = {
+ def CheckCollisionsAsGrid(start : Int, w : Int, h : Int) : Try[List[InventoryItem]] = {
val actualSlot = start - offset
if(actualSlot < 0 || actualSlot >= grid.length || (actualSlot % width) + w > width || (actualSlot / width) + h > height) {
val startx : Int = actualSlot % width
@@ -196,12 +216,12 @@ class GridInventory {
Failure(new IndexOutOfBoundsException(s"requested region escapes the $bounds edge of the grid inventory - $startx, $starty; $w x $h"))
}
else {
- val collisions : mutable.Set[Int] = mutable.Set[Int]()
+ val collisions : mutable.Set[InventoryItem] = mutable.Set[InventoryItem]()
var curr = actualSlot
for(_ <- 0 until h) {
for(col <- 0 until w) {
if(grid(curr + col) > -1) {
- collisions += items(grid(curr + col)).GUID.guid
+ collisions += items(grid(curr + col))
}
}
curr += width
diff --git a/common/src/main/scala/net/psforever/objects/inventory/InventoryEquipmentSlot.scala b/common/src/main/scala/net/psforever/objects/inventory/InventoryEquipmentSlot.scala
index 5e4515ed5..575a43a10 100644
--- a/common/src/main/scala/net/psforever/objects/inventory/InventoryEquipmentSlot.scala
+++ b/common/src/main/scala/net/psforever/objects/inventory/InventoryEquipmentSlot.scala
@@ -4,40 +4,57 @@ package net.psforever.objects.inventory
import net.psforever.objects.OffhandEquipmentSlot
import net.psforever.objects.equipment.{Equipment, EquipmentSize}
+import scala.util.{Failure, Success}
+
/**
* A slot-like interface for a specific grid position in an inventory.
- * The size is bound to anything that can be stowed, which encompasses most all `Equipment`.
- * Furthermore, rather than operating on a fixed-size slot, this "slot" represents an inventory region that either includes `slot` or starts at `slot`.
- * An object added to the underlying inventory from here can only be added with its initial point at `slot`.
- * An object found at `slot`, however, can be removed even if the starting cell is prior to `slot.`
+ * The size is typically bound to anything that can be stowed which encompasses most all `Equipment`.
+ * The capacity of this `EquipmentSlot` is essentially treated as 1x1.
+ * Upon insertions, however, the capacity temporarily is treated as the size of the item being inserted (unless `None`).
+ * This allows a proper check for insertion collision.
+ *
+ * Rather than operating on a fixed-size slot, this "slot" represents an inventory region that either includes `slot` or starts at `slot`.
+ * When determining the contents of the inventory at `slot`, only that singular cell is checked.
+ * When removing an item from `slot`, the item in inventory only has to be positioned in such a way that overlaps with `slot`.
+ * When adding an item to `slot`, `slot` is treated as the upper left corner (the initial point) of a larger capacity region.
+ *
+ * The following diagrams demonstrate the coordinate association:
+ * ` - - - - - - - - - - - - - - -`
+ * ` - - - - - - r r x - - - - - -`
+ * ` - - s - - - r r x - - - i i -`
+ * ` - - - - - - x x x - - - i i -`
+ * ` - - - - - - - - - - - - - - -`
+ * ... where 's' is the 1x1 slot,
+ * 'r' is the corner of any 2x2 item that can be removed ('x' is a potential affected edge),
+ * and 'i' is the region checked for a 2x2 insertion into `slot`.
*/
class InventoryEquipmentSlot(private val slot : Int, private val inv : GridInventory) extends OffhandEquipmentSlot(EquipmentSize.Inventory) {
- /**
- * Attempt to stow an item into the inventory at the given position.
- * @param assignEquipment the change in `Equipment` for this slot
- * @return the `Equipment` in this slot
- */
override def Equipment_=(assignEquipment : Option[Equipment]) : Option[Equipment] = {
assignEquipment match {
case Some(equip) =>
- inv += slot -> equip
+ val tile = equip.Definition.Tile
+ inv.CheckCollisionsVar(slot, tile.Width, tile.Height) match {
+ case Success(Nil) => inv += slot -> equip
+ case _ => ;
+ }
+
case None =>
inv -= slot
}
Equipment
}
- /**
- * Determine what `Equipment`, if any, is stowed in the inventory in the given position.
- * @return the `Equipment` in this slot
- */
override def Equipment : Option[Equipment] = {
- inv.Items.find({ case ((_, item : InventoryItem)) => item.start == slot }) match {
- case Some((_, item : InventoryItem)) =>
- Some(item.obj)
- case None =>
+ inv.CheckCollisionsAsGrid(slot,1,1) match {
+ case Success(list) =>
+ list.headOption match {
+ case Some(found) =>
+ Some(found.obj)
+ case None =>
+ None
+ }
+ case Failure(_) =>
None
}
}
}
-
diff --git a/common/src/test/scala/objects/InventoryTest.scala b/common/src/test/scala/objects/InventoryTest.scala
index 52698fa5e..3af8a011d 100644
--- a/common/src/test/scala/objects/InventoryTest.scala
+++ b/common/src/test/scala/objects/InventoryTest.scala
@@ -59,14 +59,30 @@ class InventoryTest extends Specification {
obj.Capacity mustEqual 45
val w = bullet9mmBox2.Tile.width
val h = bullet9mmBox2.Tile.height
- obj.CheckCollisionsAsList(0, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsList(1, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsList(2, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsList(3, w, h) mustEqual Success(Nil)
- obj.CheckCollisionsAsGrid(0, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsGrid(1, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsGrid(2, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsGrid(3, w, h) mustEqual Success(Nil)
+ val list0 = obj.CheckCollisionsAsList(0, w, h)
+ list0 match {
+ case scala.util.Success(list) => list.length mustEqual 1
+ case scala.util.Failure(_) => ko
+ }
+ val list1 = obj.CheckCollisionsAsList(1, w, h)
+ list1 match {
+ case scala.util.Success(list) => list.length mustEqual 1
+ case scala.util.Failure(_) => ko
+ }
+ val list2 = obj.CheckCollisionsAsList(2, w, h)
+ list2 match {
+ case scala.util.Success(list) => list.length mustEqual 1
+ case scala.util.Failure(_) => ko
+ }
+ val list3 = obj.CheckCollisionsAsList(3, w, h)
+ list3 match {
+ case scala.util.Success(list) => list.isEmpty mustEqual true
+ case scala.util.Failure(_) => ko
+ }
+ obj.CheckCollisionsAsGrid(0, w, h) mustEqual list0
+ obj.CheckCollisionsAsGrid(1, w, h) mustEqual list1
+ obj.CheckCollisionsAsGrid(2, w, h) mustEqual list2
+ obj.CheckCollisionsAsGrid(3, w, h) mustEqual list3
obj.Clear()
ok
}
@@ -77,14 +93,30 @@ class InventoryTest extends Specification {
obj.Capacity mustEqual 45
val w = bullet9mmBox2.Tile.width
val h = bullet9mmBox2.Tile.height
- obj.CheckCollisionsAsList(3, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsList(2, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsList(1, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsList(0, w, h) mustEqual Success(Nil)
- obj.CheckCollisionsAsGrid(3, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsGrid(2, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsGrid(1, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsGrid(0, w, h) mustEqual Success(Nil)
+ val list0 = obj.CheckCollisionsAsList(3, w, h)
+ list0 match {
+ case scala.util.Success(list) => list.length mustEqual 1
+ case scala.util.Failure(_) => ko
+ }
+ val list1 = obj.CheckCollisionsAsList(2, w, h)
+ list1 match {
+ case scala.util.Success(list) => list.length mustEqual 1
+ case scala.util.Failure(_) => ko
+ }
+ val list2 = obj.CheckCollisionsAsList(1, w, h)
+ list2 match {
+ case scala.util.Success(list) => list.length mustEqual 1
+ case scala.util.Failure(_) => ko
+ }
+ val list3 = obj.CheckCollisionsAsList(0, w, h)
+ list3 match {
+ case scala.util.Success(list) => list.isEmpty mustEqual true
+ case scala.util.Failure(_) => ko
+ }
+ obj.CheckCollisionsAsGrid(3, w, h) mustEqual list0
+ obj.CheckCollisionsAsGrid(2, w, h) mustEqual list1
+ obj.CheckCollisionsAsGrid(1, w, h) mustEqual list2
+ obj.CheckCollisionsAsGrid(0, w, h) mustEqual list3
obj.Clear()
ok
}
@@ -95,14 +127,30 @@ class InventoryTest extends Specification {
obj.Capacity mustEqual 45
val w = bullet9mmBox2.Tile.width
val h = bullet9mmBox2.Tile.height
- obj.CheckCollisionsAsList(0, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsList(9, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsList(18, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsList(27, w, h) mustEqual Success(Nil)
- obj.CheckCollisionsAsGrid(0, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsGrid(9, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsGrid(18, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsGrid(27, w, h) mustEqual Success(Nil)
+ val list0 = obj.CheckCollisionsAsList(0, w, h)
+ list0 match {
+ case scala.util.Success(list) => list.length mustEqual 1
+ case scala.util.Failure(_) => ko
+ }
+ val list1 = obj.CheckCollisionsAsList(9, w, h)
+ list1 match {
+ case scala.util.Success(list) => list.length mustEqual 1
+ case scala.util.Failure(_) => ko
+ }
+ val list2 = obj.CheckCollisionsAsList(18, w, h)
+ list2 match {
+ case scala.util.Success(list) => list.length mustEqual 1
+ case scala.util.Failure(_) => ko
+ }
+ val list3 = obj.CheckCollisionsAsList(27, w, h)
+ list3 match {
+ case scala.util.Success(list) => list.isEmpty mustEqual true
+ case scala.util.Failure(_) => ko
+ }
+ obj.CheckCollisionsAsGrid(0, w, h) mustEqual list0
+ obj.CheckCollisionsAsGrid(9, w, h) mustEqual list1
+ obj.CheckCollisionsAsGrid(18, w, h) mustEqual list2
+ obj.CheckCollisionsAsGrid(27, w, h) mustEqual list3
obj.Clear()
ok
}
@@ -113,14 +161,100 @@ class InventoryTest extends Specification {
obj.Capacity mustEqual 45
val w = bullet9mmBox2.Tile.width
val h = bullet9mmBox2.Tile.height
- obj.CheckCollisionsAsList(27, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsList(19, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsList(9, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsList(0, w, h) mustEqual Success(Nil)
- obj.CheckCollisionsAsGrid(27, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsGrid(19, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsGrid(9, w, h) mustEqual Success(1 :: Nil)
- obj.CheckCollisionsAsGrid(0, w, h) mustEqual Success(Nil)
+ val list0 = obj.CheckCollisionsAsList(27, w, h)
+ list0 match {
+ case scala.util.Success(list) => list.length mustEqual 1
+ case scala.util.Failure(_) => ko
+ }
+ val list1 = obj.CheckCollisionsAsList(18, w, h)
+ list1 match {
+ case scala.util.Success(list) => list.length mustEqual 1
+ case scala.util.Failure(_) => ko
+ }
+ val list2 = obj.CheckCollisionsAsList(9, w, h)
+ list2 match {
+ case scala.util.Success(list) => list.length mustEqual 1
+ case scala.util.Failure(_) => ko
+ }
+ val list3 = obj.CheckCollisionsAsList(0, w, h)
+ list3 match {
+ case scala.util.Success(list) => list.isEmpty mustEqual true
+ case scala.util.Failure(_) => ko
+ }
+ obj.CheckCollisionsAsGrid(27, w, h) mustEqual list0
+ obj.CheckCollisionsAsGrid(18, w, h) mustEqual list1
+ obj.CheckCollisionsAsGrid(9, w, h) mustEqual list2
+ obj.CheckCollisionsAsGrid(0, w, h) mustEqual list3
+ obj.Clear()
+ ok
+ }
+
+ "check for item collision (diagonal insert)" in {
+ /*
+ Number indicates upper-left corner of attempted 3x3 insertion by list#
+ 0 - - - - - 2 - - - - -
+ - 1 - - - 3 - - - - - -
+ - - - - - - - - - - - -
+ - - - X X X - - - - - -
+ - - - X X X - - - - - -
+ - 5 - X X 7 - - - - - -
+ 4 - - - - - 6 - - - - -
+ - - - - - - - - - - - -
+ - - - - - - - - - - - -
+ */
+ val obj : GridInventory = GridInventory(12, 9)
+ obj += 39 -> bullet9mmBox1
+ obj.Capacity mustEqual 99 //108 - 9
+ val w = bullet9mmBox2.Tile.width
+ val h = bullet9mmBox2.Tile.height
+ val list0 = obj.CheckCollisionsAsList(0, w, h)
+ list0 match {
+ case scala.util.Success(list) => list.isEmpty mustEqual true
+ case scala.util.Failure(_) => ko
+ }
+ val list1 = obj.CheckCollisionsAsList(13, w, h)
+ list1 match {
+ case scala.util.Success(list) => list.length mustEqual 1
+ case scala.util.Failure(_) => ko
+ }
+ val list2 = obj.CheckCollisionsAsList(6, w, h)
+ list2 match {
+ case scala.util.Success(list) =>list.isEmpty mustEqual true
+ case scala.util.Failure(_) => ko
+ }
+ val list3 = obj.CheckCollisionsAsList(17, w, h)
+ list3 match {
+ case scala.util.Success(list) => list.length mustEqual 1
+ case scala.util.Failure(_) => ko
+ }
+ val list4 = obj.CheckCollisionsAsList(72, w, h)
+ list4 match {
+ case scala.util.Success(list) => list.isEmpty mustEqual true
+ case scala.util.Failure(_) => ko
+ }
+ val list5 = obj.CheckCollisionsAsList(61, w, h)
+ list5 match {
+ case scala.util.Success(list) => list.length mustEqual 1
+ case scala.util.Failure(_) => ko
+ }
+ val list6 = obj.CheckCollisionsAsList(78, w, h)
+ list6 match {
+ case scala.util.Success(list) => list.isEmpty mustEqual true
+ case scala.util.Failure(_) => ko
+ }
+ val list7 = obj.CheckCollisionsAsList(65, w, h)
+ list7 match {
+ case scala.util.Success(list) => list.length mustEqual 1
+ case scala.util.Failure(_) => ko
+ }
+ obj.CheckCollisionsAsGrid(0, w, h) mustEqual list0
+ obj.CheckCollisionsAsGrid(13, w, h) mustEqual list1
+ obj.CheckCollisionsAsGrid(6, w, h) mustEqual list2
+ obj.CheckCollisionsAsGrid(17, w, h) mustEqual list3
+ obj.CheckCollisionsAsGrid(72, w, h) mustEqual list4
+ obj.CheckCollisionsAsGrid(61, w, h) mustEqual list5
+ obj.CheckCollisionsAsGrid(78, w, h) mustEqual list6
+ obj.CheckCollisionsAsGrid(65, w, h) mustEqual list7
obj.Clear()
ok
}
diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala
index ae61a4cf3..52094defe 100644
--- a/pslogin/src/main/scala/WorldSessionActor.scala
+++ b/pslogin/src/main/scala/WorldSessionActor.scala
@@ -21,6 +21,7 @@ import net.psforever.packet.game.objectcreate._
import net.psforever.types._
import scala.annotation.tailrec
+import scala.util.Success
class WorldSessionActor extends Actor with MDCContextAware {
private[this] val log = org.log4s.getLogger
@@ -857,50 +858,68 @@ class WorldSessionActor extends Actor with MDCContextAware {
player.Find(item_guid) match {
case Some(index) =>
val indexSlot = player.Slot(index)
+ var itemOpt = indexSlot.Equipment //use this to short circuit
+ val item = itemOpt.get
val destSlot = player.Slot(dest)
- val item = indexSlot.Equipment.get
- val destItem = destSlot.Equipment
- indexSlot.Equipment = None
- destSlot.Equipment = None
- (destSlot.Equipment = item) match {
- case Some(_) => //move item
- log.info(s"MoveItem: $item_guid moved from $avatar_guid_1 @ $index to $avatar_guid_1 @ $dest")
- //continue on to the code following the next match statement after resolving the match statement
- destItem match {
- case Some(item2) => //second item to swap?
- (indexSlot.Equipment = destItem) match {
- case Some(_) => //yes, swap
- log.info(s"MoveItem: ${item2.GUID} swapped to $avatar_guid_1 @ $index")
- //we must shuffle items around cleanly to avoid causing icons to "disappear"
- if(index == Player.FreeHandSlot) { //temporarily put in safe location, A -> C
- sendResponse(PacketCoding.CreateGamePacket(0, ObjectDetachMessage(player.GUID, item.GUID, Vector3(0f, 0f, 0f), 0f, 0f, 0f))) //ground
- }
- else {
- sendResponse(PacketCoding.CreateGamePacket(0, ObjectAttachMessage(player.GUID, item.GUID, Player.FreeHandSlot))) //free hand
- }
- sendResponse(PacketCoding.CreateGamePacket(0, ObjectAttachMessage(player.GUID, item2.GUID, index))) //B -> A
- if(0 <= index && index < 5) {
- avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.EquipmentInHand(player.GUID, index, item2))
- }
-
- case None => //can't complete the swap; drop the other item on the ground
- sendResponse(PacketCoding.CreateGamePacket(0, ObjectDetachMessage(player.GUID, item2.GUID, player.Position, 0f, 0f, player.Orientation.z))) //ground
- avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.EquipmentOnGround(player.GUID, player.Position, player.Orientation, item2))
- }
-
- case None => ; //just move item over
- }
- sendResponse(PacketCoding.CreateGamePacket(0, ObjectAttachMessage(avatar_guid_1, item_guid, dest)))
- if(0 <= dest && dest < 5) {
- avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.EquipmentInHand(player.GUID, dest, item))
- }
-
- case None => //restore original contents
- indexSlot.Equipment = item
- destSlot.Equipment = destItem
+ val destItem = if((-1 < dest && dest < 5) || dest == Player.FreeHandSlot) {
+ destSlot.Equipment match {
+ case Some(found) =>
+ Some(InventoryItem(found, dest))
+ case None =>
+ None
+ }
}
- case None => ;
+ else {
+ val tile = item.Definition.Tile
+ player.Inventory.CheckCollisionsVar(dest, tile.Width, tile.Height) match {
+ case Success(Nil) => None //no item swap
+ case Success(entry :: Nil) => Some(entry) //one item to swap
+ case Success(_) | scala.util.Failure(_) => itemOpt = None; None //abort item move altogether
+ }
+ }
+
+ if(itemOpt.isDefined) {
+ log.info(s"MoveItem: $item_guid moved from $avatar_guid_1 @ $index to $avatar_guid_1 @ $dest")
+ indexSlot.Equipment = None
+ destItem match { //do we have a swap item?
+ case Some(entry) => //yes, swap
+ val item2 = entry.obj
+ player.Slot(entry.start).Equipment = None //remove item2 to make room for item
+ destSlot.Equipment = item //in case dest and index could block each other
+ (indexSlot.Equipment = entry.obj) match {
+ case Some(_) => //item and item2 swapped places successfully
+ log.info(s"MoveItem: ${item2.GUID} swapped to $avatar_guid_1 @ $index")
+ //we must shuffle items around cleanly to avoid causing icons to "disappear"
+ if(index == Player.FreeHandSlot) { //temporarily put in safe location, A -> C
+ sendResponse(PacketCoding.CreateGamePacket(0, ObjectDetachMessage(player.GUID, item.GUID, Vector3(0f, 0f, 0f), 0f, 0f, 0f))) //ground
+ }
+ else {
+ sendResponse(PacketCoding.CreateGamePacket(0, ObjectAttachMessage(player.GUID, item.GUID, Player.FreeHandSlot))) //free hand
+ }
+ sendResponse(PacketCoding.CreateGamePacket(0, ObjectAttachMessage(player.GUID, item2.GUID, index))) //B -> A
+ if(0 <= index && index < 5) {
+ avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.EquipmentInHand(player.GUID, index, item2))
+ }
+
+ case None => //item2 does not fit; drop on ground
+ val pos = player.Position
+ val orient = player.Orientation
+ DropItemOnGround(item2, pos, player.Orientation)
+ sendResponse(PacketCoding.CreateGamePacket(0, ObjectDetachMessage(player.GUID, item2.GUID, pos, 0f, 0f, orient.z))) //ground
+ avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.EquipmentOnGround(player.GUID, pos, orient, item2))
+ }
+
+ case None => //just move item over
+ destSlot.Equipment = item
+ }
+ sendResponse(PacketCoding.CreateGamePacket(0, ObjectAttachMessage(avatar_guid_1, item_guid, dest)))
+ if(0 <= dest && dest < 5) {
+ avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.EquipmentInHand(player.GUID, dest, item))
+ }
+ }
+ case None =>
+ log.info(s"MoveItem: $avatar_guid_1 wanted to move the item $item_guid but could not find it")
}
case msg @ ChangeAmmoMessage(item_guid, unk1) =>