mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-01-19 18:14:44 +00:00
retooled invitation case classes into much more complicated invitation entities that manage their own behaviors for messaging invites, acceptances, rejection, and generalize queries; this removes a ton of match casting as a branch mechanic
This commit is contained in:
parent
2372a95040
commit
1968377d05
File diff suppressed because it is too large
Load diff
|
|
@ -1,25 +1,23 @@
|
|||
// Copyright (c) 2019-2022 PSForever
|
||||
// Copyright (c) 2019-2024 PSForever
|
||||
package net.psforever.services.teamwork
|
||||
|
||||
import akka.actor.{Actor, ActorRef, Terminated}
|
||||
import net.psforever.actors.session.SessionActor
|
||||
import net.psforever.packet.game.ChatMsg
|
||||
import net.psforever.types.ChatMessageType
|
||||
|
||||
import java.io.{PrintWriter, StringWriter}
|
||||
import scala.annotation.unused
|
||||
import scala.collection.concurrent.TrieMap
|
||||
import scala.collection.mutable
|
||||
//
|
||||
import net.psforever.actors.session.SessionActor
|
||||
import net.psforever.objects.{LivePlayerList, Player}
|
||||
import net.psforever.objects.teamwork.{Member, Squad, SquadFeatures}
|
||||
import net.psforever.objects.avatar.{Avatar, Certification}
|
||||
import net.psforever.objects.definition.converter.StatConverter
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game.ChatMsg
|
||||
import net.psforever.packet.game.SquadAction._
|
||||
import net.psforever.packet.game.{PlanetSideZoneID, SquadDetail, SquadInfo, SquadPositionDetail, SquadPositionEntry, SquadAction => SquadRequestAction}
|
||||
import net.psforever.services.Service
|
||||
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, SquadRequestType, SquadResponseType}
|
||||
import net.psforever.types.{ChatMessageType, PlanetSideEmpire, PlanetSideGUID, SquadRequestType, SquadResponseType}
|
||||
|
||||
class SquadService extends Actor {
|
||||
import SquadService._
|
||||
|
|
@ -75,8 +73,6 @@ class SquadService extends Actor {
|
|||
|
||||
private def info(msg: String): Unit = log.info(msg)
|
||||
|
||||
private def debug(msg: String): Unit = log.debug(msg)
|
||||
|
||||
override def postStop(): Unit = {
|
||||
//squads and members (users)
|
||||
squadFeatures.foreach {
|
||||
|
|
@ -143,13 +139,11 @@ class SquadService extends Actor {
|
|||
* @param charId the potential member identifier
|
||||
* @return the discovered squad, or `None`
|
||||
*/
|
||||
def GetParticipatingSquad(charId: Long): Option[SquadFeatures] =
|
||||
memberToSquad.get(charId) match {
|
||||
case Some(id) =>
|
||||
squadFeatures.get(id)
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
def GetParticipatingSquad(charId: Long): Option[SquadFeatures] = {
|
||||
memberToSquad
|
||||
.get(charId)
|
||||
.flatMap(GetSquad)
|
||||
}
|
||||
|
||||
/**
|
||||
* If this player is a member of any squad, discover that squad.
|
||||
|
|
@ -171,28 +165,25 @@ class SquadService extends Actor {
|
|||
* the expectation is that the provided squad is a known participating squad
|
||||
* @return the discovered squad, or `None`
|
||||
*/
|
||||
def GetLeadingSquad(charId: Long, opt: Option[SquadFeatures]): Option[SquadFeatures] =
|
||||
opt.orElse(GetParticipatingSquad(charId)) match {
|
||||
case Some(features) =>
|
||||
if (features.Squad.Leader.CharId == charId) {
|
||||
Some(features)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
case _ =>
|
||||
None
|
||||
}
|
||||
def GetLeadingSquad(charId: Long, opt: Option[SquadFeatures]): Option[SquadFeatures] = {
|
||||
opt
|
||||
.orElse(GetParticipatingSquad(charId))
|
||||
.collect {
|
||||
case features if features.Squad.Leader.CharId == charId =>
|
||||
features
|
||||
}
|
||||
}
|
||||
|
||||
def receive: Receive = {
|
||||
//subscribe to a faction's channel - necessary to receive updates about listed squads
|
||||
case Service.Join(faction) if "TRNCVS".indexOf(faction) > -1 =>
|
||||
case Service.Join(faction) if SquadService.FactionWordSalad.indexOf(faction) > -1 =>
|
||||
JoinByFaction(faction, sender())
|
||||
|
||||
//subscribe to the player's personal channel - necessary for future and previous squad information
|
||||
case Service.Join(char_id) =>
|
||||
JoinByCharacterId(char_id, sender())
|
||||
|
||||
case Service.Leave(Some(faction)) if "TRNCVS".indexOf(faction) > -1 =>
|
||||
case Service.Leave(Some(faction)) if SquadService.FactionWordSalad.indexOf(faction) > -1 =>
|
||||
LeaveByFaction(faction, sender())
|
||||
|
||||
case Service.Leave(Some(char_id)) =>
|
||||
|
|
@ -244,7 +235,7 @@ class SquadService extends Actor {
|
|||
UpdateSquadListWhenListed(features, changes)
|
||||
|
||||
case SquadService.ResendActiveInvite(charId) =>
|
||||
invitations.resendActiveInvite(charId)
|
||||
invitations.reloadActiveInvite(charId)
|
||||
|
||||
case SquadService.ListAllCurrentInvites(charId) =>
|
||||
ListCurrentInvitations(charId)
|
||||
|
|
@ -259,6 +250,121 @@ class SquadService extends Actor {
|
|||
log.warn(s"Unhandled message $msg from ${sender()}")
|
||||
}
|
||||
|
||||
def SquadActionMembership(tplayer: Player, zone: Zone, action: Any): Unit = {
|
||||
action match {
|
||||
case SquadAction.Membership(SquadRequestType.Invite, invitingPlayer, Some(_invitedPlayer), invitedName, _) =>
|
||||
SquadActionMembershipInvite(tplayer, invitingPlayer, _invitedPlayer, invitedName)
|
||||
|
||||
case SquadAction.Membership(SquadRequestType.ProximityInvite, invitingPlayer, _, _, _) =>
|
||||
SquadActionMembershipProximityInvite(zone, invitingPlayer)
|
||||
|
||||
case SquadAction.Membership(SquadRequestType.Accept, invitedPlayer, _, _, _) =>
|
||||
SquadActionMembershipAccept(tplayer, invitedPlayer)
|
||||
|
||||
case SquadAction.Membership(SquadRequestType.Leave, actingPlayer, _leavingPlayer, name, _) =>
|
||||
SquadActionMembershipLeave(tplayer, actingPlayer, _leavingPlayer, name)
|
||||
|
||||
case SquadAction.Membership(SquadRequestType.Reject, rejectingPlayer, _, _, _) =>
|
||||
SquadActionMembershipReject(tplayer, rejectingPlayer)
|
||||
|
||||
case SquadAction.Membership(SquadRequestType.Disband, char_id, _, _, _) =>
|
||||
SquadActionMembershipDisband(char_id)
|
||||
|
||||
case SquadAction.Membership(SquadRequestType.Cancel, cancellingPlayer, _, _, _) =>
|
||||
SquadActionMembershipCancel(cancellingPlayer)
|
||||
|
||||
case SquadAction.Membership(SquadRequestType.Promote, _, _, _, _) => ()
|
||||
// case SquadAction.Membership(SquadRequestType.Promote, promotingPlayer, Some(_promotedPlayer), promotedName, _) =>
|
||||
// SquadActionMembershipPromote(promotingPlayer, _promotedPlayer, promotedName, SquadServiceMessage(tplayer, zone, action), sender())
|
||||
|
||||
case SquadAction.Membership(event, _, _, _, _) =>
|
||||
info(s"SquadAction.Membership: $event is not yet supported")
|
||||
|
||||
case msg =>
|
||||
log.warn(s"Unhandled message $msg from ${sender()}")
|
||||
}
|
||||
}
|
||||
|
||||
def SquadActionDefinition(
|
||||
message: SquadServiceMessage,
|
||||
action: SquadRequestAction,
|
||||
guid: PlanetSideGUID
|
||||
): Unit = {
|
||||
val tplayer = message.tplayer
|
||||
(action match {
|
||||
//the following actions only perform an action upon the squad
|
||||
case _: ChangeSquadPurpose => GetOrCreateSquadOnlyIfLeader(tplayer)
|
||||
case _: ChangeSquadZone => GetOrCreateSquadOnlyIfLeader(tplayer)
|
||||
case _: AddSquadMemberPosition => GetOrCreateSquadOnlyIfLeader(tplayer)
|
||||
case _: ChangeSquadMemberRequirementsRole => GetOrCreateSquadOnlyIfLeader(tplayer)
|
||||
case _: ChangeSquadMemberRequirementsDetailedOrders => GetOrCreateSquadOnlyIfLeader(tplayer)
|
||||
case _: ChangeSquadMemberRequirementsCertifications => GetOrCreateSquadOnlyIfLeader(tplayer)
|
||||
case _: LocationFollowsSquadLead => GetOrCreateSquadOnlyIfLeader(tplayer)
|
||||
case _: RequestListSquad => GetOrCreateSquadOnlyIfLeader(tplayer)
|
||||
case _: StopListSquad => GetLeadingSquad(tplayer, None)
|
||||
//the following actions cause changes with the squad composition or with invitations
|
||||
case AutoApproveInvitationRequests(_) =>
|
||||
GetOrCreateSquadOnlyIfLeader(tplayer)
|
||||
.foreach(features => invitations.autoApproveInvitationRequests(tplayer.CharId, features))
|
||||
None
|
||||
case CloseSquadMemberPosition(position) =>
|
||||
GetOrCreateSquadOnlyIfLeader(tplayer)
|
||||
.collect {
|
||||
case features if features.Squad.Membership(position).CharId > 0 =>
|
||||
LeaveSquad(features.Squad.Membership(position).CharId, features)
|
||||
features
|
||||
}
|
||||
case FindLfsSoldiersForRole(position) =>
|
||||
GetLeadingSquad(tplayer, None)
|
||||
.foreach(features => invitations.findLfsSoldiersForRole(tplayer, features, position))
|
||||
None
|
||||
case CancelFind() =>
|
||||
GetLeadingSquad(tplayer, None)
|
||||
.foreach(features => invitations.cancelFind(Some(features)))
|
||||
None
|
||||
case SelectRoleForYourself(position) =>
|
||||
GetParticipatingSquad(tplayer) match {
|
||||
case out @ Some(features) =>
|
||||
if (features.Squad.GUID == guid) {
|
||||
out
|
||||
} else {
|
||||
//this isn't the squad we're looking for by GUID; as a precaution, reload all of the published squad list
|
||||
val faction = tplayer.Faction
|
||||
subs.Publish(faction, SquadResponse.InitList(PublishedLists(tplayer.Faction)))
|
||||
None
|
||||
}
|
||||
case _ =>
|
||||
GetSquad(guid)
|
||||
.foreach(features => invitations.selectRoleForYourselfAsInvite(tplayer, features, position))
|
||||
None
|
||||
}
|
||||
case _: CancelSelectRoleForYourself =>
|
||||
GetSquad(guid)
|
||||
.foreach(features => invitations.cancelSelectRoleForYourself(tplayer, features))
|
||||
None
|
||||
case search: SearchForSquadsWithParticularRole =>
|
||||
SquadActionDefinitionSearchForSquadsWithParticularRole(tplayer, search)
|
||||
None
|
||||
case _: CancelSquadSearch =>
|
||||
SquadActionDefinitionCancelSquadSearch(tplayer.CharId)
|
||||
None
|
||||
case _: DisplaySquad =>
|
||||
GetSquad(guid) match {
|
||||
case out @ Some(_) =>
|
||||
SquadActionDefinitionDisplaySquad(tplayer, guid)
|
||||
out
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
case _: SquadInitializationIssue =>
|
||||
SquadActionDefinitionSquadInitializationIssue(tplayer, guid)
|
||||
None
|
||||
case _ =>
|
||||
GetSquad(guid)
|
||||
})
|
||||
.foreach(features => features.Switchboard.tell(message, sender()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to a faction-wide channel.
|
||||
* @param faction sub-channel name
|
||||
|
|
@ -337,23 +443,17 @@ class SquadService extends Actor {
|
|||
*/
|
||||
def LeaveInGeneral(sender: ActorRef): Unit = {
|
||||
context.unwatch(sender)
|
||||
subs.UserEvents.find {
|
||||
case (_, subscription) => (subscription eq sender) || subscription.path.equals(sender.path)
|
||||
} match {
|
||||
case Some((to, _)) =>
|
||||
LeaveService(to, sender)
|
||||
case _ => ()
|
||||
}
|
||||
subs
|
||||
.UserEvents
|
||||
.find { case (_, subscription) => (subscription eq sender) || subscription.path.equals(sender.path) }
|
||||
.foreach { case (to, _) => LeaveService(to, sender) }
|
||||
}
|
||||
|
||||
def performStartSquad(sender: ActorRef, player: Player): Unit = {
|
||||
def performStartSquad(sender: ActorRef, player: Player): Option[SquadFeatures] = {
|
||||
val invitingPlayerCharId = player.CharId
|
||||
if (EnsureEmptySquad(invitingPlayerCharId)) {
|
||||
GetParticipatingSquad(player) match {
|
||||
case Some(participating) =>
|
||||
//invitingPlayer became part of a squad while invited player was answering the original summons
|
||||
Some(participating)
|
||||
case _ =>
|
||||
GetParticipatingSquad(player)
|
||||
.orElse {
|
||||
//generate a new squad, with invitingPlayer as the leader
|
||||
val features = StartSquad(player)
|
||||
val squad = features.Squad
|
||||
|
|
@ -361,7 +461,9 @@ class SquadService extends Actor {
|
|||
subs.Publish(invitingPlayerCharId, SquadResponse.IdentifyAsSquadLeader(squad.GUID))
|
||||
sender.tell(SquadInvitationManager.FinishStartSquad(features), self)
|
||||
Some(features)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -381,52 +483,14 @@ class SquadService extends Actor {
|
|||
|
||||
def SquadActionInitCharId(tplayer: Player): Unit = {
|
||||
val charId = tplayer.CharId
|
||||
GetParticipatingSquad(charId) match {
|
||||
case None => ()
|
||||
case Some(features) =>
|
||||
features.Switchboard ! SquadSwitchboard.Join(tplayer, 0, sender())
|
||||
}
|
||||
GetParticipatingSquad(charId)
|
||||
.foreach(features => features.Switchboard.tell(SquadSwitchboard.Join(tplayer, 0, sender()), self))
|
||||
}
|
||||
|
||||
def SquadServiceReloadSquadDecoration(faction: PlanetSideEmpire.Value, to: Long): Unit = {
|
||||
ApplySquadDecorationToEntriesForUser(faction, to)
|
||||
}
|
||||
|
||||
def SquadActionMembership(tplayer: Player, zone: Zone, action: Any): Unit = {
|
||||
action match {
|
||||
case SquadAction.Membership(SquadRequestType.Invite, invitingPlayer, Some(_invitedPlayer), invitedName, _) =>
|
||||
SquadActionMembershipInvite(tplayer, invitingPlayer, _invitedPlayer, invitedName)
|
||||
|
||||
case SquadAction.Membership(SquadRequestType.ProximityInvite, invitingPlayer, _, _, _) =>
|
||||
SquadActionMembershipProximityInvite(zone, invitingPlayer)
|
||||
|
||||
case SquadAction.Membership(SquadRequestType.Accept, invitedPlayer, _, _, _) =>
|
||||
SquadActionMembershipAccept(tplayer, invitedPlayer)
|
||||
|
||||
case SquadAction.Membership(SquadRequestType.Leave, actingPlayer, _leavingPlayer, name, _) =>
|
||||
SquadActionMembershipLeave(tplayer, actingPlayer, _leavingPlayer, name)
|
||||
|
||||
case SquadAction.Membership(SquadRequestType.Reject, rejectingPlayer, _, _, _) =>
|
||||
SquadActionMembershipReject(tplayer, rejectingPlayer)
|
||||
|
||||
case SquadAction.Membership(SquadRequestType.Disband, char_id, _, _, _) =>
|
||||
SquadActionMembershipDisband(char_id)
|
||||
|
||||
case SquadAction.Membership(SquadRequestType.Cancel, cancellingPlayer, _, _, _) =>
|
||||
SquadActionMembershipCancel(cancellingPlayer)
|
||||
|
||||
case SquadAction.Membership(SquadRequestType.Promote, _, _, _, _) =>
|
||||
()
|
||||
// case SquadAction.Membership(SquadRequestType.Promote, promotingPlayer, Some(_promotedPlayer), promotedName, _) =>
|
||||
// SquadActionMembershipPromote(promotingPlayer, _promotedPlayer, promotedName, SquadServiceMessage(tplayer, zone, action), sender())
|
||||
|
||||
case SquadAction.Membership(event, _, _, _, _) =>
|
||||
debug(s"SquadAction.Membership: $event is not yet supported")
|
||||
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
|
||||
def SquadActionMembershipInvite(
|
||||
tplayer: Player,
|
||||
invitingPlayer: Long,
|
||||
|
|
@ -445,59 +509,57 @@ class SquadService extends Actor {
|
|||
})
|
||||
.headOption
|
||||
.collectFirst {
|
||||
//important: squads must know about the person too
|
||||
//important: squads must know about the person too
|
||||
a => subs.UserEvents.keys.find(_ == a.id)
|
||||
}.flatten match {
|
||||
case Some(invitedPlayer) if invitingPlayer != invitedPlayer =>
|
||||
(GetParticipatingSquad(invitingPlayer), GetParticipatingSquad(invitedPlayer)) match {
|
||||
case (Some(features1), Some(features2))
|
||||
if features1.Squad.GUID == features2.Squad.GUID =>
|
||||
//both players are in the same squad; no need to do anything
|
||||
}
|
||||
.flatten
|
||||
.collect {
|
||||
case invitedPlayer if invitingPlayer != invitedPlayer =>
|
||||
(GetParticipatingSquad(invitingPlayer), GetParticipatingSquad(invitedPlayer)) match {
|
||||
case (Some(features1), Some(features2))
|
||||
if features1.Squad.GUID == features2.Squad.GUID =>
|
||||
//both players are in the same squad; no need to do anything
|
||||
|
||||
case (Some(invitersFeatures), Some(invitedFeatures)) if {
|
||||
val squad1 = invitersFeatures.Squad
|
||||
val squad2 = invitedFeatures.Squad
|
||||
squad1.Leader.CharId == invitingPlayer && squad2.Leader.CharId == invitedPlayer &&
|
||||
squad1.Size > 1 && squad2.Size > 1 } =>
|
||||
//we might do some platoon chicanery with this case later
|
||||
//TODO platoons
|
||||
case (Some(invitersFeatures), Some(invitedFeatures)) if {
|
||||
val squad1 = invitersFeatures.Squad
|
||||
val squad2 = invitedFeatures.Squad
|
||||
squad1.Leader.CharId == invitingPlayer && squad2.Leader.CharId == invitedPlayer &&
|
||||
squad1.Size > 1 && squad2.Size > 1 } =>
|
||||
//we might do some platoon chicanery with this case later
|
||||
//TODO platoons
|
||||
|
||||
case (Some(invitersFeatures), Some(invitedFeatures))
|
||||
if invitedFeatures.Squad.Size == 1 =>
|
||||
//both players belong to squads, but the invitedPlayer's squad (invitedFeatures) is underutilized
|
||||
//treat the same as "the classic situation" using invitersFeatures
|
||||
invitations.createVacancyInvite(tplayer, invitedPlayer, invitersFeatures)
|
||||
case (Some(invitersFeatures), Some(invitedFeatures))
|
||||
if invitedFeatures.Squad.Size == 1 =>
|
||||
//both players belong to squads, but the invitedPlayer's squad (invitedFeatures) is underutilized
|
||||
//treat the same as "the classic situation" using invitersFeatures
|
||||
invitations.createInvitationToJoinSquad(tplayer, invitedPlayer, invitersFeatures)
|
||||
|
||||
case (Some(invitersFeatures), Some(invitedFeatures))
|
||||
if invitersFeatures.Squad.Size == 1 =>
|
||||
//both players belong to squads, but the invitingPlayer's squad is underutilized by comparison
|
||||
//treat the same as "indirection ..." using squad2
|
||||
invitations.createIndirectInvite(tplayer, invitedPlayer, invitedFeatures)
|
||||
case (Some(invitersFeatures), Some(invitedFeatures))
|
||||
if invitersFeatures.Squad.Size == 1 =>
|
||||
//both players belong to squads, but the invitingPlayer's squad is underutilized by comparison
|
||||
//treat the same as "indirection ..." using squad2
|
||||
invitations.createIndirectInvite(tplayer, invitedPlayer, invitedFeatures)
|
||||
|
||||
case (Some(features), None) =>
|
||||
//the classic situation
|
||||
invitations.createVacancyInvite(tplayer, invitedPlayer, features)
|
||||
case (Some(features), None) =>
|
||||
//the classic situation
|
||||
invitations.createInvitationToJoinSquad(tplayer, invitedPlayer, features)
|
||||
|
||||
case (None, Some(features)) =>
|
||||
//indirection; we're trying to invite ourselves to someone else's squad
|
||||
invitations.createIndirectInvite(tplayer, invitedPlayer, features)
|
||||
case (None, Some(features)) =>
|
||||
//indirection; we're trying to invite ourselves to someone else's squad
|
||||
invitations.createIndirectInvite(tplayer, invitedPlayer, features)
|
||||
|
||||
case (None, None) =>
|
||||
//neither the invited player nor the inviting player belong to any squad
|
||||
invitations.createSpontaneousInvite(tplayer, invitedPlayer)
|
||||
case (None, None) =>
|
||||
//neither the invited player nor the inviting player belong to any squad
|
||||
invitations.createInvitationToCreateASquad(tplayer, invitedPlayer)
|
||||
|
||||
case _ => ()
|
||||
}
|
||||
case _ => ()
|
||||
}
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def SquadActionMembershipProximityInvite(zone: Zone, invitingPlayer: Long): Unit = {
|
||||
GetLeadingSquad(invitingPlayer, None) match {
|
||||
case Some(features) =>
|
||||
invitations.handleProximityInvite(zone, invitingPlayer, features)
|
||||
case _ => ()
|
||||
}
|
||||
GetLeadingSquad(invitingPlayer, None)
|
||||
.foreach(features => invitations.createProximityInvite(zone, invitingPlayer, features))
|
||||
}
|
||||
|
||||
def SquadActionMembershipAccept(tplayer: Player, invitedPlayer: Long): Unit = {
|
||||
|
|
@ -505,8 +567,8 @@ class SquadService extends Actor {
|
|||
}
|
||||
|
||||
def SquadActionMembershipLeave(tplayer: Player, actingPlayer: Long, _leavingPlayer: Option[Long], name: String): Unit = {
|
||||
GetParticipatingSquad(actingPlayer) match {
|
||||
case Some(features) =>
|
||||
GetParticipatingSquad(actingPlayer)
|
||||
.foreach { features =>
|
||||
val squad = features.Squad
|
||||
val leader = squad.Leader.CharId
|
||||
(if (name.nonEmpty) {
|
||||
|
|
@ -523,58 +585,37 @@ class SquadService extends Actor {
|
|||
case Some(id) => subs.UserEvents.keys.find(_ == id)
|
||||
case None => None
|
||||
}
|
||||
}) match {
|
||||
case _ @ Some(leavingPlayer)
|
||||
if GetParticipatingSquad(leavingPlayer).contains(features) => //kicked player must be in the same squad
|
||||
if (actingPlayer == leader) {
|
||||
if (leavingPlayer == leader || squad.Size == 2) {
|
||||
//squad leader is leaving his own squad, so it will be disbanded
|
||||
//OR squad is only composed of two people, so it will be closed-out when one of them leaves
|
||||
DisbandSquad(features)
|
||||
} else {
|
||||
//kicked by the squad leader
|
||||
subs.Publish(
|
||||
leavingPlayer,
|
||||
SquadResponse.Membership(
|
||||
SquadResponseType.Leave,
|
||||
0,
|
||||
0,
|
||||
leavingPlayer,
|
||||
Some(leader),
|
||||
tplayer.Name,
|
||||
unk5=false,
|
||||
Some(None)
|
||||
)
|
||||
)
|
||||
subs.Publish(
|
||||
leader,
|
||||
SquadResponse.Membership(
|
||||
SquadResponseType.Leave,
|
||||
0,
|
||||
0,
|
||||
leader,
|
||||
Some(leavingPlayer),
|
||||
"",
|
||||
unk5=true,
|
||||
Some(None)
|
||||
)
|
||||
)
|
||||
LeaveSquad(leavingPlayer, features)
|
||||
}
|
||||
} else if (leavingPlayer == actingPlayer) {
|
||||
if (squad.Size == 2) {
|
||||
//squad is only composed of two people, so it will be closed-out when one of them leaves
|
||||
DisbandSquad(features)
|
||||
} else {
|
||||
//leaving the squad of own accord
|
||||
LeaveSquad(actingPlayer, features)
|
||||
}
|
||||
})
|
||||
.collect { case leavingPlayer
|
||||
if GetParticipatingSquad(leavingPlayer).contains(features) => //kicked player must be in the same squad
|
||||
if (actingPlayer == leader) {
|
||||
if (leavingPlayer == leader || squad.Size == 2) {
|
||||
//squad leader is leaving his own squad, so it will be disbanded
|
||||
//OR squad is only composed of two people, so it will be closed-out when one of them leaves
|
||||
DisbandSquad(features)
|
||||
} else {
|
||||
//kicked by the squad leader
|
||||
subs.Publish(
|
||||
leavingPlayer,
|
||||
SquadResponse.Membership(SquadResponseType.Leave, leavingPlayer, Some(leader), tplayer.Name, unk5 = false)
|
||||
)
|
||||
subs.Publish(
|
||||
leader,
|
||||
SquadResponse.Membership( SquadResponseType.Leave, leader, Some(leavingPlayer), "", unk5 = true)
|
||||
)
|
||||
LeaveSquad(leavingPlayer, features)
|
||||
}
|
||||
|
||||
case _ => ()
|
||||
} else if (leavingPlayer == actingPlayer) {
|
||||
if (squad.Size == 2) {
|
||||
//squad is only composed of two people, so it will be closed-out when one of them leaves
|
||||
DisbandSquad(features)
|
||||
} else {
|
||||
//leaving the squad of own accord
|
||||
LeaveSquad(actingPlayer, features)
|
||||
}
|
||||
}
|
||||
}
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def SquadActionMembershipReject(tplayer: Player, rejectingPlayer: Long): Unit = {
|
||||
|
|
@ -586,11 +627,8 @@ class SquadService extends Actor {
|
|||
}
|
||||
|
||||
def SquadActionMembershipDisband(charId: Long): Unit = {
|
||||
GetLeadingSquad(charId, None) match {
|
||||
case Some(features) =>
|
||||
DisbandSquad(features)
|
||||
case None => ()
|
||||
}
|
||||
GetLeadingSquad(charId, None)
|
||||
.foreach(features => DisbandSquad(features))
|
||||
}
|
||||
|
||||
def SquadActionMembershipCancel(cancellingPlayer: Long): Unit = {
|
||||
|
|
@ -605,17 +643,17 @@ class SquadService extends Actor {
|
|||
msg: SquadServiceMessage,
|
||||
ref: ActorRef
|
||||
): Unit = {
|
||||
val promotedPlayer: Long = subs.UserEvents.keys.find(_ == promotionCandidatePlayer).orElse({
|
||||
LivePlayerList
|
||||
.WorldPopulation({ case (_, a: Avatar) => a.name.equalsIgnoreCase(promotionCandidateName) })
|
||||
.headOption match {
|
||||
case Some(a) => Some(a.id)
|
||||
case None => None
|
||||
val promotedPlayer: Long = subs
|
||||
.UserEvents
|
||||
.keys
|
||||
.find(_ == promotionCandidatePlayer)
|
||||
.orElse {
|
||||
LivePlayerList
|
||||
.WorldPopulation({ case (_, a: Avatar) => a.name.equalsIgnoreCase(promotionCandidateName) })
|
||||
.headOption
|
||||
.map(_.id.toLong)
|
||||
}
|
||||
}) match {
|
||||
case Some(player: Long) => player
|
||||
case _ => -1L
|
||||
}
|
||||
.getOrElse(-1L)
|
||||
//sponsorPlayer should be squad leader
|
||||
(GetLeadingSquad(sponsoringPlayer, None), GetParticipatingSquad(promotedPlayer)) match {
|
||||
case (Some(features), Some(features2)) if features.Squad.GUID == features2.Squad.GUID =>
|
||||
|
|
@ -639,113 +677,15 @@ class SquadService extends Actor {
|
|||
message: SquadServiceMessage,
|
||||
tplayer: Player
|
||||
): Unit = {
|
||||
GetParticipatingSquad(tplayer) match {
|
||||
case Some(features) =>
|
||||
GetParticipatingSquad(tplayer)
|
||||
.collect { features =>
|
||||
features.Switchboard.tell(message, sender())
|
||||
case None =>
|
||||
features
|
||||
}
|
||||
.orElse {
|
||||
log.warn(s"Unsupported squad waypoint behavior: $message")
|
||||
}
|
||||
}
|
||||
|
||||
def SquadActionDefinition(
|
||||
message: SquadServiceMessage,
|
||||
action: SquadRequestAction,
|
||||
guid: PlanetSideGUID
|
||||
): Unit = {
|
||||
val tplayer = message.tplayer
|
||||
(action match {
|
||||
//the following actions only perform an action upon the squad
|
||||
case _: ChangeSquadPurpose => GetOrCreateSquadOnlyIfLeader(tplayer)
|
||||
case _: ChangeSquadZone => GetOrCreateSquadOnlyIfLeader(tplayer)
|
||||
case _: AddSquadMemberPosition => GetOrCreateSquadOnlyIfLeader(tplayer)
|
||||
case _: ChangeSquadMemberRequirementsRole => GetOrCreateSquadOnlyIfLeader(tplayer)
|
||||
case _: ChangeSquadMemberRequirementsDetailedOrders => GetOrCreateSquadOnlyIfLeader(tplayer)
|
||||
case _: ChangeSquadMemberRequirementsCertifications => GetOrCreateSquadOnlyIfLeader(tplayer)
|
||||
case _: LocationFollowsSquadLead => GetOrCreateSquadOnlyIfLeader(tplayer)
|
||||
case _: RequestListSquad => GetOrCreateSquadOnlyIfLeader(tplayer)
|
||||
case _: StopListSquad => GetLeadingSquad(tplayer, None)
|
||||
//the following actions cause changes with the squad composition or with invitations
|
||||
case AutoApproveInvitationRequests(_) =>
|
||||
GetOrCreateSquadOnlyIfLeader(tplayer) match {
|
||||
case out @ Some(features) =>
|
||||
invitations.handleDefinitionAction(tplayer, action, features)
|
||||
out
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
case CloseSquadMemberPosition(position) =>
|
||||
GetOrCreateSquadOnlyIfLeader(tplayer) match {
|
||||
case out @ Some(features)
|
||||
if features.Squad.Membership(position).CharId > 0 =>
|
||||
val squad = features.Squad
|
||||
LeaveSquad(squad.Membership(position).CharId, features)
|
||||
out
|
||||
case _ =>
|
||||
None
|
||||
}
|
||||
case FindLfsSoldiersForRole(_) =>
|
||||
GetLeadingSquad(tplayer, None) match {
|
||||
case Some(features) =>
|
||||
invitations.handleDefinitionAction(tplayer, action, features)
|
||||
case _ => ()
|
||||
}
|
||||
None
|
||||
case CancelFind() =>
|
||||
GetLeadingSquad(tplayer, None) match {
|
||||
case Some(features) =>
|
||||
invitations.handleDefinitionAction(tplayer, action, features)
|
||||
case _ => ()
|
||||
}
|
||||
None
|
||||
case SelectRoleForYourself(_) =>
|
||||
GetParticipatingSquad(tplayer) match {
|
||||
case out @ Some(features) =>
|
||||
if (features.Squad.GUID == guid) {
|
||||
out
|
||||
} else {
|
||||
//this isn't the squad we're looking for by GUID; as a precaution, reload all of the published squad list
|
||||
val faction = tplayer.Faction
|
||||
subs.Publish(faction, SquadResponse.InitList(PublishedLists(tplayer.Faction)))
|
||||
None
|
||||
}
|
||||
case _ =>
|
||||
GetSquad(guid) match {
|
||||
case Some(features) =>
|
||||
invitations.handleDefinitionAction(tplayer, action, features)
|
||||
case _ => ()
|
||||
}
|
||||
None
|
||||
}
|
||||
case _: CancelSelectRoleForYourself =>
|
||||
GetSquad(guid) match {
|
||||
case Some(features) =>
|
||||
invitations.handleDefinitionAction(tplayer, action, features)
|
||||
case _ => ()
|
||||
}
|
||||
None
|
||||
case _/*search*/: SearchForSquadsWithParticularRole =>
|
||||
// SquadActionDefinitionSearchForSquadsWithParticularRole(tplayer, search)
|
||||
None
|
||||
case _: CancelSquadSearch =>
|
||||
// SquadActionDefinitionCancelSquadSearch(tplayer.CharId)
|
||||
None
|
||||
case _: DisplaySquad =>
|
||||
GetSquad(guid) match {
|
||||
case out @ Some(_) =>
|
||||
SquadActionDefinitionDisplaySquad(tplayer, guid)
|
||||
out
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
case _: SquadInitializationIssue =>
|
||||
SquadActionDefinitionSquadInitializationIssue(tplayer, guid)
|
||||
None
|
||||
case _ =>
|
||||
GetSquad(guid)
|
||||
}) match {
|
||||
case Some(features) => features.Switchboard.tell(message, sender())
|
||||
case None => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def SquadActionUpdate(
|
||||
|
|
@ -753,10 +693,8 @@ class SquadService extends Actor {
|
|||
char_id: Long,
|
||||
replyTo: ActorRef,
|
||||
): Unit = {
|
||||
GetParticipatingSquad(char_id) match {
|
||||
case Some(features) => features.Switchboard.tell(message, replyTo)
|
||||
case None => ()
|
||||
}
|
||||
GetParticipatingSquad(char_id)
|
||||
.foreach(features => features.Switchboard.tell(message, replyTo))
|
||||
}
|
||||
|
||||
def GetOrCreateSquadOnlyIfLeader(player: Player): Option[SquadFeatures] = {
|
||||
|
|
@ -776,14 +714,15 @@ class SquadService extends Actor {
|
|||
criteria: SearchForSquadsWithParticularRole
|
||||
): Unit = {
|
||||
val charId = tplayer.CharId
|
||||
searchData.get(charId) match {
|
||||
case Some(_) => ()
|
||||
//already searching, so do nothing(?)
|
||||
case None =>
|
||||
searchData
|
||||
.get(charId)
|
||||
.orElse {
|
||||
val data = SquadService.SearchCriteria(tplayer.Faction, criteria)
|
||||
searchData.put(charId, data)
|
||||
SquadActionDefinitionSearchForSquadsUsingCriteria(charId, data)
|
||||
}
|
||||
None
|
||||
}
|
||||
//if already searching, do nothing
|
||||
}
|
||||
|
||||
private def SquadActionDefinitionSearchForSquadsUsingCriteria(
|
||||
|
|
@ -797,22 +736,23 @@ class SquadService extends Actor {
|
|||
}
|
||||
|
||||
private def SearchForSquadsResults(criteria: SquadService.SearchCriteria): List[PlanetSideGUID] = {
|
||||
publishedLists.get(criteria.faction) match {
|
||||
case Some(squads) if squads.nonEmpty =>
|
||||
squads.flatMap { guid => SearchForSquadsResults(criteria, guid) }.toList
|
||||
case _ =>
|
||||
Nil
|
||||
}
|
||||
publishedLists
|
||||
.get(criteria.faction)
|
||||
.collect {
|
||||
case squads if squads.nonEmpty =>
|
||||
squads.flatMap { guid => SearchForSquadsResults(criteria, guid) }.toList
|
||||
}
|
||||
.getOrElse(Nil)
|
||||
}
|
||||
|
||||
def SquadActionDefinitionCancelSquadSearch(charId: Long): Unit = {
|
||||
searchData.remove(charId) match {
|
||||
case None => ()
|
||||
case Some(data) =>
|
||||
SearchForSquadsResults(data).foreach { guid =>
|
||||
subs.Publish(charId, SquadResponse.SquadDecoration(guid, squadFeatures(guid).Squad))
|
||||
}
|
||||
}
|
||||
searchData
|
||||
.remove(charId)
|
||||
.map(SearchForSquadsResults)
|
||||
.getOrElse(Nil)
|
||||
.foreach { guid =>
|
||||
subs.Publish(charId, SquadResponse.SquadDecoration(guid, squadFeatures(guid).Squad))
|
||||
}
|
||||
}
|
||||
|
||||
private def SearchForSquadsResults(
|
||||
|
|
@ -872,14 +812,14 @@ class SquadService extends Actor {
|
|||
}
|
||||
|
||||
def CleanUpSquadFeatures(removed: List[Long], guid: PlanetSideGUID, @unused position: Int): Unit = {
|
||||
GetSquad(guid) match {
|
||||
case Some(features) =>
|
||||
features.ProxyInvites = features.ProxyInvites.filterNot(removed.contains)
|
||||
if (features.ProxyInvites.isEmpty) {
|
||||
GetSquad(guid)
|
||||
.collect {
|
||||
case features if features.ProxyInvites.isEmpty =>
|
||||
features.ProxyInvites = features.ProxyInvites.filterNot(removed.contains)
|
||||
features.SearchForRole = None
|
||||
}
|
||||
case None => ()
|
||||
}
|
||||
case features =>
|
||||
features.ProxyInvites = features.ProxyInvites.filterNot(removed.contains)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -945,18 +885,19 @@ class SquadService extends Actor {
|
|||
def JoinSquad(player: Player, features: SquadFeatures, position: Int): Boolean = {
|
||||
val charId = player.CharId
|
||||
val squad = features.Squad
|
||||
subs.UserEvents.get(charId) match {
|
||||
case Some(events)
|
||||
if squad.isAvailable(position, player.avatar.certifications) &&
|
||||
EnsureEmptySquad(charId) =>
|
||||
memberToSquad(charId) = squad.GUID
|
||||
subs.MonitorSquadDetails.subtractOne(charId)
|
||||
invitations.handleCleanup(charId)
|
||||
features.Switchboard ! SquadSwitchboard.Join(player, position, events)
|
||||
true
|
||||
case _ =>
|
||||
false
|
||||
}
|
||||
subs
|
||||
.UserEvents
|
||||
.get(charId)
|
||||
.collect {
|
||||
case events
|
||||
if squad.isAvailable(position, player.avatar.certifications) && EnsureEmptySquad(charId) =>
|
||||
memberToSquad(charId) = squad.GUID
|
||||
subs.MonitorSquadDetails.subtractOne(charId)
|
||||
invitations.handleCleanup(charId)
|
||||
features.Switchboard ! SquadSwitchboard.Join(player, position, events)
|
||||
true
|
||||
}
|
||||
.getOrElse(false)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -968,16 +909,16 @@ class SquadService extends Actor {
|
|||
* `false`, otherwise
|
||||
*/
|
||||
def EnsureEmptySquad(charId: Long): Boolean = {
|
||||
GetParticipatingSquad(charId) match {
|
||||
case None =>
|
||||
true
|
||||
case Some(features) if features.Squad.Size == 1 =>
|
||||
CloseSquad(features.Squad)
|
||||
true
|
||||
case _ =>
|
||||
log.warn("EnsureEmptySquad: the invited player is already a member of a squad and can not join a second one")
|
||||
false
|
||||
}
|
||||
GetParticipatingSquad(charId)
|
||||
.collect {
|
||||
case features if features.Squad.Size == 1 =>
|
||||
CloseSquad(features.Squad)
|
||||
true
|
||||
case _ =>
|
||||
log.warn("EnsureEmptySquad: the invited player is already a member of a squad and can not join a second one")
|
||||
false
|
||||
}
|
||||
.getOrElse(true)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -992,15 +933,15 @@ class SquadService extends Actor {
|
|||
def LeaveSquad(charId: Long, features: SquadFeatures): Boolean = {
|
||||
val squad = features.Squad
|
||||
val membership = squad.Membership.zipWithIndex
|
||||
membership.find { case (_member, _) => _member.CharId == charId } match {
|
||||
case Some(_) if squad.Leader.CharId != charId =>
|
||||
membership
|
||||
.find { case (_member, _) => _member.CharId == charId }
|
||||
.collect { case _ if squad.Leader.CharId != charId =>
|
||||
memberToSquad.remove(charId)
|
||||
subs.MonitorSquadDetails.subtractOne(charId)
|
||||
features.Switchboard ! SquadSwitchboard.Leave(charId)
|
||||
true
|
||||
case _ =>
|
||||
false
|
||||
}
|
||||
}
|
||||
.getOrElse(false)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1079,7 +1020,7 @@ class SquadService extends Actor {
|
|||
)
|
||||
//the squad is being disbanded, the squad events channel is also going away; use cached character ids
|
||||
info(s"Squad #${squad.GUID.guid} has been disbanded.")
|
||||
subs.Publish(leader, SquadResponse.Membership(SquadResponseType.Disband, 0, 0, leader, None, "", unk5=true, Some(None)))
|
||||
subs.Publish(leader, SquadResponse.Membership(SquadResponseType.Disband, leader, None, "", unk5=true))
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1107,7 +1048,7 @@ class SquadService extends Actor {
|
|||
(membership.filterNot(_ == leader) ++ subs.PublishToMonitorTargets(squad.GUID, Nil))
|
||||
.toSet
|
||||
.foreach { charId : Long =>
|
||||
subs.Publish(charId, SquadResponse.Membership(SquadResponseType.Disband, 0, 0, charId, None, "", unk5=false, Some(None)))
|
||||
subs.Publish(charId, SquadResponse.Membership(SquadResponseType.Disband, charId, None, "", unk5=false))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1355,24 +1296,25 @@ class SquadService extends Actor {
|
|||
if (listOfCharIds.nonEmpty) {
|
||||
invitations.tryChainAcceptance(player, charId, listOfCharIds, features)
|
||||
} else {
|
||||
invitations.SquadActionDefinitionAutoApproveInvitationRequests(charId, features)
|
||||
invitations.autoApproveInvitationRequests(charId, features)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def ChainRejectionFromSquad(player: Player, charId: Long, listOfCharIds: List[Long]): Unit = {
|
||||
GetLeadingSquad(charId, None)
|
||||
.foreach { features =>
|
||||
if (listOfCharIds.nonEmpty) {
|
||||
.collect {
|
||||
case features if listOfCharIds.nonEmpty =>
|
||||
invitations.tryChainRejection(player, charId, listOfCharIds, features)
|
||||
} else {
|
||||
case features =>
|
||||
invitations.tryChainRejectionAll(charId, features)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object SquadService {
|
||||
final private val FactionWordSalad: String = "TRNCVS"
|
||||
|
||||
final case class PerformStartSquad(player: Player)
|
||||
|
||||
final case class PerformJoinSquad(player: Player, features: SquadFeatures, position: Int)
|
||||
|
|
|
|||
|
|
@ -41,6 +41,16 @@ object SquadResponse {
|
|||
unk5: Boolean,
|
||||
unk6: Option[Option[String]]
|
||||
) extends Response //see SquadMembershipResponse
|
||||
object Membership {
|
||||
def apply(
|
||||
requestType: SquadResponseType.Value,
|
||||
unk3: Long,
|
||||
unk4: Option[Long],
|
||||
playerName: String,
|
||||
unk5: Boolean
|
||||
): Membership = new Membership(requestType, unk1 = 0, unk2 = 0, unk3, unk4, playerName, unk5, Some(None))
|
||||
}
|
||||
|
||||
final case class WantsSquadPosition(leader_char_id: Long, bid_name: String) extends Response
|
||||
final case class Join(squad: Squad, positionsToUpdate: List[Int], channel: String, ref: ActorRef) extends Response
|
||||
final case class Leave(squad: Squad, positionsToUpdate: List[(Long, Int)]) extends Response
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.services.teamwork.invitations
|
||||
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.objects.teamwork.SquadFeatures
|
||||
import net.psforever.services.teamwork.SquadInvitationManager
|
||||
import net.psforever.types.PlanetSideGUID
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/**
|
||||
* Utilized to redirect an (accepted) invitation request to the proper squad leader.
|
||||
* No direct action causes this message.
|
||||
* Depending on the situation, either the squad leader or the player who would join the squad handle this invitation.
|
||||
*
|
||||
* @param recruitOrOwner player who would be joining the squad;
|
||||
* may or may not have actually requested it in the first place
|
||||
* @param features squad
|
||||
*/
|
||||
final case class IndirectInvite(recruitOrOwner: Player, features: SquadFeatures)
|
||||
extends Invitation(recruitOrOwner.CharId, recruitOrOwner.Name) {
|
||||
def handleInvitation(indirectInviteFunc: (IndirectInvite, Player, Long, Long, String) => Boolean)(
|
||||
manager: SquadInvitationManager,
|
||||
invitedPlayer: Long,
|
||||
invitingPlayer: Long,
|
||||
otherName: String
|
||||
): Unit = {
|
||||
indirectInviteFunc(this, recruitOrOwner, invitedPlayer, invitingPlayer, otherName)
|
||||
}
|
||||
|
||||
def handleAcceptance(
|
||||
manager: SquadInvitationManager,
|
||||
@unused player: Player,
|
||||
invitedPlayer: Long,
|
||||
@unused invitedPlayerSquadOpt: Option[SquadFeatures]
|
||||
): Unit = {
|
||||
//tplayer / invitedPlayer is actually the squad leader
|
||||
if (SquadInvitationManager.canEnrollInSquad(features, recruitOrOwner.CharId)) {
|
||||
val recruitCharId = recruitOrOwner.CharId
|
||||
manager.handleVacancyInvite(features, recruitCharId, invitedPlayer, recruitOrOwner) match {
|
||||
case Some((_, line)) =>
|
||||
manager.acceptanceMessages(invitedPlayer, recruitCharId, recruitOrOwner.Name)
|
||||
manager.joinSquad(recruitOrOwner, features, line)
|
||||
manager.cleanUpAllInvitesWithPlayer(recruitCharId)
|
||||
manager.cleanUpInvitesForSquadAndPosition(features, line)
|
||||
//TODO since we are the squad leader, we do not want to brush off our queued squad invite tasks
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def handleRejection(
|
||||
manager: SquadInvitationManager,
|
||||
player: Player,
|
||||
rejectingPlayer: Long,
|
||||
@unused squadsToLeaders: List[(PlanetSideGUID, SquadFeatures)]
|
||||
): Unit = {
|
||||
//todo how to do this?
|
||||
}
|
||||
|
||||
def doRejection(
|
||||
manager: SquadInvitationManager,
|
||||
player: Player,
|
||||
rejectingPlayer: Long
|
||||
): Unit = {
|
||||
//todo how to do this?
|
||||
}
|
||||
|
||||
def canBeAutoApproved: Boolean = true
|
||||
|
||||
def getOptionalSquad: Option[SquadFeatures] = Some(features)
|
||||
|
||||
def getPlayer: Player = recruitOrOwner
|
||||
|
||||
def appliesToPlayer(playerCharId: Long): Boolean = playerCharId == recruitOrOwner.CharId
|
||||
|
||||
def appliesToSquad(guid: PlanetSideGUID): Boolean = features.Squad.GUID == guid
|
||||
|
||||
def appliesToSquadAndPosition(guid: PlanetSideGUID, squadPosition: Int): Boolean = false
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.services.teamwork.invitations
|
||||
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.objects.teamwork.SquadFeatures
|
||||
import net.psforever.services.teamwork.SquadInvitationManager
|
||||
import net.psforever.types.PlanetSideGUID
|
||||
|
||||
/**
|
||||
* The base of all objects that exist for the purpose of communicating invitation from one player to the next.
|
||||
* @param charId inviting player's unique identifier number
|
||||
* @param name inviting player's name
|
||||
*/
|
||||
abstract class Invitation(charId: Long, name: String) {
|
||||
def inviterCharId: Long = charId
|
||||
def inviterName: String = name
|
||||
|
||||
/**
|
||||
* A branched response for processing (new) invitation objects that have been submitted to the system.<br>
|
||||
* <br>
|
||||
* A comparison is performed between the original invitation object and an invitation object
|
||||
* that represents the potential modification or redirection of the current active invitation obect.
|
||||
* Any further action is only performed when an "is equal" comparison is `true`.
|
||||
* When passing, the system publishes up to two messages
|
||||
* to users that would anticipate being informed of squad join activity.
|
||||
* @param indirectInviteFunc the method that cans the responding behavior should an `IndirectInvite` object being consumed
|
||||
* @param invitedPlayer the unique character identifier for the player being invited;
|
||||
* in actuality, represents the player who will address the invitation object
|
||||
* @param invitingPlayer the unique character identifier for the player who invited the former
|
||||
* @param otherName a name to be used in message composition
|
||||
*/
|
||||
def handleInvitation(indirectInviteFunc: (IndirectInvite, Player, Long, Long, String) => Boolean)(
|
||||
manager: SquadInvitationManager,
|
||||
invitedPlayer: Long,
|
||||
invitingPlayer: Long,
|
||||
otherName: String
|
||||
): Unit
|
||||
|
||||
def handleAcceptance(
|
||||
manager: SquadInvitationManager,
|
||||
player: Player,
|
||||
invitedPlayer: Long,
|
||||
invitedPlayerSquadOpt: Option[SquadFeatures]
|
||||
): Unit
|
||||
|
||||
def handleRejection(
|
||||
manager: SquadInvitationManager,
|
||||
player: Player,
|
||||
rejectingPlayer: Long,
|
||||
squadsToLeaders: List[(PlanetSideGUID, SquadFeatures)]
|
||||
): Unit
|
||||
|
||||
def doRejection(
|
||||
manager: SquadInvitationManager,
|
||||
player: Player,
|
||||
rejectingPlayer: Long
|
||||
): Unit
|
||||
|
||||
def canBeAutoApproved: Boolean
|
||||
|
||||
def getOptionalSquad: Option[SquadFeatures]
|
||||
|
||||
/**
|
||||
* na
|
||||
* @return active player entity associated with this invite;
|
||||
* can be `null` as some invitations do not retain such character data
|
||||
*/
|
||||
def getPlayer: Player
|
||||
|
||||
def appliesToPlayer(playerCharId: Long): Boolean
|
||||
|
||||
def appliesToSquad(guid: PlanetSideGUID): Boolean
|
||||
|
||||
def appliesToSquadAndPosition(guid: PlanetSideGUID, squadPosition: Int): Boolean
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.services.teamwork.invitations
|
||||
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.objects.teamwork.SquadFeatures
|
||||
import net.psforever.services.teamwork.SquadInvitationManager.FinishStartSquad
|
||||
import net.psforever.services.teamwork.{SquadInvitationManager, SquadResponse}
|
||||
import net.psforever.types.{PlanetSideGUID, SquadResponseType}
|
||||
|
||||
import scala.annotation.unused
|
||||
import scala.util.Success
|
||||
|
||||
/**
|
||||
* Utilized when one player issues an invite for some other player for a squad that does not yet exist.
|
||||
* This invitation is handled by the player who would be joining the squad.
|
||||
*
|
||||
* @param futureSquadLeader player who wishes to become the leader of a squad
|
||||
*/
|
||||
final case class InvitationToCreateASquad(futureSquadLeader: Player)
|
||||
extends Invitation(futureSquadLeader.CharId, futureSquadLeader.Name) {
|
||||
def handleInvitation(indirectInviteFunc: (IndirectInvite, Player, Long, Long, String) => Boolean)(
|
||||
manager: SquadInvitationManager,
|
||||
invitedPlayer: Long,
|
||||
invitingPlayer: Long,
|
||||
otherName: String
|
||||
): Unit = {
|
||||
manager.publish(
|
||||
invitedPlayer,
|
||||
SquadResponse.Membership(SquadResponseType.Invite, inviterCharId, Some(invitedPlayer), futureSquadLeader.Name, unk5 = false)
|
||||
)
|
||||
manager.publish(
|
||||
inviterCharId,
|
||||
SquadResponse.Membership(SquadResponseType.Invite, invitedPlayer, Some(inviterCharId), futureSquadLeader.Name, unk5 = true)
|
||||
)
|
||||
}
|
||||
|
||||
def handleAcceptance(
|
||||
manager: SquadInvitationManager,
|
||||
player: Player,
|
||||
invitedPlayer: Long,
|
||||
invitedPlayerSquadOpt: Option[SquadFeatures]
|
||||
): Unit = {
|
||||
if (manager.notLimitedByEnrollmentInSquad(invitedPlayerSquadOpt, invitedPlayer)) {
|
||||
//accepted an invitation to join an existing squad
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
val leaderCharId = futureSquadLeader.CharId
|
||||
manager
|
||||
.askToCreateANewSquad(futureSquadLeader)
|
||||
.onComplete {
|
||||
case Success(FinishStartSquad(features)) =>
|
||||
manager.handleVacancyInvite(features, invitedPlayer, leaderCharId, player) match {
|
||||
case Some((_, line)) =>
|
||||
manager.publish(
|
||||
invitedPlayer,
|
||||
SquadResponse.Membership(SquadResponseType.Accept, invitedPlayer, Some(leaderCharId), "", unk5 = true)
|
||||
)
|
||||
manager.publish(
|
||||
leaderCharId,
|
||||
SquadResponse.Membership(SquadResponseType.Accept, leaderCharId, Some(invitedPlayer), player.Name, unk5 = false)
|
||||
)
|
||||
manager.joinSquad(player, features, line)
|
||||
manager.cleanUpQueuedInvites(invitedPlayer)
|
||||
case _ => ()
|
||||
}
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def handleRejection(
|
||||
manager: SquadInvitationManager,
|
||||
player: Player,
|
||||
rejectingPlayer: Long,
|
||||
@unused squadsToLeaders: List[(PlanetSideGUID, SquadFeatures)]
|
||||
): Unit = {
|
||||
//rejectingPlayer is the would-be squad member; the would-be squad leader sent the request and was rejected
|
||||
val invitingPlayerCharId = futureSquadLeader.CharId
|
||||
doRejection(manager, player, rejectingPlayer)
|
||||
manager.publish(
|
||||
rejectingPlayer,
|
||||
SquadResponse.Membership(SquadResponseType.Reject, rejectingPlayer, Some(invitingPlayerCharId), "", unk5 = true)
|
||||
)
|
||||
manager.publish(
|
||||
invitingPlayerCharId,
|
||||
SquadResponse.Membership(SquadResponseType.Reject, invitingPlayerCharId, Some(rejectingPlayer), player.Name, unk5 = false)
|
||||
)
|
||||
manager.publish(
|
||||
rejectingPlayer,
|
||||
SquadResponse.SquadRelatedComment(s"Your request to form a squad has been refused.")
|
||||
)
|
||||
}
|
||||
|
||||
def doRejection(
|
||||
manager: SquadInvitationManager,
|
||||
player: Player,
|
||||
rejectingPlayer: Long
|
||||
): Unit = {
|
||||
manager.refused(rejectingPlayer, futureSquadLeader.CharId)
|
||||
}
|
||||
|
||||
def canBeAutoApproved: Boolean = false
|
||||
|
||||
def getOptionalSquad: Option[SquadFeatures] = None
|
||||
|
||||
def getPlayer: Player = futureSquadLeader
|
||||
|
||||
def appliesToPlayer(playerCharId: Long): Boolean = playerCharId == futureSquadLeader.CharId
|
||||
|
||||
def appliesToSquad(guid: PlanetSideGUID): Boolean = false
|
||||
|
||||
def appliesToSquadAndPosition(guid: PlanetSideGUID, squadPosition: Int): Boolean = false
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.services.teamwork.invitations
|
||||
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.objects.teamwork.SquadFeatures
|
||||
import net.psforever.services.teamwork.{SquadInvitationManager, SquadResponse}
|
||||
import net.psforever.types.{PlanetSideGUID, SquadResponseType}
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/**
|
||||
* Utilized when one squad member issues an invite for some other player.
|
||||
* Accessed by an existing squad member using the "Invite" menu option on another player.
|
||||
* This invitation is handled by the player who would join the squad.
|
||||
*
|
||||
* @param charId unique character identifier of the player who sent the invite
|
||||
* @param name name the player who sent the invite
|
||||
* @param features the squad
|
||||
*/
|
||||
final case class InvitationToJoinSquad(charId: Long, name: String, features: SquadFeatures)
|
||||
extends Invitation(charId, name) {
|
||||
def handleInvitation(indirectInviteFunc: (IndirectInvite, Player, Long, Long, String) => Boolean)(
|
||||
manager: SquadInvitationManager,
|
||||
invitedPlayer: Long,
|
||||
invitingPlayer: Long,
|
||||
otherName: String
|
||||
): Unit = {
|
||||
manager.publish(
|
||||
invitedPlayer,
|
||||
SquadResponse.Membership(SquadResponseType.Invite, charId, Some(invitedPlayer), name, unk5 = false)
|
||||
)
|
||||
manager.publish(
|
||||
charId,
|
||||
SquadResponse.Membership(SquadResponseType.Invite, invitedPlayer, Some(charId), name, unk5 = true)
|
||||
)
|
||||
}
|
||||
|
||||
def handleAcceptance(
|
||||
manager: SquadInvitationManager,
|
||||
player: Player,
|
||||
invitedPlayer: Long,
|
||||
@unused invitedPlayerSquadOpt: Option[SquadFeatures]
|
||||
): Unit = {
|
||||
if (
|
||||
manager.notLimitedByEnrollmentInSquad(invitedPlayerSquadOpt, invitedPlayer) &&
|
||||
SquadInvitationManager.canEnrollInSquad(features, invitedPlayer)
|
||||
) {
|
||||
//accepted an invitation to join an existing squad
|
||||
manager.handleVacancyInvite(features, invitedPlayer, charId, player) match {
|
||||
case Some((_, line)) =>
|
||||
manager.acceptanceMessages(charId, invitedPlayer, player.Name)
|
||||
manager.joinSquad(player, features, line)
|
||||
manager.cleanUpQueuedInvites(invitedPlayer)
|
||||
manager.cleanUpInvitesForSquadAndPosition(features, line)
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def handleRejection(
|
||||
manager: SquadInvitationManager,
|
||||
player: Player,
|
||||
rejectingPlayer: Long,
|
||||
@unused squadsToLeaders: List[(PlanetSideGUID, SquadFeatures)]
|
||||
): Unit = {
|
||||
/*if SquadInvitationManager.notLeaderOfThisSquad(squadsToLeaders, features.Squad.GUID, rejectingPlayer)*/
|
||||
//rejectingPlayer is the would-be squad member; the squad leader sent the request and was rejected
|
||||
doRejection(manager, player, rejectingPlayer)
|
||||
manager.rejectionMessages(rejectingPlayer, charId, player.Name)
|
||||
manager.publish(
|
||||
rejectingPlayer,
|
||||
SquadResponse.SquadRelatedComment(s"Your request to join squad '${features.Squad.Task}' has been refused.")
|
||||
)
|
||||
}
|
||||
|
||||
def doRejection(
|
||||
manager: SquadInvitationManager,
|
||||
player: Player,
|
||||
rejectingPlayer: Long
|
||||
): Unit = {
|
||||
manager.refused(rejectingPlayer, charId)
|
||||
}
|
||||
|
||||
def canBeAutoApproved: Boolean = false
|
||||
|
||||
def getOptionalSquad: Option[SquadFeatures] = Some(features)
|
||||
|
||||
def getPlayer: Player = null
|
||||
|
||||
def appliesToPlayer(playerCharId: Long): Boolean = playerCharId == charId
|
||||
|
||||
def appliesToSquad(guid: PlanetSideGUID): Boolean = features.Squad.GUID == guid
|
||||
|
||||
def appliesToSquadAndPosition(guid: PlanetSideGUID, squadPosition: Int): Boolean = false
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.services.teamwork.invitations
|
||||
|
||||
import net.psforever.objects.teamwork.{Member, SquadFeatures}
|
||||
import net.psforever.objects.{LivePlayerList, Player}
|
||||
import net.psforever.services.teamwork.{SquadInvitationManager, SquadResponse}
|
||||
import net.psforever.types.{PlanetSideGUID, SquadResponseType}
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/**
|
||||
* Utilized in conjunction with an external queuing data structure
|
||||
* to search for and submit requests to other players
|
||||
* for the purposes of fill out an unoccupied squad role.
|
||||
* This invitation is handled by the player who would be joining the squad.
|
||||
*
|
||||
* @param squadLeader squad leader
|
||||
* @param features squad with the role
|
||||
* @param position index of the role
|
||||
*/
|
||||
final case class LookingForSquadRoleInvite(squadLeader: Member, features: SquadFeatures, position: Int)
|
||||
extends Invitation(squadLeader.CharId, squadLeader.Name) {
|
||||
def handleInvitation(indirectInviteFunc: (IndirectInvite, Player, Long, Long, String) => Boolean)(
|
||||
manager: SquadInvitationManager,
|
||||
invitedPlayer: Long,
|
||||
invitingPlayer: Long,
|
||||
otherName: String
|
||||
): Unit = {
|
||||
manager.publish(
|
||||
invitedPlayer,
|
||||
SquadResponse.Membership(SquadResponseType.Invite, invitedPlayer, Some(squadLeader.CharId), squadLeader.Name, unk5 = false)
|
||||
)
|
||||
}
|
||||
|
||||
def handleAcceptance(
|
||||
manager: SquadInvitationManager,
|
||||
player: Player,
|
||||
invitedPlayer: Long,
|
||||
@unused invitedPlayerSquadOpt: Option[SquadFeatures]
|
||||
): Unit = {
|
||||
if (
|
||||
manager.notLimitedByEnrollmentInSquad(invitedPlayerSquadOpt, invitedPlayer) &&
|
||||
SquadInvitationManager.canEnrollInSquad(features, invitedPlayer)
|
||||
) {
|
||||
val invitingPlayer = squadLeader.CharId
|
||||
features.ProxyInvites = features.ProxyInvites.filterNot { _ == invitedPlayer }
|
||||
if (manager.joinSquad(player, features, position)) {
|
||||
//join this squad
|
||||
manager.acceptanceMessages(invitingPlayer, invitedPlayer, player.Name)
|
||||
manager.cleanUpQueuedInvites(player.CharId)
|
||||
manager.cleanUpInvitesForSquadAndPosition(features, position)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def handleRejection(
|
||||
manager: SquadInvitationManager,
|
||||
player: Player,
|
||||
rejectingPlayer: Long,
|
||||
@unused squadsToLeaders: List[(PlanetSideGUID, SquadFeatures)]
|
||||
): Unit = {
|
||||
val leaderCharId = squadLeader.CharId
|
||||
//rejectingPlayer is the would-be squad member; the squad leader sent the request and was rejected
|
||||
doRejection(manager, player, rejectingPlayer)
|
||||
manager.rejectionMessages(rejectingPlayer, leaderCharId, player.Name)
|
||||
manager.publish(
|
||||
rejectingPlayer,
|
||||
SquadResponse.SquadRelatedComment(s"Your request to join squad '${features.Squad.Task}' has been refused.")
|
||||
)
|
||||
}
|
||||
|
||||
def doRejection(
|
||||
manager: SquadInvitationManager,
|
||||
player: Player,
|
||||
rejectingPlayer: Long
|
||||
): Unit = {
|
||||
manager.reloadSearchForRoleInvite(
|
||||
LivePlayerList.WorldPopulation { _ => true },
|
||||
rejectingPlayer,
|
||||
features,
|
||||
position
|
||||
)
|
||||
}
|
||||
|
||||
def canBeAutoApproved: Boolean = false
|
||||
|
||||
def getOptionalSquad: Option[SquadFeatures] = Some(features)
|
||||
|
||||
def getPlayer: Player = null
|
||||
|
||||
def appliesToPlayer(playerCharId: Long): Boolean = playerCharId == squadLeader.CharId
|
||||
|
||||
def appliesToSquad(guid: PlanetSideGUID): Boolean = features.Squad.GUID == guid
|
||||
|
||||
def appliesToSquadAndPosition(guid: PlanetSideGUID, squadPosition: Int): Boolean = appliesToSquad(guid) && position == squadPosition
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.services.teamwork.invitations
|
||||
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.objects.teamwork.{Member, SquadFeatures}
|
||||
import net.psforever.services.teamwork.{SquadInvitationManager, SquadResponse}
|
||||
import net.psforever.types.{PlanetSideGUID, SquadResponseType}
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/**
|
||||
* Utilized in conjunction with an external queuing data structure
|
||||
* to search for and submit requests to other players
|
||||
* for the purposes of fill out unoccupied squad roles.
|
||||
* This invitation is handled by the player who would be joining the squad.
|
||||
*
|
||||
* @param squadLeader squad leader
|
||||
* @param features squad
|
||||
* @param position index of a role
|
||||
*/
|
||||
final case class ProximityInvite(squadLeader: Member, features: SquadFeatures, position: Int)
|
||||
extends Invitation(squadLeader.CharId, squadLeader.Name) {
|
||||
def handleInvitation(indirectInviteFunc: (IndirectInvite, Player, Long, Long, String) => Boolean)(
|
||||
manager: SquadInvitationManager,
|
||||
invitedPlayer: Long,
|
||||
invitingPlayer: Long,
|
||||
otherName: String
|
||||
): Unit = {
|
||||
manager.publish(
|
||||
invitedPlayer,
|
||||
SquadResponse.Membership(
|
||||
SquadResponseType.Invite,
|
||||
invitedPlayer,
|
||||
Some(squadLeader.CharId),
|
||||
squadLeader.Name,
|
||||
unk5 = false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
def handleAcceptance(
|
||||
manager: SquadInvitationManager,
|
||||
player: Player,
|
||||
invitedPlayer: Long,
|
||||
invitedPlayerSquadOpt: Option[SquadFeatures]
|
||||
): Unit = {
|
||||
if (
|
||||
manager.notLimitedByEnrollmentInSquad(invitedPlayerSquadOpt, invitedPlayer) &&
|
||||
SquadInvitationManager.canEnrollInSquad(features, invitedPlayer)
|
||||
) {
|
||||
val invitingPlayer = squadLeader.CharId
|
||||
features.ProxyInvites = features.ProxyInvites.filterNot { _ == invitedPlayer }
|
||||
if (manager.joinSquad(player, features, position)) {
|
||||
//join this squad
|
||||
manager.acceptanceMessages(invitingPlayer, invitedPlayer, player.Name)
|
||||
manager.cleanUpAllInvitesWithPlayer(invitedPlayer)
|
||||
val squad = features.Squad
|
||||
if (squad.Size == squad.Capacity) {
|
||||
//all available squad positions filled; terminate all remaining invitations
|
||||
manager.cleanUpAllInvitesToSquad(features)
|
||||
}
|
||||
} else {
|
||||
manager.reloadProximityInvite(player.Zone.Players, invitedPlayer, features, position) //TODO ?
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def handleRejection(
|
||||
manager: SquadInvitationManager,
|
||||
player: Player,
|
||||
rejectingPlayer: Long,
|
||||
@unused squadsToLeaders: List[(PlanetSideGUID, SquadFeatures)]
|
||||
): Unit = {
|
||||
/*if SquadInvitationManager.notLeaderOfThisSquad(squadsToLeaders, features.Squad.GUID, rejectingPlayer)*/
|
||||
//rejectingPlayer is the would-be squad member; the squad leader sent the request and was rejected
|
||||
doRejection(manager, player, rejectingPlayer)
|
||||
manager.rejectionMessage(rejectingPlayer)
|
||||
manager.publish(
|
||||
rejectingPlayer,
|
||||
SquadResponse.SquadRelatedComment(s"Your request to join squad '${features.Squad.Task}' has been refused.")
|
||||
)
|
||||
}
|
||||
|
||||
def doRejection(
|
||||
manager: SquadInvitationManager,
|
||||
player: Player,
|
||||
rejectingPlayer: Long
|
||||
): Unit = {
|
||||
manager.reloadProximityInvite(player.Zone.Players, rejectingPlayer, features, position)
|
||||
}
|
||||
|
||||
def canBeAutoApproved: Boolean = false
|
||||
|
||||
def getOptionalSquad: Option[SquadFeatures] = Some(features)
|
||||
|
||||
def getPlayer: Player = null
|
||||
|
||||
def appliesToPlayer(playerCharId: Long): Boolean = playerCharId == squadLeader.CharId
|
||||
|
||||
def appliesToSquad(guid: PlanetSideGUID): Boolean = features.Squad.GUID == guid
|
||||
|
||||
def appliesToSquadAndPosition(guid: PlanetSideGUID, squadPosition: Int): Boolean = appliesToSquad(guid) && position == squadPosition
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.services.teamwork.invitations
|
||||
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.objects.teamwork.SquadFeatures
|
||||
import net.psforever.services.teamwork.{SquadInvitationManager, SquadResponse}
|
||||
import net.psforever.types.PlanetSideGUID
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/**
|
||||
* Utilized when one player attempts to join an existing squad in a specific role.
|
||||
* Accessed by the joining player from the squad detail window.
|
||||
* This invitation is handled by the squad leader.
|
||||
*
|
||||
* @param requestee player who requested the role
|
||||
* @param features squad with the role
|
||||
* @param position index of the role
|
||||
*/
|
||||
final case class RequestToJoinSquadRole(requestee: Player, features: SquadFeatures, position: Int)
|
||||
extends Invitation(requestee.CharId, requestee.Name) {
|
||||
def handleInvitation(indirectInviteFunc: (IndirectInvite, Player, Long, Long, String) => Boolean)(
|
||||
manager: SquadInvitationManager,
|
||||
invitedPlayer: Long,
|
||||
invitingPlayer: Long,
|
||||
otherName: String
|
||||
): Unit = {
|
||||
SquadInvitationManager.handleRequestRole(manager, requestee, bid = this)
|
||||
}
|
||||
|
||||
def handleAcceptance(
|
||||
manager: SquadInvitationManager,
|
||||
@unused player: Player,
|
||||
invitedPlayer: Long,
|
||||
@unused invitedPlayerSquadOpt: Option[SquadFeatures]
|
||||
): Unit = {
|
||||
//player requested to join a squad's specific position
|
||||
//invitedPlayer is actually the squad leader; petitioner is the actual "invitedPlayer"
|
||||
if (
|
||||
SquadInvitationManager.canEnrollInSquad(features, requestee.CharId) &&
|
||||
manager.joinSquad(requestee, features, position)
|
||||
) {
|
||||
manager.acceptanceMessages(invitedPlayer, requestee.CharId, requestee.Name)
|
||||
manager.cleanUpInvitesForSquadAndPosition(features, position)
|
||||
}
|
||||
}
|
||||
|
||||
def handleRejection(
|
||||
manager: SquadInvitationManager,
|
||||
@unused player: Player,
|
||||
rejectingPlayer: Long,
|
||||
@unused squadsToLeaders: List[(PlanetSideGUID, SquadFeatures)]
|
||||
): Unit = {
|
||||
if (SquadInvitationManager.notLeaderOfThisSquad(squadsToLeaders, features.Squad.GUID, requestee.CharId)) {
|
||||
//rejected is the would-be squad member; rejectingPlayer is the squad leader who rejected the request
|
||||
doRejection(manager, player, rejectingPlayer)
|
||||
manager.rejectionMessage(rejectingPlayer)
|
||||
manager.publish(
|
||||
rejectingPlayer,
|
||||
SquadResponse.SquadRelatedComment(s"Your request to join squad '${features.Squad.Task}' has been refused.")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
def doRejection(
|
||||
manager: SquadInvitationManager,
|
||||
player: Player,
|
||||
rejectingPlayer: Long
|
||||
): Unit = {
|
||||
features.DeniedPlayers(requestee.CharId)
|
||||
}
|
||||
|
||||
def canBeAutoApproved: Boolean = true
|
||||
|
||||
def getOptionalSquad: Option[SquadFeatures] = Some(features)
|
||||
|
||||
def getPlayer: Player = requestee
|
||||
|
||||
def appliesToPlayer(playerCharId: Long): Boolean = playerCharId == requestee.CharId
|
||||
|
||||
def appliesToSquad(guid: PlanetSideGUID): Boolean = features.Squad.GUID == guid
|
||||
|
||||
def appliesToSquadAndPosition(guid: PlanetSideGUID, squadPosition: Int): Boolean = appliesToSquad(guid) && position == squadPosition
|
||||
}
|
||||
Loading…
Reference in a new issue