mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-04-28 23:35:23 +00:00
Merge pull request #203 from Fate-JH/three-grenades
Just Three More Grenades
This commit is contained in:
commit
57d92f380b
8 changed files with 161 additions and 144 deletions
|
|
@ -3,10 +3,7 @@ package net.psforever.objects
|
||||||
|
|
||||||
import net.psforever.objects.definition.EquipmentDefinition
|
import net.psforever.objects.definition.EquipmentDefinition
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.Equipment
|
||||||
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem}
|
import net.psforever.objects.inventory.{Container, GridInventory}
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The companion of a `Locker` that is carried with a player
|
* The companion of a `Locker` that is carried with a player
|
||||||
|
|
@ -21,42 +18,8 @@ class LockerContainer extends Equipment with Container {
|
||||||
|
|
||||||
def VisibleSlots : Set[Int] = Set.empty[Int]
|
def VisibleSlots : Set[Int] = Set.empty[Int]
|
||||||
|
|
||||||
override def Slot(slot : Int) : EquipmentSlot = {
|
|
||||||
if(inventory.Offset <= slot && slot <= inventory.LastIndex) {
|
|
||||||
inventory.Slot(slot)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
OffhandEquipmentSlot.BlockedSlot
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def Fit(obj : Equipment) : Option[Int] = inventory.Fit(obj.Definition.Tile)
|
def Fit(obj : Equipment) : Option[Int] = inventory.Fit(obj.Definition.Tile)
|
||||||
|
|
||||||
def Find(guid : PlanetSideGUID) : Option[Int] = {
|
|
||||||
findInInventory(inventory.Items.values.iterator, guid) match {
|
|
||||||
case Some(index) =>
|
|
||||||
Some(index)
|
|
||||||
case None =>
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@tailrec private def findInInventory(iter : Iterator[InventoryItem], guid : PlanetSideGUID) : Option[Int] = {
|
|
||||||
if(!iter.hasNext) {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val item = iter.next
|
|
||||||
if(item.obj.GUID == guid) {
|
|
||||||
Some(item.start)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
findInInventory(iter, guid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def Definition : EquipmentDefinition = GlobalDefinitions.locker_container
|
def Definition : EquipmentDefinition = GlobalDefinitions.locker_container
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -192,18 +192,13 @@ class Player(private val core : Avatar) extends PlanetSideGameObject with Factio
|
||||||
FreeHand.Equipment
|
FreeHand.Equipment
|
||||||
}
|
}
|
||||||
|
|
||||||
def Find(obj : Equipment) : Option[Int] = Find(obj.GUID)
|
override def Find(guid : PlanetSideGUID) : Option[Int] = {
|
||||||
|
|
||||||
def Find(guid : PlanetSideGUID) : Option[Int] = {
|
|
||||||
findInHolsters(holsters.iterator, guid)
|
findInHolsters(holsters.iterator, guid)
|
||||||
.orElse(findInInventory(inventory.Items.values.iterator, guid)) match {
|
.orElse(inventory.Find(guid)) match {
|
||||||
case Some(index) =>
|
case Some(index) =>
|
||||||
Some(index)
|
Some(index)
|
||||||
case None =>
|
case None =>
|
||||||
if(Locker.Find(guid).isDefined) {
|
if(freeHand.Equipment.isDefined && freeHand.Equipment.get.GUID == guid) {
|
||||||
Some(5)
|
|
||||||
}
|
|
||||||
else if(freeHand.Equipment.isDefined && freeHand.Equipment.get.GUID == guid) {
|
|
||||||
Some(Player.FreeHandSlot)
|
Some(Player.FreeHandSlot)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -227,21 +222,6 @@ class Player(private val core : Avatar) extends PlanetSideGameObject with Factio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@tailrec private def findInInventory(iter : Iterator[InventoryItem], guid : PlanetSideGUID) : Option[Int] = {
|
|
||||||
if(!iter.hasNext) {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val item = iter.next
|
|
||||||
if(item.obj.GUID == guid) {
|
|
||||||
Some(item.start)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
findInInventory(iter, guid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override def Collisions(dest : Int, width : Int, height : Int) : Try[List[InventoryItem]] = {
|
override def Collisions(dest : Int, width : Int, height : Int) : Try[List[InventoryItem]] = {
|
||||||
if(-1 < dest && dest < 5) {
|
if(-1 < dest && dest < 5) {
|
||||||
holsters(dest).Equipment match {
|
holsters(dest).Equipment match {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package net.psforever.objects
|
||||||
|
|
||||||
import net.psforever.objects.definition.VehicleDefinition
|
import net.psforever.objects.definition.VehicleDefinition
|
||||||
import net.psforever.objects.equipment.{Equipment, EquipmentSize}
|
import net.psforever.objects.equipment.{Equipment, EquipmentSize}
|
||||||
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem, InventoryTile}
|
import net.psforever.objects.inventory.{Container, GridInventory, InventoryTile}
|
||||||
import net.psforever.objects.serverobject.mount.Mountable
|
import net.psforever.objects.serverobject.mount.Mountable
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||||
|
|
@ -347,43 +347,8 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServ
|
||||||
|
|
||||||
def Inventory : GridInventory = trunk
|
def Inventory : GridInventory = trunk
|
||||||
|
|
||||||
def Find(obj : Equipment) : Option[Int] = Find(obj.GUID)
|
|
||||||
|
|
||||||
def Find(guid : PlanetSideGUID) : Option[Int] = {
|
|
||||||
findInInventory(Inventory.Items.values.iterator, guid) match {
|
|
||||||
case Some(index) =>
|
|
||||||
Some(index)
|
|
||||||
case None =>
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@tailrec private def findInInventory(iter : Iterator[InventoryItem], guid : PlanetSideGUID) : Option[Int] = {
|
|
||||||
if(!iter.hasNext) {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val item = iter.next
|
|
||||||
if(item.obj.GUID == guid) {
|
|
||||||
Some(item.start)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
findInInventory(iter, guid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def VisibleSlots : Set[Int] = weapons.keySet
|
def VisibleSlots : Set[Int] = weapons.keySet
|
||||||
|
|
||||||
override def Slot(slot : Int) : EquipmentSlot = {
|
|
||||||
if(Inventory.Offset <= slot && slot <= Inventory.LastIndex) {
|
|
||||||
Inventory.Slot(slot)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
OffhandEquipmentSlot.BlockedSlot
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A reference to the `Vehicle` `Trunk` space.
|
* A reference to the `Vehicle` `Trunk` space.
|
||||||
* @return this `Vehicle` `Trunk`
|
* @return this `Vehicle` `Trunk`
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.inventory
|
package net.psforever.objects.inventory
|
||||||
|
|
||||||
|
import net.psforever.objects.equipment.Equipment
|
||||||
import net.psforever.objects.{EquipmentSlot, OffhandEquipmentSlot}
|
import net.psforever.objects.{EquipmentSlot, OffhandEquipmentSlot}
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
|
|
||||||
|
|
@ -20,17 +21,26 @@ trait Container {
|
||||||
* A(n imperfect) reference to a generalized pool of the contained objects.
|
* A(n imperfect) reference to a generalized pool of the contained objects.
|
||||||
* Having access to all of the available positions is not required.
|
* Having access to all of the available positions is not required.
|
||||||
* The entries in this reference should definitely include all unseen positions.
|
* The entries in this reference should definitely include all unseen positions.
|
||||||
|
* The `GridInventory` returned by this accessor is also an implementation of `Container`.
|
||||||
* @see `VisibleSlots`
|
* @see `VisibleSlots`
|
||||||
*/
|
*/
|
||||||
def Inventory : GridInventory
|
def Inventory : GridInventory
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an object, attempt to locate its slot.
|
||||||
|
* All positions, `VisibleSlot` and `Inventory`, and wherever else, should be searchable.
|
||||||
|
* @param obj the `Equipment` object
|
||||||
|
* @return the index of the `EquipmentSlot`, or `None`
|
||||||
|
*/
|
||||||
|
def Find(obj : Equipment) : Option[Int] = Find(obj.GUID)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given globally unique identifier, if the object using it is stowed, attempt to locate its slot.
|
* Given globally unique identifier, if the object using it is stowed, attempt to locate its slot.
|
||||||
* All positions, `VisibleSlot` and `Inventory`, and wherever else, should be searchable.
|
* All positions, `VisibleSlot` and `Inventory`, and wherever else, should be searchable.
|
||||||
* @param guid the GUID of the `Equipment`
|
* @param guid the GUID of the `Equipment`
|
||||||
* @return the index of the `EquipmentSlot`, or `None`
|
* @return the index of the `EquipmentSlot`, or `None`
|
||||||
*/
|
*/
|
||||||
def Find(guid : PlanetSideGUID) : Option[Int]
|
def Find(guid : PlanetSideGUID) : Option[Int] = Inventory.Find(guid)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A(n imperfect) reference to a generalized pool of the contained objects.<br>
|
* A(n imperfect) reference to a generalized pool of the contained objects.<br>
|
||||||
|
|
@ -53,7 +63,14 @@ trait Container {
|
||||||
* @param slotNum an index
|
* @param slotNum an index
|
||||||
* @return the searchable position identified by that index
|
* @return the searchable position identified by that index
|
||||||
*/
|
*/
|
||||||
def Slot(slotNum : Int) : EquipmentSlot = OffhandEquipmentSlot.BlockedSlot
|
def Slot(slotNum : Int) : EquipmentSlot = {
|
||||||
|
if(Inventory.Offset <= slotNum && slotNum <= Inventory.LastIndex) {
|
||||||
|
Inventory.Slot(slotNum)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
OffhandEquipmentSlot.BlockedSlot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a region of "searchable unit positions" considered as stowable,
|
* Given a region of "searchable unit positions" considered as stowable,
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ import scala.util.{Failure, Success, Try}
|
||||||
* The `Array` of spatial GUIDs is used for quick collision lookup.
|
* The `Array` of spatial GUIDs is used for quick collision lookup.
|
||||||
* Use of the `Array` only is hitherto referred as "using the inventory as a grid."
|
* Use of the `Array` only is hitherto referred as "using the inventory as a grid."
|
||||||
*/
|
*/
|
||||||
class GridInventory {
|
class GridInventory extends Container {
|
||||||
private var width : Int = 1
|
private var width : Int = 1
|
||||||
private var height : Int = 1
|
private var height : Int = 1
|
||||||
private var offset : Int = 0 //the effective index of the first cell in the inventory where offset >= 0
|
private var offset : Int = 0 //the effective index of the first cell in the inventory where offset >= 0
|
||||||
|
|
@ -83,12 +83,21 @@ class GridInventory {
|
||||||
*/
|
*/
|
||||||
def LastIndex : Int = Offset + TotalCapacity - 1
|
def LastIndex : Int = Offset + TotalCapacity - 1
|
||||||
|
|
||||||
|
override def Find(guid : PlanetSideGUID) : Option[Int] = {
|
||||||
|
items.values.find({ case InventoryItem(obj, _) => obj.HasGUID && obj.GUID == guid}) match {
|
||||||
|
case Some(InventoryItem(_, index)) =>
|
||||||
|
Some(index)
|
||||||
|
case None =>
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get whatever is stowed in the inventory at the given index.
|
* Get whatever is stowed in the inventory at the given index.
|
||||||
* @param slot the cell index
|
* @param slot the cell index
|
||||||
* @return an `EquipmentSlot` that contains whatever `Equipment` was stored in `slot`
|
* @return an `EquipmentSlot` that contains whatever `Equipment` was stored in `slot`
|
||||||
*/
|
*/
|
||||||
def Slot(slot : Int) : EquipmentSlot = {
|
override def Slot(slot : Int) : EquipmentSlot = {
|
||||||
val actualSlot = slot - offset
|
val actualSlot = slot - offset
|
||||||
if(actualSlot < 0 || actualSlot > grid.length) {
|
if(actualSlot < 0 || actualSlot > grid.length) {
|
||||||
throw new IndexOutOfBoundsException(s"requested indices not in bounds of grid inventory - $actualSlot")
|
throw new IndexOutOfBoundsException(s"requested indices not in bounds of grid inventory - $actualSlot")
|
||||||
|
|
@ -426,6 +435,10 @@ class GridInventory {
|
||||||
height = h
|
height = h
|
||||||
grid = Array.fill[Int](w * h)(-1)
|
grid = Array.fill[Int](w * h)(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def VisibleSlots : Set[Int] = Set.empty[Int]
|
||||||
|
|
||||||
|
def Inventory = this
|
||||||
}
|
}
|
||||||
|
|
||||||
object GridInventory {
|
object GridInventory {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package objects
|
package objects
|
||||||
|
|
||||||
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem}
|
import net.psforever.objects.equipment.EquipmentSize
|
||||||
import net.psforever.objects.{GlobalDefinitions, OffhandEquipmentSlot, Tool}
|
import net.psforever.objects.inventory.{Container, GridInventory, InventoryEquipmentSlot}
|
||||||
|
import net.psforever.objects.{EquipmentSlot, GlobalDefinitions, OffhandEquipmentSlot, Tool}
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
import org.specs2.mutable._
|
import org.specs2.mutable._
|
||||||
|
|
||||||
|
|
@ -16,7 +17,11 @@ class ContainerTest extends Specification {
|
||||||
obj.Inventory.Size mustEqual 0
|
obj.Inventory.Size mustEqual 0
|
||||||
obj.Inventory.Capacity mustEqual 9
|
obj.Inventory.Capacity mustEqual 9
|
||||||
obj.Find(PlanetSideGUID(0)) mustEqual None
|
obj.Find(PlanetSideGUID(0)) mustEqual None
|
||||||
obj.Slot(0) mustEqual OffhandEquipmentSlot.BlockedSlot
|
obj.Slot(0).isInstanceOf[OffhandEquipmentSlot] mustEqual true
|
||||||
|
obj.Slot(0).isInstanceOf[InventoryEquipmentSlot] mustEqual true
|
||||||
|
obj.Slot(0).isInstanceOf[EquipmentSlot] mustEqual true
|
||||||
|
obj.Slot(0).Size mustEqual EquipmentSize.Inventory
|
||||||
|
obj.Slot(0).Equipment mustEqual None
|
||||||
obj.Collisions(0, 2, 2) mustEqual Success(List())
|
obj.Collisions(0, 2, 2) mustEqual Success(List())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,23 +54,6 @@ object ContainerTest {
|
||||||
|
|
||||||
def Inventory : GridInventory = inv
|
def Inventory : GridInventory = inv
|
||||||
|
|
||||||
def Find(guid : PlanetSideGUID) : Option[Int] = {
|
|
||||||
Inventory.Items.find({
|
|
||||||
case((_, item)) =>
|
|
||||||
if(item.obj.HasGUID) {
|
|
||||||
item.obj.GUID == guid
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}) match {
|
|
||||||
case Some((index, _)) =>
|
|
||||||
Some(index)
|
|
||||||
case None =>
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def VisibleSlots :Set[Int] = Set[Int](0,1,2, 3,4,5, 6,7,8)
|
def VisibleSlots :Set[Int] = Set[Int](0,1,2, 3,4,5, 6,7,8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -303,7 +303,7 @@ class PlayerTest extends Specification {
|
||||||
obj.Find(PlanetSideGUID(1)) mustEqual Some(0) //holsters
|
obj.Find(PlanetSideGUID(1)) mustEqual Some(0) //holsters
|
||||||
obj.Find(PlanetSideGUID(2)) mustEqual Some(4) //holsters, melee
|
obj.Find(PlanetSideGUID(2)) mustEqual Some(4) //holsters, melee
|
||||||
obj.Find(PlanetSideGUID(3)) mustEqual Some(6) //inventory
|
obj.Find(PlanetSideGUID(3)) mustEqual Some(6) //inventory
|
||||||
obj.Find(PlanetSideGUID(4)) mustEqual Some(Player.LockerSlot) //locker-space
|
obj.Find(PlanetSideGUID(4)) mustEqual None //can not find in locker-space
|
||||||
obj.Find(PlanetSideGUID(5)) mustEqual Some(Player.FreeHandSlot) //free hand
|
obj.Find(PlanetSideGUID(5)) mustEqual Some(Player.FreeHandSlot) //free hand
|
||||||
obj.Find(PlanetSideGUID(6)) mustEqual None //not here
|
obj.Find(PlanetSideGUID(6)) mustEqual None //not here
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1742,7 +1742,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
do {
|
do {
|
||||||
val requestedAmmoType = tool.NextAmmoType
|
val requestedAmmoType = tool.NextAmmoType
|
||||||
if(requestedAmmoType != tool.AmmoSlot.Box.AmmoType) {
|
if(requestedAmmoType != tool.AmmoSlot.Box.AmmoType) {
|
||||||
FindReloadAmmunition(obj, requestedAmmoType, fullMagazine).reverse match {
|
FindEquipmentStock(obj, FindAmmoBoxThatUses(requestedAmmoType), fullMagazine, CountAmmunition).reverse match {
|
||||||
case Nil => ;
|
case Nil => ;
|
||||||
case x :: xs =>
|
case x :: xs =>
|
||||||
val (deleteFunc, modifyFunc) : ((Int, AmmoBox)=>Unit, (AmmoBox, Int)=>Unit) = obj match {
|
val (deleteFunc, modifyFunc) : ((Int, AmmoBox)=>Unit, (AmmoBox, Int)=>Unit) = obj match {
|
||||||
|
|
@ -1961,10 +1961,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
val magazineSize : Int = tool.MaxMagazine
|
val magazineSize : Int = tool.MaxMagazine
|
||||||
val reloadValue : Int = magazineSize - currentMagazine
|
val reloadValue : Int = magazineSize - currentMagazine
|
||||||
if(magazineSize > 0 && reloadValue > 0) {
|
if(magazineSize > 0 && reloadValue > 0) {
|
||||||
FindReloadAmmunition(obj, tool.AmmoType, reloadValue).reverse match {
|
FindEquipmentStock(obj, FindAmmoBoxThatUses(tool.AmmoType), reloadValue, CountAmmunition).reverse match {
|
||||||
case Nil =>
|
case Nil =>
|
||||||
log.warn(s"ReloadMessage: no ammunition could be found for $item_guid")
|
log.warn(s"ReloadMessage: no ammunition could be found for $item_guid")
|
||||||
case list @ x :: xs =>
|
case x :: xs =>
|
||||||
val (deleteFunc, modifyFunc) : ((Int, AmmoBox)=>Unit, (AmmoBox, Int)=>Unit) = obj match {
|
val (deleteFunc, modifyFunc) : ((Int, AmmoBox)=>Unit, (AmmoBox, Int)=>Unit) = obj match {
|
||||||
case (veh : Vehicle) =>
|
case (veh : Vehicle) =>
|
||||||
(DeleteAmmunitionInVehicle(veh), ModifyAmmunitionInVehicle(veh))
|
(DeleteAmmunitionInVehicle(veh), ModifyAmmunitionInVehicle(veh))
|
||||||
|
|
@ -3247,37 +3247,105 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
def FindWeapon : Option[Tool] = FindContainedWeapon._2
|
def FindWeapon : Option[Tool] = FindContainedWeapon._2
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Within a specified `Container`, find the smallest number of `AmmoBox` objects of a certain type of `Ammo`
|
* Within a specified `Container`, find the smallest number of `Equipment` objects of a certain qualifying type
|
||||||
* whose sum capacities is greater than, or equal to, a `desiredAmount`.<br>
|
* whose sum count is greater than, or equal to, a `desiredAmount` based on an accumulator method.<br>
|
||||||
* <br>
|
* <br>
|
||||||
* In an occupied `List` of returned `Inventory` entries, all but the last entry is considered emptied.
|
* In an occupied `List` of returned `Inventory` entries, all but the last entry is typically considered "emptied."
|
||||||
* The last entry may require having its `Capacity` be set to a non-zero number.
|
* For objects with contained quantities, the last entry may require having that quantity be set to a non-zero number.
|
||||||
* @param obj the `Container` to search
|
* @param obj the `Container` to search
|
||||||
* @param ammoType the type of `Ammo` to search for
|
* @param filterTest test used to determine inclusivity of `Equipment` collection
|
||||||
* @param desiredAmount how much ammunition is requested to be found
|
* @param desiredAmount how much is requested
|
||||||
* @return a `List` of all discovered entries totaling approximately the amount of the requested `Ammo`
|
* @param counting test used to determine value of found `Equipment`;
|
||||||
|
* defaults to one per entry
|
||||||
|
* @return a `List` of all discovered entries totaling approximately the amount requested
|
||||||
*/
|
*/
|
||||||
def FindReloadAmmunition(obj : Container, ammoType : Ammo.Value, desiredAmount : Int) : List[InventoryItem] = {
|
def FindEquipmentStock(obj : Container,
|
||||||
|
filterTest : (Equipment)=>Boolean,
|
||||||
|
desiredAmount : Int,
|
||||||
|
counting : (Equipment)=>Int = DefaultCount) : List[InventoryItem] = {
|
||||||
var currentAmount : Int = 0
|
var currentAmount : Int = 0
|
||||||
obj.Inventory.Items
|
obj.Inventory.Items
|
||||||
.map({ case ((_, item)) => item })
|
.map({ case ((_, item)) => item })
|
||||||
.filter(obj => {
|
.filter(item => filterTest(item.obj))
|
||||||
obj.obj match {
|
|
||||||
case (box : AmmoBox) =>
|
|
||||||
box.AmmoType == ammoType
|
|
||||||
case _ =>
|
|
||||||
false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.toList
|
.toList
|
||||||
.sortBy(_.start)
|
.sortBy(_.start)
|
||||||
.takeWhile(entry => {
|
.takeWhile(entry => {
|
||||||
val previousAmount = currentAmount
|
val previousAmount = currentAmount
|
||||||
currentAmount += entry.obj.asInstanceOf[AmmoBox].Capacity
|
currentAmount += counting(entry.obj)
|
||||||
previousAmount < desiredAmount
|
previousAmount < desiredAmount
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default counting function for an item.
|
||||||
|
* Counts the number of item(s).
|
||||||
|
* @param e the `Equipment` object
|
||||||
|
* @return the quantity;
|
||||||
|
* always one
|
||||||
|
*/
|
||||||
|
def DefaultCount(e : Equipment) : Int = 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The counting function for an item of `AmmoBox`.
|
||||||
|
* Counts the `Capacity` of the ammunition.
|
||||||
|
* @param e the `Equipment` object
|
||||||
|
* @return the quantity
|
||||||
|
*/
|
||||||
|
def CountAmmunition(e : Equipment) : Int = {
|
||||||
|
e match {
|
||||||
|
case a : AmmoBox =>
|
||||||
|
a.Capacity
|
||||||
|
case _ =>
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The counting function for an item of `Tool` where the item is also a grenade.
|
||||||
|
* Counts the number of grenades.
|
||||||
|
* @see `GlobalDefinitions.isGrenade`
|
||||||
|
* @param e the `Equipment` object
|
||||||
|
* @return the quantity
|
||||||
|
*/
|
||||||
|
def CountGrenades(e : Equipment) : Int = {
|
||||||
|
e match {
|
||||||
|
case t : Tool =>
|
||||||
|
(GlobalDefinitions.isGrenade(t.Definition):Int) * t.Magazine
|
||||||
|
case _ =>
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag an `AmmoBox` object that matches for the given ammunition type.
|
||||||
|
* @param ammo the type of `Ammo` to check
|
||||||
|
* @param e the `Equipment` object
|
||||||
|
* @return `true`, if the object is an `AmmoBox` of the correct ammunition type; `false`, otherwise
|
||||||
|
*/
|
||||||
|
def FindAmmoBoxThatUses(ammo : Ammo.Value)(e : Equipment) : Boolean = {
|
||||||
|
e match {
|
||||||
|
case t : AmmoBox =>
|
||||||
|
t.AmmoType == ammo
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag a `Tool` object that matches for loading the given ammunition type.
|
||||||
|
* @param ammo the type of `Ammo` to check
|
||||||
|
* @param e the `Equipment` object
|
||||||
|
* @return `true`, if the object is a `Tool` that loads the correct ammunition type; `false`, otherwise
|
||||||
|
*/
|
||||||
|
def FindToolThatUses(ammo : Ammo.Value)(e : Equipment) : Boolean = {
|
||||||
|
e match {
|
||||||
|
case t : Tool =>
|
||||||
|
t.Definition.AmmoTypes.map { _.AmmoType }.contains(ammo)
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given an object that contains a box of amunition in its `Inventory` at a certain location,
|
* Given an object that contains a box of amunition in its `Inventory` at a certain location,
|
||||||
* remove it permanently.
|
* remove it permanently.
|
||||||
|
|
@ -3418,7 +3486,30 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
//TODO this is temporary and will be replaced by more appropriate functionality in the future.
|
//TODO this is temporary and will be replaced by more appropriate functionality in the future.
|
||||||
val tdef = tool.Definition
|
val tdef = tool.Definition
|
||||||
if(GlobalDefinitions.isGrenade(tdef)) {
|
if(GlobalDefinitions.isGrenade(tdef)) {
|
||||||
taskResolver ! RemoveEquipmentFromSlot(player, tool, player.Find(tool).get)
|
val ammoType = tool.AmmoType
|
||||||
|
FindEquipmentStock(player, FindToolThatUses(ammoType), 3, CountGrenades).reverse match { //do not search sidearm holsters
|
||||||
|
case Nil =>
|
||||||
|
log.info(s"no more $ammoType grenades")
|
||||||
|
taskResolver ! RemoveEquipmentFromSlot(player, tool, player.Find(tool).get)
|
||||||
|
|
||||||
|
case x :: xs => //this is similar to ReloadMessage
|
||||||
|
val box = x.obj.asInstanceOf[Tool]
|
||||||
|
val tailReloadValue : Int = if(xs.isEmpty) { 0 } else { xs.map(_.obj.asInstanceOf[Tool].Magazine).reduce(_ + _) }
|
||||||
|
val sumReloadValue : Int = box.Magazine + tailReloadValue
|
||||||
|
val actualReloadValue = (if(sumReloadValue <= 3) {
|
||||||
|
taskResolver ! RemoveEquipmentFromSlot(player, x.obj, x.start)
|
||||||
|
sumReloadValue
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ModifyAmmunition(player)(box.AmmoSlot.Box, 3 - tailReloadValue)
|
||||||
|
3
|
||||||
|
})
|
||||||
|
log.info(s"found $actualReloadValue more $ammoType grenades to throw")
|
||||||
|
ModifyAmmunition(player)(tool.AmmoSlot.Box, -actualReloadValue) //grenade item already in holster (negative because empty)
|
||||||
|
xs.foreach(item => {
|
||||||
|
taskResolver ! RemoveEquipmentFromSlot(player, item.obj, item.start)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(tdef == GlobalDefinitions.phoenix) {
|
else if(tdef == GlobalDefinitions.phoenix) {
|
||||||
taskResolver ! RemoveEquipmentFromSlot(player, tool, player.Find(tool).get)
|
taskResolver ! RemoveEquipmentFromSlot(player, tool, player.Find(tool).get)
|
||||||
|
|
@ -3640,7 +3731,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An event has occurred that would cause the player character to stop certain stateful activities.
|
* An event has occurred that would cause the player character to stop certain stateful activities.
|
||||||
* These activities include shooting, weapon drawing, hacking, accessing (a container), flying, and running.
|
* These activities include shooting, the weapon being drawn, hacking, accessing (a container), flying, and running.
|
||||||
* Other players in the same zone must be made aware that the player has stopped as well.<br>
|
* Other players in the same zone must be made aware that the player has stopped as well.<br>
|
||||||
* <br>
|
* <br>
|
||||||
* Things whose configuration should not be changed:<br>
|
* Things whose configuration should not be changed:<br>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue