mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-12 06:55:10 +00:00
attempting to fix BR24+ characters
This commit is contained in:
parent
349ec676d9
commit
47adfef5c8
6 changed files with 201 additions and 21 deletions
|
|
@ -13,8 +13,8 @@ import scala.collection.mutable
|
||||||
class Player(private val name : String,
|
class Player(private val name : String,
|
||||||
private val faction : PlanetSideEmpire.Value,
|
private val faction : PlanetSideEmpire.Value,
|
||||||
private val sex : CharacterGender.Value,
|
private val sex : CharacterGender.Value,
|
||||||
private val voice : Int,
|
private val head : Int,
|
||||||
private val head : Int
|
private val voice : Int
|
||||||
) extends PlanetSideGameObject {
|
) extends PlanetSideGameObject {
|
||||||
private var alive : Boolean = false
|
private var alive : Boolean = false
|
||||||
private var backpack : Boolean = false
|
private var backpack : Boolean = false
|
||||||
|
|
@ -521,11 +521,11 @@ object Player {
|
||||||
final val FreeHandSlot : Int = 250
|
final val FreeHandSlot : Int = 250
|
||||||
final val HandsDownSlot : Int = 255
|
final val HandsDownSlot : Int = 255
|
||||||
|
|
||||||
def apply(name : String, faction : PlanetSideEmpire.Value, sex : CharacterGender.Value, voice : Int, head : Int) : Player = {
|
def apply(name : String, faction : PlanetSideEmpire.Value, sex : CharacterGender.Value, head : Int, voice : Int) : Player = {
|
||||||
new Player(name, faction, sex, voice, head)
|
new Player(name, faction, sex, head, voice)
|
||||||
}
|
}
|
||||||
|
|
||||||
def apply(guid : PlanetSideGUID, name : String, faction : PlanetSideEmpire.Value, sex : CharacterGender.Value, voice : Int, head : Int) : Player = {
|
def apply(guid : PlanetSideGUID, name : String, faction : PlanetSideEmpire.Value, sex : CharacterGender.Value, head : Int, voice : Int) : Player = {
|
||||||
val obj = new Player(name, faction, sex, voice, head)
|
val obj = new Player(name, faction, sex, voice, head)
|
||||||
obj.GUID = guid
|
obj.GUID = guid
|
||||||
obj
|
obj
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ class AvatarConverter extends ObjectCreateConverter[Player]() {
|
||||||
obj.Stamina,
|
obj.Stamina,
|
||||||
obj.Certifications.toList.sortBy(_.id), //TODO is sorting necessary?
|
obj.Certifications.toList.sortBy(_.id), //TODO is sorting necessary?
|
||||||
MakeImplantEntries(obj),
|
MakeImplantEntries(obj),
|
||||||
List.empty[String], //TODO fte list
|
"xpe_battle_rank_10" :: Nil, //TODO fte list
|
||||||
List.empty[String], //TODO tutorial list
|
List.empty[String], //TODO tutorial list
|
||||||
InventoryData((MakeHolsters(obj, BuildDetailedEquipment) ++ MakeFifthSlot(obj) ++ MakeInventory(obj)).sortBy(_.parentSlot)),
|
InventoryData((MakeHolsters(obj, BuildDetailedEquipment) ++ MakeFifthSlot(obj) ++ MakeInventory(obj)).sortBy(_.parentSlot)),
|
||||||
GetDrawnSlot(obj)
|
GetDrawnSlot(obj)
|
||||||
|
|
@ -56,7 +56,7 @@ class AvatarConverter extends ObjectCreateConverter[Player]() {
|
||||||
private def MakeAppearanceData(obj : Player) : CharacterAppearanceData = {
|
private def MakeAppearanceData(obj : Player) : CharacterAppearanceData = {
|
||||||
CharacterAppearanceData(
|
CharacterAppearanceData(
|
||||||
PlacementData(obj.Position, obj.Orientation, obj.Velocity),
|
PlacementData(obj.Position, obj.Orientation, obj.Velocity),
|
||||||
BasicCharacterData(obj.Name, obj.Faction, obj.Sex, obj.Voice, obj.Head),
|
BasicCharacterData(obj.Name, obj.Faction, obj.Sex, obj.Head, obj.Voice),
|
||||||
0,
|
0,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
|
@ -132,7 +132,10 @@ class AvatarConverter extends ObjectCreateConverter[Player]() {
|
||||||
* @see `ImplantEntry` in `DetailedCharacterData`
|
* @see `ImplantEntry` in `DetailedCharacterData`
|
||||||
*/
|
*/
|
||||||
private def MakeImplantEntries(obj : Player) : List[ImplantEntry] = {
|
private def MakeImplantEntries(obj : Player) : List[ImplantEntry] = {
|
||||||
obj.Implants.map(slot => {
|
val numImplants : Int = NumberOfImplantSlots(obj.BEP)
|
||||||
|
val implants = obj.Implants
|
||||||
|
(0 until numImplants).map(index => {
|
||||||
|
val slot = implants(index)
|
||||||
slot.Installed match {
|
slot.Installed match {
|
||||||
case Some(_) =>
|
case Some(_) =>
|
||||||
if(slot.Initialized) {
|
if(slot.Initialized) {
|
||||||
|
|
@ -147,6 +150,27 @@ class AvatarConverter extends ObjectCreateConverter[Player]() {
|
||||||
}).toList
|
}).toList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A player's battle rank, determined by their battle experience points, determines how many implants to which they have access.
|
||||||
|
* Starting with "no implants" at BR1, a player earns one at each of the three ranks: BR6, BR12, and BR18.
|
||||||
|
* @param bep battle experience points
|
||||||
|
* @return the number of accessible implant slots
|
||||||
|
*/
|
||||||
|
private def NumberOfImplantSlots(bep : Long) : Int = {
|
||||||
|
if(bep > 754370) { //BR18+
|
||||||
|
3
|
||||||
|
}
|
||||||
|
else if(bep > 197753) { //BR12+
|
||||||
|
2
|
||||||
|
}
|
||||||
|
else if(bep > 29999) { //BR6+
|
||||||
|
1
|
||||||
|
}
|
||||||
|
else { //BR1+
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find an active implant whose effect will be displayed on this player.
|
* Find an active implant whose effect will be displayed on this player.
|
||||||
* @param iter an `Iterator` of `ImplantSlot` objects
|
* @param iter an `Iterator` of `ImplantSlot` objects
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,144 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
|
import net.psforever.objects.GlobalDefinitions.{advanced_regen, darklight_vision, personal_shield, surge}
|
||||||
|
import net.psforever.objects.{EquipmentSlot, GlobalDefinitions, ImplantSlot, Player}
|
||||||
|
import net.psforever.objects.equipment.Equipment
|
||||||
|
import net.psforever.packet.game.objectcreate.{BasicCharacterData, CharacterAppearanceData, CharacterData, DetailedCharacterData, DrawnSlot, ImplantEffects, ImplantEntry, InternalSlot, InventoryData, PlacementData, RibbonBars}
|
||||||
|
import net.psforever.types.{GrenadeState, ImplantType}
|
||||||
|
|
||||||
|
import scala.annotation.tailrec
|
||||||
|
import scala.util.{Failure, Success, Try}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `CharacterSelectConverter` is based on `AvatarConverter`
|
||||||
|
* but it is tailored for appearance of the player character on the character selection screen only.
|
||||||
|
* Details that would not be apparent on that screen such as implants or certifications are ignored.
|
||||||
|
*/
|
||||||
|
class CharacterSelectConverter extends ObjectCreateConverter[Player]() {
|
||||||
|
override def ConstructorData(obj : Player) : Try[CharacterData] = Failure(new Exception("CharacterSelectConverter should not be used to generate CharacterData"))
|
||||||
|
|
||||||
|
override def DetailedConstructorData(obj : Player) : Try[DetailedCharacterData] = {
|
||||||
|
Success(
|
||||||
|
DetailedCharacterData(
|
||||||
|
MakeAppearanceData(obj),
|
||||||
|
obj.BEP,
|
||||||
|
obj.CEP,
|
||||||
|
1, 1, 0, 1, 1,
|
||||||
|
Nil,
|
||||||
|
MakeImplantEntries(obj),
|
||||||
|
Nil, Nil,
|
||||||
|
InventoryData(recursiveMakeHolsters(obj.Holsters().iterator)),
|
||||||
|
GetDrawnSlot(obj)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compose some data from a `Player` into a representation common to both `CharacterData` and `DetailedCharacterData`.
|
||||||
|
* @param obj the `Player` game object
|
||||||
|
* @see `AvatarConverter.MakeAppearanceData`
|
||||||
|
* @return the resulting `CharacterAppearanceData`
|
||||||
|
*/
|
||||||
|
private def MakeAppearanceData(obj : Player) : CharacterAppearanceData = {
|
||||||
|
CharacterAppearanceData(
|
||||||
|
PlacementData(0f, 0f, 0f),
|
||||||
|
BasicCharacterData(obj.Name, obj.Faction, obj.Sex, obj.Head, 1),
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
obj.ExoSuit,
|
||||||
|
"",
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
0f,
|
||||||
|
0f,
|
||||||
|
true,
|
||||||
|
GrenadeState.None,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
RibbonBars()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform an `Array` of `Implant` objects into a `List` of `ImplantEntry` objects suitable as packet data.
|
||||||
|
* @param obj the `Player` game object
|
||||||
|
* @return the resulting implant `List`
|
||||||
|
* @see `ImplantEntry` in `DetailedCharacterData`
|
||||||
|
*/
|
||||||
|
private def MakeImplantEntries(obj : Player) : List[ImplantEntry] = {
|
||||||
|
List.fill[ImplantEntry](NumberOfImplantSlots(obj.BEP))(ImplantEntry(ImplantType.None, None))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A player's battle rank, determined by their battle experience points, determines how many implants to which they have access.
|
||||||
|
* Starting with "no implants" at BR1, a player earns one at each of the three ranks: BR6, BR12, and BR18.
|
||||||
|
* @param bep battle experience points
|
||||||
|
* @return the number of accessible implant slots
|
||||||
|
*/
|
||||||
|
private def NumberOfImplantSlots(bep : Long) : Int = {
|
||||||
|
if(bep > 754370) { //BR18+
|
||||||
|
3
|
||||||
|
}
|
||||||
|
else if(bep > 197753) { //BR12+
|
||||||
|
2
|
||||||
|
}
|
||||||
|
else if(bep > 29999) { //BR6+
|
||||||
|
1
|
||||||
|
}
|
||||||
|
else { //BR1+
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A builder method for turning an object into `0x18` decoded packet form.
|
||||||
|
* @param index the position of the object
|
||||||
|
* @param equip the game object
|
||||||
|
* @see `AvatarConverter.BuildDetailedEquipment`
|
||||||
|
* @return the game object in decoded packet form
|
||||||
|
*/
|
||||||
|
private def BuildDetailedEquipment(index : Int, equip : Equipment) : InternalSlot = {
|
||||||
|
InternalSlot(equip.Definition.ObjectId, equip.GUID, index, equip.Definition.Packet.DetailedConstructorData(equip).get)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given some equipment holsters, convert the contents of those holsters into converted-decoded packet data.
|
||||||
|
* @param iter an `Iterator` of `EquipmentSlot` objects that are a part of the player's holsters
|
||||||
|
* @param list the current `List` of transformed data
|
||||||
|
* @param index which holster is currently being explored
|
||||||
|
* @see `AvatarConverter.recursiveMakeHolsters`
|
||||||
|
* @return the `List` of inventory data created from the holsters
|
||||||
|
*/
|
||||||
|
@tailrec private def recursiveMakeHolsters(iter : Iterator[EquipmentSlot], list : List[InternalSlot] = Nil, index : Int = 0) : List[InternalSlot] = {
|
||||||
|
if(!iter.hasNext) {
|
||||||
|
list
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val slot : EquipmentSlot = iter.next
|
||||||
|
if(slot.Equipment.isDefined) {
|
||||||
|
val equip : Equipment = slot.Equipment.get
|
||||||
|
recursiveMakeHolsters(
|
||||||
|
iter,
|
||||||
|
list :+ BuildDetailedEquipment(index, equip),
|
||||||
|
index + 1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
recursiveMakeHolsters(iter, list, index + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve which holster the player has drawn, if any.
|
||||||
|
* @param obj the `Player` game object
|
||||||
|
* @see `AvatarConverter.GetDrawnSlot`
|
||||||
|
* @return the holster's Enumeration value
|
||||||
|
*/
|
||||||
|
private def GetDrawnSlot(obj : Player) : DrawnSlot.Value = {
|
||||||
|
try { DrawnSlot(obj.DrawnSlot) } catch { case _ : Exception => DrawnSlot.None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -209,7 +209,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
implantOffset += entry.bitsize.toInt
|
implantOffset += entry.bitsize.toInt
|
||||||
})
|
})
|
||||||
val resultB : Int = resultA - (implantOffset % 8)
|
val resultB : Int = resultA - (implantOffset % 8)
|
||||||
if(resultB < 0) { 8 - resultB } else { resultB }
|
if(resultB < 0) { 8 + resultB } else { resultB }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -297,8 +297,8 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
(("tutorial_length" | uint32L) >>:~ { len2 =>
|
(("tutorial_length" | uint32L) >>:~ { len2 =>
|
||||||
conditional(len2 > 0, "tutorial_firstEntry" | PacketHelpers.encodedStringAligned(tutPadding(len, len2, implantFieldPadding(implants, CharacterAppearanceData.altModelBit(app))))) ::
|
conditional(len2 > 0, "tutorial_firstEntry" | PacketHelpers.encodedStringAligned(tutPadding(len, len2, implantFieldPadding(implants, CharacterAppearanceData.altModelBit(app))))) ::
|
||||||
("tutorial_list" | PacketHelpers.listOfNSized(len2 - 1, PacketHelpers.encodedString)) ::
|
("tutorial_list" | PacketHelpers.listOfNSized(len2 - 1, PacketHelpers.encodedString)) ::
|
||||||
ignore(207) ::
|
ignore(200) ::
|
||||||
optional(bool, "inventory" | InventoryData.codec_detailed) ::
|
conditional(true, "inventory" | InventoryData.codec_detailed) ::
|
||||||
("drawn_slot" | DrawnSlot.codec) ::
|
("drawn_slot" | DrawnSlot.codec) ::
|
||||||
bool //usually false
|
bool //usually false
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,9 @@ import scodec.codecs._
|
||||||
*/
|
*/
|
||||||
object ImplantType extends Enumeration {
|
object ImplantType extends Enumeration {
|
||||||
type Type = Value
|
type Type = Value
|
||||||
val AdvancedRegen,
|
|
||||||
|
val
|
||||||
|
AdvancedRegen,
|
||||||
Targeting,
|
Targeting,
|
||||||
AudioAmplifier,
|
AudioAmplifier,
|
||||||
DarklightVision,
|
DarklightVision,
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue