too much to itemize; still getting squads working, more or less

This commit is contained in:
FateJH 2019-10-01 21:25:44 -04:00
parent 3e631657b8
commit 2a93e6a8be
10 changed files with 2481 additions and 1491 deletions

View file

@ -48,13 +48,8 @@ class Avatar(private val char_id : Long, val name : String, val faction : Planet
private val deployables : DeployableToolbox = new DeployableToolbox
/**
* Looking For Squad:<br>
* Used to indicate both the marque that appears underneath a player's nameplate and an actual player state<br>
* This `Avatar`-specific "Looking for Squad" variable
* is used to indicate the active state of the LFS marque in the game
* and will change to `false` if the player is the member of a squad.
* A client-local version of "Looking for Squad" will maintain the real state of LFS
* once the player has joined a squad.
* The client-local version will restore the `Avatar`-local variable upon leaving the squad.
* Indicates both a player state and the text on the marquee under the player nameplate.
* Should only be valid when the player is not in a squad.
*/
private var lfs : Boolean = false

View file

@ -11,11 +11,7 @@ class Squad(squadId : PlanetSideGUID, alignment : PlanetSideEmpire.Value) extend
private var zoneId : Option[Int] = None
private var task : String = ""
private val membership : Array[Member] = Array.fill[Member](10)(new Member)
private val availability : Array[Boolean] = Array.fill[Boolean](10)(true)
private var listed : Boolean = false
private var leaderPositionIndex : Int = 0
private var autoApproveInvitationRequests : Boolean = false
private var locationFollowsSquadLead : Boolean = false
private val availability : Array[Boolean] = Array.fill[Boolean](10)(elem = true)
override def GUID_=(d : PlanetSideGUID) : PlanetSideGUID = GUID
@ -23,14 +19,7 @@ class Squad(squadId : PlanetSideGUID, alignment : PlanetSideEmpire.Value) extend
def CustomZoneId : Boolean = zoneId.isDefined
def ZoneId : Int = zoneId.getOrElse({
membership.lift(leaderPositionIndex) match {
case Some(leader) =>
leader.ZoneId
case _ =>
0
}
})
def ZoneId : Int = zoneId.getOrElse(membership(0).ZoneId)
def ZoneId_=(id : Int) : Int = {
ZoneId_=(Some(id))
@ -48,42 +37,12 @@ class Squad(squadId : PlanetSideGUID, alignment : PlanetSideEmpire.Value) extend
Task
}
def Listed : Boolean = listed
def Listed_=(announce : Boolean) : Boolean = {
listed = announce
Listed
}
def LocationFollowsSquadLead : Boolean = locationFollowsSquadLead
def LocationFollowsSquadLead_=(follow : Boolean) : Boolean = {
locationFollowsSquadLead = follow
LocationFollowsSquadLead
}
def AutoApproveInvitationRequests : Boolean = autoApproveInvitationRequests
def AutoApproveInvitationRequests_=(autoApprove : Boolean) : Boolean = {
autoApproveInvitationRequests = autoApprove
AutoApproveInvitationRequests
}
def Membership : Array[Member] = membership
def Availability : Array[Boolean] = availability
def LeaderPositionIndex : Int = leaderPositionIndex
def LeaderPositionIndex_=(position : Int) : Int = {
if(availability.lift(position).contains(true)) {
leaderPositionIndex = position
}
LeaderPositionIndex
}
def Leader : Member = {
membership(leaderPositionIndex) match {
membership(0) match {
case member if !member.Name.equals("") =>
member
case _ =>
@ -102,9 +61,7 @@ object Squad {
override def ZoneId_=(id : Int) : Int = 0
override def ZoneId_=(id : Option[Int]) : Int = 0
override def Task_=(assignment : String) : String = ""
override def Listed_=(announce : Boolean) : Boolean = false
override def Membership : Array[Member] = Array.empty[Member]
override def Availability : Array[Boolean] = Array.fill[Boolean](10)(false)
override def LeaderPositionIndex_=(position : Int) : Int = 0
}
}

View file

@ -0,0 +1,154 @@
// Copyright (c) 2019 PSForever
package net.psforever.objects.teamwork
import akka.actor.{Actor, ActorContext, ActorRef, Cancellable, Props}
import net.psforever.objects.DefaultCancellable
import services.teamwork.SquadService.WaypointData
import services.teamwork.SquadSwitchboard
class SquadFeatures(val Squad : Squad) {
/**
* `initialAssociation` per squad is similar to "Does this squad want to recruit members?"
* The squad does not have to be flagged.
* Dispatches an `AssociateWithSquad` `SDAM` to the squad leader and ???
* and then a `SDDUM` that includes at least the squad owner name and char id.
* Dispatched only once when a squad is first listed
* or when the squad leader searches for recruits by proximity or for certain roles or by invite
* or when a spontaneous squad forms,
* whichever happens first.
* Additionally, the packets are also sent when the check is made when the continent is changed (or set).
*/
private var initialAssociation : Boolean = true
/**
* na
*/
private var switchboard : ActorRef = ActorRef.noSender
/**
* Waypoint data.
* The first four slots are used for squad waypoints.
* The fifth slot is used for the squad leader experience waypoint.<br>
* <br>
* All of the waypoints constantly exist as long as the squad to which they are attached exists.
* They are merely "activated" and "deactivated."
* When "activated," the waypoint knows on which continent to appear and where on the map and in the game world to be positioned.
* Waypoints manifest in the game world as a far-off beam of light that extends into the sky
* and whose ground contact utilizes a downwards pulsating arrow.
* On the continental map and deployment map, they appear as a diamond, with a differentiating number where applicable.
* The squad leader experience rally, for example, does not have a number like the preceding four waypoints.
* @see `Start`
*/
private var waypoints : Array[WaypointData] = Array[WaypointData]()
/**
* The particular position being recruited right at the moment.
* When `None`. no highlighted searches have been indicated.
* When a positive integer or 0, indicates distributed `LookingForSquadRoleInvite` messages as recorded by `proxyInvites`.
* Only one position may bne actively recruited at a time in this case.
* When -1, indicates distributed `ProximityIvite` messages as recorded by `proxyInvites`.
* Previous efforts may or may not be forgotten if there is a switch between the two modes.
*/
private var searchForRole : Option[Int] = None
/**
* Handle persistent data related to `ProximityInvite` and `LookingForSquadRoleInvite` messages
*/
private var proxyInvites : List[Long] = Nil
private var requestInvitePrompt : Cancellable = DefaultCancellable.obj
/**
* These useres rejected invitation to this squad.
* For the purposes of wide-searches for membership
* such as Looking For Squad checks and proximity invitation,
* the unique character identifier numbers in this list are skipped.
* Direct invitation requests from the non sqad member should remain functional.
*/
private var refusedPlayers : List[Long] = Nil
private var autoApproveInvitationRequests : Boolean = true
private var locationFollowsSquadLead : Boolean = true
private var listed : Boolean = false
private lazy val channel : String = s"${Squad.Faction}-Squad${Squad.GUID.guid}"
def Start(implicit context : ActorContext) : SquadFeatures = {
switchboard = context.actorOf(Props[SquadSwitchboard], s"squad${Squad.GUID.guid}")
waypoints = Array.fill[WaypointData](5)(new WaypointData())
this
}
def Stop : SquadFeatures = {
switchboard ! akka.actor.PoisonPill
switchboard = Actor.noSender
waypoints = Array.empty
requestInvitePrompt.cancel
this
}
def InitialAssociation : Boolean = initialAssociation
def InitialAssociation_=(assoc : Boolean) : Boolean = {
initialAssociation = assoc
InitialAssociation
}
def Switchboard : ActorRef = switchboard
def Waypoints : Array[WaypointData] = waypoints
def SearchForRole : Option[Int] = searchForRole
def SearchForRole_=(role : Int) : Option[Int] = SearchForRole_=(Some(role))
def SearchForRole_=(role : Option[Int]) : Option[Int] = {
searchForRole = role
SearchForRole
}
def ProxyInvites : List[Long] = proxyInvites
def ProxyInvites_=(list : List[Long]) : List[Long] = {
proxyInvites = list
ProxyInvites
}
def Refuse : List[Long] = refusedPlayers
def Refuse_=(charId : Long) : List[Long] = {
Refuse_=(List(charId))
}
def Refuse_=(list : List[Long]) : List[Long] = {
refusedPlayers = list ++ refusedPlayers
Refuse
}
def LocationFollowsSquadLead : Boolean = locationFollowsSquadLead
def LocationFollowsSquadLead_=(follow : Boolean) : Boolean = {
locationFollowsSquadLead = follow
LocationFollowsSquadLead
}
def AutoApproveInvitationRequests : Boolean = autoApproveInvitationRequests
def AutoApproveInvitationRequests_=(autoApprove : Boolean) : Boolean = {
autoApproveInvitationRequests = autoApprove
AutoApproveInvitationRequests
}
def Listed : Boolean = listed
def Listed_=(announce : Boolean) : Boolean = {
listed = announce
Listed
}
def ToChannel : String = channel
def Prompt : Cancellable = requestInvitePrompt
def Prompt_=(callback: Cancellable) : Cancellable = {
if(requestInvitePrompt.isCancelled) {
requestInvitePrompt = callback
}
Prompt
}
}

View file

@ -118,7 +118,10 @@ import scodec.codecs._
* `27 - PA_JAMMED - plays jammed buzzing sound`<br>
* `28 - PA_IMPLANT_ACTIVE - Plays implant sounds. Valid values seem to be up to 20.`<br>
* `29 - PA_VAPORIZED - Visible ?! That's not the cloaked effect, Maybe for spectator mode ?. Value is 0 to visible, 1 to invisible.`<br>
* `31 - Info under avatar name : 0 = LFS, 1 = Looking For Squad Members`<br>
* `31 - Looking for Squad info (marquee and ui):<br>
* ` - 0 is LFS`<br>
* ` - 1 is LFSM (Looking for Squad Members)`<br>
* ` - n is the supplemental squad identifier number; same as "LFS;" for the leader, sets "LFSM" after the first manual flagging`<br>
* `32 - Info under avatar name : 0 = Looking For Squad Members, 1 = LFS`<br>
* `35 - BR. Value is the BR`<br>
* `36 - CR. Value is the CR`<br>

View file

@ -360,6 +360,7 @@ object SquadAction{
* &nbsp;&nbsp;&nbsp;&nbsp;`17` - Set List Squad (ui)<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`18` - UNKNOWN<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`26` - Reset All<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`32` - UNKNOWN<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`35` - Cancel Squad Search<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`39` - No Squad Search Results<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`41` - Cancel Find<br>

View file

@ -3,11 +3,14 @@ package services.teamwork
import net.psforever.objects.zones.Zone
import net.psforever.packet.game._
import net.psforever.types.{SquadRequestType, Vector3}
import net.psforever.types.{PlanetSideEmpire, SquadRequestType, Vector3}
object SquadAction {
trait Action
final case class InitSquadList() extends Action
final case class InitCharId() extends Action
final case class Definition(guid : PlanetSideGUID, line : Int, action : SquadAction) extends Action
final case class Membership(request_type : SquadRequestType.Value, unk2 : Long, unk3 : Option[Long], player_name : String, unk5 : Option[Option[String]]) extends Action
final case class Waypoint(event_type : WaypointEventAction.Value, waypoint_type : Int, unk : Option[Long], waypoint_info : Option[WaypointInfo]) extends Action

View file

@ -20,8 +20,8 @@ object SquadResponse {
final case class Membership(request_type : SquadResponseType.Value, unk1 : Int, unk2 : Int, unk3 : Long, unk4 : Option[Long], player_name : String, unk5 : Boolean, unk6 : Option[Option[String]]) extends Response //see SquadMembershipResponse
final case class Invite(from_char_id : Long, to_char_id : Long, name : String) extends Response
final case class WantsSquadPosition(bid_name : String) extends Response
final case class Join(squad : Squad, positionsToUpdate : List[Int]) extends Response
final case class WantsSquadPosition(leader_char_id : Long, bid_name : String) extends Response
final case class Join(squad : Squad, positionsToUpdate : List[Int], channel : String) extends Response
final case class Leave(squad : Squad, positionsToUpdate : List[(Long, Int)]) extends Response
final case class UpdateMembers(squad : Squad, update_info : List[SquadAction.Update]) extends Response
final case class AssignMember(squad : Squad, from_index : Int, to_index : Int) extends Response

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,14 @@
// Copyright (c) 2019 PSForever
package services.teamwork
import net.psforever.packet.game.SquadInfo
import services.GenericEventBusMsg
final case class SquadServiceResponse(toChannel : String, response : SquadResponse.Response) extends GenericEventBusMsg
final case class SquadServiceResponse(toChannel : String, exclude : Iterable[Long], response : SquadResponse.Response) extends GenericEventBusMsg
object SquadServiceResponse {
def apply(toChannel : String, response : SquadResponse.Response) : SquadServiceResponse =
SquadServiceResponse(toChannel, Nil, response)
def apply(toChannel : String, exclude : Long, response : SquadResponse.Response) : SquadServiceResponse =
SquadServiceResponse(toChannel, Seq(exclude), response)
}