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:
Fate-JH 2023-05-02 19:08:32 -04:00
parent 72572ad125
commit d636b3593e
7 changed files with 164 additions and 72 deletions

View file

@ -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))
}
}
}

View file

@ -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, _)

View file

@ -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 {

View file

@ -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()

View file

@ -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)

View file

@ -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)

View file

@ -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]()
/**