mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-07-16 08:55:18 +00:00
new paradigm for character creation detection of old characters by name; vehicle channel when seated in vehicle (ant); second wind activates as long as non-fatal damage n>=25; coordinated sequence of deployables whose UI is being updated
This commit is contained in:
parent
72572ad125
commit
d636b3593e
7 changed files with 164 additions and 72 deletions
|
|
@ -913,43 +913,8 @@ class AvatarActor(
|
|||
AvatarActor.displayLookingForSquad(session.get, if (lfs) 1 else 0)
|
||||
Behaviors.same
|
||||
|
||||
case CreateAvatar(name, head, voice, gender, empire) =>
|
||||
import ctx._
|
||||
ctx.run(query[persistence.Avatar].filter(_.name ilike lift(name)).filter(!_.deleted)).onComplete {
|
||||
case Success(characters) =>
|
||||
characters.headOption match {
|
||||
case None =>
|
||||
val result = for {
|
||||
_ <- ctx.run(
|
||||
query[persistence.Avatar]
|
||||
.insert(
|
||||
_.name -> lift(name),
|
||||
_.accountId -> lift(account.id),
|
||||
_.factionId -> lift(empire.id),
|
||||
_.headId -> lift(head),
|
||||
_.voiceId -> lift(voice.id),
|
||||
_.genderId -> lift(gender.value),
|
||||
_.bep -> lift(Config.app.game.newAvatar.br.experience),
|
||||
_.cep -> lift(Config.app.game.newAvatar.cr.experience)
|
||||
)
|
||||
)
|
||||
} yield ()
|
||||
result.onComplete {
|
||||
case Success(_) =>
|
||||
log.debug(s"AvatarActor: created character $name for account ${account.name}")
|
||||
sessionActor ! SessionActor.SendResponse(ActionResultMessage.Pass)
|
||||
sendAvatars(account)
|
||||
case Failure(e) => log.error(e)("db failure")
|
||||
}
|
||||
case Some(_) =>
|
||||
// send "char already exists"
|
||||
sessionActor ! SessionActor.SendResponse(ActionResultMessage.Fail(1))
|
||||
}
|
||||
case Failure(e) =>
|
||||
log.error(e)("db failure")
|
||||
sessionActor ! SessionActor.SendResponse(ActionResultMessage.Fail(3))
|
||||
sendAvatars(account)
|
||||
}
|
||||
case CreateAvatar(name, head, voice, sex, empire) =>
|
||||
createAvatar(account, name, sex, empire, head, voice)
|
||||
Behaviors.same
|
||||
|
||||
case DeleteAvatar(id) =>
|
||||
|
|
@ -2999,4 +2964,114 @@ class AvatarActor(
|
|||
def updateToolDischarge(stats: EquipmentStat): Unit = {
|
||||
avatar.scorecard.rate(stats)
|
||||
}
|
||||
|
||||
def createAvatar(
|
||||
account: Account,
|
||||
name: String,
|
||||
sex: CharacterSex,
|
||||
empire: PlanetSideEmpire.Value,
|
||||
head: Int,
|
||||
voice: CharacterVoice.Value
|
||||
): Unit = {
|
||||
import ctx._
|
||||
ctx.run(
|
||||
query[persistence.Avatar]
|
||||
.filter(_.name ilike lift(name))
|
||||
.map(a => (a.accountId, a.deleted, a.created))
|
||||
)
|
||||
.onComplete {
|
||||
case Success(foundCharacters) if foundCharacters.size == 1 =>
|
||||
testFoundCharacters(
|
||||
account,
|
||||
name,
|
||||
foundCharacters
|
||||
.collect { case (a, b, c) => (a, b, c.toDate.getTime) }
|
||||
)
|
||||
case Success(foundCharacters) if foundCharacters.nonEmpty =>
|
||||
testFoundCharacters(
|
||||
account,
|
||||
name,
|
||||
foundCharacters
|
||||
.map { case (a, b, created) => (a, b, created.toDate.getTime) }
|
||||
.sortBy { case (_, _, created) => created }
|
||||
.toList
|
||||
)
|
||||
case Success(_) =>
|
||||
//create new character
|
||||
actuallyCreateNewCharacter(account.id, account.name, name, sex, empire, head, voice)
|
||||
sendAvatars(account)
|
||||
case Failure(e) =>
|
||||
log.error(e)("db failure")
|
||||
sessionActor ! SessionActor.SendResponse(ActionResultMessage.Fail(error = 3))
|
||||
sendAvatars(account)
|
||||
}
|
||||
}
|
||||
|
||||
private def testFoundCharacters(
|
||||
account: Account,
|
||||
name: String,
|
||||
foundCharacters: IterableOnce[(Int, Boolean, Long)]): Unit = {
|
||||
val foundCharactersIterator = foundCharacters.iterator
|
||||
if (foundCharactersIterator.exists { case (_, deleted, _ ) => !deleted } ||
|
||||
foundCharactersIterator.exists { case (accountId, _, _) => accountId != account.id }) {
|
||||
//send "char already exists"
|
||||
sessionActor ! SessionActor.SendResponse(ActionResultMessage.Fail(error = 1))
|
||||
} else {
|
||||
//reactivate character
|
||||
reactivateCharacter(account.id, account.name, name)
|
||||
sendAvatars(account)
|
||||
}
|
||||
}
|
||||
|
||||
private def actuallyCreateNewCharacter(
|
||||
accountId: Int,
|
||||
accountName: String,
|
||||
name: String,
|
||||
sex: CharacterSex,
|
||||
empire: PlanetSideEmpire.Value,
|
||||
head: Int,
|
||||
voice: CharacterVoice.Value
|
||||
): Unit = {
|
||||
import ctx._
|
||||
val result = for {
|
||||
_ <- ctx.run(
|
||||
query[persistence.Avatar]
|
||||
.insert(
|
||||
_.name -> lift(name),
|
||||
_.accountId -> lift(accountId),
|
||||
_.factionId -> lift(empire.id),
|
||||
_.headId -> lift(head),
|
||||
_.voiceId -> lift(voice.id),
|
||||
_.genderId -> lift(sex.value),
|
||||
_.bep -> lift(Config.app.game.newAvatar.br.experience),
|
||||
_.cep -> lift(Config.app.game.newAvatar.cr.experience)
|
||||
)
|
||||
)
|
||||
} yield ()
|
||||
result.onComplete {
|
||||
case Success(_) =>
|
||||
log.debug(s"AvatarActor: created character $name for account $accountName")
|
||||
sessionActor ! SessionActor.SendResponse(ActionResultMessage.Pass)
|
||||
case Failure(e) =>
|
||||
log.error(e)("db failure")
|
||||
sessionActor ! SessionActor.SendResponse(ActionResultMessage.Fail(error = 3))
|
||||
}
|
||||
}
|
||||
|
||||
private def reactivateCharacter(accountId: Int, accountName: String, characterName: String): Unit = {
|
||||
import ctx._
|
||||
ctx.run(
|
||||
query[persistence.Avatar]
|
||||
.filter(a => a.accountId == lift(accountId))
|
||||
.filter(a => a.name ilike lift(characterName))
|
||||
.update(_.deleted -> lift(false))
|
||||
).onComplete {
|
||||
case Success(_) =>
|
||||
log.debug(s"AvatarActor: character belonging to $accountName with name $characterName reactivated")
|
||||
sessionActor ! SessionActor.SendResponse(ActionResultMessage.Pass)
|
||||
case Failure(e) =>
|
||||
log.error(e)("db failure")
|
||||
sessionActor ! SessionActor.SendResponse(ActionResultMessage.Fail(error = 3))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ class SessionMountHandlers(
|
|||
sendResponse(PlanetsideAttributeMessage(obj_guid, obj.Definition.shieldUiAttribute, obj.Shields))
|
||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=45, obj.NtuCapacitorScaled))
|
||||
sendResponse(GenericObjectActionMessage(obj_guid, code=11))
|
||||
sessionData.accessContainer(obj)
|
||||
MountingAction(tplayer, obj, seatNumber)
|
||||
|
||||
case Mountable.CanMount(obj: Vehicle, seatNumber, _)
|
||||
|
|
|
|||
|
|
@ -279,11 +279,9 @@ class VehicleOperations(
|
|||
|
||||
def handleDismountVehicle(pkt: DismountVehicleMsg): Unit = {
|
||||
val DismountVehicleMsg(player_guid, bailType, wasKickedByDriver) = pkt
|
||||
val dError: (String, Player)=> Unit = dismountError(bailType, wasKickedByDriver)
|
||||
//TODO optimize this later
|
||||
//common warning for this section
|
||||
def dismountWarning(note: String): Unit = {
|
||||
log.error(s"$note; some vehicle might not know that ${player.Name} is no longer sitting in it")
|
||||
}
|
||||
if (player.GUID == player_guid) {
|
||||
//normally disembarking from a mount
|
||||
(sessionData.zoning.interstellarFerry.orElse(continent.GUID(player.VehicleSeated)) match {
|
||||
|
|
@ -295,10 +293,7 @@ class VehicleOperations(
|
|||
case out @ Some(_: Mountable) =>
|
||||
out
|
||||
case _ =>
|
||||
dismountWarning(
|
||||
s"DismountVehicleMsg: player ${player.Name}_guid not considered seated in a mountable entity"
|
||||
)
|
||||
sendResponse(DismountVehicleMsg(player_guid, bailType, wasKickedByDriver))
|
||||
dError(s"DismountVehicleMsg: player ${player.Name} not considered seated in a mountable entity", player)
|
||||
None
|
||||
}) match {
|
||||
case Some(_) if serverVehicleControlVelocity.nonEmpty =>
|
||||
|
|
@ -325,15 +320,14 @@ class VehicleOperations(
|
|||
}
|
||||
|
||||
case None =>
|
||||
dismountWarning(
|
||||
s"DismountVehicleMsg: can not find where player ${player.Name}_guid is seated in mountable ${player.VehicleSeated}"
|
||||
)
|
||||
dError(s"DismountVehicleMsg: can not find where player ${player.Name}_guid is seated in mountable ${player.VehicleSeated}", player)
|
||||
}
|
||||
case _ =>
|
||||
dismountWarning(s"DismountVehicleMsg: can not find mountable entity ${player.VehicleSeated}")
|
||||
dError(s"DismountVehicleMsg: can not find mountable entity ${player.VehicleSeated}", player)
|
||||
}
|
||||
} else {
|
||||
//kicking someone else out of a mount; need to own that mount/mountable
|
||||
val dWarn: (String, Player)=> Unit = dismountWarning(bailType, wasKickedByDriver)
|
||||
player.avatar.vehicle match {
|
||||
case Some(obj_guid) =>
|
||||
(
|
||||
|
|
@ -353,23 +347,47 @@ class VehicleOperations(
|
|||
case Some(seat_num) =>
|
||||
obj.Actor ! Mountable.TryDismount(tplayer, seat_num, bailType)
|
||||
case None =>
|
||||
dismountWarning(
|
||||
s"DismountVehicleMsg: can not find where other player ${player.Name}_guid is seated in mountable $obj_guid"
|
||||
)
|
||||
dError(s"DismountVehicleMsg: can not find where other player ${tplayer.Name} is seated in mountable $obj_guid", tplayer)
|
||||
}
|
||||
case (None, _) => ;
|
||||
log.warn(s"DismountVehicleMsg: ${player.Name} can not find his vehicle")
|
||||
case (_, None) => ;
|
||||
log.warn(s"DismountVehicleMsg: player $player_guid could not be found to kick, ${player.Name}")
|
||||
case (None, _) =>
|
||||
dWarn(s"DismountVehicleMsg: ${player.Name} can not find his vehicle", player)
|
||||
case (_, None) =>
|
||||
dWarn(s"DismountVehicleMsg: player $player_guid could not be found to kick, ${player.Name}", player)
|
||||
case _ =>
|
||||
log.warn(s"DismountVehicleMsg: object is either not a Mountable or not a Player")
|
||||
dWarn(s"DismountVehicleMsg: object is either not a Mountable or not a Player", player)
|
||||
}
|
||||
case None =>
|
||||
log.warn(s"DismountVehicleMsg: ${player.Name} does not own a vehicle")
|
||||
dWarn(s"DismountVehicleMsg: ${player.Name} does not own a vehicle", player)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def dismountWarning(
|
||||
bailAs: BailType.Value,
|
||||
kickedByDriver: Boolean
|
||||
)
|
||||
(
|
||||
note: String,
|
||||
player: Player
|
||||
): Unit = {
|
||||
log.warn(note)
|
||||
player.VehicleSeated = None
|
||||
sendResponse(DismountVehicleMsg(player.GUID, bailAs, kickedByDriver))
|
||||
}
|
||||
|
||||
private def dismountError(
|
||||
bailAs: BailType.Value,
|
||||
kickedByDriver: Boolean
|
||||
)
|
||||
(
|
||||
note: String,
|
||||
player: Player
|
||||
): Unit = {
|
||||
log.error(s"$note; some vehicle might not know that ${player.Name} is no longer sitting in it")
|
||||
player.VehicleSeated = None
|
||||
sendResponse(DismountVehicleMsg(player.GUID, bailAs, kickedByDriver))
|
||||
}
|
||||
|
||||
def handleMountVehicleCargo(pkt: MountVehicleCargoMsg): Unit = {
|
||||
val MountVehicleCargoMsg(_, cargo_guid, carrier_guid, _) = pkt
|
||||
(continent.GUID(cargo_guid), continent.GUID(carrier_guid)) match {
|
||||
|
|
|
|||
|
|
@ -82,19 +82,16 @@ object Deployables {
|
|||
val zone = target.Zone
|
||||
val events = zone.LocalEvents
|
||||
val item = target.Definition.Item
|
||||
target.OwnerName match {
|
||||
case Some(owner) =>
|
||||
zone.Players.find { p => owner.equals(p.name) } match {
|
||||
case Some(p) =>
|
||||
if (p.deployables.Remove(target)) {
|
||||
events ! LocalServiceMessage(owner, LocalAction.DeployableUIFor(item))
|
||||
}
|
||||
case None => ;
|
||||
}
|
||||
target.OwnerName
|
||||
.foreach { owner =>
|
||||
zone.LivePlayers.find { p => owner.equals(p.Name) }
|
||||
.orElse(zone.Corpses.find { c => owner.equals(c.Name) })
|
||||
.foreach { p =>
|
||||
p.Actor ! Player.LoseDeployable(target)
|
||||
}
|
||||
target.Owner = None
|
||||
target.OwnerName = None
|
||||
case None => ;
|
||||
}
|
||||
}
|
||||
events ! LocalServiceMessage(
|
||||
s"${target.Faction}",
|
||||
LocalAction.DeployableMapIcon(
|
||||
|
|
@ -114,6 +111,7 @@ object Deployables {
|
|||
* @return all previously-owned deployables after they have been processed;
|
||||
* boomers are listed before all other deployable types
|
||||
*/
|
||||
//noinspection ScalaUnusedSymbol
|
||||
def Disown(zone: Zone, avatar: Avatar, replyTo: ActorRef): List[Deployable] = {
|
||||
avatar.deployables
|
||||
.Clear()
|
||||
|
|
|
|||
|
|
@ -802,7 +802,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
|||
//choose
|
||||
if (target.Health > 0) {
|
||||
//alive
|
||||
if (target.Health <= 25 && target.Health + damageToHealth > 25 &&
|
||||
if (target.Health <= 25 &&
|
||||
(player.avatar.implants.flatten.find { _.definition.implantType == ImplantType.SecondWind } match {
|
||||
case Some(wind) => wind.initialized
|
||||
case _ => false
|
||||
|
|
@ -810,8 +810,8 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
|||
//activate second wind
|
||||
player.Health += 25
|
||||
player.LogActivity(HealFromImplant(ImplantType.SecondWind, 25))
|
||||
avatarActor ! AvatarActor.ResetImplant(ImplantType.SecondWind)
|
||||
avatarActor ! AvatarActor.RestoreStamina(25)
|
||||
avatarActor ! AvatarActor.ResetImplant(ImplantType.SecondWind)
|
||||
}
|
||||
//take damage/update
|
||||
DamageAwareness(target, cause, damageToHealth, damageToArmor, damageToStamina, damageToCapacitor)
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
|
|||
|
||||
def UpdateNtuUI(vehicle: Vehicle with NtuContainer): Unit = {
|
||||
if (vehicle.Seats.values.exists(_.isOccupied)) {
|
||||
val display = scala.math.ceil(vehicle.NtuCapacitorScaled).toLong
|
||||
val display = vehicle.NtuCapacitorScaled.toLong
|
||||
vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
|
||||
vehicle.Actor.toString,
|
||||
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vehicle.GUID, 45, display)
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ trait SectorTraits {
|
|||
* @param eqFunc a custom equivalence function to distinguish between the entities in the list
|
||||
* @tparam A the type of object that will be the entities stored in the list
|
||||
*/
|
||||
class SectorListOf[A](eqFunc: (A, A) => Boolean = (a: A, b: A) => a equals b) {
|
||||
class SectorListOf[A](eqFunc: (A, A) => Boolean = (a: A, b: A) => a == b) {
|
||||
private val internalList: ListBuffer[A] = ListBuffer[A]()
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue