Persistence #1 featuring quill (#508)

* Add .scalafmt.conf

* Adopt quill for database access

* Removed postgresql-async
* Refactored all instances of database access
* Creating duplicate characters of the same account is no longer possible
* Rewrote large parts of LoginSessionActor

* Implement migrations

* Move overrides into subdirectory

* Make usernames case insensitive

* Use LOWER(?) comparison instead of storing lowercased username

* import scala.util.{Success, Failure}

* Add config and joda-time dependencies

* Add sbt-scalafmt

* Use defaultWithAlign scalafmt preset

* Format all

* Add scalafix

* Remove unused imports

* Don't lowercase username when inserting

* Update readme

* Listen on worldserver.Hostname address

* Remove database test on startup

It could fail when the global thread pool is busy loading zone
maps. Migrations run on the main thread and also serve the
purpose of verifying the database configuration so it's fine to
remove the test altogether.

* Refactor chat message handlers, zones

What started as a small change to how zones are stored turned
into a pretty big effort of refactoring the chat message handler.
The !hack command was removed, the /capturebase commandwas added.

* Expose db ports in docker-compose.yml

* Silence property override log

* Rework configuration

* Unify configuration using the typesafe.config library
* Add configuration option for public address
* Configuration is now loaded from application.conf rather than worldserver.ini
* Refactor PsLogin and remove unnecessary logging
* Move pslogin into net.psforever.pslogin namespace

* Fix coverage
This commit is contained in:
Jakob Gillich 2020-07-14 05:54:05 +02:00 committed by GitHub
parent 88b194fde2
commit e0defe8240
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
850 changed files with 144487 additions and 47476 deletions

3
.gitignore vendored
View file

@ -13,8 +13,7 @@ out/
project/metals.sbt project/metals.sbt
# User configs # User configs
config/worldserver.ini config/psforever.conf
pslogin/src/main/resources/user.conf
# Log files # Log files
*.log *.log

6
.scalafix.conf Normal file
View file

@ -0,0 +1,6 @@
rules = [
RemoveUnused
]
RemoveUnused.imports = true
RemoveUnused.privates = false
RemoveUnused.locals = false

3
.scalafmt.conf Normal file
View file

@ -0,0 +1,3 @@
version = 2.6.1
preset = defaultWithAlign
maxColumn = 120

View file

@ -78,7 +78,11 @@ The Login and World servers require PostgreSQL for persistence.
- Linux - [Debian](https://www.postgresql.org/download/linux/debian/) or [Ubuntu](https://www.postgresql.org/download/linux/ubuntu/) - Linux - [Debian](https://www.postgresql.org/download/linux/debian/) or [Ubuntu](https://www.postgresql.org/download/linux/ubuntu/)
- macOS - Application https://www.postgresql.org/download/ (or `brew install postgresql && brew services start postgresql`) - macOS - Application https://www.postgresql.org/download/ (or `brew install postgresql && brew services start postgresql`)
The default database is named `psforever` and the credentials are `psforever:psforever`. To change these, make a copy of [`config/worldserver.ini.dist`](config/worldserver.ini.dist) to `config/worldserver.ini` and change the corresponding fields in the database section. This database user will need ALL access to tables, sequences, and functions. The default database is named `psforever` and the credentials are
`psforever:psforever`. To change these, create a configuration file at
`config/psforever.conf`. For configuration options and their defaults, see
[`pslogin/src/main/resources/application.conf`]. This database user will need
ALL access to tables, sequences, and functions.
The permissions required can be summarized by the SQL below. The permissions required can be summarized by the SQL below.
Loading this in requires access to a graphical tool such as [pgAdmin](https://www.pgadmin.org/download/) (highly recommended) or a PostgreSQL terminal (`psql`) for advanced users. Loading this in requires access to a graphical tool such as [pgAdmin](https://www.pgadmin.org/download/) (highly recommended) or a PostgreSQL terminal (`psql`) for advanced users.
@ -95,9 +99,9 @@ ALTER DEFAULT PRIVILEGES IN SCHEMA PUBLIC GRANT ALL ON FUNCTIONS TO psforever;
**NOTE:** applying default privileges _after_ importing the schema will not apply them to existing objects. To fix this, you must drop all objects and try again or apply permissions manually using the Query Tool / `psql`. **NOTE:** applying default privileges _after_ importing the schema will not apply them to existing objects. To fix this, you must drop all objects and try again or apply permissions manually using the Query Tool / `psql`.
Now you need to synchronize the schema. This is currently available in [`schema.sql`](schema.sql). The server will automatically apply the latest schema. Migrations can also be applied manually using
To do this right click on the psforever database -> Query Tool... -> Copy and paste / Open the `schema.sql` file into the editor -> Hit the "Play/Run" button. The schema should be loaded into the database. the [Flyway CLI](https://flywaydb.org/documentation/commandline/). Existing databases before the
Once you have the schema loaded in, the LoginServer will automatically create accounts on first login. If you'd like a nice account management interface, check out the [PSFPortal](https://github.com/psforever/PSFPortal) web interface. introduction of migrations must be baselined using the `flyway baseline` command.
### Becoming a GM ### Becoming a GM
@ -161,33 +165,6 @@ Using SBT, you can generate documentation for both the common and pslogin projec
Current documentation is available at [https://psforever.github.io/docs/master/index.html](https://psforever.github.io/docs/master/index.html) Current documentation is available at [https://psforever.github.io/docs/master/index.html](https://psforever.github.io/docs/master/index.html)
## Troubleshooting
#### Unable to initialize pscrypto
If you get an error like below
```
12:17:28.037 [main] ERROR PsLogin - Unable to initialize pscrypto
java.lang.UnsatisfiedLinkError: Unable to load library 'pscrypto': Native library (win32-x86-64/pscrypto.dll) not found in resource path
```
Then you are missing the native library required to provide cryptographic functions to the login server. To fix this, you need a binary build of [PSCrypto](#downloading-pscrypto).
If you are still having trouble on Linux, try putting the library in `root directory/pscrypto-lib/libpscrypto.so`.
## Contributing
Please fork the project and provide a pull request to contribute code. Coding guidelines and contribution checklists coming soon.
## Get in touch
- Website: http://psforever.net
- Discord (chat with us): https://discord.gg/0nRe5TNbTYoUruA4
- Join the #code channel and ask any questions you have there
Chord is the lead developer and you can contact him on Discord as Chord or by email [chord@tuta.io](mailto:chord@tuta.io). Discord is preferred.
## Tools ## Tools
### decodePackets ### decodePackets
@ -217,6 +194,33 @@ psf-decode-packets -o ./output-directory foo.gcap bar.gcap
By default, decodePackets takes in `.gcap` files, but it can also take gcapy ascii files with the By default, decodePackets takes in `.gcap` files, but it can also take gcapy ascii files with the
`-p` option. Run `psf-decode-packets --help` to get usage info. `-p` option. Run `psf-decode-packets --help` to get usage info.
## Troubleshooting
#### Unable to initialize pscrypto
If you get an error like below
```
12:17:28.037 [main] ERROR PsLogin - Unable to initialize pscrypto
java.lang.UnsatisfiedLinkError: Unable to load library 'pscrypto': Native library (win32-x86-64/pscrypto.dll) not found in resource path
```
Then you are missing the native library required to provide cryptographic functions to the login server. To fix this, you need a binary build of [PSCrypto](#downloading-pscrypto).
If you are still having trouble on Linux, try putting the library in `root directory/pscrypto-lib/libpscrypto.so`.
## Contributing
Please fork the project and provide a pull request to contribute code. Coding guidelines and contribution checklists coming soon.
## Get in touch
- Website: http://psforever.net
- Discord (chat with us): https://discord.gg/0nRe5TNbTYoUruA4
- Join the #code channel and ask any questions you have there
Chord is the lead developer and you can contact him on Discord as Chord or by email [chord@tuta.io](mailto:chord@tuta.io). Discord is preferred.
## License ## License
GNU GPLv3. See LICENSE.md for the full copy. GNU GPLv3. See LICENSE.md for the full copy.

160
build.sbt
View file

@ -4,8 +4,18 @@ lazy val commonSettings = Seq(
organization := "net.psforever", organization := "net.psforever",
version := "1.0.2-SNAPSHOT", version := "1.0.2-SNAPSHOT",
scalaVersion := "2.13.2", scalaVersion := "2.13.2",
scalacOptions := Seq("-unchecked", "-feature", "-deprecation", "-encoding", "utf8", "-language:postfixOps"), semanticdbEnabled := true,
semanticdbVersion := scalafixSemanticdb.revision,
scalacOptions := Seq(
"-unchecked",
"-feature",
"-deprecation",
"-encoding",
"utf8",
"-language:postfixOps",
"-Wunused:imports",
"-Xmacro-settings:materialize-derivations"
),
// Quiet test options // Quiet test options
// https://github.com/etorreborre/specs2/blob/8305db76c5084e4b3ce5827ce23117f6fb6beee4/common/shared/src/main/scala/org/specs2/main/Report.scala#L94 // https://github.com/etorreborre/specs2/blob/8305db76c5084e4b3ce5827ce23117f6fb6beee4/common/shared/src/main/scala/org/specs2/main/Report.scala#L94
// https://etorreborre.github.io/specs2/guide/SPECS2-2.4.17/org.specs2.guide.Runners.html // https://etorreborre.github.io/specs2/guide/SPECS2-2.4.17/org.specs2.guide.Runners.html
@ -14,41 +24,56 @@ lazy val commonSettings = Seq(
testOptions in QuietTest += Tests.Argument(TestFrameworks.ScalaTest, "-oCEHILMNOPQRX"), testOptions in QuietTest += Tests.Argument(TestFrameworks.ScalaTest, "-oCEHILMNOPQRX"),
// Trick taken from https://groups.google.com/d/msg/scala-user/mxV9ok7J_Eg/kt-LnsrD0bkJ // Trick taken from https://groups.google.com/d/msg/scala-user/mxV9ok7J_Eg/kt-LnsrD0bkJ
// scaladoc flags: https://github.com/scala/scala/blob/2.11.x/src/scaladoc/scala/tools/nsc/doc/Settings.scala // scaladoc flags: https://github.com/scala/scala/blob/2.11.x/src/scaladoc/scala/tools/nsc/doc/Settings.scala
scalacOptions in (Compile,doc) := { Seq( scalacOptions in (Compile, doc) ++= Seq(
"-groups", "-groups",
"-implicits", "-implicits",
"-doc-title", "PSF-LoginServer - ", "-doc-title",
"-doc-version", "master", "PSF-LoginServer - ",
"-doc-footer", "Copyright PSForever", "-doc-version",
"master",
"-doc-footer",
"Copyright PSForever",
// For non unidoc builds, you may need bd.getName before the template parameter // For non unidoc builds, you may need bd.getName before the template parameter
"-doc-source-url", "https://github.com/psforever/PSF-LoginServer/blob/master/€{FILE_PATH}.scala", "-doc-source-url",
"-sourcepath", baseDirectory.value.getAbsolutePath // needed for scaladoc relative source paths "https://github.com/psforever/PSF-LoginServer/blob/master/€{FILE_PATH}.scala",
) "-sourcepath",
}, baseDirectory.value.getAbsolutePath // needed for scaladoc relative source paths
),
classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.Flat, classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.Flat,
resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots", resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots",
libraryDependencies ++= Seq( libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-actor" % "2.6.5", "com.typesafe.akka" %% "akka-actor" % "2.6.6",
"com.typesafe.akka" %% "akka-testkit" % "2.6.5" % "test", "com.typesafe.akka" %% "akka-slf4j" % "2.6.6",
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.2", "com.typesafe.akka" %% "akka-protobuf-v3" % "2.6.6",
"org.specs2" %% "specs2-core" % "4.9.4" % "test", "com.typesafe.akka" %% "akka-stream" % "2.6.6",
"org.scalatest" %% "scalatest" % "3.1.2" % "test", "com.typesafe.akka" %% "akka-testkit" % "2.6.6" % "test",
"org.scodec" %% "scodec-core" % "1.11.7", "com.typesafe.akka" %% "akka-actor-typed" % "2.6.6",
"net.java.dev.jna" % "jna" % "5.5.0", "com.typesafe.akka" %% "akka-cluster-typed" % "2.6.6",
"com.typesafe.akka" %% "akka-slf4j" % "2.6.5", "com.typesafe.scala-logging" %% "scala-logging" % "3.9.2",
"ch.qos.logback" % "logback-classic" % "1.2.3", "org.specs2" %% "specs2-core" % "4.9.4" % "test",
"org.log4s" %% "log4s" % "1.8.2", "org.scalatest" %% "scalatest" % "3.1.2" % "test",
"org.fusesource.jansi" % "jansi" % "1.12", "org.scodec" %% "scodec-core" % "1.11.7",
"net.java.dev.jna" % "jna" % "5.5.0",
"com.typesafe.akka" %% "akka-slf4j" % "2.6.5",
"ch.qos.logback" % "logback-classic" % "1.2.3",
"org.log4s" %% "log4s" % "1.8.2",
"org.fusesource.jansi" % "jansi" % "1.12",
"org.scoverage" %% "scalac-scoverage-plugin" % "1.4.1", "org.scoverage" %% "scalac-scoverage-plugin" % "1.4.1",
"com.github.nscala-time" %% "nscala-time" % "2.24.0", "com.github.nscala-time" %% "nscala-time" % "2.24.0",
"com.github.postgresql-async" %% "postgresql-async" % "0.3.0", "com.github.t3hnar" %% "scala-bcrypt" % "4.1",
"com.github.t3hnar" %% "scala-bcrypt" % "4.1", "org.scala-graph" %% "graph-core" % "1.13.1",
"org.ini4j" % "ini4j" % "0.5.4", "io.kamon" %% "kamon-bundle" % "2.1.0",
"org.scala-graph" %% "graph-core" % "1.13.1", "io.kamon" %% "kamon-apm-reporter" % "2.1.0",
"io.kamon" %% "kamon-bundle" % "2.1.0", "org.json4s" %% "json4s-native" % "3.6.8",
"io.kamon" %% "kamon-apm-reporter" % "2.1.0", "com.typesafe.akka" %% "akka-stream" % "2.6.5",
"org.json4s" %% "json4s-native" % "3.6.8", "io.getquill" %% "quill-jasync-postgres" % "3.5.2",
"com.typesafe.akka" %% "akka-stream" % "2.6.5" "org.flywaydb" % "flyway-core" % "6.5.0",
"org.postgresql" % "postgresql" % "42.2.14",
"com.typesafe" % "config" % "1.4.0",
"com.github.pureconfig" %% "pureconfig" % "0.13.0",
"com.beachape" %% "enumeratum" % "1.6.1",
"joda-time" % "joda-time" % "2.10.6",
"commons-io" % "commons-io" % "2.6"
) )
) )
@ -61,63 +86,58 @@ lazy val pscryptoSettings = Seq(
lazy val psloginPackSettings = Seq( lazy val psloginPackSettings = Seq(
packMain := Map("ps-login" -> "PsLogin"), packMain := Map("ps-login" -> "PsLogin"),
packArchivePrefix := "pslogin", packArchivePrefix := "pslogin",
packExtraClasspath := Map("ps-login" -> Seq("${PROG_HOME}/pscrypto-lib", packExtraClasspath := Map("ps-login" -> Seq("${PROG_HOME}/pscrypto-lib", "${PROG_HOME}/config")),
"${PROG_HOME}/config")), packResourceDir += (baseDirectory.value / "pscrypto-lib" -> "pscrypto-lib"),
packResourceDir += (baseDirectory.value / "pscrypto-lib" -> "pscrypto-lib"), packResourceDir += (baseDirectory.value / "config" -> "config"),
packResourceDir += (baseDirectory.value / "config" -> "config"),
packResourceDir += (baseDirectory.value / "pslogin/src/main/resources" -> "config") packResourceDir += (baseDirectory.value / "pslogin/src/main/resources" -> "config")
) )
lazy val root = (project in file(".")). lazy val root = (project in file("."))
configs(QuietTest). .configs(QuietTest)
enablePlugins(PackPlugin). .enablePlugins(PackPlugin)
settings(commonSettings: _*). .settings(commonSettings: _*)
settings(psloginPackSettings: _*). .settings(psloginPackSettings: _*)
enablePlugins(ScalaUnidocPlugin). .enablePlugins(ScalaUnidocPlugin)
aggregate(pslogin, common). .aggregate(pslogin, common)
dependsOn(pslogin, common)
lazy val pslogin = (project in file("pslogin")). lazy val pslogin = (project in file("pslogin"))
configs(QuietTest). .configs(QuietTest)
settings(commonSettings: _*). .settings(commonSettings: _*)
settings( .settings(
name := "pslogin", name := "pslogin",
// ActorTests have specific timing requirements and will be flaky if run in parallel // ActorTests have specific timing requirements and will be flaky if run in parallel
parallelExecution in Test := false, parallelExecution in Test := false,
// TODO(chord): remove exclusion when WorldSessionActor is refactored: https://github.com/psforever/PSF-LoginServer/issues/279 // TODO(chord): remove exclusion when WorldSessionActor is refactored: https://github.com/psforever/PSF-LoginServer/issues/279
coverageExcludedPackages := "WorldSessionActor.*;zonemaps.*", coverageExcludedPackages := "net.psforever.pslogin.WorldSessionActor.*;net.psforever.pslogin.zonemaps.*",
// Copy all tests from Test -> QuietTest (we're only changing the run options) // Copy all tests from Test -> QuietTest (we're only changing the run options)
inConfig(QuietTest)(Defaults.testTasks) inConfig(QuietTest)(Defaults.testTasks)
). )
settings(pscryptoSettings: _*). .settings(pscryptoSettings: _*)
dependsOn(common) .dependsOn(common)
lazy val common = (project in file("common")). lazy val common = (project in file("common"))
configs(QuietTest). .configs(QuietTest)
settings(commonSettings: _*). .settings(commonSettings: _*)
settings( .settings(
name := "common", name := "common",
// Copy all tests from Test -> QuietTest (we're only changing the run options) // Copy all tests from Test -> QuietTest (we're only changing the run options)
inConfig(QuietTest)(Defaults.testTasks) inConfig(QuietTest)(Defaults.testTasks)
). )
settings(pscryptoSettings: _*) .settings(pscryptoSettings: _*)
lazy val decodePackets = (project in file("tools/decode-packets")). lazy val decodePackets = (project in file("tools/decode-packets"))
enablePlugins(PackPlugin). .enablePlugins(PackPlugin)
settings(commonSettings: _*). .settings(commonSettings: _*)
settings(decodePacketsPackSettings: _*). .settings(decodePacketsPackSettings: _*)
settings( .settings(
libraryDependencies ++= Seq( libraryDependencies ++= Seq(
"org.scala-lang.modules" %% "scala-parallel-collections" % "0.2.0", "org.scala-lang.modules" %% "scala-parallel-collections" % "0.2.0",
"com.github.scopt" %% "scopt" % "4.0.0-RC2", "com.github.scopt" %% "scopt" % "4.0.0-RC2"
"commons-io" % "commons-io" % "2.6"
) )
). )
dependsOn(common) .dependsOn(common)
lazy val decodePacketsPackSettings = Seq( lazy val decodePacketsPackSettings = Seq(packMain := Map("psf-decode-packets" -> "DecodePackets"))
packMain := Map("psf-decode-packets" -> "DecodePackets"),
)
// Special test configuration for really quiet tests (used in CI) // Special test configuration for really quiet tests (used in CI)
lazy val QuietTest = config("quiet") extend(Test) lazy val QuietTest = config("quiet") extend (Test)

View file

@ -1,13 +1,13 @@
// Copyright (c) 2017 PSForever
// Taken from http://code.hootsuite.com/logging-contextual-info-in-an-asynchronous-scala-application/
package akka.actor package akka.actor
// Taken from https://medium.com/hootsuite-engineering/logging-contextual-info-in-an-asynchronous-scala-application-8ea33bfec9b3
import akka.util.Timeout import akka.util.Timeout
import org.slf4j.MDC import org.slf4j.MDC
import scala.concurrent.Future import scala.concurrent.Future
trait MDCContextAware extends Actor with ActorLogging { trait MDCContextAware extends Actor with ActorLogging {
import MDCContextAware._ import MDCContextAware._
// This is why this needs to be in package akka.actor // This is why this needs to be in package akka.actor
@ -52,7 +52,7 @@ object MDCContextAware {
* the current MDC values. Note: we MUST capture the ActorContext in order for senders * the current MDC values. Note: we MUST capture the ActorContext in order for senders
* to be correct! This was a bug from the original author. * to be correct! This was a bug from the original author.
*/ */
def !>(msg: Any)(implicit context: ActorContext) : Unit = def !>(msg: Any)(implicit context: ActorContext): Unit =
ref.tell(MdcMsg(MDC.getCopyOfContextMap, msg), context.self) ref.tell(MdcMsg(MDC.getCopyOfContextMap, msg), context.self)
/** /**
@ -63,4 +63,4 @@ object MDCContextAware {
ref.ask(MdcMsg(MDC.getCopyOfContextMap, msg), context.self) ref.ask(MdcMsg(MDC.getCopyOfContextMap, msg), context.self)
} }
} }
} }

View file

@ -0,0 +1,69 @@
package akka.actor
// Taken from https://medium.com/hootsuite-engineering/logging-contextual-info-in-an-asynchronous-scala-application-8ea33bfec9b3
import org.slf4j.MDC
import scala.concurrent.ExecutionContext
trait MDCPropagatingExecutionContext extends ExecutionContext {
// name the self-type "self" so we can refer to it inside the nested class
self =>
override def prepare(): ExecutionContext =
new ExecutionContext {
// Save the call-site MDC state
val context = MDC.getCopyOfContextMap
def execute(r: Runnable): Unit =
self.execute(new Runnable {
def run(): Unit = {
// Save the existing execution-site MDC state
val oldContext = MDC.getCopyOfContextMap
try {
// Set the call-site MDC state into the execution-site MDC
if (context != null)
MDC.setContextMap(context)
else
MDC.clear()
r.run()
} finally {
// Restore the existing execution-site MDC state
if (oldContext != null)
MDC.setContextMap(oldContext)
else
MDC.clear()
}
}
})
def reportFailure(t: Throwable): Unit = self.reportFailure(t)
}
}
object MDCPropagatingExecutionContext {
object Implicits {
// Convenience wrapper around the Scala global ExecutionContext so you can just do:
// import MDCPropagatingExecutionContext.Implicits.global
implicit lazy val global = MDCPropagatingExecutionContextWrapper(ExecutionContext.Implicits.global)
}
}
/**
* Wrapper around an existing ExecutionContext that makes it propagate MDC information.
*/
class MDCPropagatingExecutionContextWrapper(wrapped: ExecutionContext)
extends ExecutionContext
with MDCPropagatingExecutionContext {
override def execute(r: Runnable): Unit = wrapped.execute(r)
override def reportFailure(t: Throwable): Unit = wrapped.reportFailure(t)
}
object MDCPropagatingExecutionContextWrapper {
def apply(wrapped: ExecutionContext): MDCPropagatingExecutionContextWrapper = {
new MDCPropagatingExecutionContextWrapper(wrapped)
}
}

View file

@ -1,7 +1,7 @@
// Copyright (c) 2017 PSForever // Copyright (c) 2017 PSForever
package net.psforever package net.psforever
class ObjectFinalizedException(msg : String) extends Exception(msg) class ObjectFinalizedException(msg: String) extends Exception(msg)
trait IFinalizable { trait IFinalizable {
var closed = false var closed = false
@ -11,12 +11,14 @@ trait IFinalizable {
} }
def assertNotClosed = { def assertNotClosed = {
if(closed) if (closed)
throw new ObjectFinalizedException(this.getClass.getCanonicalName + ": already finalized. Cannot interact with object") throw new ObjectFinalizedException(
this.getClass.getCanonicalName + ": already finalized. Cannot interact with object"
)
} }
override def finalize() = { override def finalize() = {
if(!closed) if (!closed)
println(this.getClass.getCanonicalName + ": class not closed. memory leaked") println(this.getClass.getCanonicalName + ": class not closed. memory leaked")
} }
} }

View file

@ -1,240 +0,0 @@
// Copyright (c) 2019 PSForever
package net.psforever.config
import org.ini4j
import scala.reflect.ClassTag
import scala.reflect.runtime.universe.TypeTag
import scala.annotation.implicitNotFound
import scala.concurrent.duration._
import scala.collection.mutable.Map
case class ConfigValueMapper[T](name: String)(f: (String => Option[T])) {
def apply(t: String): Option[T] = f(t)
}
object ConfigValueMapper {
import scala.language.implicitConversions
implicit val toInt : ConfigValueMapper[Int] = ConfigValueMapper[Int]("toInt") { e =>
try {
Some(e.toInt)
} catch {
case e: Exception => None
}
}
// TypeTag is necessary to be able to retrieve an instance of the Enum class
// at runtime as it is usually erased at runtime. This is low cost as its only
// used during the config parsing
implicit def toEnum[E <: Enumeration#Value](implicit m: TypeTag[E]) : ConfigValueMapper[E] = ConfigValueMapper[E]("toEnum") { e =>
try {
Some(EnumReflector.withName[E](e))
} catch {
case e: Exception => None
}
}
implicit val toBool : ConfigValueMapper[Boolean] = ConfigValueMapper[Boolean]("toBool") { e =>
if (e == "yes") {
Some(true)
} else if (e == "no") {
Some(false)
} else {
None
}
}
implicit val toFloat : ConfigValueMapper[Float] = ConfigValueMapper[Float]("toFloat") { e =>
try {
Some(e.toFloat)
} catch {
case e: Exception => None
}
}
implicit val toDuration : ConfigValueMapper[Duration] = ConfigValueMapper[Duration]("toDuration") { e =>
try {
Some(Duration(e))
} catch {
case e: Exception => None
}
}
implicit val toStr : ConfigValueMapper[String] = ConfigValueMapper[String]("toString") { e =>
Some(e)
}
}
sealed trait ConfigEntry {
type Value
val key : String
val default : Value
def getType : String
val constraints : Seq[Constraint[Value]]
def read(v: String): Option[Value]
}
final case class ConfigEntryString(key: String, default : String, constraints : Constraint[String]*) extends ConfigEntry {
type Value = String
def getType = "String"
def read(v : String) = ConfigValueMapper.toStr(v)
}
final case class ConfigEntryInt(key: String, default : Int, constraints : Constraint[Int]*) extends ConfigEntry {
type Value = Int
def getType = "Int"
def read(v : String) = ConfigValueMapper.toInt(v)
}
final case class ConfigEntryBool(key: String, default : Boolean, constraints : Constraint[Boolean]*) extends ConfigEntry {
type Value = Boolean
def getType = "Bool"
def read(v : String) = ConfigValueMapper.toBool(v)
}
final case class ConfigEntryEnum[E <: Enumeration](key: String, default : E#Value)(implicit m : TypeTag[E#Value], implicit val m2 : TypeTag[E#ValueSet]) extends ConfigEntry {
type Value = E#Value
val constraints : Seq[Constraint[E#Value]] = Seq()
def getType = EnumReflector.values[E#ValueSet](m2).mkString(", ")
def read(v : String) = ConfigValueMapper.toEnum[E#Value](m)(v)
}
final case class ConfigEntryFloat(key: String, default : Float, constraints : Constraint[Float]*) extends ConfigEntry {
type Value = Float
def getType = "Float"
def read(v : String) = ConfigValueMapper.toFloat(v)
}
final case class ConfigEntryTime(key: String, default : Duration, constraints : Constraint[Duration]*) extends ConfigEntry {
type Value = Duration
def getType = "Time"
def read(v : String) = ConfigValueMapper.toDuration(v)
}
case class ConfigSection(name: String, entries: ConfigEntry*)
@implicitNotFound("Nothing was inferred")
sealed trait ConfigTypeRequired[-T]
object ConfigTypeRequired {
implicit object cfgTypeRequired extends ConfigTypeRequired[Any]
//We do not want Nothing to be inferred, so make an ambiguous implicit
implicit object `\n The Get[T] call needs a type T matching the corresponding ConfigEntry` extends ConfigTypeRequired[Nothing]
}
trait ConfigParser {
protected var config_map : Map[String, Any] = Map()
protected val config_template : Seq[ConfigSection]
// Misuse of this function can lead to run time exceptions when the types don't match
// ClassTag is needed due to type erasure on T
// https://dzone.com/articles/scala-classtag-a-simple-use-case
def Get[T : ConfigTypeRequired](key : String)(implicit m: ClassTag[T]) : T = {
config_map.get(key) match {
case Some(value : T) => value
case None =>
throw new NoSuchElementException(s"Config key '${key}' not found")
case Some(value : Any) =>
throw new ClassCastException(s"Incorrect type T = ${m.runtimeClass.getSimpleName} passed to Get[T]: needed ${value.getClass.getSimpleName}")
}
}
def Load(filename : String) : ValidationResult = {
var map : Map[String, Any] = scala.collection.mutable.Map()
LoadMap(filename, map) match {
case i : Invalid =>
i
case Valid =>
ReplaceConfig(map)
// run post-parse validation only if we successfully parsed
postParseChecks match {
case i : Invalid =>
i
case Valid =>
Valid
}
}
}
def LoadMap(filename : String, map : Map[String, Any]) : ValidationResult = {
val ini = new org.ini4j.Ini()
try {
ini.load(new java.io.File(filename))
} catch {
case e : org.ini4j.InvalidFileFormatException =>
return Invalid(e.getMessage)
case e : java.io.FileNotFoundException =>
return Invalid(e.getMessage)
}
val result : Seq[ValidationResult] = config_template.map { section =>
val sectionIni = ini.get(section.name)
if (sectionIni == null)
Seq(Invalid("section.missing", section.name))
else
section.entries.map(parseSection(sectionIni, _, map))
}.reduceLeft((x, y) => x ++ y)
val errors : Seq[Invalid] = result.collect { case iv : Invalid => iv }
if (errors.length > 0)
errors.reduceLeft((x, y) => x ++ y)
else
Valid
}
def ReplaceConfig(map : Map[String, Any]) : Unit = {
config_map = map
}
def GetRawConfig : Map[String, Any] = {
config_map
}
def FormatErrors(invalidResult : Invalid) : Seq[String] = {
var count = 0;
invalidResult.errors.map((error) => {
var message = error.message;
if (error.args.length > 0)
message += " ("+error.args(0)+")"
count += 1;
s"Error ${count}: ${message}"
});
}
protected def postParseChecks : ValidationResult = {
Valid
}
protected def parseSection(sectionIni : org.ini4j.Profile.Section, entry : ConfigEntry, map : Map[String, Any]) : ValidationResult = {
var rawValue = sectionIni.get(entry.key, 0)
val full_key : String = sectionIni.getName + "." + entry.key
val value = if (rawValue == null) {
println(s"config warning: missing key '${entry.key}', using default value '${entry.default}'")
entry.default
} else {
rawValue = rawValue.stripPrefix("\"").stripSuffix("\"")
entry.read(rawValue) match {
case Some(v) => v
case None => return Invalid(ValidationError(String.format("%s: value format error (expected: %s)", full_key, entry.getType)))
}
}
map += (full_key -> value)
ParameterValidator(entry.constraints, Some(value)) match {
case v @ Valid => v
case i @ Invalid(errors) => {
Invalid(errors.map(x => ValidationError(x.messages.map(full_key + ": " + _), x.args: _*)))
}
}
}
}

View file

@ -1,290 +0,0 @@
// Copyright (c) 2019 PSForever
// Lifted from https://raw.githubusercontent.com/playframework/playframework/2.7.x/core/play/src/main/scala/play/api/data/validation/Validation.scala
package net.psforever.config
/**
* A form constraint.
*
* @tparam T type of values handled by this constraint
* @param name the constraint name, to be displayed to final user
* @param args the message arguments, to format the constraint name
* @param f the validation function
*/
case class Constraint[-T](name: Option[String], args: Seq[Any])(f: (T => ValidationResult)) {
/**
* Run the constraint validation.
*
* @param t the value to validate
* @return the validation result
*/
def apply(t: T): ValidationResult = f(t)
}
/**
* This object provides helpers for creating `Constraint` values.
*
* For example:
* {{{
* val negative = Constraint[Int] {
* case i if i < 0 => Valid
* case _ => Invalid("Must be a negative number.")
* }
* }}}
*/
object Constraint {
/**
* Creates a new anonymous constraint from a validation function.
*
* @param f the validation function
* @return a constraint
*/
def apply[T](f: (T => ValidationResult)): Constraint[T] = apply(None, Nil)(f)
/**
* Creates a new named constraint from a validation function.
*
* @param name the constraint name
* @param args the constraint arguments, used to format the constraint name
* @param f the validation function
* @return a constraint
*/
def apply[T](name: String, args: Any*)(f: (T => ValidationResult)): Constraint[T] = apply(Some(name), args.toSeq)(f)
}
/**
* Defines a set of built-in constraints.
*/
object Constraints extends Constraints
/**
* Defines a set of built-in constraints.
*
* @define emailAddressDoc Defines an emailAddress constraint for `String` values which will validate email addresses.
*
* '''name'''[constraint.email]
* '''error'''[error.email]
*
* @define nonEmptyDoc Defines a required constraint for `String` values, i.e. one in which empty strings are invalid.
*
* '''name'''[constraint.required]
* '''error'''[error.required]
*/
trait Constraints {
private val emailRegex =
"""^[a-zA-Z0-9\.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$""".r
/**
* $emailAddressDoc
*/
def emailAddress(errorMessage: String = "error.email"): Constraint[String] = Constraint[String]("constraint.email") {
e =>
if (e == null) Invalid(ValidationError(errorMessage))
else if (e.trim.isEmpty) Invalid(ValidationError(errorMessage))
else
emailRegex
.findFirstMatchIn(e)
.map(_ => Valid)
.getOrElse(Invalid(ValidationError(errorMessage)))
}
/**
* $emailAddressDoc
*
*/
def emailAddress: Constraint[String] = emailAddress()
/**
* $nonEmptyDoc
*/
def nonEmpty(errorMessage: String = "error.required"): Constraint[String] =
Constraint[String]("constraint.required") { o =>
if (o == null) Invalid(ValidationError(errorMessage))
else if (o.trim.isEmpty) Invalid(ValidationError(errorMessage))
else Valid
}
/**
* $nonEmptyDoc
*
*/
def nonEmpty: Constraint[String] = nonEmpty()
/**
* Defines a minimum value for `Ordered` values, by default the value must be greater than or equal to the constraint parameter
*
* '''name'''[constraint.min(minValue)]
* '''error'''[error.min(minValue)] or [error.min.strict(minValue)]
*/
def min[T](
minValue: T,
strict: Boolean = false,
errorMessage: String = "error.min",
strictErrorMessage: String = "error.min.strict"
)(implicit ordering: scala.math.Ordering[T]): Constraint[T] = Constraint[T]("constraint.min", minValue) { o =>
(ordering.compare(o, minValue).sign, strict) match {
case (1, _) | (0, false) => Valid
case (_, false) => Invalid(ValidationError(errorMessage, minValue))
case (_, true) => Invalid(ValidationError(strictErrorMessage, minValue))
}
}
/**
* Defines a maximum value for `Ordered` values, by default the value must be less than or equal to the constraint parameter
*
* '''name'''[constraint.max(maxValue)]
* '''error'''[error.max(maxValue)] or [error.max.strict(maxValue)]
*/
def max[T](
maxValue: T,
strict: Boolean = false,
errorMessage: String = "error.max",
strictErrorMessage: String = "error.max.strict"
)(implicit ordering: scala.math.Ordering[T]): Constraint[T] = Constraint[T]("constraint.max", maxValue) { o =>
(ordering.compare(o, maxValue).sign, strict) match {
case (-1, _) | (0, false) => Valid
case (_, false) => Invalid(ValidationError(errorMessage, maxValue))
case (_, true) => Invalid(ValidationError(strictErrorMessage, maxValue))
}
}
/**
* Defines a minimum length constraint for `String` values, i.e. the strings length must be greater than or equal to the constraint parameter
*
* '''name'''[constraint.minLength(length)]
* '''error'''[error.minLength(length)]
*/
def minLength(length: Int, errorMessage: String = "error.minLength"): Constraint[String] =
Constraint[String]("constraint.minLength", length) { o =>
require(length >= 0, "string minLength must not be negative")
if (o == null) Invalid(ValidationError(errorMessage, length))
else if (o.size >= length) Valid
else Invalid(ValidationError(errorMessage, length))
}
/**
* Defines a maximum length constraint for `String` values, i.e. the strings length must be less than or equal to the constraint parameter
*
* '''name'''[constraint.maxLength(length)]
* '''error'''[error.maxLength(length)]
*/
def maxLength(length: Int, errorMessage: String = "error.maxLength"): Constraint[String] =
Constraint[String]("constraint.maxLength", length) { o =>
require(length >= 0, "string maxLength must not be negative")
if (o == null) Invalid(ValidationError(errorMessage, length))
else if (o.size <= length) Valid
else Invalid(ValidationError(errorMessage, length))
}
/**
* Defines a regular expression constraint for `String` values, i.e. the string must match the regular expression pattern
*
* '''name'''[constraint.pattern(regex)] or defined by the name parameter.
* '''error'''[error.pattern(regex)] or defined by the error parameter.
*/
def pattern(
regex: => scala.util.matching.Regex,
name: String = "constraint.pattern",
error: String = "error.pattern"
): Constraint[String] = Constraint[String](name, () => regex) { o =>
require(regex != null, "regex must not be null")
require(name != null, "name must not be null")
require(error != null, "error must not be null")
if (o == null) Invalid(ValidationError(error, regex))
else regex.unapplySeq(o).map(_ => Valid).getOrElse(Invalid(ValidationError(error, name)))
}
}
/**
* A validation result.
*/
sealed trait ValidationResult
/**
* Validation was a success.
*/
case object Valid extends ValidationResult
/**
* Validation was a failure.
*
* @param errors the resulting errors
*/
case class Invalid(errors: Seq[ValidationError]) extends ValidationResult {
/**
* Combines these validation errors with another validation failure.
*
* @param other validation failure
* @return a new merged `Invalid`
*/
def ++(other: Invalid): Invalid = Invalid(this.errors ++ other.errors)
}
/**
* This object provides helper methods to construct `Invalid` values.
*/
object Invalid {
/**
* Creates an `Invalid` value with a single error.
*
* @param error the validation error
* @return an `Invalid` value
*/
def apply(error: ValidationError): Invalid = Invalid(Seq(error))
/**
* Creates an `Invalid` value with a single error.
*
* @param error the validation error message
* @param args the validation error message arguments
* @return an `Invalid` value
*/
def apply(error: String, args: Any*): Invalid = Invalid(Seq(ValidationError(error, args: _*)))
}
object ParameterValidator {
def apply[T](constraints: Iterable[Constraint[T]], optionalParam: Option[T]*) =
optionalParam.flatMap {
_.map { param =>
constraints.flatMap {
_(param) match {
case i: Invalid => Some(i)
case _ => None
}
}
}
}.flatten match {
case Nil => Valid
case invalids =>
invalids.reduceLeft { (a, b) =>
a ++ b
}
}
}
/**
* A validation error.
*
* @param messages the error message, if more then one message is passed it will use the last one
* @param args the error message arguments
*/
case class ValidationError(messages: Seq[String], args: Any*) {
lazy val message = messages.last
}
object ValidationError {
def apply(message: String, args: Any*) = new ValidationError(Seq(message), args: _*)
}

View file

@ -1,54 +0,0 @@
// Copyright (c) 2019 PSForever
package net.psforever.config
import scala.reflect.runtime.universe._
/**
* Scala [[Enumeration]] helpers implementing Scala versions of
* Java's [[java.lang.Enum.valueOf(Class[Enum], String)]].
* @author Dmitriy Yefremov (http://yefremov.net/blog/scala-enum-by-name/)
*/
object EnumReflector {
private val mirror: Mirror = runtimeMirror(getClass.getClassLoader)
/**
* Returns a value of the specified enumeration with the given name.
* @param name value name
* @tparam T enumeration type
* @return enumeration value, see [[scala.Enumeration.withName(String)]]
*/
def withName[T <: Enumeration#Value: TypeTag](name: String): T = {
typeOf[T] match {
case valueType @ TypeRef(enumType, _, _) =>
val methodSymbol = factoryMethodSymbol(enumType, "withName")
val moduleSymbol = enumType.termSymbol.asModule
reflect(moduleSymbol, methodSymbol)(name).asInstanceOf[T]
}
}
/**
* Returns the set of values of an enumeration
* @tparam T enumeration type
* @return possible enumeration values, see [[scala.Enumeration.values()]]
*/
def values[T <: Enumeration#ValueSet: TypeTag]: T = {
typeOf[T] match {
case valueType @ TypeRef(enumType, _, _) =>
val methodSymbol = factoryMethodSymbol(enumType, "values")
val moduleSymbol = enumType.termSymbol.asModule
reflect(moduleSymbol, methodSymbol)().asInstanceOf[T]
}
}
private def factoryMethodSymbol(enumType: Type, name : String): MethodSymbol = {
enumType.member(TermName(name)).asMethod
}
private def reflect(module: ModuleSymbol, method: MethodSymbol)(args: Any*): Any = {
val moduleMirror = mirror.reflectModule(module)
val instanceMirror = mirror.reflect(moduleMirror.instance)
instanceMirror.reflectMethod(method)(args:_*)
}
}

View file

@ -4,33 +4,33 @@ package net.psforever.crypto
import com.sun.jna.ptr.IntByReference import com.sun.jna.ptr.IntByReference
import net.psforever.IFinalizable import net.psforever.IFinalizable
import sna.Library import sna.Library
import com.sun.jna.{NativeLibrary, Pointer} import com.sun.jna.Pointer
import scodec.bits.ByteVector import scodec.bits.ByteVector
object CryptoInterface { object CryptoInterface {
final val libName = "pscrypto" final val libName = "pscrypto"
final val fullLibName = libName final val fullLibName = libName
final val PSCRYPTO_VERSION_MAJOR = 1 final val PSCRYPTO_VERSION_MAJOR = 1
final val PSCRYPTO_VERSION_MINOR = 1 final val PSCRYPTO_VERSION_MINOR = 1
/** /**
NOTE: this is a single, global shared library for the entire server's crypto needs * NOTE: this is a single, global shared library for the entire server's crypto needs
*
Unfortunately, access to this object didn't used to be synchronized. I noticed that * Unfortunately, access to this object didn't used to be synchronized. I noticed that
tests for this module were hanging ("arrive at a shared secret" & "must fail to agree on * tests for this module were hanging ("arrive at a shared secret" & "must fail to agree on
a secret..."). This heisenbug was responsible for failed Travis test runs and developer * a secret..."). This heisenbug was responsible for failed Travis test runs and developer
issues as well. Using Windows minidumps, I tracked the issue to a single thread deep in * issues as well. Using Windows minidumps, I tracked the issue to a single thread deep in
pscrypto.dll. It appeared to be executing an EB FE instruction (on Intel x86 this is * pscrypto.dll. It appeared to be executing an EB FE instruction (on Intel x86 this is
`jmp $-2` or jump to self), which is an infinite loop. The stack trace made little to no * `jmp $-2` or jump to self), which is an infinite loop. The stack trace made little to no
sense and after banging my head on the wall for many hours, I assumed that something deep * sense and after banging my head on the wall for many hours, I assumed that something deep
in CryptoPP, the libgcc libraries, or MSVC++ was the cause (or myself). Now all access to * in CryptoPP, the libgcc libraries, or MSVC++ was the cause (or myself). Now all access to
pscrypto functions that allocate and deallocate memory (DH_Start, RC5_Init) are synchronized. * pscrypto functions that allocate and deallocate memory (DH_Start, RC5_Init) are synchronized.
This *appears* to have fixed the problem. * This *appears* to have fixed the problem.
*/ */
final val psLib = new Library(libName) final val psLib = new Library(libName)
final val RC5_BLOCK_SIZE = 8 final val RC5_BLOCK_SIZE = 8
final val MD5_MAC_SIZE = 16 final val MD5_MAC_SIZE = 16
val functionsList = List( val functionsList = List(
"PSCrypto_Init", "PSCrypto_Init",
@ -51,7 +51,7 @@ object CryptoInterface {
* Used to initialize the crypto library at runtime. The version is checked and * Used to initialize the crypto library at runtime. The version is checked and
* all functions are mapped. * all functions are mapped.
*/ */
def initialize() : Unit = { def initialize(): Unit = {
// preload all library functions for speed // preload all library functions for speed
functionsList foreach psLib.prefetch functionsList foreach psLib.prefetch
@ -60,24 +60,26 @@ object CryptoInterface {
psLib.PSCrypto_Get_Version(libraryMajor, libraryMinor)[Unit] psLib.PSCrypto_Get_Version(libraryMajor, libraryMinor)[Unit]
if(!psLib.PSCrypto_Init(PSCRYPTO_VERSION_MAJOR, PSCRYPTO_VERSION_MINOR)[Boolean]) { if (!psLib.PSCrypto_Init(PSCRYPTO_VERSION_MAJOR, PSCRYPTO_VERSION_MINOR)[Boolean]) {
throw new IllegalArgumentException(s"Invalid PSCrypto library version ${libraryMajor.getValue}.${libraryMinor.getValue}. Expected " + throw new IllegalArgumentException(
s"$PSCRYPTO_VERSION_MAJOR.$PSCRYPTO_VERSION_MINOR") s"Invalid PSCrypto library version ${libraryMajor.getValue}.${libraryMinor.getValue}. Expected " +
s"$PSCRYPTO_VERSION_MAJOR.$PSCRYPTO_VERSION_MINOR"
)
} }
} }
/** /**
* Used for debugging object loading * Used for debugging object loading
*/ */
def printEnvironment() : Unit = { def printEnvironment(): Unit = {
import java.io.File import java.io.File
val classpath = System.getProperty("java.class.path") val classpath = System.getProperty("java.class.path")
val classpathEntries = classpath.split(File.pathSeparator) val classpathEntries = classpath.split(File.pathSeparator)
val myLibraryPath = System.getProperty("user.dir") val myLibraryPath = System.getProperty("user.dir")
val jnaLibrary = System.getProperty("jna.library.path") val jnaLibrary = System.getProperty("jna.library.path")
val javaLibrary = System.getProperty("java.library.path") val javaLibrary = System.getProperty("java.library.path")
println("User dir: " + myLibraryPath) println("User dir: " + myLibraryPath)
println("JNA Lib: " + jnaLibrary) println("JNA Lib: " + jnaLibrary)
println("Java Lib: " + javaLibrary) println("Java Lib: " + javaLibrary)
@ -87,13 +89,13 @@ object CryptoInterface {
println("Required data model: " + System.getProperty("sun.arch.data.model")) println("Required data model: " + System.getProperty("sun.arch.data.model"))
} }
def MD5MAC(key : ByteVector, message : ByteVector, bytesWanted : Int) : ByteVector = { def MD5MAC(key: ByteVector, message: ByteVector, bytesWanted: Int): ByteVector = {
val out = Array.ofDim[Byte](bytesWanted) val out = Array.ofDim[Byte](bytesWanted)
// WARNING BUG: the function must be cast to something (even if void) otherwise it doesnt work // WARNING BUG: the function must be cast to something (even if void) otherwise it doesnt work
val ret = psLib.MD5_MAC(key.toArray, key.length, message.toArray, message.length, out, out.length)[Boolean] val ret = psLib.MD5_MAC(key.toArray, key.length, message.toArray, message.length, out, out.length)[Boolean]
if(!ret) if (!ret)
throw new Exception("MD5MAC failed to process") throw new Exception("MD5MAC failed to process")
ByteVector(out) ByteVector(out)
@ -106,15 +108,15 @@ object CryptoInterface {
* @param mac1 A MAC value * @param mac1 A MAC value
* @param mac2 Another MAC value * @param mac2 Another MAC value
*/ */
def verifyMAC(mac1 : ByteVector, mac2 : ByteVector) : Boolean = { def verifyMAC(mac1: ByteVector, mac2: ByteVector): Boolean = {
var okay = true var okay = true
// prevent byte by byte guessing // prevent byte by byte guessing
if(mac1.length != mac2.length) if (mac1.length != mac2.length)
return false return false
for(i <- 0 until mac1.length.toInt) { for (i <- 0 until mac1.length.toInt) {
okay = okay && mac1{i} == mac2{i} okay = okay && mac1 { i } == mac2 { i }
} }
okay okay
@ -124,22 +126,22 @@ object CryptoInterface {
var started = false var started = false
// these types MUST be Arrays of bytes for JNA to work // these types MUST be Arrays of bytes for JNA to work
val privateKey = Array.ofDim[Byte](16) val privateKey = Array.ofDim[Byte](16)
val publicKey = Array.ofDim[Byte](16) val publicKey = Array.ofDim[Byte](16)
val p = Array.ofDim[Byte](16) val p = Array.ofDim[Byte](16)
val g = Array.ofDim[Byte](16) val g = Array.ofDim[Byte](16)
var dhHandle = Pointer.NULL var dhHandle = Pointer.NULL
def start(modulus : ByteVector, generator : ByteVector) : Unit = { def start(modulus: ByteVector, generator: ByteVector): Unit = {
assertNotClosed assertNotClosed
if(started) if (started)
throw new IllegalStateException("DH state has already been started") throw new IllegalStateException("DH state has already been started")
psLib.synchronized { psLib.synchronized {
dhHandle = psLib.DH_Start(modulus.toArray, generator.toArray, privateKey, publicKey)[Pointer] dhHandle = psLib.DH_Start(modulus.toArray, generator.toArray, privateKey, publicKey)[Pointer]
} }
if(dhHandle == Pointer.NULL) if (dhHandle == Pointer.NULL)
throw new Exception("DH initialization failed!") throw new Exception("DH initialization failed!")
modulus.copyToArray(p, 0) modulus.copyToArray(p, 0)
@ -148,37 +150,37 @@ object CryptoInterface {
started = true started = true
} }
def start() : Unit = { def start(): Unit = {
assertNotClosed assertNotClosed
if(started) if (started)
throw new IllegalStateException("DH state has already been started") throw new IllegalStateException("DH state has already been started")
psLib.synchronized { psLib.synchronized {
dhHandle = psLib.DH_Start_Generate(privateKey, publicKey, p, g)[Pointer] dhHandle = psLib.DH_Start_Generate(privateKey, publicKey, p, g)[Pointer]
} }
if(dhHandle == Pointer.NULL) if (dhHandle == Pointer.NULL)
throw new Exception("DH initialization failed!") throw new Exception("DH initialization failed!")
started = true started = true
} }
def agree(otherPublicKey : ByteVector) = { def agree(otherPublicKey: ByteVector) = {
if(!started) if (!started)
throw new IllegalStateException("DH state has not been started") throw new IllegalStateException("DH state has not been started")
val agreedValue = Array.ofDim[Byte](16) val agreedValue = Array.ofDim[Byte](16)
val agreed = psLib.DH_Agree(dhHandle, agreedValue, privateKey, otherPublicKey.toArray)[Boolean] val agreed = psLib.DH_Agree(dhHandle, agreedValue, privateKey, otherPublicKey.toArray)[Boolean]
if(!agreed) if (!agreed)
throw new Exception("Failed to DH agree") throw new Exception("Failed to DH agree")
ByteVector.view(agreedValue) ByteVector.view(agreedValue)
} }
private def checkAndReturnView(array : Array[Byte]) = { private def checkAndReturnView(array: Array[Byte]) = {
if(!started) if (!started)
throw new IllegalStateException("DH state has not been started") throw new IllegalStateException("DH state has not been started")
ByteVector.view(array) ByteVector.view(array)
@ -201,7 +203,7 @@ object CryptoInterface {
} }
override def close = { override def close = {
if(started) { if (started) {
// TODO: zero private key material // TODO: zero private key material
psLib.synchronized { psLib.synchronized {
psLib.Free_DH(dhHandle)[Unit] psLib.Free_DH(dhHandle)[Unit]
@ -213,46 +215,45 @@ object CryptoInterface {
} }
} }
class CryptoState(val decryptionKey : ByteVector, class CryptoState(val decryptionKey: ByteVector, val encryptionKey: ByteVector) extends IFinalizable {
val encryptionKey : ByteVector) extends IFinalizable {
// Note that the keys must be returned as primitive Arrays for JNA to work // Note that the keys must be returned as primitive Arrays for JNA to work
var encCryptoHandle : Pointer = Pointer.NULL var encCryptoHandle: Pointer = Pointer.NULL
var decCryptoHandle : Pointer = Pointer.NULL var decCryptoHandle: Pointer = Pointer.NULL
psLib.synchronized { psLib.synchronized {
encCryptoHandle = psLib.RC5_Init(encryptionKey.toArray, encryptionKey.length, true)[Pointer] encCryptoHandle = psLib.RC5_Init(encryptionKey.toArray, encryptionKey.length, true)[Pointer]
decCryptoHandle = psLib.RC5_Init(decryptionKey.toArray, decryptionKey.length, false)[Pointer] decCryptoHandle = psLib.RC5_Init(decryptionKey.toArray, decryptionKey.length, false)[Pointer]
} }
if(encCryptoHandle == Pointer.NULL) if (encCryptoHandle == Pointer.NULL)
throw new Exception("Encryption initialization failed!") throw new Exception("Encryption initialization failed!")
if(decCryptoHandle == Pointer.NULL) if (decCryptoHandle == Pointer.NULL)
throw new Exception("Decryption initialization failed!") throw new Exception("Decryption initialization failed!")
def encrypt(plaintext : ByteVector) : ByteVector = { def encrypt(plaintext: ByteVector): ByteVector = {
if(plaintext.length % RC5_BLOCK_SIZE != 0) if (plaintext.length % RC5_BLOCK_SIZE != 0)
throw new IllegalArgumentException(s"input must be padded to the nearest $RC5_BLOCK_SIZE byte boundary") throw new IllegalArgumentException(s"input must be padded to the nearest $RC5_BLOCK_SIZE byte boundary")
val ciphertext = Array.ofDim[Byte](plaintext.length.toInt) val ciphertext = Array.ofDim[Byte](plaintext.length.toInt)
val ret = psLib.RC5_Encrypt(encCryptoHandle, plaintext.toArray, plaintext.length, ciphertext)[Boolean] val ret = psLib.RC5_Encrypt(encCryptoHandle, plaintext.toArray, plaintext.length, ciphertext)[Boolean]
if(!ret) if (!ret)
throw new Exception("Failed to encrypt plaintext") throw new Exception("Failed to encrypt plaintext")
ByteVector.view(ciphertext) ByteVector.view(ciphertext)
} }
def decrypt(ciphertext : ByteVector) : ByteVector = { def decrypt(ciphertext: ByteVector): ByteVector = {
if(ciphertext.length % RC5_BLOCK_SIZE != 0) if (ciphertext.length % RC5_BLOCK_SIZE != 0)
throw new IllegalArgumentException(s"input must be padded to the nearest $RC5_BLOCK_SIZE byte boundary") throw new IllegalArgumentException(s"input must be padded to the nearest $RC5_BLOCK_SIZE byte boundary")
val plaintext = Array.ofDim[Byte](ciphertext.length.toInt) val plaintext = Array.ofDim[Byte](ciphertext.length.toInt)
val ret = psLib.RC5_Decrypt(decCryptoHandle, ciphertext.toArray, ciphertext.length, plaintext)[Boolean] val ret = psLib.RC5_Decrypt(decCryptoHandle, ciphertext.toArray, ciphertext.length, plaintext)[Boolean]
if(!ret) if (!ret)
throw new Exception("Failed to decrypt ciphertext") throw new Exception("Failed to decrypt ciphertext")
ByteVector.view(plaintext) ByteVector.view(plaintext)
@ -267,17 +268,20 @@ object CryptoInterface {
} }
} }
class CryptoStateWithMAC(decryptionKey : ByteVector, class CryptoStateWithMAC(
encryptionKey : ByteVector, decryptionKey: ByteVector,
val decryptionMACKey : ByteVector, encryptionKey: ByteVector,
val encryptionMACKey : ByteVector) extends CryptoState(decryptionKey, encryptionKey) { val decryptionMACKey: ByteVector,
val encryptionMACKey: ByteVector
) extends CryptoState(decryptionKey, encryptionKey) {
/** /**
* Performs a MAC operation over the message. Used when encrypting packets * Performs a MAC operation over the message. Used when encrypting packets
* *
* @param message the input message * @param message the input message
* @return ByteVector * @return ByteVector
*/ */
def macForEncrypt(message : ByteVector) : ByteVector = { def macForEncrypt(message: ByteVector): ByteVector = {
MD5MAC(encryptionMACKey, message, MD5_MAC_SIZE) MD5MAC(encryptionMACKey, message, MD5_MAC_SIZE)
} }
@ -287,18 +291,18 @@ object CryptoInterface {
* @param message the input message * @param message the input message
* @return ByteVector * @return ByteVector
*/ */
def macForDecrypt(message : ByteVector) : ByteVector = { def macForDecrypt(message: ByteVector): ByteVector = {
MD5MAC(decryptionMACKey, message, MD5_MAC_SIZE) MD5MAC(decryptionMACKey, message, MD5_MAC_SIZE)
} }
/** /**
* MACs the plaintext message, encrypts it, and then returns the encrypted message with the * MACs the plaintext message, encrypts it, and then returns the encrypted message with the
* MAC appended to the end. * MAC appended to the end.
* *
* @param message Arbitrary set of bytes * @param message Arbitrary set of bytes
* @return ByteVector * @return ByteVector
*/ */
def macAndEncrypt(message : ByteVector) : ByteVector = { def macAndEncrypt(message: ByteVector): ByteVector = {
encrypt(message) ++ MD5MAC(encryptionMACKey, message, MD5_MAC_SIZE) encrypt(message) ++ MD5MAC(encryptionMACKey, message, MD5_MAC_SIZE)
} }
} }

View file

@ -1,13 +1,14 @@
// Copyright (c) 2017 PSForever // Copyright (c) 2017 PSForever
package net.psforever.newcodecs package net.psforever.newcodecs
import scodec.{ Codec, SizeBound } import scodec.Codec
import scodec.bits.BitVector import scodec.bits.BitVector
private[newcodecs] final class BinaryChoiceCodec[A](choice: Boolean, codec_true: => Codec[A], codec_false: => Codec[A]) extends Codec[A] { private[newcodecs] final class BinaryChoiceCodec[A](choice: Boolean, codec_true: => Codec[A], codec_false: => Codec[A])
extends Codec[A] {
private lazy val evaluatedCodec_true = codec_true private lazy val evaluatedCodec_true = codec_true
private lazy val evaluatedCodec_false = codec_false private lazy val evaluatedCodec_false = codec_false
override def sizeBound = if (choice) evaluatedCodec_true.sizeBound else evaluatedCodec_false.sizeBound override def sizeBound = if (choice) evaluatedCodec_true.sizeBound else evaluatedCodec_false.sizeBound
@ -26,6 +27,7 @@ private[newcodecs] final class BinaryChoiceCodec[A](choice: Boolean, codec_true:
evaluatedCodec_false.decode(buffer) evaluatedCodec_false.decode(buffer)
} }
override def toString = if(choice) s"binarychoice(true, $evaluatedCodec_true, ?)" else "binarychoice(false, ?, $evaluatedCodec_false)" override def toString =
if (choice) s"binarychoice(true, $evaluatedCodec_true, ?)" else "binarychoice(false, ?, $evaluatedCodec_false)"
} }

View file

@ -4,30 +4,33 @@ package net.psforever.newcodecs
import scodec._ import scodec._
import scodec.bits.BitVector import scodec.bits.BitVector
final class PrefixedVectorCodec[A](firstCodec: Codec[A], codec: Codec[A], limit: Option[Int] = None) extends Codec[Vector[A]] { final class PrefixedVectorCodec[A](firstCodec: Codec[A], codec: Codec[A], limit: Option[Int] = None)
extends Codec[Vector[A]] {
def sizeBound = limit match { def sizeBound =
case None => SizeBound.unknown limit match {
case Some(lim) => codec.sizeBound * lim.toLong case None => SizeBound.unknown
} case Some(lim) => codec.sizeBound * lim.toLong
}
def encode(vector: Vector[A]) = Encoder.encodeSeq(firstCodec)(vector.slice(0,1)).map { bits => def encode(vector: Vector[A]) =
Encoder.encodeSeq(firstCodec)(vector.slice(0, 1)).map { bits =>
if (vector.length > 1) if (vector.length > 1)
bits ++ (Encoder.encodeSeq(codec)(vector.tail) getOrElse BitVector.empty) bits ++ (Encoder.encodeSeq(codec)(vector.tail) getOrElse BitVector.empty)
else else
bits bits
} }
def decode(buffer: BitVector) : scodec.Attempt[scodec.DecodeResult[Vector[A]]] = { def decode(buffer: BitVector): scodec.Attempt[scodec.DecodeResult[Vector[A]]] = {
Decoder.decodeCollect[Vector, A](firstCodec, Some(1))(buffer) match { Decoder.decodeCollect[Vector, A](firstCodec, Some(1))(buffer) match {
case Attempt.Successful(firstValue) => case Attempt.Successful(firstValue) =>
Decoder.decodeCollect[Vector, A](codec, limit map { _ - 1 })(firstValue.remainder) match { Decoder.decodeCollect[Vector, A](codec, limit map { _ - 1 })(firstValue.remainder) match {
case Attempt.Successful(secondValue) => case Attempt.Successful(secondValue) =>
Attempt.successful(DecodeResult(firstValue.value ++ secondValue.value, secondValue.remainder)) Attempt.successful(DecodeResult(firstValue.value ++ secondValue.value, secondValue.remainder))
case Attempt.Failure(e) => Attempt.failure(e) case Attempt.Failure(e) => Attempt.failure(e)
} }
case Attempt.Failure(e) => Attempt.failure(e) case Attempt.Failure(e) => Attempt.failure(e)
} }
} }
override def toString = s"vector($codec)" override def toString = s"vector($codec)"

View file

@ -1,8 +1,8 @@
// Copyright (c) 2017 PSForever // Copyright (c) 2017 PSForever
package net.psforever.newcodecs package net.psforever.newcodecs
import scodec.{ Attempt, Codec, DecodeResult, Err, SizeBound } import scodec.{Attempt, Codec, DecodeResult, Err, SizeBound}
import scodec.bits.{ BitVector, ByteOrdering } import scodec.bits.{BitVector, ByteOrdering}
final class QuantizedDoubleCodec(min: Double, max: Double, bits: Int) extends Codec[Double] { final class QuantizedDoubleCodec(min: Double, max: Double, bits: Int) extends Codec[Double] {
@ -14,14 +14,14 @@ final class QuantizedDoubleCodec(min: Double, max: Double, bits: Int) extends Co
override def sizeBound = SizeBound.exact(bitsL) override def sizeBound = SizeBound.exact(bitsL)
def QuantizeDouble(value : Double) : Int = { def QuantizeDouble(value: Double): Int = {
val range : Double = max - min; val range: Double = max - min;
if (range == 0.0) if (range == 0.0)
return 0 return 0
val bit_max : Int = 1 << bits; val bit_max: Int = 1 << bits;
val rounded_quantized : Int = math.floor((value - min) * bit_max.toDouble / range + 0.5).toInt val rounded_quantized: Int = math.floor((value - min) * bit_max.toDouble / range + 0.5).toInt
if (rounded_quantized < 0) if (rounded_quantized < 0)
return 0 return 0
@ -32,7 +32,7 @@ final class QuantizedDoubleCodec(min: Double, max: Double, bits: Int) extends Co
return rounded_quantized return rounded_quantized
} }
def UnquantizeDouble(value : Int) : Double = { def UnquantizeDouble(value: Int): Double = {
return ((max - min) * value.toDouble / (1 << bitsL.toInt).toDouble + min) return ((max - min) * value.toDouble / (1 << bitsL.toInt).toDouble + min)
} }
@ -42,7 +42,9 @@ final class QuantizedDoubleCodec(min: Double, max: Double, bits: Int) extends Co
override def decode(buffer: BitVector) = { override def decode(buffer: BitVector) = {
if (buffer.sizeGreaterThanOrEqual(bitsL)) if (buffer.sizeGreaterThanOrEqual(bitsL))
Attempt.successful(DecodeResult(UnquantizeDouble(buffer.take(bitsL).toInt(false, ByteOrdering.LittleEndian)), buffer.drop(bitsL))) Attempt.successful(
DecodeResult(UnquantizeDouble(buffer.take(bitsL).toInt(false, ByteOrdering.LittleEndian)), buffer.drop(bitsL))
)
else else
Attempt.failure(Err.insufficientBits(bitsL, buffer.size)) Attempt.failure(Err.insufficientBits(bitsL, buffer.size))
} }

View file

@ -2,23 +2,28 @@
package net.psforever.newcodecs package net.psforever.newcodecs
import scodec.Attempt import scodec.Attempt
import scodec.Attempt.{Failure, Successful}
import scodec._ import scodec._
import scodec.bits.BitVector
package object newcodecs { package object newcodecs {
def q_double(min: Double, max: Double, bits: Int): Codec[Double] = new QuantizedDoubleCodec(min, max, bits) def q_double(min: Double, max: Double, bits: Int): Codec[Double] = new QuantizedDoubleCodec(min, max, bits)
def q_float(min : Double, max : Double, bits : Int): Codec[Float] = q_double(min, max, bits).narrow(v => Attempt.successful(v.toFloat), _.toDouble) def q_float(min: Double, max: Double, bits: Int): Codec[Float] =
q_double(min, max, bits).narrow(v => Attempt.successful(v.toFloat), _.toDouble)
def binary_choice[A](choice: Boolean, codec_true: => Codec[A], codec_false: => Codec[A]): Codec[A] = new BinaryChoiceCodec(choice, codec_true, codec_false) def binary_choice[A](choice: Boolean, codec_true: => Codec[A], codec_false: => Codec[A]): Codec[A] =
new BinaryChoiceCodec(choice, codec_true, codec_false)
def prefixedVectorOfN[A](countCodec: Codec[Int], firstValueCodec: Codec[A], valueCodec: Codec[A]): Codec[Vector[A]] = def prefixedVectorOfN[A](countCodec: Codec[Int], firstValueCodec: Codec[A], valueCodec: Codec[A]): Codec[Vector[A]] =
countCodec. countCodec
flatZip { count => new PrefixedVectorCodec(firstValueCodec, valueCodec, Some(count)) }. .flatZip { count => new PrefixedVectorCodec(firstValueCodec, valueCodec, Some(count)) }
narrow[Vector[A]]({ case (cnt, xs) => .narrow[Vector[A]](
if (xs.size == cnt) Attempt.successful(xs) {
else Attempt.failure(Err(s"Insufficient number of elements: decoded ${xs.size} but should have decoded $cnt")) case (cnt, xs) =>
}, xs => (xs.size, xs)). if (xs.size == cnt) Attempt.successful(xs)
withToString(s"vectorOfN($countCodec, $valueCodec)") else
Attempt.failure(Err(s"Insufficient number of elements: decoded ${xs.size} but should have decoded $cnt"))
},
xs => (xs.size, xs)
)
.withToString(s"vectorOfN($countCodec, $valueCodec)")
} }

View file

@ -1,8 +1,8 @@
// Copyright (c) 2017 PSForever // Copyright (c) 2017 PSForever
package net.psforever.objects package net.psforever.objects
class Account(private val accountId : Int, private val username : String, private val gm : Boolean = false) { class Account(private val accountId: Int, private val username: String, private val gm: Boolean = false) {
def AccountId : Int = accountId def AccountId: Int = accountId
def Username : String = username def Username: String = username
def GM : Boolean = gm def GM: Boolean = gm
} }

View file

@ -5,37 +5,36 @@ import net.psforever.objects.definition.AmmoBoxDefinition
import net.psforever.objects.equipment.{Ammo, Equipment} import net.psforever.objects.equipment.{Ammo, Equipment}
import net.psforever.types.PlanetSideEmpire import net.psforever.types.PlanetSideEmpire
class AmmoBox(private val ammoDef : AmmoBoxDefinition, class AmmoBox(private val ammoDef: AmmoBoxDefinition, cap: Option[Int] = None) extends Equipment {
cap : Option[Int] = None private var capacity = if (cap.isDefined) { AmmoBox.limitCapacity(cap.get, 1) }
) extends Equipment { else { FullCapacity }
private var capacity = if(cap.isDefined) { AmmoBox.limitCapacity(cap.get, 1) } else { FullCapacity }
def AmmoType : Ammo.Value = ammoDef.AmmoType def AmmoType: Ammo.Value = ammoDef.AmmoType
def Capacity : Int = capacity def Capacity: Int = capacity
def Capacity_=(toCapacity : Int) : Int = { def Capacity_=(toCapacity: Int): Int = {
capacity = AmmoBox.limitCapacity(toCapacity) capacity = AmmoBox.limitCapacity(toCapacity)
Capacity Capacity
} }
def FullCapacity : Int = ammoDef.Capacity def FullCapacity: Int = ammoDef.Capacity
def Definition : AmmoBoxDefinition = ammoDef def Definition: AmmoBoxDefinition = ammoDef
override def Faction_=(fact : PlanetSideEmpire.Value) : PlanetSideEmpire.Value = Faction override def Faction_=(fact: PlanetSideEmpire.Value): PlanetSideEmpire.Value = Faction
override def toString : String = { override def toString: String = {
AmmoBox.toString(this) AmmoBox.toString(this)
} }
} }
object AmmoBox { object AmmoBox {
def apply(ammoDef : AmmoBoxDefinition) : AmmoBox = { def apply(ammoDef: AmmoBoxDefinition): AmmoBox = {
new AmmoBox(ammoDef) new AmmoBox(ammoDef)
} }
def apply(ammoDef : AmmoBoxDefinition, capacity : Int) : AmmoBox = { def apply(ammoDef: AmmoBoxDefinition, capacity: Int): AmmoBox = {
new AmmoBox(ammoDef, Some(capacity)) new AmmoBox(ammoDef, Some(capacity))
} }
@ -48,25 +47,25 @@ object AmmoBox {
* @param box an `AmmoBox` object of unspecified capacity * @param box an `AmmoBox` object of unspecified capacity
* @return a `List` of `AmmoBox` objects with correct capacities * @return a `List` of `AmmoBox` objects with correct capacities
*/ */
def Split(box : AmmoBox) : List[AmmoBox] = { def Split(box: AmmoBox): List[AmmoBox] = {
val ammoDef = box.Definition val ammoDef = box.Definition
val boxCap : Int = box.Capacity val boxCap: Int = box.Capacity
val maxCap : Int = ammoDef.Capacity val maxCap: Int = ammoDef.Capacity
val splitCap : Int = boxCap / maxCap val splitCap: Int = boxCap / maxCap
box.Capacity = math.min(box.Capacity, maxCap) box.Capacity = math.min(box.Capacity, maxCap)
val list : List[AmmoBox] = if(splitCap == 0) { Nil } else { box +: List.fill(splitCap - 1)(new AmmoBox(ammoDef)) } val list: List[AmmoBox] = if (splitCap == 0) { Nil }
else { box +: List.fill(splitCap - 1)(new AmmoBox(ammoDef)) }
val leftover = boxCap - maxCap * splitCap val leftover = boxCap - maxCap * splitCap
if(leftover > 0) { if (leftover > 0) {
list :+ AmmoBox(ammoDef, leftover) list :+ AmmoBox(ammoDef, leftover)
} } else {
else {
list list
} }
} }
def limitCapacity(count : Int, min : Int = 0) : Int = math.min(math.max(min, count), 65535) def limitCapacity(count: Int, min: Int = 0): Int = math.min(math.max(min, count), 65535)
def toString(obj : AmmoBox) : String = { def toString(obj: AmmoBox): String = {
s"box of ${obj.AmmoType} ammo (${obj.Capacity})" s"box of ${obj.AmmoType} ammo (${obj.Capacity})"
} }
} }

View file

@ -10,16 +10,28 @@ import net.psforever.types._
import scala.annotation.tailrec import scala.annotation.tailrec
import scala.collection.mutable import scala.collection.mutable
class Avatar(private val char_id : Long, val name : String, val faction : PlanetSideEmpire.Value, val sex : CharacterGender.Value, val head : Int, val voice : CharacterVoice.Value) { class Avatar(
private val char_id: Long,
val name: String,
val faction: PlanetSideEmpire.Value,
val sex: CharacterGender.Value,
val head: Int,
val voice: CharacterVoice.Value
) {
/** char_id, Character ID; a unique identifier corresponding to a database table row index */ /** char_id, Character ID; a unique identifier corresponding to a database table row index */
/** Battle Experience Points */ /** Battle Experience Points */
private var bep : Long = 0 private var bep: Long = 0
/** Command Experience Points */ /** Command Experience Points */
private var cep : Long = 0 private var cep: Long = 0
/** Cosmetics **/
private var pStyle : Option[Cosmetics] = None /** Cosmetics * */
private var pStyle: Option[Cosmetics] = None
/** Certifications */ /** Certifications */
private val certs : mutable.Set[CertificationType.Value] = mutable.Set[CertificationType.Value]() private val certs: mutable.Set[CertificationType.Value] = mutable.Set[CertificationType.Value]()
/** Implants<br> /** Implants<br>
* Unlike other objects, all `ImplantSlot` objects are already built into the `Avatar`. * Unlike other objects, all `ImplantSlot` objects are already built into the `Avatar`.
* Additionally, implants do not have tightly-coupled "`Definition` objects" that explain a formal implant object. * Additionally, implants do not have tightly-coupled "`Definition` objects" that explain a formal implant object.
@ -28,53 +40,60 @@ class Avatar(private val char_id : Long, val name : String, val faction : Planet
* @see `ImplantSlot` * @see `ImplantSlot`
* @see `DetailedCharacterData.implants` * @see `DetailedCharacterData.implants`
*/ */
private val implants : Array[ImplantSlot] = Array.fill[ImplantSlot](3)(new ImplantSlot) private val implants: Array[ImplantSlot] = Array.fill[ImplantSlot](3)(new ImplantSlot)
/** Equipment Loadouts<br> /** Equipment Loadouts<br>
* 0-9 are Infantry loadouts<br> * 0-9 are Infantry loadouts<br>
* 10-14 are Vehicle loadouts * 10-14 are Vehicle loadouts
*/ */
private val equipmentLoadouts : LoadoutManager = new LoadoutManager(15) private val equipmentLoadouts: LoadoutManager = new LoadoutManager(15)
/** /**
* Squad Loadouts * Squad Loadouts
*/ */
private val squadLoadouts : LoadoutManager = new LoadoutManager(10) private val squadLoadouts: LoadoutManager = new LoadoutManager(10)
/** Locker */ /** Locker */
private val locker : LockerContainer = new LockerContainer() { private val locker: LockerContainer = new LockerContainer() {
override def toString : String = { override def toString: String = {
s"$name's ${Definition.Name}" s"$name's ${Definition.Name}"
} }
} }
private val deployables : DeployableToolbox = new DeployableToolbox private val deployables: DeployableToolbox = new DeployableToolbox
private var firstTimeEvents : List[String] = List[String]() private var firstTimeEvents: List[String] = List[String]()
/** /**
* Looking For Squad:<br> * Looking For Squad:<br>
* Indicates both a player state and the text on the marquee under the player nameplate. * 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. * Should only be valid when the player is not in a squad.
*/ */
private var lfs : Boolean = false private var lfs: Boolean = false
private var vehicleOwned: Option[PlanetSideGUID] = None
private var vehicleOwned : Option[PlanetSideGUID] = None
/** key - object id<br> /** key - object id<br>
* value - time last used (ms) * value - time last used (ms)
* */ */
private var lastUsedEquipmentTimes : mutable.LongMap[Long] = mutable.LongMap[Long]() private var lastUsedEquipmentTimes: mutable.LongMap[Long] = mutable.LongMap[Long]()
/** exo-suit times are sorted by `Enumeration` order, which was determined by packet process<br> /** exo-suit times are sorted by `Enumeration` order, which was determined by packet process<br>
* key - exo-suit id<br> * key - exo-suit id<br>
* value - time last used (ms) * value - time last used (ms)
* */ */
private val lastUsedExoSuitTimes : Array[Long] = Array.fill[Long](ExoSuitType.values.size)(0L) private val lastUsedExoSuitTimes: Array[Long] = Array.fill[Long](ExoSuitType.values.size)(0L)
/** mechanized exo-suit times are sorted by subtype distinction, which was determined by packet process<br> /** mechanized exo-suit times are sorted by subtype distinction, which was determined by packet process<br>
* key - subtype id<br> * key - subtype id<br>
* value - time last used (ms) * value - time last used (ms)
* */ */
private val lastUsedMaxExoSuitTimes : Array[Long] = Array.fill[Long](4)(0L) //invalid, ai, av, aa private val lastUsedMaxExoSuitTimes: Array[Long] = Array.fill[Long](4)(0L) //invalid, ai, av, aa
/** key - object id<br> /** key - object id<br>
* value - time last acquired (from a terminal) (ms) * value - time last acquired (from a terminal) (ms)
* */ */
private var lastPurchaseTimes : mutable.LongMap[Long] = mutable.LongMap[Long]() private var lastPurchaseTimes: mutable.LongMap[Long] = mutable.LongMap[Long]()
/** /**
* To reload purchase and use timers, a string representing the item must be produced. * To reload purchase and use timers, a string representing the item must be produced.
* Point directly from the object id to the object definition and get the `Name` from that definition. * Point directly from the object id to the object definition and get the `Name` from that definition.
@ -83,29 +102,29 @@ class Avatar(private val char_id : Long, val name : String, val faction : Planet
* key - object id<br> * key - object id<br>
* value - most basic object definition information * value - most basic object definition information
*/ */
private val objectTypeNameReference : mutable.LongMap[String] = new mutable.LongMap[String]() private val objectTypeNameReference: mutable.LongMap[String] = new mutable.LongMap[String]()
def CharId : Long = char_id def CharId: Long = char_id
def BEP : Long = bep def BEP: Long = bep
def BEP_=(battleExperiencePoints : Long) : Long = { def BEP_=(battleExperiencePoints: Long): Long = {
bep = math.max(0L, math.min(battleExperiencePoints, 4294967295L)) bep = math.max(0L, math.min(battleExperiencePoints, 4294967295L))
BEP BEP
} }
def Certifications : mutable.Set[CertificationType.Value] = certs def Certifications: mutable.Set[CertificationType.Value] = certs
def CEP : Long = cep def CEP: Long = cep
def CEP_=(commandExperiencePoints : Long) : Long = { def CEP_=(commandExperiencePoints: Long): Long = {
cep = math.max(0L, math.min(commandExperiencePoints, 4294967295L)) cep = math.max(0L, math.min(commandExperiencePoints, 4294967295L))
CEP CEP
} }
def PersonalStyleFeatures : Option[Cosmetics] = pStyle def PersonalStyleFeatures: Option[Cosmetics] = pStyle
def PersonalStyleFeatures_=(app : Cosmetics) : Option[Cosmetics] = { def PersonalStyleFeatures_=(app: Cosmetics): Option[Cosmetics] = {
pStyle = Some(app) pStyle = Some(app)
pStyle pStyle
} }
@ -114,7 +133,7 @@ class Avatar(private val char_id : Long, val name : String, val faction : Planet
* Retrieve the three implant slots for this player. * Retrieve the three implant slots for this player.
* @return an `Array` of `ImplantSlot` objects * @return an `Array` of `ImplantSlot` objects
*/ */
def Implants : Array[ImplantSlot] = implants def Implants: Array[ImplantSlot] = implants
/** /**
* What kind of implant is installed into the given slot number? * What kind of implant is installed into the given slot number?
@ -122,8 +141,9 @@ class Avatar(private val char_id : Long, val name : String, val faction : Planet
* @param slot the slot number * @param slot the slot number
* @return the tye of implant * @return the tye of implant
*/ */
def Implant(slot : Int) : ImplantType.Value = { def Implant(slot: Int): ImplantType.Value = {
if(-1 < slot && slot < implants.length) { implants(slot).Implant } else { ImplantType.None } if (-1 < slot && slot < implants.length) { implants(slot).Implant }
else { ImplantType.None }
} }
/** /**
@ -136,8 +156,9 @@ class Avatar(private val char_id : Long, val name : String, val faction : Planet
* @param implant the implant being installed * @param implant the implant being installed
* @return the index of the `ImplantSlot` where the implant was installed * @return the index of the `ImplantSlot` where the implant was installed
*/ */
def InstallImplant(implant : ImplantDefinition) : Option[Int] = { def InstallImplant(implant: ImplantDefinition): Option[Int] = {
implants.find({p => p.Installed.contains(implant) || p.Implant == implant.Type}) match { //try to find the installed implant implants
.find({ p => p.Installed.contains(implant) || p.Implant == implant.Type }) match { //try to find the installed implant
case None => case None =>
recursiveFindImplantInSlot(implants.iterator, ImplantType.None) match { //install in a free slot recursiveFindImplantInSlot(implants.iterator, ImplantType.None) match { //install in a free slot
case Some(slot) => case Some(slot) =>
@ -164,7 +185,7 @@ class Avatar(private val char_id : Long, val name : String, val faction : Planet
* @param implantType the type of implant being uninstalled * @param implantType the type of implant being uninstalled
* @return the index of the `ImplantSlot` where the implant was found and uninstalled * @return the index of the `ImplantSlot` where the implant was found and uninstalled
*/ */
def UninstallImplant(implantType : ImplantType.Value) : Option[Int] = { def UninstallImplant(implantType: ImplantType.Value): Option[Int] = {
recursiveFindImplantInSlot(implants.iterator, implantType) match { recursiveFindImplantInSlot(implants.iterator, implantType) match {
case Some(slot) => case Some(slot) =>
implants(slot).Implant = None implants(slot).Implant = None
@ -183,22 +204,24 @@ class Avatar(private val char_id : Long, val name : String, val faction : Planet
* @param index a defaulted index value representing the structure underlying the `Iterator` param * @param index a defaulted index value representing the structure underlying the `Iterator` param
* @return the index where the target implant is installed * @return the index where the target implant is installed
*/ */
@tailrec private def recursiveFindImplantInSlot(iter : Iterator[ImplantSlot], implantType : ImplantType.Value, index : Int = 0) : Option[Int] = { @tailrec private def recursiveFindImplantInSlot(
if(!iter.hasNext) { iter: Iterator[ImplantSlot],
implantType: ImplantType.Value,
index: Int = 0
): Option[Int] = {
if (!iter.hasNext) {
None None
} } else {
else {
val slot = iter.next val slot = iter.next
if(slot.Unlocked && slot.Implant == implantType) { if (slot.Unlocked && slot.Implant == implantType) {
Some(index) Some(index)
} } else {
else {
recursiveFindImplantInSlot(iter, implantType, index + 1) recursiveFindImplantInSlot(iter, implantType, index + 1)
} }
} }
} }
def ResetAllImplants() : Unit = { def ResetAllImplants(): Unit = {
implants.foreach(slot => { implants.foreach(slot => {
slot.Installed match { slot.Installed match {
case Some(_) => case Some(_) =>
@ -210,111 +233,110 @@ class Avatar(private val char_id : Long, val name : String, val faction : Planet
}) })
} }
def EquipmentLoadouts : LoadoutManager = equipmentLoadouts def EquipmentLoadouts: LoadoutManager = equipmentLoadouts
def SquadLoadouts : LoadoutManager = squadLoadouts def SquadLoadouts: LoadoutManager = squadLoadouts
def Locker : LockerContainer = locker def Locker: LockerContainer = locker
def FifthSlot : EquipmentSlot = { def FifthSlot: EquipmentSlot = {
new OffhandEquipmentSlot(EquipmentSize.Inventory) { new OffhandEquipmentSlot(EquipmentSize.Inventory) {
val obj = new LockerEquipment(locker) val obj = new LockerEquipment(locker)
Equipment = obj Equipment = obj
} }
} }
def Deployables : DeployableToolbox = deployables def Deployables: DeployableToolbox = deployables
def FirstTimeEvents : List[String] = firstTimeEvents def FirstTimeEvents: List[String] = firstTimeEvents
def FirstTimeEvents_=(event : String) : List[String] = FirstTimeEvents_=(List(event)) def FirstTimeEvents_=(event: String): List[String] = FirstTimeEvents_=(List(event))
def FirstTimeEvents_=(events : List[String]) : List[String] = { def FirstTimeEvents_=(events: List[String]): List[String] = {
firstTimeEvents ++= events firstTimeEvents ++= events
FirstTimeEvents FirstTimeEvents
} }
def LFS : Boolean = lfs def LFS: Boolean = lfs
def LFS_=(looking : Boolean) : Boolean = { def LFS_=(looking: Boolean): Boolean = {
lfs = looking lfs = looking
LFS LFS
} }
def VehicleOwned : Option[PlanetSideGUID] = vehicleOwned def VehicleOwned: Option[PlanetSideGUID] = vehicleOwned
def VehicleOwned_=(guid : PlanetSideGUID) : Option[PlanetSideGUID] = VehicleOwned_=(Some(guid)) def VehicleOwned_=(guid: PlanetSideGUID): Option[PlanetSideGUID] = VehicleOwned_=(Some(guid))
def VehicleOwned_=(guid : Option[PlanetSideGUID]) : Option[PlanetSideGUID] = { def VehicleOwned_=(guid: Option[PlanetSideGUID]): Option[PlanetSideGUID] = {
vehicleOwned = guid vehicleOwned = guid
VehicleOwned VehicleOwned
} }
def GetLastUsedTime(code : Int) : Long = { def GetLastUsedTime(code: Int): Long = {
lastUsedEquipmentTimes.get(code) match { lastUsedEquipmentTimes.get(code) match {
case Some(time) => time case Some(time) => time
case None => 0 case None => 0
} }
} }
def GetLastUsedTime(code : ExoSuitType.Value) : Long = { def GetLastUsedTime(code: ExoSuitType.Value): Long = {
lastUsedExoSuitTimes(code.id) lastUsedExoSuitTimes(code.id)
} }
def GetLastUsedTime(code : ExoSuitType.Value, subtype : Int) : Long = { def GetLastUsedTime(code: ExoSuitType.Value, subtype: Int): Long = {
if(code == ExoSuitType.MAX) { if (code == ExoSuitType.MAX) {
lastUsedMaxExoSuitTimes(subtype) lastUsedMaxExoSuitTimes(subtype)
} } else {
else {
GetLastUsedTime(code) GetLastUsedTime(code)
} }
} }
def GetAllLastUsedTimes : Map[Long, Long] = lastUsedEquipmentTimes.toMap def GetAllLastUsedTimes: Map[Long, Long] = lastUsedEquipmentTimes.toMap
def SetLastUsedTime(code : Int, time : Long) : Unit = { def SetLastUsedTime(code: Int, time: Long): Unit = {
lastUsedEquipmentTimes += code.toLong -> time lastUsedEquipmentTimes += code.toLong -> time
} }
def SetLastUsedTime(code : ExoSuitType.Value) : Unit = SetLastUsedTime(code, System.currentTimeMillis()) def SetLastUsedTime(code: ExoSuitType.Value): Unit = SetLastUsedTime(code, System.currentTimeMillis())
def SetLastUsedTime(code : ExoSuitType.Value, time : Long) : Unit = { def SetLastUsedTime(code: ExoSuitType.Value, time: Long): Unit = {
lastUsedExoSuitTimes(code.id) = time lastUsedExoSuitTimes(code.id) = time
} }
def SetLastUsedTime(code : ExoSuitType.Value, subtype : Int, time : Long) : Unit = { def SetLastUsedTime(code: ExoSuitType.Value, subtype: Int, time: Long): Unit = {
if(code == ExoSuitType.MAX) { if (code == ExoSuitType.MAX) {
lastUsedMaxExoSuitTimes(subtype) = time lastUsedMaxExoSuitTimes(subtype) = time
} }
SetLastUsedTime(code, time) SetLastUsedTime(code, time)
} }
def GetLastPurchaseTime(code : Int) : Long = { def GetLastPurchaseTime(code: Int): Long = {
lastPurchaseTimes.get(code) match { lastPurchaseTimes.get(code) match {
case Some(time) => time case Some(time) => time
case None => 0 case None => 0
} }
} }
def GetAllLastPurchaseTimes : Map[Long, Long] = lastPurchaseTimes.toMap def GetAllLastPurchaseTimes: Map[Long, Long] = lastPurchaseTimes.toMap
def SetLastPurchaseTime(code : Int, time : Long) : Unit = { def SetLastPurchaseTime(code: Int, time: Long): Unit = {
lastPurchaseTimes += code.toLong -> time lastPurchaseTimes += code.toLong -> time
} }
def ObjectTypeNameReference(id : Long) : String = { def ObjectTypeNameReference(id: Long): String = {
objectTypeNameReference.get(id) match { objectTypeNameReference.get(id) match {
case Some(objectName) => objectName case Some(objectName) => objectName
case None => "" case None => ""
} }
} }
def ObjectTypeNameReference(id : Long, name : String) : String = { def ObjectTypeNameReference(id: Long, name: String): String = {
objectTypeNameReference(id) = name objectTypeNameReference(id) = name
name name
} }
def Definition : AvatarDefinition = GlobalDefinitions.avatar def Definition: AvatarDefinition = GlobalDefinitions.avatar
/* /*
Merit Commendations and Ribbons Merit Commendations and Ribbons
@ -326,19 +348,20 @@ class Avatar(private val char_id : Long, val name : String, val faction : Planet
def canEqual(other: Any): Boolean = other.isInstanceOf[Avatar] def canEqual(other: Any): Boolean = other.isInstanceOf[Avatar]
override def equals(other : Any) : Boolean = other match { override def equals(other: Any): Boolean =
case that: Avatar => other match {
(that canEqual this) && case that: Avatar =>
name == that.name && (that canEqual this) &&
faction == that.faction && name == that.name &&
sex == that.sex && faction == that.faction &&
head == that.head && sex == that.sex &&
voice == that.voice head == that.head &&
case _ => voice == that.voice
false case _ =>
} false
}
override def hashCode() : Int = { override def hashCode(): Int = {
val state = Seq(name, faction, sex, head, voice) val state = Seq(name, faction, sex, head, voice)
state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b) state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b)
} }
@ -347,9 +370,15 @@ class Avatar(private val char_id : Long, val name : String, val faction : Planet
} }
object Avatar { object Avatar {
def apply(name : String, faction : PlanetSideEmpire.Value, sex : CharacterGender.Value, head : Int, voice : CharacterVoice.Value) : Avatar = { def apply(
name: String,
faction: PlanetSideEmpire.Value,
sex: CharacterGender.Value,
head: Int,
voice: CharacterVoice.Value
): Avatar = {
new Avatar(0L, name, faction, sex, head, voice) new Avatar(0L, name, faction, sex, head, voice)
} }
def toString(avatar : Avatar) : String = s"${avatar.faction} ${avatar.name}" def toString(avatar: Avatar): String = s"${avatar.faction} ${avatar.name}"
} }

View file

@ -1,20 +1,20 @@
// Copyright (c) 2017 PSForever // Copyright (c) 2017 PSForever
package net.psforever.objects package net.psforever.objects
class BoomerDeployable(cdef : ExplosiveDeployableDefinition) extends ExplosiveDeployable(cdef) { class BoomerDeployable(cdef: ExplosiveDeployableDefinition) extends ExplosiveDeployable(cdef) {
private var trigger : Option[BoomerTrigger] = None private var trigger: Option[BoomerTrigger] = None
def Trigger : Option[BoomerTrigger] = trigger def Trigger: Option[BoomerTrigger] = trigger
def Trigger_=(item : BoomerTrigger) : Option[BoomerTrigger] = { def Trigger_=(item: BoomerTrigger): Option[BoomerTrigger] = {
if(trigger.isEmpty) { //can only set trigger once if (trigger.isEmpty) { //can only set trigger once
trigger = Some(item) trigger = Some(item)
} }
Trigger Trigger
} }
def Trigger_=(item : Option[BoomerTrigger]) : Option[BoomerTrigger] = { def Trigger_=(item: Option[BoomerTrigger]): Option[BoomerTrigger] = {
if(item.isEmpty) { if (item.isEmpty) {
trigger = None trigger = None
} }
Trigger Trigger

View file

@ -5,5 +5,5 @@ import net.psforever.objects.equipment.RemoteUnit
import net.psforever.types.PlanetSideEmpire import net.psforever.types.PlanetSideEmpire
class BoomerTrigger extends SimpleItem(GlobalDefinitions.boomer_trigger) with RemoteUnit { class BoomerTrigger extends SimpleItem(GlobalDefinitions.boomer_trigger) with RemoteUnit {
override def Faction_=(fact : PlanetSideEmpire.Value) : PlanetSideEmpire.Value = Faction override def Faction_=(fact: PlanetSideEmpire.Value): PlanetSideEmpire.Value = Faction
} }

View file

@ -20,47 +20,48 @@ import net.psforever.types.CertificationType
* indicate whether the current output product is something the player is permitted to utilize. * indicate whether the current output product is something the player is permitted to utilize.
* @param cItemDef the `ObjectDefinition` that constructs this item and maintains some of its immutable fields * @param cItemDef the `ObjectDefinition` that constructs this item and maintains some of its immutable fields
*/ */
class ConstructionItem(private val cItemDef : ConstructionItemDefinition) extends Equipment class ConstructionItem(private val cItemDef: ConstructionItemDefinition)
with FireModeSwitch[ConstructionFireMode] { extends Equipment
private var fireModeIndex : Int = 0 with FireModeSwitch[ConstructionFireMode] {
private var ammoTypeIndex : Int = 0 private var fireModeIndex: Int = 0
private var ammoTypeIndex: Int = 0
def FireModeIndex : Int = fireModeIndex def FireModeIndex: Int = fireModeIndex
def FireModeIndex_=(index : Int) : Int = { def FireModeIndex_=(index: Int): Int = {
fireModeIndex = index % Definition.Modes.length fireModeIndex = index % Definition.Modes.length
FireModeIndex FireModeIndex
} }
def FireMode : ConstructionFireMode = Definition.Modes(fireModeIndex) def FireMode: ConstructionFireMode = Definition.Modes(fireModeIndex)
def NextFireMode : ConstructionFireMode = { def NextFireMode: ConstructionFireMode = {
FireModeIndex = FireModeIndex + 1 FireModeIndex = FireModeIndex + 1
ammoTypeIndex = 0 ammoTypeIndex = 0
FireMode FireMode
} }
def AmmoTypeIndex : Int = ammoTypeIndex def AmmoTypeIndex: Int = ammoTypeIndex
def AmmoTypeIndex_=(index : Int) : Int = { def AmmoTypeIndex_=(index: Int): Int = {
ammoTypeIndex = index % FireMode.Deployables.length ammoTypeIndex = index % FireMode.Deployables.length
AmmoTypeIndex AmmoTypeIndex
} }
def AmmoType : DeployedItem.Value = FireMode.Deployables(ammoTypeIndex) def AmmoType: DeployedItem.Value = FireMode.Deployables(ammoTypeIndex)
def NextAmmoType : DeployedItem.Value = { def NextAmmoType: DeployedItem.Value = {
AmmoTypeIndex = AmmoTypeIndex + 1 AmmoTypeIndex = AmmoTypeIndex + 1
FireMode.Deployables(ammoTypeIndex) FireMode.Deployables(ammoTypeIndex)
} }
def ModePermissions : Set[CertificationType.Value] = FireMode.Permissions(ammoTypeIndex) def ModePermissions: Set[CertificationType.Value] = FireMode.Permissions(ammoTypeIndex)
def Definition : ConstructionItemDefinition = cItemDef def Definition: ConstructionItemDefinition = cItemDef
} }
object ConstructionItem { object ConstructionItem {
def apply(cItemDef : ConstructionItemDefinition) : ConstructionItem = { def apply(cItemDef: ConstructionItemDefinition): ConstructionItem = {
new ConstructionItem(cItemDef) new ConstructionItem(cItemDef)
} }
} }

View file

@ -5,20 +5,21 @@ object Default {
//cancellable //cancellable
import akka.actor.Cancellable import akka.actor.Cancellable
protected class InternalCancellable extends Cancellable { protected class InternalCancellable extends Cancellable {
override def cancel : Boolean = true override def cancel: Boolean = true
override def isCancelled : Boolean = true override def isCancelled: Boolean = true
} }
private val cancellable : Cancellable = new InternalCancellable private val cancellable: Cancellable = new InternalCancellable
/** /**
* Used to initialize the value of a re-usable `Cancellable` object. * Used to initialize the value of a re-usable `Cancellable` object.
* By convention, it always acts like it has been cancelled before and can be cancelled. * By convention, it always acts like it has been cancelled before and can be cancelled.
* Should be replaced with pertinent `Cancellable` logic through the initialization of an executor. * Should be replaced with pertinent `Cancellable` logic through the initialization of an executor.
*/ */
final def Cancellable : Cancellable = cancellable final def Cancellable: Cancellable = cancellable
//actor //actor
import akka.actor.{Actor => AkkaActor, ActorRef, ActorSystem, DeadLetter, Props} import akka.actor.{Actor => AkkaActor, ActorRef, ActorSystem, DeadLetter, Props}
/** /**
* An actor designed to wrap around `deadLetters` and redirect all normal messages to it. * An actor designed to wrap around `deadLetters` and redirect all normal messages to it.
* This measure is more to "protect" `deadLetters` than anything else. * This measure is more to "protect" `deadLetters` than anything else.
@ -26,22 +27,23 @@ object Default {
* The original target to which the actor is assigned will not be implicitly accredited. * The original target to which the actor is assigned will not be implicitly accredited.
*/ */
private class DefaultActor extends AkkaActor { private class DefaultActor extends AkkaActor {
def receive : Receive = { def receive: Receive = {
case msg => context.system.deadLetters ! DeadLetter(msg, sender, self) case msg => context.system.deadLetters ! DeadLetter(msg, sender, self)
} }
} }
private var defaultRef : ActorRef = ActorRef.noSender private var defaultRef: ActorRef = ActorRef.noSender
/** /**
* Instigate the default actor. * Instigate the default actor.
* @param sys the actor universe under which this default actor will exist * @param sys the actor universe under which this default actor will exist
* @return the new default actor * @return the new default actor
*/ */
def apply(sys : ActorSystem) : ActorRef = { def apply(sys: ActorSystem): ActorRef = {
if(defaultRef == ActorRef.noSender) { if (defaultRef == ActorRef.noSender) {
defaultRef = sys.actorOf(Props[DefaultActor], name = s"system-default-actor") defaultRef = sys.actorOf(Props[DefaultActor], name = s"system-default-actor")
} }
defaultRef defaultRef
} }
final def Actor : ActorRef = defaultRef final def Actor: ActorRef = defaultRef
} }

View file

@ -16,26 +16,36 @@ object Deployables {
private val log = org.log4s.getLogger("Deployables") private val log = org.log4s.getLogger("Deployables")
object Make { object Make {
def apply(item : DeployedItem.Value) : ()=>PlanetSideGameObject with Deployable = cemap(item) def apply(item: DeployedItem.Value): () => PlanetSideGameObject with Deployable = cemap(item)
private val cemap : Map[DeployedItem.Value, ()=>PlanetSideGameObject with Deployable] = Map( private val cemap: Map[DeployedItem.Value, () => PlanetSideGameObject with Deployable] = Map(
DeployedItem.boomer -> { ()=> new BoomerDeployable(GlobalDefinitions.boomer) }, DeployedItem.boomer -> { () => new BoomerDeployable(GlobalDefinitions.boomer) },
DeployedItem.he_mine -> { ()=> new ExplosiveDeployable(GlobalDefinitions.he_mine) }, DeployedItem.he_mine -> { () => new ExplosiveDeployable(GlobalDefinitions.he_mine) },
DeployedItem.jammer_mine -> { ()=> new ExplosiveDeployable(GlobalDefinitions.jammer_mine) }, DeployedItem.jammer_mine -> { () => new ExplosiveDeployable(GlobalDefinitions.jammer_mine) },
DeployedItem.spitfire_turret -> { ()=> new TurretDeployable(GlobalDefinitions.spitfire_turret) }, DeployedItem.spitfire_turret -> { () => new TurretDeployable(GlobalDefinitions.spitfire_turret) },
DeployedItem.spitfire_cloaked -> { ()=> new TurretDeployable(GlobalDefinitions.spitfire_cloaked) }, DeployedItem.spitfire_cloaked -> { () => new TurretDeployable(GlobalDefinitions.spitfire_cloaked) },
DeployedItem.spitfire_aa -> { ()=> new TurretDeployable(GlobalDefinitions.spitfire_aa) }, DeployedItem.spitfire_aa -> { () => new TurretDeployable(GlobalDefinitions.spitfire_aa) },
DeployedItem.motionalarmsensor -> { ()=> new SensorDeployable(GlobalDefinitions.motionalarmsensor) }, DeployedItem.motionalarmsensor -> { () => new SensorDeployable(GlobalDefinitions.motionalarmsensor) },
DeployedItem.sensor_shield -> { ()=> new SensorDeployable(GlobalDefinitions.sensor_shield) }, DeployedItem.sensor_shield -> { () => new SensorDeployable(GlobalDefinitions.sensor_shield) },
DeployedItem.tank_traps -> { ()=> new TrapDeployable(GlobalDefinitions.tank_traps) }, DeployedItem.tank_traps -> { () => new TrapDeployable(GlobalDefinitions.tank_traps) },
DeployedItem.portable_manned_turret -> { ()=> new TurretDeployable(GlobalDefinitions.portable_manned_turret) }, DeployedItem.portable_manned_turret -> { () => new TurretDeployable(GlobalDefinitions.portable_manned_turret) },
DeployedItem.portable_manned_turret -> { ()=> new TurretDeployable(GlobalDefinitions.portable_manned_turret) }, DeployedItem.portable_manned_turret -> { () => new TurretDeployable(GlobalDefinitions.portable_manned_turret) },
DeployedItem.portable_manned_turret_nc -> { ()=> new TurretDeployable(GlobalDefinitions.portable_manned_turret_nc) }, DeployedItem.portable_manned_turret_nc -> { () =>
DeployedItem.portable_manned_turret_tr -> { ()=> new TurretDeployable(GlobalDefinitions.portable_manned_turret_tr) }, new TurretDeployable(GlobalDefinitions.portable_manned_turret_nc)
DeployedItem.portable_manned_turret_vs -> { ()=> new TurretDeployable(GlobalDefinitions.portable_manned_turret_vs) }, },
DeployedItem.deployable_shield_generator -> { ()=> new ShieldGeneratorDeployable(GlobalDefinitions.deployable_shield_generator) }, DeployedItem.portable_manned_turret_tr -> { () =>
DeployedItem.router_telepad_deployable -> { () => new TelepadDeployable(GlobalDefinitions.router_telepad_deployable) } new TurretDeployable(GlobalDefinitions.portable_manned_turret_tr)
).withDefaultValue( { ()=> new ExplosiveDeployable(GlobalDefinitions.boomer) } ) },
DeployedItem.portable_manned_turret_vs -> { () =>
new TurretDeployable(GlobalDefinitions.portable_manned_turret_vs)
},
DeployedItem.deployable_shield_generator -> { () =>
new ShieldGeneratorDeployable(GlobalDefinitions.deployable_shield_generator)
},
DeployedItem.router_telepad_deployable -> { () =>
new TelepadDeployable(GlobalDefinitions.router_telepad_deployable)
}
).withDefaultValue({ () => new ExplosiveDeployable(GlobalDefinitions.boomer) })
} }
/** /**
@ -60,7 +70,7 @@ object Deployables {
* @param time length of time that the deployable is allowed to exist in the game world; * @param time length of time that the deployable is allowed to exist in the game world;
* `None` indicates the normal un-owned existence time (180 seconds) * `None` indicates the normal un-owned existence time (180 seconds)
*/ */
def AnnounceDestroyDeployable(target : PlanetSideGameObject with Deployable, time : Option[FiniteDuration]) : Unit = { def AnnounceDestroyDeployable(target: PlanetSideGameObject with Deployable, time: Option[FiniteDuration]): Unit = {
val zone = target.Zone val zone = target.Zone
target.OwnerName match { target.OwnerName match {
case Some(owner) => case Some(owner) =>
@ -68,10 +78,13 @@ object Deployables {
zone.LocalEvents ! LocalServiceMessage(owner, LocalAction.AlertDestroyDeployable(PlanetSideGUID(0), target)) zone.LocalEvents ! LocalServiceMessage(owner, LocalAction.AlertDestroyDeployable(PlanetSideGUID(0), target))
case None => ; case None => ;
} }
zone.LocalEvents ! LocalServiceMessage(s"${target.Faction}", LocalAction.DeployableMapIcon( zone.LocalEvents ! LocalServiceMessage(
PlanetSideGUID(0), s"${target.Faction}",
DeploymentAction.Dismiss, LocalAction.DeployableMapIcon(
DeployableInfo(target.GUID, Deployable.Icon(target.Definition.Item), target.Position, PlanetSideGUID(0))) PlanetSideGUID(0),
DeploymentAction.Dismiss,
DeployableInfo(target.GUID, Deployable.Icon(target.Definition.Item), target.Position, PlanetSideGUID(0))
)
) )
zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(target), zone)) zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(target), zone))
zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(target, zone, time)) zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(target, zone, time))
@ -86,17 +99,22 @@ object Deployables {
* @return all previously-owned deployables after they have been processed; * @return all previously-owned deployables after they have been processed;
* boomers are listed before all other deployable types * boomers are listed before all other deployable types
*/ */
def Disown(zone : Zone, avatar : Avatar, replyTo : ActorRef) : List[PlanetSideGameObject with Deployable] = { def Disown(zone: Zone, avatar: Avatar, replyTo: ActorRef): List[PlanetSideGameObject with Deployable] = {
val (boomers, deployables) = val (boomers, deployables) =
avatar.Deployables.Clear() avatar.Deployables
.Clear()
.map(zone.GUID) .map(zone.GUID)
.collect { case Some(obj) => obj.asInstanceOf[PlanetSideGameObject with Deployable] } .collect { case Some(obj) => obj.asInstanceOf[PlanetSideGameObject with Deployable] }
.partition(_.isInstanceOf[BoomerDeployable]) .partition(_.isInstanceOf[BoomerDeployable])
//do not change the OwnerName field at this time //do not change the OwnerName field at this time
boomers.collect({ case obj : BoomerDeployable => boomers.collect({
zone.LocalEvents.tell(LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, zone, Some(0 seconds))), replyTo) //near-instant case obj: BoomerDeployable =>
obj.Owner = None zone.LocalEvents.tell(
obj.Trigger = None LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, zone, Some(0 seconds))),
replyTo
) //near-instant
obj.Owner = None
obj.Trigger = None
}) })
deployables.foreach(obj => { deployables.foreach(obj => {
zone.LocalEvents.tell(LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, zone)), replyTo) //normal decay zone.LocalEvents.tell(LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, zone)), replyTo) //normal decay
@ -105,17 +123,17 @@ object Deployables {
boomers ++ deployables boomers ++ deployables
} }
def RemoveTelepad(vehicle: Vehicle) : Unit = { def RemoveTelepad(vehicle: Vehicle): Unit = {
val zone = vehicle.Zone val zone = vehicle.Zone
(vehicle.Utility(UtilityType.internal_router_telepad_deployable) match { (vehicle.Utility(UtilityType.internal_router_telepad_deployable) match {
case Some(util : Utility.InternalTelepad) => case Some(util: Utility.InternalTelepad) =>
val telepad = util.Telepad val telepad = util.Telepad
util.Telepad = None util.Telepad = None
zone.GUID(telepad) zone.GUID(telepad)
case _ => case _ =>
None None
}) match { }) match {
case Some(telepad : TelepadDeployable) => case Some(telepad: TelepadDeployable) =>
log.info(s"BeforeUnload: deconstructing telepad $telepad that was linked to router $vehicle ...") log.info(s"BeforeUnload: deconstructing telepad $telepad that was linked to router $vehicle ...")
telepad.Active = false telepad.Active = false
zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(telepad), zone)) zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(telepad), zone))
@ -124,13 +142,11 @@ object Deployables {
} }
} }
/** /**
* Initialize the deployables backend information. * Initialize the deployables backend information.
* @param avatar the player's core * @param avatar the player's core
*/ */
def InitializeDeployableQuantities(avatar : Avatar) : Boolean = { def InitializeDeployableQuantities(avatar: Avatar): Boolean = {
log.info("Setting up combat engineering ...") log.info("Setting up combat engineering ...")
avatar.Deployables.Initialize(avatar.Certifications.toSet) avatar.Deployables.Initialize(avatar.Certifications.toSet)
} }
@ -139,7 +155,7 @@ object Deployables {
* Initialize the UI elements for deployables. * Initialize the UI elements for deployables.
* @param avatar the player's core * @param avatar the player's core
*/ */
def InitializeDeployableUIElements(avatar : Avatar) : List[(Int,Int,Int,Int)] = { def InitializeDeployableUIElements(avatar: Avatar): List[(Int, Int, Int, Int)] = {
log.info("Setting up combat engineering UI ...") log.info("Setting up combat engineering UI ...")
avatar.Deployables.UpdateUI() avatar.Deployables.UpdateUI()
} }
@ -151,7 +167,11 @@ object Deployables {
* @param certification the certification that was added * @param certification the certification that was added
* @param certificationSet all applicable certifications * @param certificationSet all applicable certifications
*/ */
def AddToDeployableQuantities(avatar : Avatar, certification : CertificationType.Value, certificationSet : Set[CertificationType.Value]) : List[(Int,Int,Int,Int)] = { def AddToDeployableQuantities(
avatar: Avatar,
certification: CertificationType.Value,
certificationSet: Set[CertificationType.Value]
): List[(Int, Int, Int, Int)] = {
avatar.Deployables.AddToDeployableQuantities(certification, certificationSet) avatar.Deployables.AddToDeployableQuantities(certification, certificationSet)
avatar.Deployables.UpdateUI(certification) avatar.Deployables.UpdateUI(certification)
} }
@ -163,7 +183,11 @@ object Deployables {
* @param certification the certification that was added * @param certification the certification that was added
* @param certificationSet all applicable certifications * @param certificationSet all applicable certifications
*/ */
def RemoveFromDeployableQuantities(avatar : Avatar, certification : CertificationType.Value, certificationSet : Set[CertificationType.Value]) : List[(Int,Int,Int,Int)] = { def RemoveFromDeployableQuantities(
avatar: Avatar,
certification: CertificationType.Value,
certificationSet: Set[CertificationType.Value]
): List[(Int, Int, Int, Int)] = {
avatar.Deployables.RemoveFromDeployableQuantities(certification, certificationSet) avatar.Deployables.RemoveFromDeployableQuantities(certification, certificationSet)
avatar.Deployables.UpdateUI(certification) avatar.Deployables.UpdateUI(certification)
} }

View file

@ -18,61 +18,60 @@ import services.local.{LocalAction, LocalServiceMessage}
import scala.concurrent.duration._ import scala.concurrent.duration._
class ExplosiveDeployable(cdef : ExplosiveDeployableDefinition) extends ComplexDeployable(cdef) class ExplosiveDeployable(cdef: ExplosiveDeployableDefinition) extends ComplexDeployable(cdef) with JammableUnit {
with JammableUnit {
override def Definition : ExplosiveDeployableDefinition = cdef override def Definition: ExplosiveDeployableDefinition = cdef
} }
class ExplosiveDeployableDefinition(private val objectId : Int) extends ComplexDeployableDefinition(objectId) { class ExplosiveDeployableDefinition(private val objectId: Int) extends ComplexDeployableDefinition(objectId) {
Name = "explosive_deployable" Name = "explosive_deployable"
DeployCategory = DeployableCategory.Mines DeployCategory = DeployableCategory.Mines
Model = StandardResolutions.SimpleDeployables Model = StandardResolutions.SimpleDeployables
Packet = new SmallDeployableConverter Packet = new SmallDeployableConverter
private var detonateOnJamming : Boolean = true private var detonateOnJamming: Boolean = true
def DetonateOnJamming : Boolean = detonateOnJamming def DetonateOnJamming: Boolean = detonateOnJamming
def DetonateOnJamming_=(detonate : Boolean) : Boolean = { def DetonateOnJamming_=(detonate: Boolean): Boolean = {
detonateOnJamming = detonate detonateOnJamming = detonate
DetonateOnJamming DetonateOnJamming
} }
override def Initialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = { override def Initialize(obj: PlanetSideServerObject with Deployable, context: ActorContext) = {
obj.Actor = context.actorOf(Props(classOf[ExplosiveDeployableControl], obj), PlanetSideServerObject.UniqueActorName(obj)) obj.Actor =
context.actorOf(Props(classOf[ExplosiveDeployableControl], obj), PlanetSideServerObject.UniqueActorName(obj))
} }
override def Uninitialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = { override def Uninitialize(obj: PlanetSideServerObject with Deployable, context: ActorContext) = {
SimpleDeployableDefinition.SimpleUninitialize(obj, context) SimpleDeployableDefinition.SimpleUninitialize(obj, context)
} }
} }
object ExplosiveDeployableDefinition { object ExplosiveDeployableDefinition {
def apply(dtype : DeployedItem.Value) : ExplosiveDeployableDefinition = { def apply(dtype: DeployedItem.Value): ExplosiveDeployableDefinition = {
new ExplosiveDeployableDefinition(dtype.id) new ExplosiveDeployableDefinition(dtype.id)
} }
} }
class ExplosiveDeployableControl(mine : ExplosiveDeployable) extends Actor class ExplosiveDeployableControl(mine: ExplosiveDeployable) extends Actor with Damageable {
with Damageable {
def DamageableObject = mine def DamageableObject = mine
def receive : Receive = takesDamage def receive: Receive =
.orElse { takesDamage
case _ => ; .orElse {
} case _ => ;
}
protected def TakesDamage : Receive = { protected def TakesDamage: Receive = {
case Vitality.Damage(applyDamageTo) => case Vitality.Damage(applyDamageTo) =>
if(mine.CanDamage) { if (mine.CanDamage) {
val originalHealth = mine.Health val originalHealth = mine.Health
val cause = applyDamageTo(mine) val cause = applyDamageTo(mine)
val damage = originalHealth - mine.Health val damage = originalHealth - mine.Health
if(Damageable.CanDamageOrJammer(mine, damage, cause)) { if (Damageable.CanDamageOrJammer(mine, damage, cause)) {
ExplosiveDeployableControl.DamageResolution(mine, cause, damage) ExplosiveDeployableControl.DamageResolution(mine, cause, damage)
} } else {
else {
mine.Health = originalHealth mine.Health = originalHealth
} }
} }
@ -80,17 +79,18 @@ class ExplosiveDeployableControl(mine : ExplosiveDeployable) extends Actor
} }
object ExplosiveDeployableControl { object ExplosiveDeployableControl {
def DamageResolution(target : ExplosiveDeployable, cause : ResolvedProjectile, damage : Int) : Unit = { def DamageResolution(target: ExplosiveDeployable, cause: ResolvedProjectile, damage: Int): Unit = {
target.History(cause) target.History(cause)
if(target.Health == 0) { if (target.Health == 0) {
DestructionAwareness(target, cause) DestructionAwareness(target, cause)
} } else if (!target.Jammed && Damageable.CanJammer(target, cause)) {
else if(!target.Jammed && Damageable.CanJammer(target, cause)) { if (
if(target.Jammed = { target.Jammed = {
val radius = cause.projectile.profile.DamageRadius val radius = cause.projectile.profile.DamageRadius
Vector3.DistanceSquared(cause.hit_pos, cause.target.Position) < radius * radius Vector3.DistanceSquared(cause.hit_pos, cause.target.Position) < radius * radius
}) { }
if(target.Definition.DetonateOnJamming) { ) {
if (target.Definition.DetonateOnJamming) {
val zone = target.Zone val zone = target.Zone
zone.Activity ! Zone.HotSpot.Activity(cause.target, cause.projectile.owner, cause.hit_pos) zone.Activity ! Zone.HotSpot.Activity(cause.target, cause.projectile.owner, cause.hit_pos)
zone.LocalEvents ! LocalServiceMessage(zone.Id, LocalAction.Detonate(target.GUID, target)) zone.LocalEvents ! LocalServiceMessage(zone.Id, LocalAction.Detonate(target.GUID, target))
@ -105,17 +105,23 @@ object ExplosiveDeployableControl {
* @param target na * @param target na
* @param cause na * @param cause na
*/ */
def DestructionAwareness(target : ExplosiveDeployable, cause : ResolvedProjectile) : Unit = { def DestructionAwareness(target: ExplosiveDeployable, cause: ResolvedProjectile): Unit = {
val zone = target.Zone val zone = target.Zone
val attribution = zone.LivePlayers.find { p => cause.projectile.owner.Name.equals(p.Name) } match { val attribution = zone.LivePlayers.find { p => cause.projectile.owner.Name.equals(p.Name) } match {
case Some(player) => player.GUID case Some(player) => player.GUID
case _ => PlanetSideGUID(0) case _ => PlanetSideGUID(0)
} }
target.Destroyed = true target.Destroyed = true
Deployables.AnnounceDestroyDeployable(target, Some(if(target.Jammed) 0 seconds else 500 milliseconds)) Deployables.AnnounceDestroyDeployable(target, Some(if (target.Jammed) 0 seconds else 500 milliseconds))
zone.AvatarEvents ! AvatarServiceMessage(zone.Id, AvatarAction.Destroy(target.GUID, attribution, Service.defaultPlayerGUID, target.Position)) zone.AvatarEvents ! AvatarServiceMessage(
if(target.Health == 0) { zone.Id,
zone.LocalEvents ! LocalServiceMessage(zone.Id, LocalAction.TriggerEffect(Service.defaultPlayerGUID, "detonate_damaged_mine", target.GUID)) AvatarAction.Destroy(target.GUID, attribution, Service.defaultPlayerGUID, target.Position)
)
if (target.Health == 0) {
zone.LocalEvents ! LocalServiceMessage(
zone.Id,
LocalAction.TriggerEffect(Service.defaultPlayerGUID, "detonate_damaged_mine", target.GUID)
)
} }
} }
} }

View file

@ -14,61 +14,68 @@ import net.psforever.types.{ExoSuitType, ImplantType}
* Being jammed de-activates the implant, put it into a state of "not being ready," and causes the initialization to repeat. * Being jammed de-activates the implant, put it into a state of "not being ready," and causes the initialization to repeat.
*/ */
class ImplantSlot { class ImplantSlot {
/** is this slot available for holding an implant */ /** is this slot available for holding an implant */
private var unlocked : Boolean = false private var unlocked: Boolean = false
/** whether this implant is ready for use */ /** whether this implant is ready for use */
private var initialized : Boolean = false private var initialized: Boolean = false
/** */
private var initializeTime : Long = 0L /**
*/
private var initializeTime: Long = 0L
/** is this implant active */ /** is this implant active */
private var active : Boolean = false private var active: Boolean = false
/** what implant is currently installed in this slot; None if there is no implant currently installed */ /** what implant is currently installed in this slot; None if there is no implant currently installed */
private var implant : Option[ImplantDefinition] = None private var implant: Option[ImplantDefinition] = None
def InitializeTime : Long = initializeTime def InitializeTime: Long = initializeTime
def InitializeTime_=(time : Long) : Long = { def InitializeTime_=(time: Long): Long = {
initializeTime = time initializeTime = time
InitializeTime InitializeTime
} }
def Unlocked : Boolean = unlocked def Unlocked: Boolean = unlocked
def Unlocked_=(lock : Boolean) : Boolean = { def Unlocked_=(lock: Boolean): Boolean = {
unlocked = lock || unlocked //do not let re-lock unlocked = lock || unlocked //do not let re-lock
Unlocked Unlocked
} }
def Initialized : Boolean = initialized def Initialized: Boolean = initialized
def Initialized_=(init : Boolean) : Boolean = { def Initialized_=(init: Boolean): Boolean = {
initialized = Installed.isDefined && init initialized = Installed.isDefined && init
Active = Active && initialized //can not be active just yet Active = Active && initialized //can not be active just yet
Initialized Initialized
} }
def Active : Boolean = active def Active: Boolean = active
def Active_=(state : Boolean) : Boolean = { def Active_=(state: Boolean): Boolean = {
active = Initialized && state active = Initialized && state
Active Active
} }
def Implant : ImplantType.Value = Installed match { def Implant: ImplantType.Value =
case Some(idef) => Installed match {
idef.Type case Some(idef) =>
case None => idef.Type
Active = false case None =>
Initialized = false Active = false
ImplantType.None Initialized = false
} ImplantType.None
}
def Implant_=(anImplant : ImplantDefinition) : ImplantType.Value = { def Implant_=(anImplant: ImplantDefinition): ImplantType.Value = {
Implant_=(Some(anImplant)) Implant_=(Some(anImplant))
} }
def Implant_=(anImplant : Option[ImplantDefinition]) : ImplantType.Value = { def Implant_=(anImplant: Option[ImplantDefinition]): ImplantType.Value = {
if(Unlocked) { if (Unlocked) {
anImplant match { anImplant match {
case Some(_) => case Some(_) =>
implant = anImplant implant = anImplant
@ -81,20 +88,20 @@ class ImplantSlot {
Implant Implant
} }
def Installed : Option[ImplantDefinition] = implant def Installed: Option[ImplantDefinition] = implant
def MaxTimer : Long = Implant match { def MaxTimer: Long =
case ImplantType.None => Implant match {
-1L case ImplantType.None =>
case _ => -1L
Installed.get.InitializationDuration case _ =>
} Installed.get.InitializationDuration
def ActivationCharge : Int = {
if(Active) {
Installed.get.ActivationStaminaCost
} }
else {
def ActivationCharge: Int = {
if (Active) {
Installed.get.ActivationStaminaCost
} else {
0 0
} }
} }
@ -104,24 +111,23 @@ class ImplantSlot {
* @param suit the exo-suit being worn * @param suit the exo-suit being worn
* @return the amount of stamina (energy) that is consumed * @return the amount of stamina (energy) that is consumed
*/ */
def Charge(suit : ExoSuitType.Value) : Int = { def Charge(suit: ExoSuitType.Value): Int = {
if(Active) { if (Active) {
val inst = Installed.get val inst = Installed.get
inst.StaminaCost inst.StaminaCost
} } else {
else {
0 0
} }
} }
def Jammed() : Unit = { def Jammed(): Unit = {
Active = false Active = false
Initialized = false Initialized = false
} }
} }
object ImplantSlot { object ImplantSlot {
def apply() : ImplantSlot = { def apply(): ImplantSlot = {
new ImplantSlot() new ImplantSlot()
} }
} }

View file

@ -8,12 +8,12 @@ import net.psforever.objects.equipment.Equipment
* A one-time-use recovery item that can be applied by the player while held within their inventory. * A one-time-use recovery item that can be applied by the player while held within their inventory.
* @param kitDef the `ObjectDefinition` that constructs this item and maintains some of its immutable fields * @param kitDef the `ObjectDefinition` that constructs this item and maintains some of its immutable fields
*/ */
class Kit(private val kitDef : KitDefinition) extends Equipment { class Kit(private val kitDef: KitDefinition) extends Equipment {
def Definition : KitDefinition = kitDef def Definition: KitDefinition = kitDef
} }
object Kit { object Kit {
def apply(kitDef : KitDefinition) : Kit = { def apply(kitDef: KitDefinition): Kit = {
new Kit(kitDef) new Kit(kitDef)
} }
} }

View file

@ -8,14 +8,15 @@ import scala.collection.concurrent.{Map, TrieMap}
* `LivePlayerList` is a singleton and this private class lacks exposure. * `LivePlayerList` is a singleton and this private class lacks exposure.
*/ */
private class LivePlayerList { private class LivePlayerList {
/** key - the session id; value - a `Player` object */
private val sessionMap : Map[Long, Avatar] = new TrieMap[Long, Avatar]
def WorldPopulation(predicate : ((_, Avatar)) => Boolean) : List[Avatar] = { /** key - the session id; value - a `Player` object */
private val sessionMap: Map[Long, Avatar] = new TrieMap[Long, Avatar]
def WorldPopulation(predicate: ((_, Avatar)) => Boolean): List[Avatar] = {
sessionMap.filter(predicate).values.toList sessionMap.filter(predicate).values.toList
} }
def Add(sessionId : Long, avatar : Avatar) : Boolean = { def Add(sessionId: Long, avatar: Avatar): Boolean = {
sessionMap.values.find(char => char.equals(avatar)) match { sessionMap.values.find(char => char.equals(avatar)) match {
case None => case None =>
sessionMap.putIfAbsent(sessionId, avatar).isEmpty sessionMap.putIfAbsent(sessionId, avatar).isEmpty
@ -24,11 +25,11 @@ private class LivePlayerList {
} }
} }
def Remove(sessionId : Long) : Option[Avatar] = { def Remove(sessionId: Long): Option[Avatar] = {
sessionMap.remove(sessionId) sessionMap.remove(sessionId)
} }
def Shutdown : List[Avatar] = { def Shutdown: List[Avatar] = {
val list = sessionMap.values.toList val list = sessionMap.values.toList
sessionMap.clear sessionMap.clear
list list
@ -48,8 +49,9 @@ private class LivePlayerList {
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`LivePlayerList.Remove(session)` * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`LivePlayerList.Remove(session)`
*/ */
object LivePlayerList { object LivePlayerList {
/** As `LivePlayerList` is a singleton, an object of `LivePlayerList` is automatically instantiated. */ /** As `LivePlayerList` is a singleton, an object of `LivePlayerList` is automatically instantiated. */
private val Instance : LivePlayerList = new LivePlayerList private val Instance: LivePlayerList = new LivePlayerList
/** /**
* Given some criteria, examine the mapping of user characters and find the ones that fulfill the requirements.<br> * Given some criteria, examine the mapping of user characters and find the ones that fulfill the requirements.<br>
@ -61,7 +63,7 @@ object LivePlayerList {
* @param predicate the conditions for filtering the live `Player`s * @param predicate the conditions for filtering the live `Player`s
* @return a list of users's `Player`s that fit the criteria * @return a list of users's `Player`s that fit the criteria
*/ */
def WorldPopulation(predicate : ((_, Avatar)) => Boolean) : List[Avatar] = Instance.WorldPopulation(predicate) def WorldPopulation(predicate: ((_, Avatar)) => Boolean): List[Avatar] = Instance.WorldPopulation(predicate)
/** /**
* Create a mapped entry between the user's session and a user's character. * Create a mapped entry between the user's session and a user's character.
@ -70,7 +72,7 @@ object LivePlayerList {
* @param avatar the character * @param avatar the character
* @return `true`, if the session was association was made; `false`, otherwise * @return `true`, if the session was association was made; `false`, otherwise
*/ */
def Add(sessionId : Long, avatar : Avatar) : Boolean = Instance.Add(sessionId, avatar) def Add(sessionId: Long, avatar: Avatar): Boolean = Instance.Add(sessionId, avatar)
/** /**
* Remove all entries related to the given session identifier from the mappings. * Remove all entries related to the given session identifier from the mappings.
@ -78,11 +80,11 @@ object LivePlayerList {
* @param sessionId the session * @param sessionId the session
* @return any character that was afffected by the mapping removal * @return any character that was afffected by the mapping removal
*/ */
def Remove(sessionId : Long) : Option[Avatar] = Instance.Remove(sessionId) def Remove(sessionId: Long): Option[Avatar] = Instance.Remove(sessionId)
/** /**
* Hastily remove all mappings and ids. * Hastily remove all mappings and ids.
* @return an unsorted list of the characters that were still online * @return an unsorted list of the characters that were still online
*/ */
def Shutdown : List[Avatar] = Instance.Shutdown def Shutdown: List[Avatar] = Instance.Shutdown
} }

View file

@ -30,7 +30,7 @@ object LocalProjectile {
* @param context a context to allow the object to properly set up `ActorSystem` functionality * @param context a context to allow the object to properly set up `ActorSystem` functionality
* @return the `LocalProjectile` object * @return the `LocalProjectile` object
*/ */
def Constructor(id : Int, context : ActorContext) : LocalProjectile = { def Constructor(id: Int, context: ActorContext): LocalProjectile = {
new LocalProjectile() new LocalProjectile()
} }
} }

View file

@ -19,62 +19,60 @@ import services.avatar.{AvatarAction, AvatarServiceMessage}
* The `Player` class refers to it as the "fifth slot" as its permanent slot number is encoded as `0x85`. * The `Player` class refers to it as the "fifth slot" as its permanent slot number is encoded as `0x85`.
* The inventory of this object is accessed using a game world `Locker` object (`mb_locker`). * The inventory of this object is accessed using a game world `Locker` object (`mb_locker`).
*/ */
class LockerContainer extends PlanetSideServerObject class LockerContainer extends PlanetSideServerObject with Container {
with Container { private var faction: PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL private val inventory = GridInventory(30, 20)
private val inventory = GridInventory(30, 20)
def Faction : PlanetSideEmpire.Value = faction def Faction: PlanetSideEmpire.Value = faction
override def Faction_=(fact : PlanetSideEmpire.Value) : PlanetSideEmpire.Value = { override def Faction_=(fact: PlanetSideEmpire.Value): PlanetSideEmpire.Value = {
faction = fact faction = fact
Faction Faction
} }
def Inventory : GridInventory = inventory def Inventory: GridInventory = inventory
def VisibleSlots : Set[Int] = Set.empty[Int] def VisibleSlots: Set[Int] = Set.empty[Int]
def Definition : EquipmentDefinition = GlobalDefinitions.locker_container def Definition: EquipmentDefinition = GlobalDefinitions.locker_container
} }
object LockerContainer { object LockerContainer {
def apply() : LockerContainer = { def apply(): LockerContainer = {
new LockerContainer() new LockerContainer()
} }
} }
class LockerEquipment(locker : LockerContainer) extends Equipment class LockerEquipment(locker: LockerContainer) extends Equipment with Container {
with Container {
private val obj = locker private val obj = locker
override def GUID : PlanetSideGUID = obj.GUID override def GUID: PlanetSideGUID = obj.GUID
override def GUID_=(guid : PlanetSideGUID) : PlanetSideGUID = obj.GUID_=(guid) override def GUID_=(guid: PlanetSideGUID): PlanetSideGUID = obj.GUID_=(guid)
override def HasGUID : Boolean = obj.HasGUID override def HasGUID: Boolean = obj.HasGUID
override def Invalidate() : Unit = obj.Invalidate() override def Invalidate(): Unit = obj.Invalidate()
override def Faction : PlanetSideEmpire.Value = obj.Faction override def Faction: PlanetSideEmpire.Value = obj.Faction
def Inventory : GridInventory = obj.Inventory def Inventory: GridInventory = obj.Inventory
def VisibleSlots : Set[Int] = Set.empty[Int] def VisibleSlots: Set[Int] = Set.empty[Int]
def Definition : EquipmentDefinition = obj.Definition def Definition: EquipmentDefinition = obj.Definition
} }
class LockerContainerControl(locker : LockerContainer, toChannel : String) extends Actor class LockerContainerControl(locker: LockerContainer, toChannel: String) extends Actor with ContainableBehavior {
with ContainableBehavior {
def ContainerObject = locker def ContainerObject = locker
def receive : Receive = containerBehavior def receive: Receive =
.orElse { containerBehavior
case _ => ; .orElse {
} case _ => ;
}
def MessageDeferredCallback(msg : Any) : Unit = { def MessageDeferredCallback(msg: Any): Unit = {
msg match { msg match {
case Containable.MoveItem(_, item, _) => case Containable.MoveItem(_, item, _) =>
//momentarily put item back where it was originally //momentarily put item back where it was originally
@ -91,13 +89,13 @@ class LockerContainerControl(locker : LockerContainer, toChannel : String) exten
} }
} }
def RemoveItemFromSlotCallback(item : Equipment, slot : Int) : Unit = { def RemoveItemFromSlotCallback(item: Equipment, slot: Int): Unit = {
val zone = locker.Zone val zone = locker.Zone
zone.AvatarEvents ! AvatarServiceMessage(toChannel, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, item.GUID)) zone.AvatarEvents ! AvatarServiceMessage(toChannel, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, item.GUID))
} }
def PutItemInSlotCallback(item : Equipment, slot : Int) : Unit = { def PutItemInSlotCallback(item: Equipment, slot: Int): Unit = {
val zone = locker.Zone val zone = locker.Zone
val definition = item.Definition val definition = item.Definition
item.Faction = PlanetSideEmpire.NEUTRAL item.Faction = PlanetSideEmpire.NEUTRAL
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! AvatarServiceMessage(
@ -114,8 +112,14 @@ class LockerContainerControl(locker : LockerContainer, toChannel : String) exten
) )
} }
def SwapItemCallback(item : Equipment) : Unit = { def SwapItemCallback(item: Equipment): Unit = {
val zone = locker.Zone val zone = locker.Zone
zone.AvatarEvents ! AvatarServiceMessage(toChannel, AvatarAction.SendResponse(Service.defaultPlayerGUID, ObjectDetachMessage(locker.GUID, item.GUID, Vector3.Zero, 0f))) zone.AvatarEvents ! AvatarServiceMessage(
toChannel,
AvatarAction.SendResponse(
Service.defaultPlayerGUID,
ObjectDetachMessage(locker.GUID, item.GUID, Vector3.Zero, 0f)
)
)
} }
} }

View file

@ -4,93 +4,93 @@ package net.psforever.objects
object ObjectType extends Enumeration { object ObjectType extends Enumeration {
type Value = String type Value = String
val AmbientSoundSource = "ambient_sound_source" val AmbientSoundSource = "ambient_sound_source"
val Ammunition = "ammunition" val Ammunition = "ammunition"
val AnimatedBarrier = "animated_barrier" val AnimatedBarrier = "animated_barrier"
val Applicator = "applicator" val Applicator = "applicator"
val Armor = "armor" val Armor = "armor"
val ArmorSiphon = "armor_siphon" val ArmorSiphon = "armor_siphon"
val AwardStatistic = "award_statistic" val AwardStatistic = "award_statistic"
val Avatar = "avatar" val Avatar = "avatar"
val AvatarBot = "avatar_bot" val AvatarBot = "avatar_bot"
val Ball = "ball" val Ball = "ball"
val Bank = "bank" val Bank = "bank"
val Barrier = "barrier" val Barrier = "barrier"
val BfrTerminal = "bfr_terminal" val BfrTerminal = "bfr_terminal"
val Billboard = "billboard" val Billboard = "billboard"
val Boomer = "boomer" val Boomer = "boomer"
val BoomerTrigger = "boomer_trigger" val BoomerTrigger = "boomer_trigger"
val Building = "building" val Building = "building"
val CaptureFlag = "capture_flag" val CaptureFlag = "capture_flag"
val CaptureFlagSocket = "capture_flag_socket" val CaptureFlagSocket = "capture_flag_socket"
val CaptureTerminal = "capture_terminal" val CaptureTerminal = "capture_terminal"
val CertTerminal = "cert_terminal" val CertTerminal = "cert_terminal"
val ChainLashDamager = "chain_lash_damager" val ChainLashDamager = "chain_lash_damager"
val Dispenser = "dispenser" val Dispenser = "dispenser"
val Door = "door" val Door = "door"
val EmpBlast = "emp_blast" val EmpBlast = "emp_blast"
val FrameVehicle = "framevehicle" val FrameVehicle = "framevehicle"
val Flag = "flag" val Flag = "flag"
val FlightVehicle = "flightvehicle" val FlightVehicle = "flightvehicle"
val ForceDome = "forcedome" val ForceDome = "forcedome"
val ForceDomeGenerator = "forcedomegenerator" val ForceDomeGenerator = "forcedomegenerator"
val Game = "game" val Game = "game"
val Generic = "generic" val Generic = "generic"
val GenericTeleportion = "generic_teleportation" val GenericTeleportion = "generic_teleportation"
val GeneratorTerminal = "generator_terminal" val GeneratorTerminal = "generator_terminal"
val GsGenbase = "GS_genbase" val GsGenbase = "GS_genbase"
val HandGrenade = "hand_grenade" val HandGrenade = "hand_grenade"
val HeMine = "he_mine" val HeMine = "he_mine"
val HeavyWeapon = "heavy_weapon" val HeavyWeapon = "heavy_weapon"
val HoverVehicle = "hovervehicle" val HoverVehicle = "hovervehicle"
val Implant = "implant" val Implant = "implant"
val ImplantInterfaceTerminal = "implant_terminal_interface" val ImplantInterfaceTerminal = "implant_terminal_interface"
val Lazer = "lazer" val Lazer = "lazer"
val Locker = "locker" val Locker = "locker"
val LockerContainer = "locker_container" val LockerContainer = "locker_container"
val LockExternal = "lock_external" val LockExternal = "lock_external"
val LockSmall = "lock_small" val LockSmall = "lock_small"
val MainTerminal = "main_terminal" val MainTerminal = "main_terminal"
val Map = "map" val Map = "map"
val MedicalTerminal = "medical_terminal" val MedicalTerminal = "medical_terminal"
val Medkit = "medkit" val Medkit = "medkit"
val Monolith = "monolith" val Monolith = "monolith"
val MonolithUnit = "monolith_unit" val MonolithUnit = "monolith_unit"
val MotionAlarmSensorDest = "motion_alarm_sensor_dest" val MotionAlarmSensorDest = "motion_alarm_sensor_dest"
val NanoDispenser = "nano_dispenser" val NanoDispenser = "nano_dispenser"
val NtuSipon = "ntu_siphon" val NtuSipon = "ntu_siphon"
val OrbitalShuttlePad = "orbital_shuttle_pad" val OrbitalShuttlePad = "orbital_shuttle_pad"
val OrbitalStrike = "orbital_strike" val OrbitalStrike = "orbital_strike"
val OrderTerminal = "order_terminal" val OrderTerminal = "order_terminal"
val PainTerminal = "pain_terminal" val PainTerminal = "pain_terminal"
val Projectile = "projectile" val Projectile = "projectile"
val RadiationCloud = "radiation_cloud" val RadiationCloud = "radiation_cloud"
val RearmTerminal = "rearm_terminal" val RearmTerminal = "rearm_terminal"
val RechargeTerminal = "recharge_terminal" val RechargeTerminal = "recharge_terminal"
val Rek = "rek" val Rek = "rek"
val RepairTerminal = "repair_terminal" val RepairTerminal = "repair_terminal"
val ResourceSilo = "resource_silo" val ResourceSilo = "resource_silo"
val RespawnTube = "respawn_tube" val RespawnTube = "respawn_tube"
val SensorShield = "sensor_shield" val SensorShield = "sensor_shield"
val ShieldGenerator = "shield_generator" val ShieldGenerator = "shield_generator"
val Shifter = "shifter" val Shifter = "shifter"
val SkyDome = "skydome" val SkyDome = "skydome"
val SpawnPlayer = "spawn_player" val SpawnPlayer = "spawn_player"
val SpawnPoint = "spawn_point" val SpawnPoint = "spawn_point"
val SpawnTerminal = "spawn_terminal" val SpawnTerminal = "spawn_terminal"
val TeleportPad = "teleport_pad" val TeleportPad = "teleport_pad"
val Terminal = "terminal" val Terminal = "terminal"
val TradeContainer = "trade_container" val TradeContainer = "trade_container"
val UplinkDevice = "uplink_device" val UplinkDevice = "uplink_device"
val VanuCradleClass = "vanu_cradle_class" val VanuCradleClass = "vanu_cradle_class"
val VanuModuleClass = "vanu_module_class" val VanuModuleClass = "vanu_module_class"
val VanuModuleFactory = "vanu_module_factory" val VanuModuleFactory = "vanu_module_factory"
val VanuReceptacleClass = "vanu_receptacle_class" val VanuReceptacleClass = "vanu_receptacle_class"
val Vehicle = "vehicle" val Vehicle = "vehicle"
val VehicleCreationPad = "vehicle_creation_pad" val VehicleCreationPad = "vehicle_creation_pad"
val VehicleLandingPad = "vehicle_landing_pad" val VehicleLandingPad = "vehicle_landing_pad"
val VehicleTerminal = "vehicle_terminal" val VehicleTerminal = "vehicle_terminal"
val Warpgate = "waprgate" val Warpgate = "waprgate"
val WarpZone = "warp_zone" val WarpZone = "warp_zone"
val Weapon = "weapon" val Weapon = "weapon"
} }

View file

@ -8,7 +8,7 @@ import net.psforever.objects.equipment.{EquipmentSize, EquipmentSlot}
* Unlike conventional `EquipmentSlot` space, this size of allowable `Equipment` is fixed. * Unlike conventional `EquipmentSlot` space, this size of allowable `Equipment` is fixed.
* @param size the permanent size of the `Equipment` allowed in this slot * @param size the permanent size of the `Equipment` allowed in this slot
*/ */
class OffhandEquipmentSlot(size : EquipmentSize.Value) extends EquipmentSlot { class OffhandEquipmentSlot(size: EquipmentSize.Value) extends EquipmentSlot {
super.Size_=(size) super.Size_=(size)
/** /**
@ -16,10 +16,11 @@ class OffhandEquipmentSlot(size : EquipmentSize.Value) extends EquipmentSlot {
* @param assignSize the changed in capacity for this slot * @param assignSize the changed in capacity for this slot
* @return the capacity for this slot * @return the capacity for this slot
*/ */
override def Size_=(assignSize : EquipmentSize.Value) : EquipmentSize.Value = Size override def Size_=(assignSize: EquipmentSize.Value): EquipmentSize.Value = Size
} }
object OffhandEquipmentSlot { object OffhandEquipmentSlot {
/** /**
* An `EquipmentSlot` that can not be manipulated because its size is `Blocked` permanently. * An `EquipmentSlot` that can not be manipulated because its size is `Blocked` permanently.
*/ */

View file

@ -4,16 +4,16 @@ package net.psforever.objects
import net.psforever.types.PlanetSideGUID import net.psforever.types.PlanetSideGUID
trait OwnableByPlayer { trait OwnableByPlayer {
private var owner : Option[PlanetSideGUID] = None private var owner: Option[PlanetSideGUID] = None
private var ownerName : Option[String] = None private var ownerName: Option[String] = None
def Owner : Option[PlanetSideGUID] = owner def Owner: Option[PlanetSideGUID] = owner
def Owner_=(owner : PlanetSideGUID) : Option[PlanetSideGUID] = Owner_=(Some(owner)) def Owner_=(owner: PlanetSideGUID): Option[PlanetSideGUID] = Owner_=(Some(owner))
def Owner_=(owner : Player) : Option[PlanetSideGUID] = Owner_=(Some(owner.GUID)) def Owner_=(owner: Player): Option[PlanetSideGUID] = Owner_=(Some(owner.GUID))
def Owner_=(owner : Option[PlanetSideGUID]) : Option[PlanetSideGUID] = { def Owner_=(owner: Option[PlanetSideGUID]): Option[PlanetSideGUID] = {
owner match { owner match {
case Some(_) => case Some(_) =>
this.owner = owner this.owner = owner
@ -23,13 +23,13 @@ trait OwnableByPlayer {
Owner Owner
} }
def OwnerName : Option[String] = ownerName def OwnerName: Option[String] = ownerName
def OwnerName_=(owner : String) : Option[String] = OwnerName_=(Some(owner)) def OwnerName_=(owner: String): Option[String] = OwnerName_=(Some(owner))
def OwnerName_=(owner : Player) : Option[String] = OwnerName_=(Some(owner.Name)) def OwnerName_=(owner: Player): Option[String] = OwnerName_=(Some(owner.Name))
def OwnerName_=(owner : Option[String]) : Option[String] = { def OwnerName_=(owner: Option[String]): Option[String] = {
owner match { owner match {
case Some(_) => case Some(_) =>
ownerName = owner ownerName = owner
@ -44,14 +44,14 @@ trait OwnableByPlayer {
* @param player na * @param player na
* @return na * @return na
*/ */
def AssignOwnership(player : Player) : OwnableByPlayer = AssignOwnership(Some(player)) def AssignOwnership(player: Player): OwnableByPlayer = AssignOwnership(Some(player))
/** /**
* na * na
* @param playerOpt na * @param playerOpt na
* @return na * @return na
*/ */
def AssignOwnership(playerOpt : Option[Player]) : OwnableByPlayer = { def AssignOwnership(playerOpt: Option[Player]): OwnableByPlayer = {
playerOpt match { playerOpt match {
case Some(player) => case Some(player) =>
Owner = player Owner = player

View file

@ -9,47 +9,48 @@ import net.psforever.types.Vector3
* A basic class that indicates an entity that exists somewhere in the world and has a globally unique identifier. * A basic class that indicates an entity that exists somewhere in the world and has a globally unique identifier.
*/ */
abstract class PlanetSideGameObject extends IdentifiableEntity with WorldEntity { abstract class PlanetSideGameObject extends IdentifiableEntity with WorldEntity {
private var entity : WorldEntity = new SimpleWorldEntity() private var entity: WorldEntity = new SimpleWorldEntity()
private var destroyed : Boolean = false private var destroyed: Boolean = false
def Entity : WorldEntity = entity def Entity: WorldEntity = entity
def Entity_=(newEntity : WorldEntity) : Unit = { def Entity_=(newEntity: WorldEntity): Unit = {
entity = newEntity entity = newEntity
} }
def Position : Vector3 = Entity.Position def Position: Vector3 = Entity.Position
def Position_=(vec : Vector3) : Vector3 = { def Position_=(vec: Vector3): Vector3 = {
Entity.Position = vec Entity.Position = vec
} }
def Orientation : Vector3 = Entity.Orientation def Orientation: Vector3 = Entity.Orientation
def Orientation_=(vec : Vector3) : Vector3 = { def Orientation_=(vec: Vector3): Vector3 = {
Entity.Orientation = vec Entity.Orientation = vec
} }
def Velocity : Option[Vector3] = Entity.Velocity def Velocity: Option[Vector3] = Entity.Velocity
def Velocity_=(vec : Option[Vector3]) : Option[Vector3] = { def Velocity_=(vec: Option[Vector3]): Option[Vector3] = {
Entity.Velocity = vec Entity.Velocity = vec
} }
def Destroyed : Boolean = destroyed def Destroyed: Boolean = destroyed
def Destroyed_=(state : Boolean) : Boolean = { def Destroyed_=(state: Boolean): Boolean = {
destroyed = state destroyed = state
Destroyed Destroyed
} }
def Definition : ObjectDefinition def Definition: ObjectDefinition
} }
object PlanetSideGameObject { object PlanetSideGameObject {
def toString(obj : PlanetSideGameObject) : String = { def toString(obj: PlanetSideGameObject): String = {
val guid : String = if(obj.HasGUID) { obj.GUID.toString } else { "NOGUID" } val guid: String = if (obj.HasGUID) { obj.GUID.toString }
else { "NOGUID" }
val P = obj.Position val P = obj.Position
s"[$guid](x,y,z=${P.x%.3f},${P.y%.3f},${P.z%.3f})" s"[$guid](x,y,z=${P.x % .3f},${P.y % .3f},${P.z % .3f})"
} }
} }

View file

@ -2,7 +2,12 @@
package net.psforever.objects package net.psforever.objects
import net.psforever.objects.avatar.LoadoutManager import net.psforever.objects.avatar.LoadoutManager
import net.psforever.objects.definition.{AvatarDefinition, ExoSuitDefinition, ImplantDefinition, SpecialExoSuitDefinition} import net.psforever.objects.definition.{
AvatarDefinition,
ExoSuitDefinition,
ImplantDefinition,
SpecialExoSuitDefinition
}
import net.psforever.objects.equipment.{Equipment, EquipmentSize, EquipmentSlot, JammableUnit} import net.psforever.objects.equipment.{Equipment, EquipmentSize, EquipmentSlot, JammableUnit}
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem} import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem}
import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.PlanetSideServerObject
@ -16,76 +21,79 @@ import net.psforever.types.{PlanetSideGUID, _}
import scala.annotation.tailrec import scala.annotation.tailrec
import scala.util.{Success, Try} import scala.util.{Success, Try}
class Player(private val core : Avatar) extends PlanetSideServerObject class Player(private val core: Avatar)
with FactionAffinity extends PlanetSideServerObject
with Vitality with FactionAffinity
with ResistanceProfile with Vitality
with Container with ResistanceProfile
with JammableUnit with Container
with ZoneAware { with JammableUnit
Health = 0 //player health is artificially managed as a part of their lifecycle; start entity as dead with ZoneAware {
Health = 0 //player health is artificially managed as a part of their lifecycle; start entity as dead
Destroyed = true //see isAlive Destroyed = true //see isAlive
private var backpack : Boolean = false private var backpack: Boolean = false
private var stamina : Int = 0 private var stamina: Int = 0
private var armor : Int = 0 private var armor: Int = 0
private var capacitor : Float = 0f private var capacitor: Float = 0f
private var capacitorState : CapacitorStateType.Value = CapacitorStateType.Idle private var capacitorState: CapacitorStateType.Value = CapacitorStateType.Idle
private var capacitorLastUsedMillis : Long = 0 private var capacitorLastUsedMillis: Long = 0
private var capacitorLastChargedMillis : Long = 0 private var capacitorLastChargedMillis: Long = 0
private var maxStamina : Int = 100 //does anything affect this? private var maxStamina: Int = 100 //does anything affect this?
private var exosuit : ExoSuitDefinition = GlobalDefinitions.Standard private var exosuit: ExoSuitDefinition = GlobalDefinitions.Standard
private val freeHand : EquipmentSlot = new OffhandEquipmentSlot(EquipmentSize.Inventory) private val freeHand: EquipmentSlot = new OffhandEquipmentSlot(EquipmentSize.Inventory)
private val holsters : Array[EquipmentSlot] = Array.fill[EquipmentSlot](5)(new EquipmentSlot) private val holsters: Array[EquipmentSlot] = Array.fill[EquipmentSlot](5)(new EquipmentSlot)
private val inventory : GridInventory = GridInventory() private val inventory: GridInventory = GridInventory()
private var drawnSlot : Int = Player.HandsDownSlot private var drawnSlot: Int = Player.HandsDownSlot
private var lastDrawnSlot : Int = Player.HandsDownSlot private var lastDrawnSlot: Int = Player.HandsDownSlot
private var backpackAccess : Option[PlanetSideGUID] = None private var backpackAccess: Option[PlanetSideGUID] = None
private var facingYawUpper : Float = 0f private var facingYawUpper: Float = 0f
private var crouching : Boolean = false private var crouching: Boolean = false
private var jumping : Boolean = false private var jumping: Boolean = false
private var cloaked : Boolean = false private var cloaked: Boolean = false
private var fatigued : Boolean = false // If stamina drops to 0, player is fatigued until regenerating at least 20 stamina private var fatigued: Boolean =
private var afk : Boolean = false false // If stamina drops to 0, player is fatigued until regenerating at least 20 stamina
private var afk: Boolean = false
private var vehicleSeated : Option[PlanetSideGUID] = None private var vehicleSeated: Option[PlanetSideGUID] = None
Continent = "home2" //the zone id Continent = "home2" //the zone id
var spectator : Boolean = false var spectator: Boolean = false
var silenced : Boolean = false var silenced: Boolean = false
var death_by : Int = 0 var death_by: Int = 0
var lastSeenStreamMessage : Array[Long] = Array.fill[Long](65535)(0L) var lastSeenStreamMessage: Array[Long] = Array.fill[Long](65535)(0L)
var lastShotSeq_time : Int = -1 var lastShotSeq_time: Int = -1
/** From PlanetsideAttributeMessage */ /** From PlanetsideAttributeMessage */
var PlanetsideAttribute : Array[Long] = Array.ofDim(120) var PlanetsideAttribute: Array[Long] = Array.ofDim(120)
var skipStaminaRegenForTurns : Int = 0 var skipStaminaRegenForTurns: Int = 0
Player.SuitSetup(this, exosuit) Player.SuitSetup(this, exosuit)
def CharId : Long = core.CharId def CharId: Long = core.CharId
def Name : String = core.name def Name: String = core.name
def Faction : PlanetSideEmpire.Value = core.faction def Faction: PlanetSideEmpire.Value = core.faction
def Sex : CharacterGender.Value = core.sex def Sex: CharacterGender.Value = core.sex
def Head : Int = core.head def Head: Int = core.head
def Voice : CharacterVoice.Value = core.voice def Voice: CharacterVoice.Value = core.voice
def LFS : Boolean = core.LFS def LFS: Boolean = core.LFS
def isAlive : Boolean = !Destroyed def isAlive: Boolean = !Destroyed
def isBackpack : Boolean = backpack def isBackpack: Boolean = backpack
def Spawn : Boolean = { def Spawn: Boolean = {
if(!isAlive && !isBackpack) { if (!isAlive && !isBackpack) {
Destroyed = false Destroyed = false
Health = Definition.DefaultHealth Health = Definition.DefaultHealth
Stamina = MaxStamina Stamina = MaxStamina
@ -96,66 +104,64 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
isAlive isAlive
} }
def Die : Boolean = { def Die: Boolean = {
Destroyed = true Destroyed = true
Health = 0 Health = 0
Stamina = 0 Stamina = 0
false false
} }
def Revive : Boolean = { def Revive: Boolean = {
Destroyed = false Destroyed = false
Health = Definition.DefaultHealth Health = Definition.DefaultHealth
true true
} }
def Release : Boolean = { def Release: Boolean = {
if(!isAlive) { if (!isAlive) {
backpack = true backpack = true
true true
} } else {
else {
false false
} }
} }
def Stamina : Int = stamina def Stamina: Int = stamina
def Stamina_=(assignStamina : Int) : Int = { def Stamina_=(assignStamina: Int): Int = {
stamina = if(isAlive) { math.min(math.max(0, assignStamina), MaxStamina) } else { 0 } stamina = if (isAlive) { math.min(math.max(0, assignStamina), MaxStamina) }
else { 0 }
Stamina Stamina
} }
def MaxStamina : Int = maxStamina def MaxStamina: Int = maxStamina
def MaxStamina_=(max : Int) : Int = { def MaxStamina_=(max: Int): Int = {
maxStamina = math.min(math.max(0, max), 65535) maxStamina = math.min(math.max(0, max), 65535)
MaxStamina MaxStamina
} }
def Armor : Int = armor def Armor: Int = armor
def Armor_=(assignArmor : Int) : Int = { def Armor_=(assignArmor: Int): Int = {
armor = math.min(math.max(0, assignArmor), MaxArmor) armor = math.min(math.max(0, assignArmor), MaxArmor)
Armor Armor
} }
def MaxArmor : Int = exosuit.MaxArmor def MaxArmor: Int = exosuit.MaxArmor
def Capacitor : Float = capacitor def Capacitor: Float = capacitor
def Capacitor_=(value : Float) : Float = { def Capacitor_=(value: Float): Float = {
val newValue = math.min(math.max(0, value), ExoSuitDef.MaxCapacitor.toFloat) val newValue = math.min(math.max(0, value), ExoSuitDef.MaxCapacitor.toFloat)
if(newValue < capacitor) { if (newValue < capacitor) {
capacitorLastUsedMillis = System.currentTimeMillis() capacitorLastUsedMillis = System.currentTimeMillis()
capacitorLastChargedMillis = 0 capacitorLastChargedMillis = 0
} } else if (newValue > capacitor && newValue < ExoSuitDef.MaxCapacitor) {
else if(newValue > capacitor && newValue < ExoSuitDef.MaxCapacitor) {
capacitorLastChargedMillis = System.currentTimeMillis() capacitorLastChargedMillis = System.currentTimeMillis()
capacitorLastUsedMillis = 0 capacitorLastUsedMillis = 0
} } else if (newValue > capacitor && newValue == ExoSuitDef.MaxCapacitor) {
else if(newValue > capacitor && newValue == ExoSuitDef.MaxCapacitor) {
capacitorLastChargedMillis = 0 capacitorLastChargedMillis = 0
capacitorLastUsedMillis = 0 capacitorLastUsedMillis = 0
capacitorState = CapacitorStateType.Idle capacitorState = CapacitorStateType.Idle
@ -165,55 +171,51 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
capacitor capacitor
} }
def CapacitorState : CapacitorStateType.Value = capacitorState def CapacitorState: CapacitorStateType.Value = capacitorState
def CapacitorState_=(value : CapacitorStateType.Value) : CapacitorStateType.Value = { def CapacitorState_=(value: CapacitorStateType.Value): CapacitorStateType.Value = {
value match { value match {
case CapacitorStateType.Charging => capacitorLastChargedMillis = System.currentTimeMillis() case CapacitorStateType.Charging => capacitorLastChargedMillis = System.currentTimeMillis()
case CapacitorStateType.Discharging => capacitorLastUsedMillis = System.currentTimeMillis() case CapacitorStateType.Discharging => capacitorLastUsedMillis = System.currentTimeMillis()
case _ => ; case _ => ;
} }
capacitorState = value capacitorState = value
capacitorState capacitorState
} }
def CapacitorLastUsedMillis = capacitorLastUsedMillis def CapacitorLastUsedMillis = capacitorLastUsedMillis
def CapacitorLastChargedMillis = capacitorLastChargedMillis def CapacitorLastChargedMillis = capacitorLastChargedMillis
def VisibleSlots : Set[Int] = if(exosuit.SuitType == ExoSuitType.MAX) { def VisibleSlots: Set[Int] =
Set(0) if (exosuit.SuitType == ExoSuitType.MAX) {
} Set(0)
else { } else {
(0 to 4).filterNot(index => holsters(index).Size == EquipmentSize.Blocked).toSet (0 to 4).filterNot(index => holsters(index).Size == EquipmentSize.Blocked).toSet
} }
override def Slot(slot : Int) : EquipmentSlot = { override def Slot(slot: Int): EquipmentSlot = {
if(inventory.Offset <= slot && slot <= inventory.LastIndex) { if (inventory.Offset <= slot && slot <= inventory.LastIndex) {
inventory.Slot(slot) inventory.Slot(slot)
} } else if (slot > -1 && slot < 5) {
else if(slot > -1 && slot < 5) {
holsters(slot) holsters(slot)
} } else if (slot == 5) {
else if(slot == 5) {
core.FifthSlot core.FifthSlot
} } else if (slot == Player.FreeHandSlot) {
else if(slot == Player.FreeHandSlot) {
freeHand freeHand
} } else {
else {
OffhandEquipmentSlot.BlockedSlot OffhandEquipmentSlot.BlockedSlot
} }
} }
def Holsters() : Array[EquipmentSlot] = holsters def Holsters(): Array[EquipmentSlot] = holsters
def Inventory : GridInventory = inventory def Inventory: GridInventory = inventory
def Locker : LockerContainer = core.Locker def Locker: LockerContainer = core.Locker
def FifthSlot : EquipmentSlot = core.FifthSlot def FifthSlot: EquipmentSlot = core.FifthSlot
override def Fit(obj : Equipment) : Option[Int] = { override def Fit(obj: Equipment): Option[Int] = {
recursiveHolsterFit(holsters.iterator, obj.Size) match { recursiveHolsterFit(holsters.iterator, obj.Size) match {
case Some(index) => case Some(index) =>
Some(index) Some(index)
@ -222,21 +224,24 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
case Some(index) => case Some(index) =>
Some(index) Some(index)
case None => case None =>
if(freeHand.Equipment.isDefined) { None } else { Some(Player.FreeHandSlot) } if (freeHand.Equipment.isDefined) { None }
else { Some(Player.FreeHandSlot) }
} }
} }
} }
@tailrec private def recursiveHolsterFit(iter : Iterator[EquipmentSlot], objSize : EquipmentSize.Value, index : Int = 0) : Option[Int] = { @tailrec private def recursiveHolsterFit(
if(!iter.hasNext) { iter: Iterator[EquipmentSlot],
objSize: EquipmentSize.Value,
index: Int = 0
): Option[Int] = {
if (!iter.hasNext) {
None None
} } else {
else {
val slot = iter.next val slot = iter.next
if(slot.Equipment.isEmpty && slot.Size.equals(objSize)) { if (slot.Equipment.isEmpty && slot.Size.equals(objSize)) {
Some(index) Some(index)
} } else {
else {
recursiveHolsterFit(iter, objSize, index + 1) recursiveHolsterFit(iter, objSize, index + 1)
} }
} }
@ -244,73 +249,71 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
def FreeHand = freeHand def FreeHand = freeHand
def FreeHand_=(item : Option[Equipment]) : Option[Equipment] = { def FreeHand_=(item: Option[Equipment]): Option[Equipment] = {
if(freeHand.Equipment.isEmpty || item.isEmpty) { if (freeHand.Equipment.isEmpty || item.isEmpty) {
freeHand.Equipment = item freeHand.Equipment = item
} }
FreeHand.Equipment FreeHand.Equipment
} }
override def Find(guid : PlanetSideGUID) : Option[Int] = { override def Find(guid: PlanetSideGUID): Option[Int] = {
findInHolsters(holsters.iterator, guid) findInHolsters(holsters.iterator, guid)
.orElse(inventory.Find(guid)) match { .orElse(inventory.Find(guid)) match {
case Some(index) => case Some(index) =>
Some(index) Some(index)
case None => case None =>
if(freeHand.Equipment.isDefined && freeHand.Equipment.get.GUID == guid) { if (freeHand.Equipment.isDefined && freeHand.Equipment.get.GUID == guid) {
Some(Player.FreeHandSlot) Some(Player.FreeHandSlot)
} } else {
else {
None None
} }
} }
} }
@tailrec private def findInHolsters(iter : Iterator[EquipmentSlot], guid : PlanetSideGUID, index : Int = 0) : Option[Int] = { @tailrec private def findInHolsters(
if(!iter.hasNext) { iter: Iterator[EquipmentSlot],
guid: PlanetSideGUID,
index: Int = 0
): Option[Int] = {
if (!iter.hasNext) {
None None
} } else {
else {
val slot = iter.next val slot = iter.next
if(slot.Equipment.isDefined && slot.Equipment.get.GUID == guid) { if (slot.Equipment.isDefined && slot.Equipment.get.GUID == guid) {
Some(index) Some(index)
} } else {
else {
findInHolsters(iter, guid, index + 1) findInHolsters(iter, guid, index + 1)
} }
} }
} }
override def Collisions(dest : Int, width : Int, height : Int) : Try[List[InventoryItem]] = { override def Collisions(dest: Int, width: Int, height: Int): Try[List[InventoryItem]] = {
if(-1 < dest && dest < 5) { if (-1 < dest && dest < 5) {
holsters(dest).Equipment match { holsters(dest).Equipment match {
case Some(item) => case Some(item) =>
Success(List(InventoryItem(item, dest))) Success(List(InventoryItem(item, dest)))
case None => case None =>
Success(List()) Success(List())
} }
} } else if (dest == Player.FreeHandSlot) {
else if(dest == Player.FreeHandSlot) {
freeHand.Equipment match { freeHand.Equipment match {
case Some(item) => case Some(item) =>
Success(List(InventoryItem(item, dest))) Success(List(InventoryItem(item, dest)))
case None => case None =>
Success(List()) Success(List())
} }
} } else {
else {
super.Collisions(dest, width, height) super.Collisions(dest, width, height)
} }
} }
def DrawnSlot : Int = drawnSlot def DrawnSlot: Int = drawnSlot
def DrawnSlot_=(slot : Int) : Int = { def DrawnSlot_=(slot: Int): Int = {
if(slot != drawnSlot) { if (slot != drawnSlot) {
if(slot == Player.HandsDownSlot) { if (slot == Player.HandsDownSlot) {
drawnSlot = slot drawnSlot = slot
} } else if (VisibleSlots.contains(slot) && holsters(slot).Equipment.isDefined) {
else if(VisibleSlots.contains(slot) && holsters(slot).Equipment.isDefined) {
drawnSlot = slot drawnSlot = slot
lastDrawnSlot = slot lastDrawnSlot = slot
} }
@ -318,12 +321,12 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
DrawnSlot DrawnSlot
} }
def LastDrawnSlot : Int = lastDrawnSlot def LastDrawnSlot: Int = lastDrawnSlot
def ExoSuit : ExoSuitType.Value = exosuit.SuitType def ExoSuit: ExoSuitType.Value = exosuit.SuitType
def ExoSuitDef : ExoSuitDefinition = exosuit def ExoSuitDef: ExoSuitDefinition = exosuit
def ExoSuit_=(suit : ExoSuitType.Value) : Unit = { def ExoSuit_=(suit: ExoSuitType.Value): Unit = {
val eSuit = ExoSuitDefinition.Select(suit, Faction) val eSuit = ExoSuitDefinition.Select(suit, Faction)
exosuit = eSuit exosuit = eSuit
Player.SuitSetup(this, eSuit) Player.SuitSetup(this, eSuit)
@ -340,15 +343,15 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
def RadiationShielding = exosuit.RadiationShielding def RadiationShielding = exosuit.RadiationShielding
def EquipmentLoadouts : LoadoutManager = core.EquipmentLoadouts def EquipmentLoadouts: LoadoutManager = core.EquipmentLoadouts
def SquadLoadouts : LoadoutManager = core.SquadLoadouts def SquadLoadouts: LoadoutManager = core.SquadLoadouts
def BEP : Long = core.BEP def BEP: Long = core.BEP
def CEP : Long = core.CEP def CEP: Long = core.CEP
def Certifications : Set[CertificationType.Value] = core.Certifications.toSet def Certifications: Set[CertificationType.Value] = core.Certifications.toSet
/** /**
* What kind of implant is installed into the given slot number? * What kind of implant is installed into the given slot number?
@ -356,71 +359,71 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
* @param slot the slot number * @param slot the slot number
* @return the tye of implant * @return the tye of implant
*/ */
def Implant(slot : Int) : ImplantType.Value = core.Implant(slot) def Implant(slot: Int): ImplantType.Value = core.Implant(slot)
def ImplantSlot(slot: Int) : ImplantSlot = core.Implants(slot) def ImplantSlot(slot: Int): ImplantSlot = core.Implants(slot)
/** /**
* A read-only `Array` of tuples representing important information about all unlocked implant slots. * A read-only `Array` of tuples representing important information about all unlocked implant slots.
* @return a maximum of three implant types, initialization times, and active flags * @return a maximum of three implant types, initialization times, and active flags
*/ */
def Implants : Array[(ImplantType.Value, Long, Boolean)] = { def Implants: Array[(ImplantType.Value, Long, Boolean)] = {
core.Implants.takeWhile(_.Unlocked).map( implant => { (implant.Implant, implant.MaxTimer, implant.Active) }) core.Implants.takeWhile(_.Unlocked).map(implant => { (implant.Implant, implant.MaxTimer, implant.Active) })
} }
def InstallImplant(implant : ImplantDefinition) : Option[Int] = core.InstallImplant(implant) def InstallImplant(implant: ImplantDefinition): Option[Int] = core.InstallImplant(implant)
def UninstallImplant(implant : ImplantType.Value) : Option[Int] = core.UninstallImplant(implant) def UninstallImplant(implant: ImplantType.Value): Option[Int] = core.UninstallImplant(implant)
def ResetAllImplants() : Unit = core.ResetAllImplants() def ResetAllImplants(): Unit = core.ResetAllImplants()
def FacingYawUpper : Float = facingYawUpper def FacingYawUpper: Float = facingYawUpper
def FacingYawUpper_=(facing : Float) : Float = { def FacingYawUpper_=(facing: Float): Float = {
facingYawUpper = facing facingYawUpper = facing
FacingYawUpper FacingYawUpper
} }
def Crouching : Boolean = crouching def Crouching: Boolean = crouching
def Crouching_=(crouched : Boolean) : Boolean = { def Crouching_=(crouched: Boolean): Boolean = {
crouching = crouched crouching = crouched
Crouching Crouching
} }
def Jumping : Boolean = jumping def Jumping: Boolean = jumping
def Jumping_=(jumped : Boolean) : Boolean = { def Jumping_=(jumped: Boolean): Boolean = {
jumping = jumped jumping = jumped
Jumping Jumping
} }
def Cloaked : Boolean = cloaked def Cloaked: Boolean = cloaked
def Cloaked_=(isCloaked : Boolean) : Boolean = { def Cloaked_=(isCloaked: Boolean): Boolean = {
cloaked = isCloaked cloaked = isCloaked
Cloaked Cloaked
} }
def Fatigued : Boolean = fatigued def Fatigued: Boolean = fatigued
def Fatigued_=(isFatigued : Boolean) : Boolean = { def Fatigued_=(isFatigued: Boolean): Boolean = {
fatigued = isFatigued fatigued = isFatigued
Fatigued Fatigued
} }
def AwayFromKeyboard : Boolean = afk def AwayFromKeyboard: Boolean = afk
def AwayFromKeyboard_=(away : Boolean) : Boolean = { def AwayFromKeyboard_=(away: Boolean): Boolean = {
afk = away afk = away
AwayFromKeyboard AwayFromKeyboard
} }
def PersonalStyleFeatures : Option[Cosmetics] = core.PersonalStyleFeatures def PersonalStyleFeatures: Option[Cosmetics] = core.PersonalStyleFeatures
def AddToPersonalStyle(value : PersonalStyle.Value) : (Option[Cosmetics], Option[Cosmetics]) = { def AddToPersonalStyle(value: PersonalStyle.Value): (Option[Cosmetics], Option[Cosmetics]) = {
val original = core.PersonalStyleFeatures val original = core.PersonalStyleFeatures
if(DetailedCharacterData.isBR24(core.BEP)) { if (DetailedCharacterData.isBR24(core.BEP)) {
core.PersonalStyleFeatures = original match { core.PersonalStyleFeatures = original match {
case Some(cosmetic) => case Some(cosmetic) =>
cosmetic + value cosmetic + value
@ -428,51 +431,47 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
Cosmetics(value) Cosmetics(value)
} }
(original, core.PersonalStyleFeatures) (original, core.PersonalStyleFeatures)
} } else {
else {
(None, None) (None, None)
} }
} }
def RemoveFromPersonalStyle(value : PersonalStyle.Value) : (Option[Cosmetics], Option[Cosmetics]) = { def RemoveFromPersonalStyle(value: PersonalStyle.Value): (Option[Cosmetics], Option[Cosmetics]) = {
val original = core.PersonalStyleFeatures val original = core.PersonalStyleFeatures
original match { original match {
case Some(cosmetics) => case Some(cosmetics) =>
(original, core.PersonalStyleFeatures = cosmetics - value) (original, core.PersonalStyleFeatures = cosmetics - value)
case None => case None =>
(None, None) (None, None)
} }
} }
private def BasicFeatureToggle(feature : PersonalStyle.Value) : (Option[Cosmetics], Option[Cosmetics]) = core.PersonalStyleFeatures match { private def BasicFeatureToggle(feature: PersonalStyle.Value): (Option[Cosmetics], Option[Cosmetics]) =
case Some(c : Cosmetics) =>
if(c.Styles.contains(feature)) {
RemoveFromPersonalStyle(feature)
}
else {
AddToPersonalStyle(feature)
}
case None =>
AddToPersonalStyle(feature)
}
def ToggleHelmet : (Option[Cosmetics], Option[Cosmetics]) = BasicFeatureToggle(PersonalStyle.NoHelmet)
def ToggleShades : (Option[Cosmetics], Option[Cosmetics]) = BasicFeatureToggle(PersonalStyle.Sunglasses)
def ToggleEarpiece : (Option[Cosmetics], Option[Cosmetics]) = BasicFeatureToggle(PersonalStyle.Earpiece)
def ToggleHat : (Option[Cosmetics], Option[Cosmetics]) = {
core.PersonalStyleFeatures match { core.PersonalStyleFeatures match {
case Some(c : Cosmetics) => case Some(c: Cosmetics) =>
if(c.Styles.contains(PersonalStyle.BrimmedCap)) { if (c.Styles.contains(feature)) {
(RemoveFromPersonalStyle(PersonalStyle.BrimmedCap)._1, RemoveFromPersonalStyle(feature)
AddToPersonalStyle(PersonalStyle.Beret)._2) } else {
AddToPersonalStyle(feature)
} }
else if(c.Styles.contains(PersonalStyle.Beret)) { case None =>
AddToPersonalStyle(feature)
}
def ToggleHelmet: (Option[Cosmetics], Option[Cosmetics]) = BasicFeatureToggle(PersonalStyle.NoHelmet)
def ToggleShades: (Option[Cosmetics], Option[Cosmetics]) = BasicFeatureToggle(PersonalStyle.Sunglasses)
def ToggleEarpiece: (Option[Cosmetics], Option[Cosmetics]) = BasicFeatureToggle(PersonalStyle.Earpiece)
def ToggleHat: (Option[Cosmetics], Option[Cosmetics]) = {
core.PersonalStyleFeatures match {
case Some(c: Cosmetics) =>
if (c.Styles.contains(PersonalStyle.BrimmedCap)) {
(RemoveFromPersonalStyle(PersonalStyle.BrimmedCap)._1, AddToPersonalStyle(PersonalStyle.Beret)._2)
} else if (c.Styles.contains(PersonalStyle.Beret)) {
RemoveFromPersonalStyle(PersonalStyle.Beret) RemoveFromPersonalStyle(PersonalStyle.Beret)
} } else {
else {
AddToPersonalStyle(PersonalStyle.BrimmedCap) AddToPersonalStyle(PersonalStyle.BrimmedCap)
} }
case None => case None =>
@ -480,96 +479,99 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
} }
} }
private var usingSpecial : SpecialExoSuitDefinition.Mode.Value=>SpecialExoSuitDefinition.Mode.Value = DefaultUsingSpecial private var usingSpecial: SpecialExoSuitDefinition.Mode.Value => SpecialExoSuitDefinition.Mode.Value =
DefaultUsingSpecial
private var gettingSpecial : ()=>SpecialExoSuitDefinition.Mode.Value = DefaultGettingSpecial private var gettingSpecial: () => SpecialExoSuitDefinition.Mode.Value = DefaultGettingSpecial
private def ChangeSpecialAbility() : Unit = { private def ChangeSpecialAbility(): Unit = {
if(ExoSuit == ExoSuitType.MAX) { if (ExoSuit == ExoSuitType.MAX) {
gettingSpecial = MAXGettingSpecial gettingSpecial = MAXGettingSpecial
usingSpecial = Faction match { usingSpecial = Faction match {
case PlanetSideEmpire.TR => UsingAnchorsOrOverdrive case PlanetSideEmpire.TR => UsingAnchorsOrOverdrive
case PlanetSideEmpire.NC => UsingShield case PlanetSideEmpire.NC => UsingShield
case _ => DefaultUsingSpecial case _ => DefaultUsingSpecial
} }
} } else {
else {
usingSpecial = DefaultUsingSpecial usingSpecial = DefaultUsingSpecial
gettingSpecial = DefaultGettingSpecial gettingSpecial = DefaultGettingSpecial
} }
} }
def UsingSpecial : SpecialExoSuitDefinition.Mode.Value = { gettingSpecial() } def UsingSpecial: SpecialExoSuitDefinition.Mode.Value = { gettingSpecial() }
def UsingSpecial_=(state : SpecialExoSuitDefinition.Mode.Value) : SpecialExoSuitDefinition.Mode.Value = usingSpecial(state) def UsingSpecial_=(state: SpecialExoSuitDefinition.Mode.Value): SpecialExoSuitDefinition.Mode.Value =
usingSpecial(state)
private def DefaultUsingSpecial(state : SpecialExoSuitDefinition.Mode.Value) : SpecialExoSuitDefinition.Mode.Value = SpecialExoSuitDefinition.Mode.Normal private def DefaultUsingSpecial(state: SpecialExoSuitDefinition.Mode.Value): SpecialExoSuitDefinition.Mode.Value =
SpecialExoSuitDefinition.Mode.Normal
private def UsingAnchorsOrOverdrive(state : SpecialExoSuitDefinition.Mode.Value) : SpecialExoSuitDefinition.Mode.Value = { private def UsingAnchorsOrOverdrive(
state: SpecialExoSuitDefinition.Mode.Value
): SpecialExoSuitDefinition.Mode.Value = {
import SpecialExoSuitDefinition.Mode._ import SpecialExoSuitDefinition.Mode._
val curr = UsingSpecial val curr = UsingSpecial
val next = if(curr == Normal) { val next = if (curr == Normal) {
if(state == Anchored || state == Overdrive) { if (state == Anchored || state == Overdrive) {
state state
} } else {
else {
Normal Normal
} }
} } else if (state == Normal) {
else if(state == Normal) {
Normal Normal
} } else {
else {
curr curr
} }
MAXUsingSpecial(next) MAXUsingSpecial(next)
} }
private def UsingShield(state : SpecialExoSuitDefinition.Mode.Value) : SpecialExoSuitDefinition.Mode.Value = { private def UsingShield(state: SpecialExoSuitDefinition.Mode.Value): SpecialExoSuitDefinition.Mode.Value = {
import SpecialExoSuitDefinition.Mode._ import SpecialExoSuitDefinition.Mode._
val curr = UsingSpecial val curr = UsingSpecial
val next = if(curr == Normal) { val next = if (curr == Normal) {
if(state == Shielded) { if (state == Shielded) {
state state
} } else {
else {
Normal Normal
} }
} } else if (state == Normal) {
else if(state == Normal) {
Normal Normal
} } else {
else {
curr curr
} }
MAXUsingSpecial(next) MAXUsingSpecial(next)
} }
private def DefaultGettingSpecial() : SpecialExoSuitDefinition.Mode.Value = SpecialExoSuitDefinition.Mode.Normal private def DefaultGettingSpecial(): SpecialExoSuitDefinition.Mode.Value = SpecialExoSuitDefinition.Mode.Normal
private def MAXUsingSpecial(state : SpecialExoSuitDefinition.Mode.Value) : SpecialExoSuitDefinition.Mode.Value = exosuit match { private def MAXUsingSpecial(state: SpecialExoSuitDefinition.Mode.Value): SpecialExoSuitDefinition.Mode.Value =
case obj : SpecialExoSuitDefinition => exosuit match {
obj.UsingSpecial = state case obj: SpecialExoSuitDefinition =>
case _ => obj.UsingSpecial = state
SpecialExoSuitDefinition.Mode.Normal case _ =>
} SpecialExoSuitDefinition.Mode.Normal
}
private def MAXGettingSpecial() : SpecialExoSuitDefinition.Mode.Value = exosuit match { private def MAXGettingSpecial(): SpecialExoSuitDefinition.Mode.Value =
case obj : SpecialExoSuitDefinition => exosuit match {
obj.UsingSpecial case obj: SpecialExoSuitDefinition =>
case _ => obj.UsingSpecial
SpecialExoSuitDefinition.Mode.Normal case _ =>
} SpecialExoSuitDefinition.Mode.Normal
}
def isAnchored : Boolean = ExoSuit == ExoSuitType.MAX && Faction == PlanetSideEmpire.TR && UsingSpecial == SpecialExoSuitDefinition.Mode.Anchored def isAnchored: Boolean =
ExoSuit == ExoSuitType.MAX && Faction == PlanetSideEmpire.TR && UsingSpecial == SpecialExoSuitDefinition.Mode.Anchored
def isOverdrived : Boolean = ExoSuit == ExoSuitType.MAX && Faction == PlanetSideEmpire.TR && UsingSpecial == SpecialExoSuitDefinition.Mode.Overdrive def isOverdrived: Boolean =
ExoSuit == ExoSuitType.MAX && Faction == PlanetSideEmpire.TR && UsingSpecial == SpecialExoSuitDefinition.Mode.Overdrive
def isShielded : Boolean = ExoSuit == ExoSuitType.MAX && Faction == PlanetSideEmpire.NC && UsingSpecial == SpecialExoSuitDefinition.Mode.Shielded def isShielded: Boolean =
ExoSuit == ExoSuitType.MAX && Faction == PlanetSideEmpire.NC && UsingSpecial == SpecialExoSuitDefinition.Mode.Shielded
def AccessingBackpack : Option[PlanetSideGUID] = backpackAccess def AccessingBackpack: Option[PlanetSideGUID] = backpackAccess
def AccessingBackpack_=(guid : PlanetSideGUID) : Option[PlanetSideGUID] = { def AccessingBackpack_=(guid: PlanetSideGUID): Option[PlanetSideGUID] = {
AccessingBackpack = Some(guid) AccessingBackpack = Some(guid)
} }
@ -579,12 +581,12 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
* @param guid the player who wishes to access the backpack * @param guid the player who wishes to access the backpack
* @return the player who is currently allowed to access the backpack * @return the player who is currently allowed to access the backpack
*/ */
def AccessingBackpack_=(guid : Option[PlanetSideGUID]) : Option[PlanetSideGUID] = { def AccessingBackpack_=(guid: Option[PlanetSideGUID]): Option[PlanetSideGUID] = {
guid match { guid match {
case None => case None =>
backpackAccess = None backpackAccess = None
case Some(player) => case Some(player) =>
if(isBackpack && backpackAccess.isEmpty) { if (isBackpack && backpackAccess.isEmpty) {
backpackAccess = Some(player) backpackAccess = Some(player)
} }
} }
@ -596,94 +598,96 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
* @param player a player attempting to access this backpack * @param player a player attempting to access this backpack
* @return `true`, if the `player` is permitted access; `false`, otherwise * @return `true`, if the `player` is permitted access; `false`, otherwise
*/ */
def CanAccessBackpack(player : Player) : Boolean = { def CanAccessBackpack(player: Player): Boolean = {
isBackpack && (backpackAccess.isEmpty || backpackAccess.contains(player.GUID)) isBackpack && (backpackAccess.isEmpty || backpackAccess.contains(player.GUID))
} }
def FirstTimeEvents : List[String] = core.FirstTimeEvents def FirstTimeEvents: List[String] = core.FirstTimeEvents
def VehicleSeated : Option[PlanetSideGUID] = vehicleSeated def VehicleSeated: Option[PlanetSideGUID] = vehicleSeated
def VehicleSeated_=(guid : PlanetSideGUID) : Option[PlanetSideGUID] = VehicleSeated_=(Some(guid)) def VehicleSeated_=(guid: PlanetSideGUID): Option[PlanetSideGUID] = VehicleSeated_=(Some(guid))
def VehicleSeated_=(guid : Option[PlanetSideGUID]) : Option[PlanetSideGUID] = { def VehicleSeated_=(guid: Option[PlanetSideGUID]): Option[PlanetSideGUID] = {
vehicleSeated = guid vehicleSeated = guid
VehicleSeated VehicleSeated
} }
def VehicleOwned : Option[PlanetSideGUID] = core.VehicleOwned def VehicleOwned: Option[PlanetSideGUID] = core.VehicleOwned
def VehicleOwned_=(guid : PlanetSideGUID) : Option[PlanetSideGUID] = core.VehicleOwned_=(Some(guid)) def VehicleOwned_=(guid: PlanetSideGUID): Option[PlanetSideGUID] = core.VehicleOwned_=(Some(guid))
def VehicleOwned_=(guid : Option[PlanetSideGUID]) : Option[PlanetSideGUID] = core.VehicleOwned_=(guid) def VehicleOwned_=(guid: Option[PlanetSideGUID]): Option[PlanetSideGUID] = core.VehicleOwned_=(guid)
def GetLastUsedTime(code : Int) : Long = core.GetLastUsedTime(code) def GetLastUsedTime(code: Int): Long = core.GetLastUsedTime(code)
def GetLastUsedTime(code : ExoSuitType.Value) : Long = core.GetLastUsedTime(code) def GetLastUsedTime(code: ExoSuitType.Value): Long = core.GetLastUsedTime(code)
def GetLastUsedTime(code : ExoSuitType.Value, subtype : Int) : Long = core.GetLastUsedTime(code, subtype) def GetLastUsedTime(code: ExoSuitType.Value, subtype: Int): Long = core.GetLastUsedTime(code, subtype)
def SetLastUsedTime(code : Int, time : Long) : Unit = core.SetLastUsedTime(code, time) def SetLastUsedTime(code: Int, time: Long): Unit = core.SetLastUsedTime(code, time)
def SetLastUsedTime(code : ExoSuitType.Value): Unit = core.SetLastUsedTime(code) def SetLastUsedTime(code: ExoSuitType.Value): Unit = core.SetLastUsedTime(code)
def SetLastUsedTime(code : ExoSuitType.Value, time : Long) : Unit = core.SetLastUsedTime(code, time) def SetLastUsedTime(code: ExoSuitType.Value, time: Long): Unit = core.SetLastUsedTime(code, time)
def SetLastUsedTime(code : ExoSuitType.Value, subtype : Int): Unit = core.SetLastUsedTime(code, subtype) def SetLastUsedTime(code: ExoSuitType.Value, subtype: Int): Unit = core.SetLastUsedTime(code, subtype)
def SetLastUsedTime(code : ExoSuitType.Value, subtype : Int, time : Long) : Unit = core.SetLastUsedTime(code, subtype, time) def SetLastUsedTime(code: ExoSuitType.Value, subtype: Int, time: Long): Unit =
core.SetLastUsedTime(code, subtype, time)
def GetLastPurchaseTime(code : Int) : Long = core.GetLastPurchaseTime(code) def GetLastPurchaseTime(code: Int): Long = core.GetLastPurchaseTime(code)
def SetLastPurchaseTime(code : Int, time : Long) : Unit = core.SetLastPurchaseTime(code, time) def SetLastPurchaseTime(code: Int, time: Long): Unit = core.SetLastPurchaseTime(code, time)
def ObjectTypeNameReference(id : Long) : String = core.ObjectTypeNameReference(id) def ObjectTypeNameReference(id: Long): String = core.ObjectTypeNameReference(id)
def ObjectTypeNameReference(id : Long, name : String) : String = core.ObjectTypeNameReference(id, name) def ObjectTypeNameReference(id: Long, name: String): String = core.ObjectTypeNameReference(id, name)
def DamageModel = exosuit.asInstanceOf[DamageResistanceModel] def DamageModel = exosuit.asInstanceOf[DamageResistanceModel]
def Definition : AvatarDefinition = core.Definition def Definition: AvatarDefinition = core.Definition
def canEqual(other: Any): Boolean = other.isInstanceOf[Player] def canEqual(other: Any): Boolean = other.isInstanceOf[Player]
override def equals(other : Any) : Boolean = other match { override def equals(other: Any): Boolean =
case that: Player => other match {
(that canEqual this) && case that: Player =>
core == that.core (that canEqual this) &&
case _ => core == that.core
false case _ =>
} false
}
override def hashCode() : Int = { override def hashCode(): Int = {
core.hashCode() core.hashCode()
} }
override def toString : String = Player.toString(this) override def toString: String = Player.toString(this)
} }
object Player { object Player {
final val LockerSlot : Int = 5 final val LockerSlot: Int = 5
final val FreeHandSlot : Int = 250 final val FreeHandSlot: Int = 250
final val HandsDownSlot : Int = 255 final val HandsDownSlot: Int = 255
final case class Die() final case class Die()
final case class ImplantActivation(slot : Int, status : Int) final case class ImplantActivation(slot: Int, status: Int)
final case class ImplantInitializationStart(slot : Int) final case class ImplantInitializationStart(slot: Int)
final case class UninitializeImplant(slot : Int) final case class UninitializeImplant(slot: Int)
final case class ImplantInitializationComplete(slot : Int) final case class ImplantInitializationComplete(slot: Int)
final case class StaminaRegen() final case class StaminaRegen()
final case class StaminaChanged(currentStamina : Option[Int] = None) final case class StaminaChanged(currentStamina: Option[Int] = None)
object StaminaChanged { object StaminaChanged {
def apply(amount : Int) : StaminaChanged = StaminaChanged(Some(amount)) def apply(amount: Int): StaminaChanged = StaminaChanged(Some(amount))
} }
def apply(core : Avatar) : Player = { def apply(core: Avatar): Player = {
new Player(core) new Player(core)
} }
private def SuitSetup(player : Player, eSuit : ExoSuitDefinition) : Unit = { private def SuitSetup(player: Player, eSuit: ExoSuitDefinition): Unit = {
//inventory //inventory
player.Inventory.Clear() player.Inventory.Clear()
player.Inventory.Resize(eSuit.InventoryScale.Width, eSuit.InventoryScale.Height) player.Inventory.Resize(eSuit.InventoryScale.Width, eSuit.InventoryScale.Height)
@ -692,34 +696,35 @@ object Player {
(0 until 5).foreach(index => { player.Slot(index).Size = eSuit.Holster(index) }) (0 until 5).foreach(index => { player.Slot(index).Size = eSuit.Holster(index) })
} }
def Respawn(player : Player) : Player = { def Respawn(player: Player): Player = {
if(player.Release) { if (player.Release) {
val obj = new Player(player.core) val obj = new Player(player.core)
obj.Continent = player.Continent obj.Continent = player.Continent
obj obj
} } else {
else {
player player
} }
} }
def GetHackLevel(player : Player): Int = { def GetHackLevel(player: Player): Int = {
if(player.Certifications.contains(CertificationType.ExpertHacking) || player.Certifications.contains(CertificationType.ElectronicsExpert)) { if (
player.Certifications.contains(CertificationType.ExpertHacking) || player.Certifications.contains(
CertificationType.ElectronicsExpert
)
) {
3 3
} } else if (player.Certifications.contains(CertificationType.AdvancedHacking)) {
else if(player.Certifications.contains(CertificationType.AdvancedHacking)) {
2 2
} } else if (player.Certifications.contains(CertificationType.Hacking)) {
else if (player.Certifications.contains(CertificationType.Hacking)) {
1 1
} } else {
else {
0 0
} }
} }
def toString(obj : Player) : String = { def toString(obj: Player): String = {
val guid = if(obj.HasGUID) { s" ${obj.Continent}-${obj.GUID.guid}" } else { "" } val guid = if (obj.HasGUID) { s" ${obj.Continent}-${obj.GUID.guid}" }
else { "" }
s"${obj.core}$guid ${obj.Health}/${obj.MaxHealth} ${obj.Armor}/${obj.MaxArmor}" s"${obj.core}$guid ${obj.Health}/${obj.MaxHealth} ${obj.Armor}/${obj.MaxArmor}"
} }
} }

View file

@ -25,17 +25,21 @@ object Players {
* @return `true`, if the next cycle of progress should occur; * @return `true`, if the next cycle of progress should occur;
* `false`, otherwise * `false`, otherwise
*/ */
def RevivingTickAction(target : Player, user : Player, item : Tool)(progress : Float) : Boolean = { def RevivingTickAction(target: Player, user: Player, item: Tool)(progress: Float): Boolean = {
if(!target.isAlive && !target.isBackpack && if (
!target.isAlive && !target.isBackpack &&
user.isAlive && !user.isMoving && user.isAlive && !user.isMoving &&
user.Slot(user.DrawnSlot).Equipment.contains(item) && item.Magazine >= 25 && user.Slot(user.DrawnSlot).Equipment.contains(item) && item.Magazine >= 25 &&
Vector3.Distance(target.Position, user.Position) < target.Definition.RepairDistance) { Vector3.Distance(target.Position, user.Position) < target.Definition.RepairDistance
) {
val events = target.Zone.AvatarEvents val events = target.Zone.AvatarEvents
val uname = user.Name val uname = user.Name
events ! AvatarServiceMessage(uname, AvatarAction.SendResponse(Service.defaultPlayerGUID, RepairMessage(target.GUID, progress.toInt))) events ! AvatarServiceMessage(
uname,
AvatarAction.SendResponse(Service.defaultPlayerGUID, RepairMessage(target.GUID, progress.toInt))
)
true true
} } else {
else {
false false
} }
} }
@ -48,11 +52,17 @@ object Players {
* @param medic the name of the player doing the reviving * @param medic the name of the player doing the reviving
* @param item the tool being used to revive the target player * @param item the tool being used to revive the target player
*/ */
def FinishRevivingPlayer(target : Player, medic : String, item : Tool)() : Unit = { def FinishRevivingPlayer(target: Player, medic: String, item: Tool)(): Unit = {
val name = target.Name val name = target.Name
log.info(s"$medic had revived $name") log.info(s"$medic had revived $name")
val magazine = item.Discharge(Some(25)) val magazine = item.Discharge(Some(25))
target.Zone.AvatarEvents ! AvatarServiceMessage(medic, AvatarAction.SendResponse(Service.defaultPlayerGUID, InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine))) target.Zone.AvatarEvents ! AvatarServiceMessage(
medic,
AvatarAction.SendResponse(
Service.defaultPlayerGUID,
InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine)
)
)
target.Zone.AvatarEvents ! AvatarServiceMessage(name, AvatarAction.Revive(target.GUID)) target.Zone.AvatarEvents ! AvatarServiceMessage(name, AvatarAction.Revive(target.GUID))
} }
@ -64,11 +74,14 @@ object Players {
* @param list a persistent `List` of `Equipment` in the holster slots * @param list a persistent `List` of `Equipment` in the holster slots
* @return a `List` of `Equipment` in the holster slots * @return a `List` of `Equipment` in the holster slots
*/ */
@tailrec def clearHolsters(iter : Iterator[EquipmentSlot], index : Int = 0, list : List[InventoryItem] = Nil) : List[InventoryItem] = { @tailrec def clearHolsters(
if(!iter.hasNext) { iter: Iterator[EquipmentSlot],
index: Int = 0,
list: List[InventoryItem] = Nil
): List[InventoryItem] = {
if (!iter.hasNext) {
list list
} } else {
else {
val slot = iter.next val slot = iter.next
slot.Equipment match { slot.Equipment match {
case Some(equipment) => case Some(equipment) =>
@ -88,13 +101,12 @@ object Players {
* @param list a `List` of all `Equipment` that is not yet assigned to a holster slot or an inventory slot * @param list a `List` of all `Equipment` that is not yet assigned to a holster slot or an inventory slot
* @return the `List` of all `Equipment` not yet assigned to a holster slot or an inventory slot * @return the `List` of all `Equipment` not yet assigned to a holster slot or an inventory slot
*/ */
@tailrec def fillEmptyHolsters(iter : Iterator[EquipmentSlot], list : List[InventoryItem]) : List[InventoryItem] = { @tailrec def fillEmptyHolsters(iter: Iterator[EquipmentSlot], list: List[InventoryItem]): List[InventoryItem] = {
if(!iter.hasNext) { if (!iter.hasNext) {
list list
} } else {
else {
val slot = iter.next val slot = iter.next
if(slot.Equipment.isEmpty) { if (slot.Equipment.isEmpty) {
list.find(item => item.obj.Size == slot.Size) match { list.find(item => item.obj.Size == slot.Size) match {
case Some(obj) => case Some(obj) =>
val index = list.indexOf(obj) val index = list.indexOf(obj)
@ -103,21 +115,20 @@ object Players {
case None => case None =>
fillEmptyHolsters(iter, list) fillEmptyHolsters(iter, list)
} }
} } else {
else {
fillEmptyHolsters(iter, list) fillEmptyHolsters(iter, list)
} }
} }
} }
def CertificationToUseExoSuit(player : Player, exosuit : ExoSuitType.Value, subtype : Int) : Boolean = { def CertificationToUseExoSuit(player: Player, exosuit: ExoSuitType.Value, subtype: Int): Boolean = {
ExoSuitDefinition.Select(exosuit, player.Faction).Permissions match { ExoSuitDefinition.Select(exosuit, player.Faction).Permissions match {
case Nil => case Nil =>
true true
case permissions if subtype != 0 => case permissions if subtype != 0 =>
val certs = player.Certifications val certs = player.Certifications
certs.intersect(permissions.toSet).nonEmpty && certs.intersect(permissions.toSet).nonEmpty &&
certs.intersect(InfantryLoadout.DetermineSubtypeC(subtype)).nonEmpty certs.intersect(InfantryLoadout.DetermineSubtypeC(subtype)).nonEmpty
case permissions => case permissions =>
player.Certifications.intersect(permissions.toSet).nonEmpty player.Certifications.intersect(permissions.toSet).nonEmpty
} }

View file

@ -19,82 +19,97 @@ import services.vehicle.{VehicleAction, VehicleServiceMessage}
import scala.concurrent.duration._ import scala.concurrent.duration._
class SensorDeployable(cdef : SensorDeployableDefinition) extends ComplexDeployable(cdef) class SensorDeployable(cdef: SensorDeployableDefinition) extends ComplexDeployable(cdef) with Hackable with JammableUnit
with Hackable
with JammableUnit
class SensorDeployableDefinition(private val objectId : Int) extends ComplexDeployableDefinition(objectId) { class SensorDeployableDefinition(private val objectId: Int) extends ComplexDeployableDefinition(objectId) {
Name = "sensor_deployable" Name = "sensor_deployable"
DeployCategory = DeployableCategory.Sensors DeployCategory = DeployableCategory.Sensors
Model = StandardResolutions.SimpleDeployables Model = StandardResolutions.SimpleDeployables
Packet = new SmallDeployableConverter Packet = new SmallDeployableConverter
override def Initialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = { override def Initialize(obj: PlanetSideServerObject with Deployable, context: ActorContext) = {
obj.Actor = context.actorOf(Props(classOf[SensorDeployableControl], obj), PlanetSideServerObject.UniqueActorName(obj)) obj.Actor =
context.actorOf(Props(classOf[SensorDeployableControl], obj), PlanetSideServerObject.UniqueActorName(obj))
} }
override def Uninitialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = { override def Uninitialize(obj: PlanetSideServerObject with Deployable, context: ActorContext) = {
SimpleDeployableDefinition.SimpleUninitialize(obj, context) SimpleDeployableDefinition.SimpleUninitialize(obj, context)
} }
} }
object SensorDeployableDefinition { object SensorDeployableDefinition {
def apply(dtype : DeployedItem.Value) : SensorDeployableDefinition = { def apply(dtype: DeployedItem.Value): SensorDeployableDefinition = {
new SensorDeployableDefinition(dtype.id) new SensorDeployableDefinition(dtype.id)
} }
} }
class SensorDeployableControl(sensor : SensorDeployable) extends Actor class SensorDeployableControl(sensor: SensorDeployable)
with JammableBehavior extends Actor
with DamageableEntity with JammableBehavior
with RepairableEntity { with DamageableEntity
def JammableObject = sensor with RepairableEntity {
def JammableObject = sensor
def DamageableObject = sensor def DamageableObject = sensor
def RepairableObject = sensor def RepairableObject = sensor
def receive : Receive = jammableBehavior def receive: Receive =
.orElse(takesDamage) jammableBehavior
.orElse(canBeRepairedByNanoDispenser) .orElse(takesDamage)
.orElse { .orElse(canBeRepairedByNanoDispenser)
case _ => ; .orElse {
} case _ => ;
}
override protected def DamageLog(msg : String) : Unit = { } override protected def DamageLog(msg: String): Unit = {}
override protected def DestructionAwareness(target : Damageable.Target, cause : ResolvedProjectile) : Unit = { override protected def DestructionAwareness(target: Damageable.Target, cause: ResolvedProjectile): Unit = {
super.DestructionAwareness(target, cause) super.DestructionAwareness(target, cause)
SensorDeployableControl.DestructionAwareness(sensor, PlanetSideGUID(0)) SensorDeployableControl.DestructionAwareness(sensor, PlanetSideGUID(0))
} }
override def StartJammeredSound(target : Any, dur : Int) : Unit = target match { override def StartJammeredSound(target: Any, dur: Int): Unit =
case obj : PlanetSideServerObject if !jammedSound =>
obj.Zone.VehicleEvents ! VehicleServiceMessage(obj.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 1))
super.StartJammeredSound(obj, dur)
case _ => ;
}
override def StartJammeredStatus(target : Any, dur : Int) : Unit = target match {
case obj : PlanetSideServerObject with JammableUnit if !obj.Jammed =>
val zone = obj.Zone
zone.LocalEvents ! LocalServiceMessage(zone.Id, LocalAction.TriggerEffectInfo(Service.defaultPlayerGUID, "on", obj.GUID, false, 1000))
super.StartJammeredStatus(obj, dur)
case _ => ;
}
override def CancelJammeredSound(target : Any) : Unit = {
target match { target match {
case obj : PlanetSideServerObject if jammedSound => case obj: PlanetSideServerObject if !jammedSound =>
obj.Zone.VehicleEvents ! VehicleServiceMessage(
obj.Zone.Id,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 1)
)
super.StartJammeredSound(obj, dur)
case _ => ;
}
override def StartJammeredStatus(target: Any, dur: Int): Unit =
target match {
case obj: PlanetSideServerObject with JammableUnit if !obj.Jammed =>
val zone = obj.Zone val zone = obj.Zone
zone.VehicleEvents ! VehicleServiceMessage(zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 0)) zone.LocalEvents ! LocalServiceMessage(
zone.Id,
LocalAction.TriggerEffectInfo(Service.defaultPlayerGUID, "on", obj.GUID, false, 1000)
)
super.StartJammeredStatus(obj, dur)
case _ => ;
}
override def CancelJammeredSound(target: Any): Unit = {
target match {
case obj: PlanetSideServerObject if jammedSound =>
val zone = obj.Zone
zone.VehicleEvents ! VehicleServiceMessage(
zone.Id,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 0)
)
case _ => ; case _ => ;
} }
super.CancelJammeredSound(target) super.CancelJammeredSound(target)
} }
override def CancelJammeredStatus(target : Any) : Unit = { override def CancelJammeredStatus(target: Any): Unit = {
target match { target match {
case obj : PlanetSideServerObject with JammableUnit if obj.Jammed => case obj: PlanetSideServerObject with JammableUnit if obj.Jammed =>
sensor.Zone.LocalEvents ! LocalServiceMessage(sensor.Zone.Id, LocalAction.TriggerEffectInfo(Service.defaultPlayerGUID, "on", obj.GUID, true, 1000)) sensor.Zone.LocalEvents ! LocalServiceMessage(
sensor.Zone.Id,
LocalAction.TriggerEffectInfo(Service.defaultPlayerGUID, "on", obj.GUID, true, 1000)
)
case _ => ; case _ => ;
} }
super.CancelJammeredStatus(target) super.CancelJammeredStatus(target)
@ -102,30 +117,33 @@ class SensorDeployableControl(sensor : SensorDeployable) extends Actor
} }
object SensorDeployableControl { object SensorDeployableControl {
/** /**
* na * na
* @param target na * @param target na
* @param attribution na * @param attribution na
*/ */
def DestructionAwareness(target : Damageable.Target with Deployable, attribution : PlanetSideGUID) : Unit = { def DestructionAwareness(target: Damageable.Target with Deployable, attribution: PlanetSideGUID): Unit = {
Deployables.AnnounceDestroyDeployable(target, Some(1 seconds)) Deployables.AnnounceDestroyDeployable(target, Some(1 seconds))
val zone = target.Zone val zone = target.Zone
zone.LocalEvents ! LocalServiceMessage(zone.Id, zone.LocalEvents ! LocalServiceMessage(
zone.Id,
LocalAction.TriggerEffectInfo(Service.defaultPlayerGUID, "on", target.GUID, false, 1000) LocalAction.TriggerEffectInfo(Service.defaultPlayerGUID, "on", target.GUID, false, 1000)
) )
//position the explosion effect near the bulky area of the sensor stalk //position the explosion effect near the bulky area of the sensor stalk
val ang = target.Orientation val ang = target.Orientation
val explosionPos = { val explosionPos = {
val pos = target.Position val pos = target.Position
val yRadians = ang.y.toRadians val yRadians = ang.y.toRadians
val d = Vector3.Rz(Vector3(0, 0.875f, 0), ang.z) * math.sin(yRadians).toFloat val d = Vector3.Rz(Vector3(0, 0.875f, 0), ang.z) * math.sin(yRadians).toFloat
Vector3( Vector3(
pos.x + d.x, pos.x + d.x,
pos.y + d.y, pos.y + d.y,
pos.z + math.cos(yRadians).toFloat * 0.875f pos.z + math.cos(yRadians).toFloat * 0.875f
) )
} }
zone.LocalEvents ! LocalServiceMessage(zone.Id, zone.LocalEvents ! LocalServiceMessage(
zone.Id,
LocalAction.TriggerEffectLocation(Service.defaultPlayerGUID, "motion_sensor_destroyed", explosionPos, ang) LocalAction.TriggerEffectLocation(Service.defaultPlayerGUID, "motion_sensor_destroyed", explosionPos, ang)
) )
//TODO replaced by an alternate model (charred stub)? //TODO replaced by an alternate model (charred stub)?

View file

@ -17,38 +17,42 @@ import net.psforever.types.PlanetSideGUID
import services.Service import services.Service
import services.vehicle.{VehicleAction, VehicleServiceMessage} import services.vehicle.{VehicleAction, VehicleServiceMessage}
class ShieldGeneratorDeployable(cdef : ShieldGeneratorDefinition) extends ComplexDeployable(cdef) class ShieldGeneratorDeployable(cdef: ShieldGeneratorDefinition)
with Hackable extends ComplexDeployable(cdef)
with JammableUnit with Hackable
with JammableUnit
class ShieldGeneratorDefinition extends ComplexDeployableDefinition(240) { class ShieldGeneratorDefinition extends ComplexDeployableDefinition(240) {
Packet = new ShieldGeneratorConverter Packet = new ShieldGeneratorConverter
DeployCategory = DeployableCategory.ShieldGenerators DeployCategory = DeployableCategory.ShieldGenerators
override def Initialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = { override def Initialize(obj: PlanetSideServerObject with Deployable, context: ActorContext) = {
obj.Actor = context.actorOf(Props(classOf[ShieldGeneratorControl], obj), PlanetSideServerObject.UniqueActorName(obj)) obj.Actor =
context.actorOf(Props(classOf[ShieldGeneratorControl], obj), PlanetSideServerObject.UniqueActorName(obj))
} }
override def Uninitialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = { override def Uninitialize(obj: PlanetSideServerObject with Deployable, context: ActorContext) = {
SimpleDeployableDefinition.SimpleUninitialize(obj, context) SimpleDeployableDefinition.SimpleUninitialize(obj, context)
} }
} }
class ShieldGeneratorControl(gen : ShieldGeneratorDeployable) extends Actor class ShieldGeneratorControl(gen: ShieldGeneratorDeployable)
with JammableBehavior extends Actor
with DamageableEntity with JammableBehavior
with RepairableEntity { with DamageableEntity
def JammableObject = gen with RepairableEntity {
def DamageableObject = gen def JammableObject = gen
def RepairableObject = gen def DamageableObject = gen
private var handleDamageToShields : Boolean = false def RepairableObject = gen
private var handleDamageToShields: Boolean = false
def receive : Receive = jammableBehavior def receive: Receive =
.orElse(takesDamage) jammableBehavior
.orElse(canBeRepairedByNanoDispenser) .orElse(takesDamage)
.orElse { .orElse(canBeRepairedByNanoDispenser)
case _ => ; .orElse {
} case _ => ;
}
/** /**
* The shield generator has two upgrade paths - blocking projectiles, and providing ammunition like a terminal. * The shield generator has two upgrade paths - blocking projectiles, and providing ammunition like a terminal.
@ -59,44 +63,48 @@ class ShieldGeneratorControl(gen : ShieldGeneratorDeployable) extends Actor
* @param player the user of the nano dispenser tool * @param player the user of the nano dispenser tool
* @param item the nano dispenser tool * @param item the nano dispenser tool
*/ */
override def CanBeRepairedByNanoDispenser(player : Player, item : Tool) : Unit = { override def CanBeRepairedByNanoDispenser(player: Player, item: Tool): Unit = {
if(gen.CanRepair) { if (gen.CanRepair) {
super.CanBeRepairedByNanoDispenser(player, item) super.CanBeRepairedByNanoDispenser(player, item)
} } else if (!gen.Destroyed) {
else if(!gen.Destroyed) {
//TODO reinforced shield upgrade not implemented yet //TODO reinforced shield upgrade not implemented yet
//TODO ammunition supply upgrade not implemented yet //TODO ammunition supply upgrade not implemented yet
} }
} }
override protected def PerformDamage(target : Damageable.Target, applyDamageTo : ResolutionCalculations.Output) : Unit = { override protected def PerformDamage(
val originalHealth = gen.Health target: Damageable.Target,
applyDamageTo: ResolutionCalculations.Output
): Unit = {
val originalHealth = gen.Health
val originalShields = gen.Shields val originalShields = gen.Shields
val cause = applyDamageTo(target) val cause = applyDamageTo(target)
val health = gen.Health val health = gen.Health
val shields = gen.Shields val shields = gen.Shields
val damageToHealth = originalHealth - health val damageToHealth = originalHealth - health
val damageToShields = originalShields - shields val damageToShields = originalShields - shields
val damage = damageToHealth + damageToShields val damage = damageToHealth + damageToShields
if(WillAffectTarget(target, damage, cause)) { if (WillAffectTarget(target, damage, cause)) {
target.History(cause) target.History(cause)
DamageLog(target,s"BEFORE=$originalHealth/$originalShields, AFTER=$health/$shields, CHANGE=$damageToHealth/$damageToShields") DamageLog(
target,
s"BEFORE=$originalHealth/$originalShields, AFTER=$health/$shields, CHANGE=$damageToHealth/$damageToShields"
)
handleDamageToShields = damageToShields > 0 handleDamageToShields = damageToShields > 0
HandleDamage(target, cause, damageToHealth) HandleDamage(target, cause, damageToHealth)
} } else {
else {
gen.Health = originalHealth gen.Health = originalHealth
gen.Shields = originalShields gen.Shields = originalShields
} }
} }
override protected def DamageAwareness(target : Damageable.Target, cause : ResolvedProjectile, amount : Int) : Unit = { override protected def DamageAwareness(target: Damageable.Target, cause: ResolvedProjectile, amount: Int): Unit = {
super.DamageAwareness(target, cause, amount) super.DamageAwareness(target, cause, amount)
ShieldGeneratorControl.DamageAwareness(gen, cause, handleDamageToShields) ShieldGeneratorControl.DamageAwareness(gen, cause, handleDamageToShields)
handleDamageToShields = false handleDamageToShields = false
} }
override protected def DestructionAwareness(target : Target, cause : ResolvedProjectile) : Unit = { override protected def DestructionAwareness(target: Target, cause: ResolvedProjectile): Unit = {
super.DestructionAwareness(target, cause) super.DestructionAwareness(target, cause)
ShieldGeneratorControl.DestructionAwareness(gen, PlanetSideGUID(0)) ShieldGeneratorControl.DestructionAwareness(gen, PlanetSideGUID(0))
} }
@ -105,21 +113,28 @@ class ShieldGeneratorControl(gen : ShieldGeneratorDeployable) extends Actor
while the shield generator is technically a supported jammable target, how that works is currently unknown while the shield generator is technically a supported jammable target, how that works is currently unknown
check the object definition for proper feature activation check the object definition for proper feature activation
*/ */
override def StartJammeredSound(target : Any, dur : Int) : Unit = { } override def StartJammeredSound(target: Any, dur: Int): Unit = {}
override def StartJammeredStatus(target : Any, dur : Int) : Unit = target match { override def StartJammeredStatus(target: Any, dur: Int): Unit =
case obj : PlanetSideServerObject with JammableUnit if !obj.Jammed =>
obj.Zone.VehicleEvents ! VehicleServiceMessage(obj.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 27, 1))
super.StartJammeredStatus(obj, dur)
case _ => ;
}
override def CancelJammeredSound(target : Any) : Unit = { }
override def CancelJammeredStatus(target : Any) : Unit = {
target match { target match {
case obj : PlanetSideServerObject with JammableUnit if obj.Jammed => case obj: PlanetSideServerObject with JammableUnit if !obj.Jammed =>
obj.Zone.VehicleEvents ! VehicleServiceMessage(obj.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 27, 0)) obj.Zone.VehicleEvents ! VehicleServiceMessage(
obj.Zone.Id,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 27, 1)
)
super.StartJammeredStatus(obj, dur)
case _ => ;
}
override def CancelJammeredSound(target: Any): Unit = {}
override def CancelJammeredStatus(target: Any): Unit = {
target match {
case obj: PlanetSideServerObject with JammableUnit if obj.Jammed =>
obj.Zone.VehicleEvents ! VehicleServiceMessage(
obj.Zone.Id,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 27, 0)
)
case _ => ; case _ => ;
} }
super.CancelJammeredStatus(target) super.CancelJammeredStatus(target)
@ -127,17 +142,21 @@ class ShieldGeneratorControl(gen : ShieldGeneratorDeployable) extends Actor
} }
object ShieldGeneratorControl { object ShieldGeneratorControl {
/** /**
* na * na
* @param target na * @param target na
* @param cause na * @param cause na
* @param damageToShields na * @param damageToShields na
*/ */
def DamageAwareness(target : ShieldGeneratorDeployable, cause : ResolvedProjectile, damageToShields : Boolean) : Unit = { def DamageAwareness(target: ShieldGeneratorDeployable, cause: ResolvedProjectile, damageToShields: Boolean): Unit = {
//shields //shields
if(damageToShields) { if (damageToShields) {
val zone = target.Zone val zone = target.Zone
zone.VehicleEvents ! VehicleServiceMessage(zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 68, target.Shields)) zone.VehicleEvents ! VehicleServiceMessage(
zone.Id,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 68, target.Shields)
)
} }
} }
@ -146,7 +165,7 @@ object ShieldGeneratorControl {
* @param target na * @param target na
* @param attribution na * @param attribution na
*/ */
def DestructionAwareness(target : Damageable.Target with Deployable, attribution : PlanetSideGUID) : Unit = { def DestructionAwareness(target: Damageable.Target with Deployable, attribution: PlanetSideGUID): Unit = {
Deployables.AnnounceDestroyDeployable(target, None) Deployables.AnnounceDestroyDeployable(target, None)
} }
} }

View file

@ -4,12 +4,12 @@ package net.psforever.objects
import net.psforever.objects.definition.SimpleItemDefinition import net.psforever.objects.definition.SimpleItemDefinition
import net.psforever.objects.equipment.Equipment import net.psforever.objects.equipment.Equipment
class SimpleItem(private val simpDef : SimpleItemDefinition) extends Equipment { class SimpleItem(private val simpDef: SimpleItemDefinition) extends Equipment {
def Definition : SimpleItemDefinition = simpDef def Definition: SimpleItemDefinition = simpDef
} }
object SimpleItem { object SimpleItem {
def apply(simpDef : SimpleItemDefinition) : SimpleItem = { def apply(simpDef: SimpleItemDefinition): SimpleItem = {
new SimpleItem(simpDef) new SimpleItem(simpDef)
} }
} }

View file

@ -8,27 +8,31 @@ import net.psforever.types.{PlanetSideGUID, Vector3}
import scala.collection.mutable import scala.collection.mutable
trait SpawnPoint { trait SpawnPoint {
psso : PlanetSideServerObject => psso: PlanetSideServerObject =>
/** /**
* An element of the contract of `PlanetSideServerObject`; * An element of the contract of `PlanetSideServerObject`;
* but, this makes it visible to a `SpawnPoint` object without casting. * but, this makes it visible to a `SpawnPoint` object without casting.
* @see `Identifiable.GUID` * @see `Identifiable.GUID`
*/ */
def GUID : PlanetSideGUID def GUID: PlanetSideGUID
/** /**
* An element of the contract of `PlanetSideServerObject`; * An element of the contract of `PlanetSideServerObject`;
* but, this makes it visible to a `SpawnPoint` object without casting. * but, this makes it visible to a `SpawnPoint` object without casting.
* @see `WorldEntity.GUID` * @see `WorldEntity.GUID`
* @see `SpecificPoint` * @see `SpecificPoint`
*/ */
def Position : Vector3 def Position: Vector3
/** /**
* An element of the contract of `PlanetSideServerObject`; * An element of the contract of `PlanetSideServerObject`;
* but, this makes it visible to a `SpawnPoint` object without casting. * but, this makes it visible to a `SpawnPoint` object without casting.
* @see `WorldEntity.GUID` * @see `WorldEntity.GUID`
* @see `SpecificPoint` * @see `SpecificPoint`
*/ */
def Orientation : Vector3 def Orientation: Vector3
/** /**
* An element of an unspoken contract with `Amenity`. * An element of an unspoken contract with `Amenity`.
* While not all `SpawnPoint` objects will be `Amenity` objects, a subclass of the `PlanetSideServerObject` class, * While not all `SpawnPoint` objects will be `Amenity` objects, a subclass of the `PlanetSideServerObject` class,
@ -36,16 +40,17 @@ trait SpawnPoint {
* This should generally be themselves. * This should generally be themselves.
* @see `Amenity.Owner` * @see `Amenity.Owner`
*/ */
def Owner : PlanetSideServerObject def Owner: PlanetSideServerObject
/** /**
* An element of the contract of `PlanetSideServerObject`; * An element of the contract of `PlanetSideServerObject`;
* but, this makes it visible to a `SpawnPoint` object without casting. * but, this makes it visible to a `SpawnPoint` object without casting.
* @see `PlanetSideGameObject.Definition` * @see `PlanetSideGameObject.Definition`
* @see `SpecificPoint` * @see `SpecificPoint`
*/ */
def Definition : ObjectDefinition with SpawnPointDefinition def Definition: ObjectDefinition with SpawnPointDefinition
def Offline : Boolean = psso.Destroyed def Offline: Boolean = psso.Destroyed
/** /**
* Determine a specific position and orientation in which to spawn the target. * Determine a specific position and orientation in which to spawn the target.
@ -53,9 +58,9 @@ trait SpawnPoint {
* the first represents the game world position of spawning; * the first represents the game world position of spawning;
* the second represents the game world direction of spawning * the second represents the game world direction of spawning
*/ */
def SpecificPoint(target : PlanetSideGameObject) : (Vector3, Vector3) = { def SpecificPoint(target: PlanetSideGameObject): (Vector3, Vector3) = {
psso.Definition match { psso.Definition match {
case d : SpawnPointDefinition => case d: SpawnPointDefinition =>
d.SpecificPoint(this, target) d.SpecificPoint(this, target)
case _ => case _ =>
SpawnPoint.Default(this, target) SpawnPoint.Default(this, target)
@ -64,49 +69,53 @@ trait SpawnPoint {
} }
object SpawnPoint { object SpawnPoint {
def Default(obj : SpawnPoint, target : PlanetSideGameObject) : (Vector3, Vector3) = (obj.Position, obj.Orientation) def Default(obj: SpawnPoint, target: PlanetSideGameObject): (Vector3, Vector3) = (obj.Position, obj.Orientation)
def Tube(obj : SpawnPoint, target : PlanetSideGameObject) : (Vector3, Vector3) = ( def Tube(obj: SpawnPoint, target: PlanetSideGameObject): (Vector3, Vector3) =
obj.Position + Vector3.z(1.5f),
obj.Orientation.xy + Vector3.z(obj.Orientation.z + 90 % 360)
)
def AMS(obj : SpawnPoint, target : PlanetSideGameObject) : (Vector3, Vector3) = {
//position the player alongside either of the AMS's terminals, facing away from it
val ori = obj.Orientation
val side = if(System.currentTimeMillis() % 2 == 0) 1 else -1 //right | left
val x = ori.x
val xsin = 3 * side * math.abs(math.sin(math.toRadians(x))).toFloat + 0.5f //sin because 0-degrees is up
val z = ori.z
val zrot = (z + 90) % 360
val zrad = math.toRadians(zrot)
val shift = Vector3(math.sin(zrad).toFloat, math.cos(zrad).toFloat, 0) * (3 * side).toFloat //x=sin, y=cos because compass-0 is East, not North
( (
obj.Position + shift + (if(x >= 330) { //ams leaning to the left obj.Position + Vector3.z(1.5f),
Vector3.z(xsin) obj.Orientation.xy + Vector3.z(obj.Orientation.z + 90 % 360)
} )
else { //ams leaning to the right
Vector3.z(-xsin) def AMS(obj: SpawnPoint, target: PlanetSideGameObject): (Vector3, Vector3) = {
}), //position the player alongside either of the AMS's terminals, facing away from it
if(side == 1) { val ori = obj.Orientation
val side = if (System.currentTimeMillis() % 2 == 0) 1 else -1 //right | left
val x = ori.x
val xsin = 3 * side * math.abs(math.sin(math.toRadians(x))).toFloat + 0.5f //sin because 0-degrees is up
val z = ori.z
val zrot = (z + 90) % 360
val zrad = math.toRadians(zrot)
val shift = Vector3(
math.sin(zrad).toFloat,
math.cos(zrad).toFloat,
0
) * (3 * side).toFloat //x=sin, y=cos because compass-0 is East, not North
(
obj.Position + shift + (if (x >= 330) { //ams leaning to the left
Vector3.z(xsin)
} else { //ams leaning to the right
Vector3.z(-xsin)
}),
if (side == 1) {
Vector3.z(zrot) Vector3.z(zrot)
} } else {
else {
Vector3.z((z - 90) % 360) Vector3.z((z - 90) % 360)
} }
) )
} }
def Gate(obj : SpawnPoint, target : PlanetSideGameObject) : (Vector3, Vector3) = { def Gate(obj: SpawnPoint, target: PlanetSideGameObject): (Vector3, Vector3) = {
obj.Definition match { obj.Definition match {
case d : SpawnPointDefinition => case d: SpawnPointDefinition =>
val ori = target.Orientation val ori = target.Orientation
val zrad = math.toRadians(ori.z) val zrad = math.toRadians(ori.z)
val radius = scala.math.random.toFloat * d.UseRadius/2 + 20f //20 is definitely outside of the gating energy field val radius =
val shift = Vector3(math.sin(zrad).toFloat, math.cos(zrad).toFloat, 0) * radius scala.math.random.toFloat * d.UseRadius / 2 + 20f //20 is definitely outside of the gating energy field
val shift = Vector3(math.sin(zrad).toFloat, math.cos(zrad).toFloat, 0) * radius
val altitudeShift = target.Definition match { val altitudeShift = target.Definition match {
case vdef : VehicleDefinition if GlobalDefinitions.isFlightVehicle(vdef) => case vdef: VehicleDefinition if GlobalDefinitions.isFlightVehicle(vdef) =>
Vector3.z(scala.math.random.toFloat * d.UseRadius/4 + 20f) Vector3.z(scala.math.random.toFloat * d.UseRadius / 4 + 20f)
case _ => case _ =>
Vector3.Zero Vector3.Zero
} }
@ -118,46 +127,45 @@ object SpawnPoint {
} }
trait SpawnPointDefinition { trait SpawnPointDefinition {
private var radius : Float = 0f //m private var radius: Float = 0f //m
private var delay : Long = 0 //s private var delay: Long = 0 //s
private var noWarp : Option[mutable.Set[VehicleDefinition]] = None private var noWarp: Option[mutable.Set[VehicleDefinition]] = None
private var spawningFunc : (SpawnPoint, PlanetSideGameObject) => (Vector3, Vector3) = SpawnPoint.Default private var spawningFunc: (SpawnPoint, PlanetSideGameObject) => (Vector3, Vector3) = SpawnPoint.Default
def UseRadius : Float = radius def UseRadius: Float = radius
def UseRadius_=(rad : Float) : Float = { def UseRadius_=(rad: Float): Float = {
radius = rad radius = rad
UseRadius UseRadius
} }
def Delay : Long = delay def Delay: Long = delay
def Delay_=(toDelay : Long) : Long = { def Delay_=(toDelay: Long): Long = {
delay = toDelay delay = toDelay
Delay Delay
} }
def VehicleAllowance : Boolean = noWarp.isDefined def VehicleAllowance: Boolean = noWarp.isDefined
def VehicleAllowance_=(allow : Boolean) : Boolean = { def VehicleAllowance_=(allow: Boolean): Boolean = {
if(allow && noWarp.isEmpty) { if (allow && noWarp.isEmpty) {
noWarp = Some(mutable.Set.empty[VehicleDefinition]) noWarp = Some(mutable.Set.empty[VehicleDefinition])
} } else if (!allow && noWarp.isDefined) {
else if(!allow && noWarp.isDefined) {
noWarp = None noWarp = None
} }
VehicleAllowance VehicleAllowance
} }
def NoWarp : mutable.Set[VehicleDefinition] = { def NoWarp: mutable.Set[VehicleDefinition] = {
noWarp.getOrElse(mutable.Set.empty[VehicleDefinition]) noWarp.getOrElse(mutable.Set.empty[VehicleDefinition])
} }
def SpecificPointFunc : (SpawnPoint, PlanetSideGameObject) => (Vector3, Vector3) = spawningFunc def SpecificPointFunc: (SpawnPoint, PlanetSideGameObject) => (Vector3, Vector3) = spawningFunc
def SpecificPointFunc_=(func : (SpawnPoint, PlanetSideGameObject) => (Vector3, Vector3)) : Unit = { def SpecificPointFunc_=(func: (SpawnPoint, PlanetSideGameObject) => (Vector3, Vector3)): Unit = {
spawningFunc = func spawningFunc = func
} }
def SpecificPoint(obj : SpawnPoint, target : PlanetSideGameObject) : (Vector3, Vector3) = spawningFunc(obj, target) def SpecificPoint(obj: SpawnPoint, target: PlanetSideGameObject): (Vector3, Vector3) = spawningFunc(obj, target)
} }

View file

@ -4,11 +4,10 @@ package net.psforever.objects
import net.psforever.objects.ce.TelepadLike import net.psforever.objects.ce.TelepadLike
import net.psforever.objects.definition.ConstructionItemDefinition import net.psforever.objects.definition.ConstructionItemDefinition
class Telepad(private val cdef : ConstructionItemDefinition) extends ConstructionItem(cdef) class Telepad(private val cdef: ConstructionItemDefinition) extends ConstructionItem(cdef) with TelepadLike
with TelepadLike
object Telepad { object Telepad {
def apply(cdef : ConstructionItemDefinition) : Telepad = { def apply(cdef: ConstructionItemDefinition): Telepad = {
new Telepad(cdef) new Telepad(cdef)
} }
} }

View file

@ -4,5 +4,4 @@ package net.psforever.objects
import net.psforever.objects.ce.{SimpleDeployable, TelepadLike} import net.psforever.objects.ce.{SimpleDeployable, TelepadLike}
import net.psforever.objects.definition.SimpleDeployableDefinition import net.psforever.objects.definition.SimpleDeployableDefinition
class TelepadDeployable(ddef : SimpleDeployableDefinition) extends SimpleDeployable(ddef) class TelepadDeployable(ddef: SimpleDeployableDefinition) extends SimpleDeployable(ddef) with TelepadLike
with TelepadLike

View file

@ -17,77 +17,79 @@ import scala.annotation.tailrec
* Some weapons Chainblade have ammunition but do not consume it. * Some weapons Chainblade have ammunition but do not consume it.
* @param toolDef the `ObjectDefinition` that constructs this item and maintains some of its immutable fields * @param toolDef the `ObjectDefinition` that constructs this item and maintains some of its immutable fields
*/ */
class Tool(private val toolDef : ToolDefinition) extends Equipment class Tool(private val toolDef: ToolDefinition)
with FireModeSwitch[FireModeDefinition] extends Equipment
with JammableUnit { with FireModeSwitch[FireModeDefinition]
with JammableUnit {
/** index of the current fire mode on the `ToolDefinition`'s list of fire modes */ /** index of the current fire mode on the `ToolDefinition`'s list of fire modes */
private var fireModeIndex : Int = toolDef.DefaultFireModeIndex private var fireModeIndex: Int = toolDef.DefaultFireModeIndex
/** current ammunition slot being used by this fire mode */ /** current ammunition slot being used by this fire mode */
private var ammoSlots : List[Tool.FireModeSlot] = List.empty private var ammoSlots: List[Tool.FireModeSlot] = List.empty
var lastDischarge : Long = 0 var lastDischarge: Long = 0
Tool.LoadDefinition(this) Tool.LoadDefinition(this)
def FireModeIndex : Int = fireModeIndex def FireModeIndex: Int = fireModeIndex
def FireModeIndex_=(index : Int) : Int = { def FireModeIndex_=(index: Int): Int = {
fireModeIndex = index % Definition.FireModes.length fireModeIndex = index % Definition.FireModes.length
FireModeIndex FireModeIndex
} }
def FireMode : FireModeDefinition = Definition.FireModes(fireModeIndex) def FireMode: FireModeDefinition = Definition.FireModes(fireModeIndex)
def NextFireMode : FireModeDefinition = { def NextFireMode: FireModeDefinition = {
FireModeIndex = Definition.NextFireModeIndex(FireModeIndex) FireModeIndex = Definition.NextFireModeIndex(FireModeIndex)
AmmoSlot.Chamber = FireMode.Chamber AmmoSlot.Chamber = FireMode.Chamber
FireMode FireMode
} }
def ToFireMode : Int = Definition.NextFireModeIndex(FireModeIndex) def ToFireMode: Int = Definition.NextFireModeIndex(FireModeIndex)
def ToFireMode_=(index : Int) : FireModeDefinition = { def ToFireMode_=(index: Int): FireModeDefinition = {
FireModeIndex = index FireModeIndex = index
AmmoSlot.Chamber = FireMode.Chamber AmmoSlot.Chamber = FireMode.Chamber
FireMode FireMode
} }
def AmmoTypeIndex : Int = FireMode.AmmoTypeIndices(AmmoSlot.AmmoTypeIndex) def AmmoTypeIndex: Int = FireMode.AmmoTypeIndices(AmmoSlot.AmmoTypeIndex)
def AmmoTypeIndex_=(index : Int) : Int = { def AmmoTypeIndex_=(index: Int): Int = {
AmmoSlot.AmmoTypeIndex = index % FireMode.AmmoTypeIndices.length AmmoSlot.AmmoTypeIndex = index % FireMode.AmmoTypeIndices.length
AmmoTypeIndex AmmoTypeIndex
} }
def AmmoType : Ammo.Value = Definition.AmmoTypes(AmmoTypeIndex).AmmoType def AmmoType: Ammo.Value = Definition.AmmoTypes(AmmoTypeIndex).AmmoType
def NextAmmoType : Ammo.Value = { def NextAmmoType: Ammo.Value = {
AmmoSlot.AmmoTypeIndex = AmmoSlot.AmmoTypeIndex + 1 AmmoSlot.AmmoTypeIndex = AmmoSlot.AmmoTypeIndex + 1
AmmoType AmmoType
} }
def Projectile : ProjectileDefinition = { def Projectile: ProjectileDefinition = {
Definition.ProjectileTypes({ Definition.ProjectileTypes({
val projIndices = FireMode.ProjectileTypeIndices val projIndices = FireMode.ProjectileTypeIndices
if(projIndices.isEmpty) { if (projIndices.isEmpty) {
AmmoTypeIndex //e.g., bullet_9mm -> bullet_9mm_projectile, bullet_9mm_AP -> bullet_9mm_AP_projectile AmmoTypeIndex //e.g., bullet_9mm -> bullet_9mm_projectile, bullet_9mm_AP -> bullet_9mm_AP_projectile
} } else {
else {
projIndices(AmmoSlot.AmmoTypeIndex) //e.g., pulsar: f.mode1 -> pulsar_projectile, f.mode2 = pulsar_ap_projectile projIndices(AmmoSlot.AmmoTypeIndex) //e.g., pulsar: f.mode1 -> pulsar_projectile, f.mode2 = pulsar_ap_projectile
} }
}) })
} }
def ProjectileType : Projectiles.Value = Projectile.ProjectileType def ProjectileType: Projectiles.Value = Projectile.ProjectileType
def Magazine : Int = AmmoSlot.Magazine def Magazine: Int = AmmoSlot.Magazine
def Magazine_=(mag : Int) : Int = { def Magazine_=(mag: Int): Int = {
//AmmoSlot.Magazine = Math.min(Math.max(0, mag), MaxMagazine) //AmmoSlot.Magazine = Math.min(Math.max(0, mag), MaxMagazine)
AmmoSlot.Magazine = Math.max(0, mag) AmmoSlot.Magazine = Math.max(0, mag)
Magazine Magazine
} }
def MaxMagazine : Int = { def MaxMagazine: Int = {
val fmode = FireMode val fmode = FireMode
fmode.CustomMagazine.get(AmmoType) match { fmode.CustomMagazine.get(AmmoType) match {
case Some(magSize) => case Some(magSize) =>
@ -97,30 +99,30 @@ class Tool(private val toolDef : ToolDefinition) extends Equipment
} }
} }
def Discharge(rounds : Option[Int] = None) : Int = { def Discharge(rounds: Option[Int] = None): Int = {
lastDischarge = System.nanoTime() lastDischarge = System.nanoTime()
Magazine = FireMode.Discharge(this, rounds) Magazine = FireMode.Discharge(this, rounds)
} }
def LastDischarge : Long = { def LastDischarge: Long = {
lastDischarge lastDischarge
} }
def AmmoSlot : Tool.FireModeSlot = ammoSlots(FireMode.AmmoSlotIndex) def AmmoSlot: Tool.FireModeSlot = ammoSlots(FireMode.AmmoSlotIndex)
def AmmoSlots : List[Tool.FireModeSlot] = ammoSlots def AmmoSlots: List[Tool.FireModeSlot] = ammoSlots
def MaxAmmoSlot : Int = ammoSlots.length def MaxAmmoSlot: Int = ammoSlots.length
def Definition : ToolDefinition = toolDef def Definition: ToolDefinition = toolDef
override def toString : String = Tool.toString(this) override def toString: String = Tool.toString(this)
} }
//AmmoType = Definition.AmmoTypes( (Definition.FireModes(fireModeIndex)).AmmoTypeIndices( (ammoSlots((Definition.FireModes(fireModeIndex)).AmmoSlotIndex)).AmmoTypeIndex) ).AmmoType //AmmoType = Definition.AmmoTypes( (Definition.FireModes(fireModeIndex)).AmmoTypeIndices( (ammoSlots((Definition.FireModes(fireModeIndex)).AmmoSlotIndex)).AmmoTypeIndex) ).AmmoType
object Tool { object Tool {
def apply(toolDef : ToolDefinition) : Tool = { def apply(toolDef: ToolDefinition): Tool = {
new Tool(toolDef) new Tool(toolDef)
} }
@ -128,28 +130,34 @@ object Tool {
* Use the `*Definition` that was provided to this object to initialize its fields and settings. * Use the `*Definition` that was provided to this object to initialize its fields and settings.
* @param tool the `Tool` being initialized * @param tool the `Tool` being initialized
*/ */
def LoadDefinition(tool : Tool) : Unit = { def LoadDefinition(tool: Tool): Unit = {
val tdef : ToolDefinition = tool.Definition val tdef: ToolDefinition = tool.Definition
val maxSlot = tdef.FireModes.maxBy(fmode => fmode.AmmoSlotIndex).AmmoSlotIndex val maxSlot = tdef.FireModes.maxBy(fmode => fmode.AmmoSlotIndex).AmmoSlotIndex
tool.ammoSlots = buildFireModes(tdef, (0 to maxSlot).iterator, tdef.FireModes.toList) tool.ammoSlots = buildFireModes(tdef, (0 to maxSlot).iterator, tdef.FireModes.toList)
} }
@tailrec private def buildFireModes(tdef : ToolDefinition, iter : Iterator[Int], fmodes : List[FireModeDefinition], list : List[FireModeSlot] = Nil) : List[FireModeSlot] = { @tailrec private def buildFireModes(
if(!iter.hasNext) { tdef: ToolDefinition,
iter: Iterator[Int],
fmodes: List[FireModeDefinition],
list: List[FireModeSlot] = Nil
): List[FireModeSlot] = {
if (!iter.hasNext) {
list list
} } else {
else {
val index = iter.next val index = iter.next
fmodes.filter(fmode => fmode.AmmoSlotIndex == index) match { fmodes.filter(fmode => fmode.AmmoSlotIndex == index) match {
case fmode :: _ => case fmode :: _ =>
buildFireModes(tdef, iter, fmodes, list :+ new FireModeSlot(tdef, fmode)) buildFireModes(tdef, iter, fmodes, list :+ new FireModeSlot(tdef, fmode))
case Nil => case Nil =>
throw new IllegalArgumentException(s"tool ${tdef.Name} ammo slot #$index is missing a fire mode specification; do not skip") throw new IllegalArgumentException(
s"tool ${tdef.Name} ammo slot #$index is missing a fire mode specification; do not skip"
)
} }
} }
} }
def toString(obj : Tool) : String = { def toString(obj: Tool): String = {
s"${obj.Definition.Name} (mode=${obj.FireModeIndex}-${obj.AmmoType})(${obj.Magazine}/${obj.MaxMagazine})" s"${obj.Definition.Name} (mode=${obj.FireModeIndex}-${obj.AmmoType})(${obj.Magazine}/${obj.MaxMagazine})"
} }
@ -166,24 +174,26 @@ object Tool {
* two exclusive groups of ammunition divided into 2 cycled types and 4 cycled types - * two exclusive groups of ammunition divided into 2 cycled types and 4 cycled types -
* is an example of a weapon that benefits from this implementation. * is an example of a weapon that benefits from this implementation.
*/ */
class FireModeSlot(private val tdef : ToolDefinition, private val fdef : FireModeDefinition) { class FireModeSlot(private val tdef: ToolDefinition, private val fdef: FireModeDefinition) {
/** /**
* if this fire mode has multiple types of ammunition * if this fire mode has multiple types of ammunition
* this is the index of the fire mode's ammo List, not a reference to the tool's ammo List * this is the index of the fire mode's ammo List, not a reference to the tool's ammo List
*/ */
private var ammoTypeIndex : Int = 0 private var ammoTypeIndex: Int = 0
/** a reference to the actual `AmmoBox` of this slot */ /** a reference to the actual `AmmoBox` of this slot */
private var box : AmmoBox = AmmoBox(AmmoDefinition, fdef.Magazine) private var box: AmmoBox = AmmoBox(AmmoDefinition, fdef.Magazine)
private var chamber = fdef.Chamber private var chamber = fdef.Chamber
def AmmoTypeIndex : Int = ammoTypeIndex def AmmoTypeIndex: Int = ammoTypeIndex
def AmmoTypeIndex_=(index : Int) : Int = { def AmmoTypeIndex_=(index: Int): Int = {
ammoTypeIndex = index % fdef.AmmoTypeIndices.length ammoTypeIndex = index % fdef.AmmoTypeIndices.length
AmmoTypeIndex AmmoTypeIndex
} }
private def AmmoDefinition : AmmoBoxDefinition = { private def AmmoDefinition: AmmoBoxDefinition = {
tdef.AmmoTypes(fdef.AmmoTypeIndices(ammoTypeIndex)) tdef.AmmoTypes(fdef.AmmoTypeIndices(ammoTypeIndex))
} }
@ -193,40 +203,39 @@ object Tool {
* Generally, convert from this index, to the index in the fire mode's ammunition list, to the index in the `ToolDefinition`'s ammunition list. * Generally, convert from this index, to the index in the fire mode's ammunition list, to the index in the `ToolDefinition`'s ammunition list.
* @return the `Ammo` type that should be loaded into the magazine right now * @return the `Ammo` type that should be loaded into the magazine right now
*/ */
def AmmoType : Ammo.Value = AmmoDefinition.AmmoType def AmmoType: Ammo.Value = AmmoDefinition.AmmoType
def AllAmmoTypes : List[Ammo.Value] = { def AllAmmoTypes: List[Ammo.Value] = {
fdef.AmmoTypeIndices.map(index => tdef.AmmoTypes(fdef.AmmoTypeIndices(index)).AmmoType).toList fdef.AmmoTypeIndices.map(index => tdef.AmmoTypes(fdef.AmmoTypeIndices(index)).AmmoType).toList
} }
def Magazine : Int = box.Capacity def Magazine: Int = box.Capacity
def Magazine_=(mag : Int) : Int = { def Magazine_=(mag: Int): Int = {
box.Capacity = mag box.Capacity = mag
Magazine Magazine
} }
def Chamber : Int = chamber def Chamber: Int = chamber
def Chamber_=(chmbr : Int) : Int = { def Chamber_=(chmbr: Int): Int = {
chamber = math.min(math.max(0, chmbr), fdef.Chamber) chamber = math.min(math.max(0, chmbr), fdef.Chamber)
Chamber Chamber
} }
def Box : AmmoBox = box def Box: AmmoBox = box
def Box_=(toBox : AmmoBox) : Option[AmmoBox] = { def Box_=(toBox: AmmoBox): Option[AmmoBox] = {
if(toBox.AmmoType == AmmoType) { if (toBox.AmmoType == AmmoType) {
box = toBox box = toBox
Some(Box) Some(Box)
} } else {
else {
None None
} }
} }
def Tool : ToolDefinition = tdef def Tool: ToolDefinition = tdef
def Definition : FireModeDefinition = fdef def Definition: FireModeDefinition = fdef
} }
} }

View file

@ -11,40 +11,39 @@ import net.psforever.objects.serverobject.damage.{Damageable, DamageableEntity}
import net.psforever.objects.serverobject.repair.RepairableEntity import net.psforever.objects.serverobject.repair.RepairableEntity
import net.psforever.objects.vital.StandardResolutions import net.psforever.objects.vital.StandardResolutions
class TrapDeployable(cdef : TrapDeployableDefinition) extends ComplexDeployable(cdef) class TrapDeployable(cdef: TrapDeployableDefinition) extends ComplexDeployable(cdef)
class TrapDeployableDefinition(objectId : Int) extends ComplexDeployableDefinition(objectId) { class TrapDeployableDefinition(objectId: Int) extends ComplexDeployableDefinition(objectId) {
Model = StandardResolutions.SimpleDeployables Model = StandardResolutions.SimpleDeployables
Packet = new TRAPConverter Packet = new TRAPConverter
override def Initialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = { override def Initialize(obj: PlanetSideServerObject with Deployable, context: ActorContext) = {
obj.Actor = context.actorOf(Props(classOf[TrapDeployableControl], obj), PlanetSideServerObject.UniqueActorName(obj)) obj.Actor = context.actorOf(Props(classOf[TrapDeployableControl], obj), PlanetSideServerObject.UniqueActorName(obj))
} }
override def Uninitialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = { override def Uninitialize(obj: PlanetSideServerObject with Deployable, context: ActorContext) = {
SimpleDeployableDefinition.SimpleUninitialize(obj, context) SimpleDeployableDefinition.SimpleUninitialize(obj, context)
} }
} }
object TrapDeployableDefinition { object TrapDeployableDefinition {
def apply(dtype : DeployedItem.Value) : TrapDeployableDefinition = { def apply(dtype: DeployedItem.Value): TrapDeployableDefinition = {
new TrapDeployableDefinition(dtype.id) new TrapDeployableDefinition(dtype.id)
} }
} }
class TrapDeployableControl(trap : TrapDeployable) extends Actor class TrapDeployableControl(trap: TrapDeployable) extends Actor with DamageableEntity with RepairableEntity {
with DamageableEntity
with RepairableEntity {
def DamageableObject = trap def DamageableObject = trap
def RepairableObject = trap def RepairableObject = trap
def receive : Receive = takesDamage def receive: Receive =
.orElse(canBeRepairedByNanoDispenser) takesDamage
.orElse { .orElse(canBeRepairedByNanoDispenser)
case _ => .orElse {
} case _ =>
}
override protected def DestructionAwareness(target : Damageable.Target, cause : ResolvedProjectile) : Unit = { override protected def DestructionAwareness(target: Damageable.Target, cause: ResolvedProjectile): Unit = {
super.DestructionAwareness(target, cause) super.DestructionAwareness(target, cause)
Deployables.AnnounceDestroyDeployable(trap, None) Deployables.AnnounceDestroyDeployable(trap, None)
} }

View file

@ -17,19 +17,21 @@ import net.psforever.objects.serverobject.repair.RepairableWeaponTurret
import net.psforever.objects.serverobject.turret.{TurretDefinition, WeaponTurret} import net.psforever.objects.serverobject.turret.{TurretDefinition, WeaponTurret}
import net.psforever.objects.vital.{StandardResolutions, StandardVehicleDamage, StandardVehicleResistance} import net.psforever.objects.vital.{StandardResolutions, StandardVehicleDamage, StandardVehicleResistance}
class TurretDeployable(tdef : TurretDeployableDefinition) extends ComplexDeployable(tdef) class TurretDeployable(tdef: TurretDeployableDefinition)
with WeaponTurret extends ComplexDeployable(tdef)
with JammableUnit with WeaponTurret
with Hackable { with JammableUnit
with Hackable {
WeaponTurret.LoadDefinition(this) WeaponTurret.LoadDefinition(this)
def MountPoints : Map[Int, Int] = Definition.MountPoints.toMap def MountPoints: Map[Int, Int] = Definition.MountPoints.toMap
override def Definition = tdef override def Definition = tdef
} }
class TurretDeployableDefinition(private val objectId : Int) extends ComplexDeployableDefinition(objectId) class TurretDeployableDefinition(private val objectId: Int)
with TurretDefinition { extends ComplexDeployableDefinition(objectId)
with TurretDefinition {
Name = "turret_deployable" Name = "turret_deployable"
Packet = new SmallTurretConverter Packet = new SmallTurretConverter
DamageUsing = StandardVehicleDamage DamageUsing = StandardVehicleDamage
@ -37,51 +39,53 @@ class TurretDeployableDefinition(private val objectId : Int) extends ComplexDepl
Model = StandardResolutions.FacilityTurrets Model = StandardResolutions.FacilityTurrets
//override to clarify inheritance conflict //override to clarify inheritance conflict
override def MaxHealth : Int = super[ComplexDeployableDefinition].MaxHealth override def MaxHealth: Int = super[ComplexDeployableDefinition].MaxHealth
//override to clarify inheritance conflict //override to clarify inheritance conflict
override def MaxHealth_=(max : Int) : Int = super[ComplexDeployableDefinition].MaxHealth_=(max) override def MaxHealth_=(max: Int): Int = super[ComplexDeployableDefinition].MaxHealth_=(max)
override def Initialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = { override def Initialize(obj: PlanetSideServerObject with Deployable, context: ActorContext) = {
obj.Actor = context.actorOf(Props(classOf[TurretControl], obj), PlanetSideServerObject.UniqueActorName(obj)) obj.Actor = context.actorOf(Props(classOf[TurretControl], obj), PlanetSideServerObject.UniqueActorName(obj))
} }
override def Uninitialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) = { override def Uninitialize(obj: PlanetSideServerObject with Deployable, context: ActorContext) = {
SimpleDeployableDefinition.SimpleUninitialize(obj, context) SimpleDeployableDefinition.SimpleUninitialize(obj, context)
} }
} }
object TurretDeployableDefinition { object TurretDeployableDefinition {
def apply(dtype : DeployedItem.Value) : TurretDeployableDefinition = { def apply(dtype: DeployedItem.Value): TurretDeployableDefinition = {
new TurretDeployableDefinition(dtype.id) new TurretDeployableDefinition(dtype.id)
} }
} }
/** control actors */ /** control actors */
class TurretControl(turret : TurretDeployable) extends Actor class TurretControl(turret: TurretDeployable)
with FactionAffinityBehavior.Check extends Actor
with JammableMountedWeapons //note: jammable status is reported as vehicle events, not local events with FactionAffinityBehavior.Check
with MountableBehavior.TurretMount with JammableMountedWeapons //note: jammable status is reported as vehicle events, not local events
with MountableBehavior.Dismount with MountableBehavior.TurretMount
with DamageableWeaponTurret with MountableBehavior.Dismount
with RepairableWeaponTurret { with DamageableWeaponTurret
def MountableObject = turret with RepairableWeaponTurret {
def JammableObject = turret def MountableObject = turret
def FactionObject = turret def JammableObject = turret
def FactionObject = turret
def DamageableObject = turret def DamageableObject = turret
def RepairableObject = turret def RepairableObject = turret
def receive : Receive = checkBehavior def receive: Receive =
.orElse(jammableBehavior) checkBehavior
.orElse(mountBehavior) .orElse(jammableBehavior)
.orElse(dismountBehavior) .orElse(mountBehavior)
.orElse(takesDamage) .orElse(dismountBehavior)
.orElse(canBeRepairedByNanoDispenser) .orElse(takesDamage)
.orElse { .orElse(canBeRepairedByNanoDispenser)
case _ => ; .orElse {
} case _ => ;
}
override protected def DestructionAwareness(target : Target, cause : ResolvedProjectile) : Unit = { override protected def DestructionAwareness(target: Target, cause: ResolvedProjectile): Unit = {
super.DestructionAwareness(target, cause) super.DestructionAwareness(target, cause)
Deployables.AnnounceDestroyDeployable(turret, None) Deployables.AnnounceDestroyDeployable(turret, None)
} }

View file

@ -66,45 +66,48 @@ import scala.util.{Success, Try}
* stores and unloads pertinent information about the `Vehicle`'s configuration; * stores and unloads pertinent information about the `Vehicle`'s configuration;
* used in the initialization process (`loadVehicleDefinition`) * used in the initialization process (`loadVehicleDefinition`)
*/ */
class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner class Vehicle(private val vehicleDef: VehicleDefinition)
with Hackable extends AmenityOwner
with FactionAffinity with Hackable
with Mountable with FactionAffinity
with MountedWeapons with Mountable
with Deployment with MountedWeapons
with Vitality with Deployment
with OwnableByPlayer with Vitality
with StandardResistanceProfile with OwnableByPlayer
with JammableUnit with StandardResistanceProfile
with Container { with JammableUnit
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL with Container {
private var shields : Int = 0 private var faction: PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
private var decal : Int = 0 private var shields: Int = 0
private var trunkAccess : Option[PlanetSideGUID] = None private var decal: Int = 0
private var jammered : Boolean = false private var trunkAccess: Option[PlanetSideGUID] = None
private var cloaked : Boolean = false private var jammered: Boolean = false
private var flying : Boolean = false private var cloaked: Boolean = false
private var ntuCapacitor : Int = 0 private var flying: Boolean = false
private var capacitor : Int = 0 private var ntuCapacitor: Int = 0
private var capacitor: Int = 0
/** /**
* Permissions control who gets to access different parts of the vehicle; * Permissions control who gets to access different parts of the vehicle;
* the groups are Driver (seat), Gunner (seats), Passenger (seats), and the Trunk * the groups are Driver (seat), Gunner (seats), Passenger (seats), and the Trunk
*/ */
private val groupPermissions : Array[VehicleLockState.Value] = Array(VehicleLockState.Locked, VehicleLockState.Empire, VehicleLockState.Empire, VehicleLockState.Locked) private val groupPermissions: Array[VehicleLockState.Value] =
private var seats : Map[Int, Seat] = Map.empty Array(VehicleLockState.Locked, VehicleLockState.Empire, VehicleLockState.Empire, VehicleLockState.Locked)
private var cargoHolds : Map[Int, Cargo] = Map.empty private var seats: Map[Int, Seat] = Map.empty
private var weapons : Map[Int, EquipmentSlot] = Map.empty private var cargoHolds: Map[Int, Cargo] = Map.empty
private var utilities : Map[Int, Utility] = Map() private var weapons: Map[Int, EquipmentSlot] = Map.empty
private val trunk : GridInventory = GridInventory() private var utilities: Map[Int, Utility] = Map()
private val trunk: GridInventory = GridInventory()
/** /**
* Records the GUID of the cargo vehicle (galaxy/lodestar) this vehicle is stored in for DismountVehicleCargoMsg use * Records the GUID of the cargo vehicle (galaxy/lodestar) this vehicle is stored in for DismountVehicleCargoMsg use
* DismountVehicleCargoMsg only passes the player_guid and this vehicle's guid * DismountVehicleCargoMsg only passes the player_guid and this vehicle's guid
*/ */
private var mountedIn : Option[PlanetSideGUID] = None private var mountedIn: Option[PlanetSideGUID] = None
private var vehicleGatingManifest : Option[VehicleManifest] = None private var vehicleGatingManifest: Option[VehicleManifest] = None
private var previousVehicleGatingManifest : Option[VehicleManifest] = None private var previousVehicleGatingManifest: Option[VehicleManifest] = None
//init //init
LoadDefinition() LoadDefinition()
@ -113,15 +116,15 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
* Override this method to perform any special setup that is not standardized to `*Definition`. * Override this method to perform any special setup that is not standardized to `*Definition`.
* @see `Vehicle.LoadDefinition` * @see `Vehicle.LoadDefinition`
*/ */
protected def LoadDefinition() : Unit = { protected def LoadDefinition(): Unit = {
Vehicle.LoadDefinition(this) Vehicle.LoadDefinition(this)
} }
def Faction : PlanetSideEmpire.Value = { def Faction: PlanetSideEmpire.Value = {
this.faction this.faction
} }
override def Faction_=(faction : PlanetSideEmpire.Value) : PlanetSideEmpire.Value = { override def Faction_=(faction: PlanetSideEmpire.Value): PlanetSideEmpire.Value = {
this.faction = faction this.faction = faction
faction faction
} }
@ -129,13 +132,13 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
/** How long it takes to jack the vehicle in seconds, based on the hacker's certification level */ /** How long it takes to jack the vehicle in seconds, based on the hacker's certification level */
def JackingDuration: Array[Int] = Definition.JackingDuration def JackingDuration: Array[Int] = Definition.JackingDuration
def MountedIn : Option[PlanetSideGUID] = { def MountedIn: Option[PlanetSideGUID] = {
this.mountedIn this.mountedIn
} }
def MountedIn_=(cargo_vehicle_guid : PlanetSideGUID) : Option[PlanetSideGUID] = MountedIn_=(Some(cargo_vehicle_guid)) def MountedIn_=(cargo_vehicle_guid: PlanetSideGUID): Option[PlanetSideGUID] = MountedIn_=(Some(cargo_vehicle_guid))
def MountedIn_=(cargo_vehicle_guid : Option[PlanetSideGUID]) : Option[PlanetSideGUID] = { def MountedIn_=(cargo_vehicle_guid: Option[PlanetSideGUID]): Option[PlanetSideGUID] = {
cargo_vehicle_guid match { cargo_vehicle_guid match {
case Some(_) => case Some(_) =>
this.mountedIn = cargo_vehicle_guid this.mountedIn = cargo_vehicle_guid
@ -145,61 +148,61 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
MountedIn MountedIn
} }
override def Health_=(assignHealth : Int) : Int = { override def Health_=(assignHealth: Int): Int = {
//TODO should vehicle class enforce this? //TODO should vehicle class enforce this?
if(!Destroyed) { if (!Destroyed) {
super.Health_=(assignHealth) super.Health_=(assignHealth)
} }
Health Health
} }
def Shields : Int = { def Shields: Int = {
shields shields
} }
def Shields_=(strength : Int) : Int = { def Shields_=(strength: Int): Int = {
shields = math.min(math.max(0, strength), MaxShields) shields = math.min(math.max(0, strength), MaxShields)
Shields Shields
} }
def MaxShields : Int = { def MaxShields: Int = {
Definition.MaxShields Definition.MaxShields
} }
def Decal : Int = { def Decal: Int = {
decal decal
} }
def Decal_=(logo : Int) : Int = { def Decal_=(logo: Int): Int = {
decal = logo decal = logo
Decal Decal
} }
def Jammered : Boolean = jammered def Jammered: Boolean = jammered
def Jammered_=(jamState : Boolean) : Boolean = { def Jammered_=(jamState: Boolean): Boolean = {
jammered = jamState jammered = jamState
Jammered Jammered
} }
def Cloaked : Boolean = cloaked def Cloaked: Boolean = cloaked
def Cloaked_=(isCloaked : Boolean) : Boolean = { def Cloaked_=(isCloaked: Boolean): Boolean = {
cloaked = isCloaked cloaked = isCloaked
Cloaked Cloaked
} }
def Flying : Boolean = flying def Flying: Boolean = flying
def Flying_=(isFlying : Boolean) : Boolean = { def Flying_=(isFlying: Boolean): Boolean = {
flying = isFlying flying = isFlying
Flying Flying
} }
def NtuCapacitor : Int = ntuCapacitor def NtuCapacitor: Int = ntuCapacitor
def NtuCapacitor_=(value: Int) : Int = { def NtuCapacitor_=(value: Int): Int = {
if(value > Definition.MaxNtuCapacitor) { if (value > Definition.MaxNtuCapacitor) {
ntuCapacitor = Definition.MaxNtuCapacitor ntuCapacitor = Definition.MaxNtuCapacitor
} else if (value < 0) { } else if (value < 0) {
ntuCapacitor = 0 ntuCapacitor = 0
@ -218,9 +221,9 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
} }
def Capacitor : Int = capacitor def Capacitor : Int = capacitor
def Capacitor_=(value: Int) : Int = { def Capacitor_=(value: Int): Int = {
if(value > Definition.MaxCapacitor) { if (value > Definition.MaxCapacitor) {
capacitor = Definition.MaxCapacitor capacitor = Definition.MaxCapacitor
} else if (value < 0) { } else if (value < 0) {
capacitor = 0 capacitor = 0
@ -235,18 +238,18 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
* @param mountPoint an index representing the seat position / mounting point * @param mountPoint an index representing the seat position / mounting point
* @return a seat number, or `None` * @return a seat number, or `None`
*/ */
def GetSeatFromMountPoint(mountPoint : Int) : Option[Int] = { def GetSeatFromMountPoint(mountPoint: Int): Option[Int] = {
Definition.MountPoints.get(mountPoint) Definition.MountPoints.get(mountPoint)
} }
def MountPoints : Map[Int, Int] = Definition.MountPoints.toMap def MountPoints: Map[Int, Int] = Definition.MountPoints.toMap
/** /**
* What are the access permissions for a position on this vehicle, seats or trunk? * What are the access permissions for a position on this vehicle, seats or trunk?
* @param group the group index * @param group the group index
* @return what sort of access permission exist for this group * @return what sort of access permission exist for this group
*/ */
def PermissionGroup(group : Int) : Option[VehicleLockState.Value] = { def PermissionGroup(group: Int): Option[VehicleLockState.Value] = {
reindexPermissionsGroup(group) match { reindexPermissionsGroup(group) match {
case Some(index) => case Some(index) =>
Some(groupPermissions(index)) Some(groupPermissions(index))
@ -262,16 +265,17 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
* @return the new access permission for this group; * @return the new access permission for this group;
* `None`, if the group does not exist or the level of permission was not changed * `None`, if the group does not exist or the level of permission was not changed
*/ */
def PermissionGroup(group : Int, level : Long) : Option[VehicleLockState.Value] = { def PermissionGroup(group: Int, level: Long): Option[VehicleLockState.Value] = {
reindexPermissionsGroup(group) match { reindexPermissionsGroup(group) match {
case Some(index) => case Some(index) =>
val current = groupPermissions(index) val current = groupPermissions(index)
val next = try { VehicleLockState(level.toInt) } catch { case _ : Exception => groupPermissions(index) } val next =
if(current != next) { try { VehicleLockState(level.toInt) }
catch { case _: Exception => groupPermissions(index) }
if (current != next) {
groupPermissions(index) = next groupPermissions(index) = next
PermissionGroup(index) PermissionGroup(index)
} } else {
else {
None None
} }
case None => case None =>
@ -285,15 +289,14 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
* @param group the group index * @param group the group index
* @return the modified group index * @return the modified group index
*/ */
private def reindexPermissionsGroup(group : Int) : Option[Int] = if(group > 9 && group < 14) { private def reindexPermissionsGroup(group: Int): Option[Int] =
Some(group - 10) if (group > 9 && group < 14) {
} Some(group - 10)
else if(group > -1 && group < 4) { } else if (group > -1 && group < 4) {
Some(group) Some(group)
} } else {
else { None
None }
}
/** /**
* Get the seat at the index. * Get the seat at the index.
@ -301,37 +304,34 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
* @param seatNumber an index representing the seat position / mounting point * @param seatNumber an index representing the seat position / mounting point
* @return a `Seat`, or `None` * @return a `Seat`, or `None`
*/ */
def Seat(seatNumber : Int) : Option[Seat] = { def Seat(seatNumber: Int): Option[Seat] = {
if(seatNumber >= 0 && seatNumber < this.seats.size) { if (seatNumber >= 0 && seatNumber < this.seats.size) {
this.seats.get(seatNumber) this.seats.get(seatNumber)
} } else {
else {
None None
} }
} }
def Seats : Map[Int, Seat] = { def Seats: Map[Int, Seat] = {
seats seats
} }
def CargoHold(cargoNumber : Int) : Option[Cargo] = { def CargoHold(cargoNumber: Int): Option[Cargo] = {
if(cargoNumber >= 0) { if (cargoNumber >= 0) {
this.cargoHolds.get(cargoNumber) this.cargoHolds.get(cargoNumber)
} } else {
else {
None None
} }
} }
def CargoHolds : Map[Int, Cargo] = { def CargoHolds: Map[Int, Cargo] = {
cargoHolds cargoHolds
} }
def SeatPermissionGroup(seatNumber : Int) : Option[AccessPermissionGroup.Value] = { def SeatPermissionGroup(seatNumber: Int): Option[AccessPermissionGroup.Value] = {
if(seatNumber == 0) { if (seatNumber == 0) {
Some(AccessPermissionGroup.Driver) Some(AccessPermissionGroup.Driver)
} } else {
else {
Seat(seatNumber) match { Seat(seatNumber) match {
case Some(seat) => case Some(seat) =>
seat.ControlledWeapon match { seat.ControlledWeapon match {
@ -351,14 +351,14 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
} }
} }
def Weapons : Map[Int, EquipmentSlot] = weapons def Weapons: Map[Int, EquipmentSlot] = weapons
/** /**
* Get the weapon at the index. * Get the weapon at the index.
* @param wepNumber an index representing the seat position / mounting point * @param wepNumber an index representing the seat position / mounting point
* @return a weapon, or `None` * @return a weapon, or `None`
*/ */
def ControlledWeapon(wepNumber : Int) : Option[Equipment] = { def ControlledWeapon(wepNumber: Int): Option[Equipment] = {
weapons.get(wepNumber) match { weapons.get(wepNumber) match {
case Some(mount) => case Some(mount) =>
mount.Equipment mount.Equipment
@ -372,45 +372,42 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
* @param player the player * @param player the player
* @return a seat number, or `None` if the `player` is not actually seated in this vehicle * @return a seat number, or `None` if the `player` is not actually seated in this vehicle
*/ */
def PassengerInSeat(player : Player) : Option[Int] = recursivePassengerInSeat(seats.iterator, player) def PassengerInSeat(player: Player): Option[Int] = recursivePassengerInSeat(seats.iterator, player)
@tailrec private def recursivePassengerInSeat(iter : Iterator[(Int, Seat)], player : Player) : Option[Int] = { @tailrec private def recursivePassengerInSeat(iter: Iterator[(Int, Seat)], player: Player): Option[Int] = {
if(!iter.hasNext) { if (!iter.hasNext) {
None None
} } else {
else {
val (seatNumber, seat) = iter.next val (seatNumber, seat) = iter.next
if(seat.Occupant.contains(player)) { if (seat.Occupant.contains(player)) {
Some(seatNumber) Some(seatNumber)
} } else {
else {
recursivePassengerInSeat(iter, player) recursivePassengerInSeat(iter, player)
} }
} }
} }
def Utilities : Map[Int, Utility] = utilities def Utilities: Map[Int, Utility] = utilities
/** /**
* Get a reference to a certain `Utility` attached to this `Vehicle`. * Get a reference to a certain `Utility` attached to this `Vehicle`.
* @param utilNumber the attachment number of the `Utility` * @param utilNumber the attachment number of the `Utility`
* @return the `Utility` or `None` (if invalid) * @return the `Utility` or `None` (if invalid)
*/ */
def Utility(utilNumber : Int) : Option[PlanetSideServerObject] = { def Utility(utilNumber: Int): Option[PlanetSideServerObject] = {
if(utilNumber >= 0 && utilNumber < this.utilities.size) { if (utilNumber >= 0 && utilNumber < this.utilities.size) {
this.utilities.get(utilNumber) match { this.utilities.get(utilNumber) match {
case Some(util) => case Some(util) =>
Some(util()) Some(util())
case None => case None =>
None None
} }
} } else {
else {
None None
} }
} }
def Utility(utilType : UtilityType.Value) : Option[PlanetSideServerObject] = { def Utility(utilType: UtilityType.Value): Option[PlanetSideServerObject] = {
utilities.values.find(_.UtilType == utilType) match { utilities.values.find(_.UtilType == utilType) match {
case Some(util) => case Some(util) =>
Some(util()) Some(util())
@ -423,35 +420,37 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
override def UndeployTime = Definition.UndeployTime override def UndeployTime = Definition.UndeployTime
def Inventory : GridInventory = trunk def Inventory: GridInventory = trunk
def VisibleSlots : Set[Int] = weapons.keySet def VisibleSlots: Set[Int] = weapons.keySet
override def Slot(slotNum : Int) : EquipmentSlot = { override def Slot(slotNum: Int): EquipmentSlot = {
weapons.get(slotNum) weapons
// .orElse(utilities.get(slotNum) match { .get(slotNum)
// case Some(_) => // .orElse(utilities.get(slotNum) match {
// //TODO what do now? // case Some(_) =>
// None // //TODO what do now?
// case None => ; // None
// None // case None => ;
// }) // None
.orElse(Some(Inventory.Slot(slotNum))).get // })
.orElse(Some(Inventory.Slot(slotNum)))
.get
} }
override def Find(guid : PlanetSideGUID) : Option[Int] = { override def Find(guid: PlanetSideGUID): Option[Int] = {
weapons.find({ case (_, obj) => weapons.find({
obj.Equipment match { case (_, obj) =>
case Some(item) => obj.Equipment match {
if(item.HasGUID && item.GUID == guid) { case Some(item) =>
true if (item.HasGUID && item.GUID == guid) {
} true
else { } else {
false
}
case None =>
false false
} }
case None =>
false
}
}) match { }) match {
case Some((index, _)) => case Some((index, _)) =>
Some(index) Some(index)
@ -460,7 +459,7 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
} }
} }
override def Collisions(dest : Int, width : Int, height : Int) : Try[List[InventoryItem]] = { override def Collisions(dest: Int, width: Int, height: Int): Try[List[InventoryItem]] = {
weapons.get(dest) match { weapons.get(dest) match {
case Some(slot) => case Some(slot) =>
slot.Equipment match { slot.Equipment match {
@ -478,13 +477,13 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
* A reference to the `Vehicle` `Trunk` space. * A reference to the `Vehicle` `Trunk` space.
* @return this `Vehicle` `Trunk` * @return this `Vehicle` `Trunk`
*/ */
def Trunk : GridInventory = { def Trunk: GridInventory = {
this.trunk this.trunk
} }
def AccessingTrunk : Option[PlanetSideGUID] = trunkAccess def AccessingTrunk: Option[PlanetSideGUID] = trunkAccess
def AccessingTrunk_=(guid : PlanetSideGUID) : Option[PlanetSideGUID] = { def AccessingTrunk_=(guid: PlanetSideGUID): Option[PlanetSideGUID] = {
AccessingTrunk = Some(guid) AccessingTrunk = Some(guid)
} }
@ -494,12 +493,12 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
* @param guid the player who wishes to access the trunk * @param guid the player who wishes to access the trunk
* @return the player who is currently allowed to access the trunk * @return the player who is currently allowed to access the trunk
*/ */
def AccessingTrunk_=(guid : Option[PlanetSideGUID]) : Option[PlanetSideGUID] = { def AccessingTrunk_=(guid: Option[PlanetSideGUID]): Option[PlanetSideGUID] = {
guid match { guid match {
case None => case None =>
trunkAccess = None trunkAccess = None
case Some(player) => case Some(player) =>
if(trunkAccess.isEmpty) { if (trunkAccess.isEmpty) {
trunkAccess = Some(player) trunkAccess = Some(player)
} }
} }
@ -511,8 +510,8 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
* @param player a player attempting to access this `Trunk` * @param player a player attempting to access this `Trunk`
* @return `true`, if the `player` is permitted access; `false`, otherwise * @return `true`, if the `player` is permitted access; `false`, otherwise
*/ */
def CanAccessTrunk(player : Player) : Boolean = { def CanAccessTrunk(player: Player): Boolean = {
if(trunkAccess.isEmpty || trunkAccess.contains(player.GUID)) { if (trunkAccess.isEmpty || trunkAccess.contains(player.GUID)) {
groupPermissions(3) match { groupPermissions(3) match {
case VehicleLockState.Locked => //only the owner case VehicleLockState.Locked => //only the owner
Owner.isEmpty || (Owner.isDefined && player.GUID == Owner.get) Owner.isEmpty || (Owner.isDefined && player.GUID == Owner.get)
@ -521,8 +520,7 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
case VehicleLockState.Empire => //anyone of the owner's faction case VehicleLockState.Empire => //anyone of the owner's faction
faction == player.Faction faction == player.Faction
} }
} } else {
else {
false false
} }
} }
@ -531,18 +529,18 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
* Check access to the `Trunk`. * Check access to the `Trunk`.
* @return the current access value for the `Vehicle` `Trunk` * @return the current access value for the `Vehicle` `Trunk`
*/ */
def TrunkLockState : VehicleLockState.Value = groupPermissions(3) def TrunkLockState: VehicleLockState.Value = groupPermissions(3)
/** /**
* Trunk locations are stored as the orientation zero point being to the East. We need to convert that to a North = 0 orientation before returning the location * Trunk locations are stored as the orientation zero point being to the East. We need to convert that to a North = 0 orientation before returning the location
* @return A Vector3 of the current trunk location, orientated with North as the zero point * @return A Vector3 of the current trunk location, orientated with North as the zero point
*/ */
def TrunkLocation : Vector3 = { def TrunkLocation: Vector3 = {
val rotationRadians = -math.toRadians(Orientation.z - 90f).toFloat val rotationRadians = -math.toRadians(Orientation.z - 90f).toFloat
Vector3.PlanarRotateAroundPoint(Position + Definition.TrunkLocation, Position, rotationRadians) Vector3.PlanarRotateAroundPoint(Position + Definition.TrunkLocation, Position, rotationRadians)
} }
def PrepareGatingManifest() : VehicleManifest = { def PrepareGatingManifest(): VehicleManifest = {
val manifest = VehicleManifest(this) val manifest = VehicleManifest(this)
seats.collect { case (index, seat) if index > 0 => seat.Occupant = None } seats.collect { case (index, seat) if index > 0 => seat.Occupant = None }
vehicleGatingManifest = Some(manifest) vehicleGatingManifest = Some(manifest)
@ -550,14 +548,14 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
manifest manifest
} }
def PublishGatingManifest() : Option[VehicleManifest] = { def PublishGatingManifest(): Option[VehicleManifest] = {
val out = vehicleGatingManifest val out = vehicleGatingManifest
previousVehicleGatingManifest = vehicleGatingManifest previousVehicleGatingManifest = vehicleGatingManifest
vehicleGatingManifest = None vehicleGatingManifest = None
out out
} }
def PreviousGatingManifest() : Option[VehicleManifest] = previousVehicleGatingManifest def PreviousGatingManifest(): Option[VehicleManifest] = previousVehicleGatingManifest
def DamageModel = Definition.asInstanceOf[DamageResistanceModel] def DamageModel = Definition.asInstanceOf[DamageResistanceModel]
@ -565,30 +563,32 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
* This is the definition entry that is used to store and unload pertinent information about the `Vehicle`. * This is the definition entry that is used to store and unload pertinent information about the `Vehicle`.
* @return the vehicle's definition entry * @return the vehicle's definition entry
*/ */
def Definition : VehicleDefinition = vehicleDef def Definition: VehicleDefinition = vehicleDef
def canEqual(other: Any): Boolean = other.isInstanceOf[Vehicle] def canEqual(other: Any): Boolean = other.isInstanceOf[Vehicle]
override def equals(other : Any) : Boolean = other match { override def equals(other: Any): Boolean =
case that: Vehicle => other match {
(that canEqual this) && case that: Vehicle =>
hashCode() == that.hashCode() (that canEqual this) &&
case _ => hashCode() == that.hashCode()
false case _ =>
} false
}
override def hashCode() : Int = Actor.hashCode() override def hashCode(): Int = Actor.hashCode()
/** /**
* Override the string representation to provide additional information. * Override the string representation to provide additional information.
* @return the string output * @return the string output
*/ */
override def toString : String = { override def toString: String = {
Vehicle.toString(this) Vehicle.toString(this)
} }
} }
object Vehicle { object Vehicle {
/** /**
* A basic `Trait` connecting all of the actionable `Vehicle` response messages. * A basic `Trait` connecting all of the actionable `Vehicle` response messages.
*/ */
@ -599,7 +599,7 @@ object Vehicle {
* @param player the player who sent this request message * @param player the player who sent this request message
* @param response the result of the processed request * @param response the result of the processed request
*/ */
final case class VehicleMessages(player : Player, response : Exchange) final case class VehicleMessages(player: Player, response: Exchange)
/** /**
* Initiate vehicle deconstruction. * Initiate vehicle deconstruction.
@ -607,7 +607,7 @@ object Vehicle {
* @param time the delay before deconstruction should initiate; * @param time the delay before deconstruction should initiate;
* should initiate instantly when `None` * should initiate instantly when `None`
*/ */
final case class Deconstruct(time : Option[FiniteDuration] = None) final case class Deconstruct(time: Option[FiniteDuration] = None)
/** /**
* The `Vehicle` will resume previous unresponsiveness to player activity. * The `Vehicle` will resume previous unresponsiveness to player activity.
@ -620,23 +620,23 @@ object Vehicle {
* @see `FacilityBenefitShieldChargeRequestMessage` * @see `FacilityBenefitShieldChargeRequestMessage`
* @param amount the number of points to charge * @param amount the number of points to charge
*/ */
final case class ChargeShields(amount : Int) final case class ChargeShields(amount: Int)
/** /**
* Following a successful shield charge tick, display the results of the update. * Following a successful shield charge tick, display the results of the update.
* @see `FacilityBenefitShieldChargeRequestMessage` * @see `FacilityBenefitShieldChargeRequestMessage`
* @param vehicle the updated vehicle * @param vehicle the updated vehicle
*/ */
final case class UpdateShieldsCharge(vehicle : Vehicle) final case class UpdateShieldsCharge(vehicle: Vehicle)
/** /**
* Change a vehicle's internal ownership property to match that of the target player. * Change a vehicle's internal ownership property to match that of the target player.
* @param player the person who will own the vehicle, or `None` if the vehicle will go unowned * @param player the person who will own the vehicle, or `None` if the vehicle will go unowned
*/ */
final case class Ownership(player : Option[Player]) final case class Ownership(player: Option[Player])
object Ownership { object Ownership {
def apply(player : Player) : Ownership = Ownership(Some(player)) def apply(player: Player): Ownership = Ownership(Some(player))
} }
/** /**
@ -644,7 +644,7 @@ object Vehicle {
* @param vehicleDef the vehicle's definition entry * @param vehicleDef the vehicle's definition entry
* @return a `Vehicle` object * @return a `Vehicle` object
*/ */
def apply(vehicleDef : VehicleDefinition) : Vehicle = { def apply(vehicleDef: VehicleDefinition): Vehicle = {
new Vehicle(vehicleDef) new Vehicle(vehicleDef)
} }
@ -652,8 +652,8 @@ object Vehicle {
* Given a `Map` of `Utility` objects, only return the objects with a positive or zero-index position. * Given a `Map` of `Utility` objects, only return the objects with a positive or zero-index position.
* @return a map of applicable utilities * @return a map of applicable utilities
*/ */
def EquipmentUtilities(utilities : Map[Int, Utility]) : Map[Int, Utility] = { def EquipmentUtilities(utilities: Map[Int, Utility]): Map[Int, Utility] = {
utilities.filter({ case(index : Int, _ : Utility) => index > -1 }) utilities.filter({ case (index: Int, _: Utility) => index > -1 })
} }
/** /**
@ -661,30 +661,35 @@ object Vehicle {
* @param vehicle the `Vehicle` being initialized * @param vehicle the `Vehicle` being initialized
* @see `{object}.LoadDefinition` * @see `{object}.LoadDefinition`
*/ */
def LoadDefinition(vehicle : Vehicle) : Vehicle = { def LoadDefinition(vehicle: Vehicle): Vehicle = {
val vdef : VehicleDefinition = vehicle.Definition val vdef: VehicleDefinition = vehicle.Definition
//general stuff //general stuff
vehicle.Health = vdef.DefaultHealth vehicle.Health = vdef.DefaultHealth
//create weapons //create weapons
vehicle.weapons = vdef.Weapons.map({case (num, definition) => vehicle.weapons = vdef.Weapons
val slot = EquipmentSlot(EquipmentSize.VehicleWeapon) .map({
slot.Equipment = Tool(definition) case (num, definition) =>
num -> slot val slot = EquipmentSlot(EquipmentSize.VehicleWeapon)
}).toMap slot.Equipment = Tool(definition)
num -> slot
})
.toMap
//create seats //create seats
vehicle.seats = vdef.Seats.map({ case(num, definition) => num -> Seat(definition)}).toMap vehicle.seats = vdef.Seats.map({ case (num, definition) => num -> Seat(definition) }).toMap
// create cargo holds // create cargo holds
vehicle.cargoHolds = vdef.Cargo.map({ case(num, definition) => num -> Cargo(definition)}).toMap vehicle.cargoHolds = vdef.Cargo.map({ case (num, definition) => num -> Cargo(definition) }).toMap
//create utilities //create utilities
vehicle.utilities = vdef.Utilities.map({ vehicle.utilities = vdef.Utilities
case(num, util) => .map({
val obj = Utility(util, vehicle) case (num, util) =>
val utilObj = obj() val obj = Utility(util, vehicle)
vehicle.Amenities = utilObj val utilObj = obj()
utilObj.LocationOffset = vdef.UtilityOffset.get(num) vehicle.Amenities = utilObj
num -> obj utilObj.LocationOffset = vdef.UtilityOffset.get(num)
}).toMap num -> obj
})
.toMap
//trunk //trunk
vdef.TrunkSize match { vdef.TrunkSize match {
case InventoryTile.None => ; case InventoryTile.None => ;
@ -699,7 +704,7 @@ object Vehicle {
* Provide a fixed string representation. * Provide a fixed string representation.
* @return the string output * @return the string output
*/ */
def toString(obj : Vehicle) : String = { def toString(obj: Vehicle): String = {
val occupancy = obj.Seats.values.count(seat => seat.isOccupied) val occupancy = obj.Seats.values.count(seat => seat.isOccupied)
s"${obj.Definition.Name}, owned by ${obj.Owner}: (${obj.Health}/${obj.MaxHealth})(${obj.Shields}/${obj.MaxShields}) ($occupancy)" s"${obj.Definition.Name}, owned by ${obj.Owner}: (${obj.Health}/${obj.MaxHealth})(${obj.Shields}/${obj.MaxShields}) ($occupancy)"
} }

View file

@ -20,7 +20,7 @@ object Vehicles {
* @param player na * @param player na
* @return na * @return na
*/ */
def Own(vehicle : Vehicle, player : Player) : Option[Vehicle] = Own(vehicle, Some(player)) def Own(vehicle: Vehicle, player: Player): Option[Vehicle] = Own(vehicle, Some(player))
/** /**
* na * na
@ -28,12 +28,15 @@ object Vehicles {
* @param playerOpt na * @param playerOpt na
* @return na * @return na
*/ */
def Own(vehicle : Vehicle, playerOpt : Option[Player]) : Option[Vehicle] = { def Own(vehicle: Vehicle, playerOpt: Option[Player]): Option[Vehicle] = {
playerOpt match { playerOpt match {
case Some(tplayer) => case Some(tplayer) =>
tplayer.VehicleOwned = vehicle.GUID tplayer.VehicleOwned = vehicle.GUID
vehicle.AssignOwnership(playerOpt) vehicle.AssignOwnership(playerOpt)
vehicle.Zone.VehicleEvents ! VehicleServiceMessage(vehicle.Zone.Id, VehicleAction.Ownership(tplayer.GUID, vehicle.GUID)) vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
vehicle.Zone.Id,
VehicleAction.Ownership(tplayer.GUID, vehicle.GUID)
)
Vehicles.ReloadAccessPermissions(vehicle, tplayer.Name) Vehicles.ReloadAccessPermissions(vehicle, tplayer.Name)
Some(vehicle) Some(vehicle)
case None => case None =>
@ -48,26 +51,31 @@ object Vehicles {
* @return the vehicle, if it had a previous owner; * @return the vehicle, if it had a previous owner;
* `None`, otherwise * `None`, otherwise
*/ */
def Disown(guid : PlanetSideGUID, vehicle : Vehicle) : Option[Vehicle] = vehicle.Zone.GUID(vehicle.Owner) match { def Disown(guid: PlanetSideGUID, vehicle: Vehicle): Option[Vehicle] =
case Some(player : Player) => vehicle.Zone.GUID(vehicle.Owner) match {
if(player.VehicleOwned.contains(guid)) { case Some(player: Player) =>
player.VehicleOwned = None if (player.VehicleOwned.contains(guid)) {
vehicle.Zone.VehicleEvents ! VehicleServiceMessage(player.Name, VehicleAction.Ownership(player.GUID, PlanetSideGUID(0))) player.VehicleOwned = None
} vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
vehicle.AssignOwnership(None) player.Name,
val empire = VehicleLockState.Empire.id VehicleAction.Ownership(player.GUID, PlanetSideGUID(0))
val factionChannel = s"${vehicle.Faction}" )
(0 to 2).foreach(group => { }
vehicle.PermissionGroup(group, empire) vehicle.AssignOwnership(None)
vehicle.Zone.VehicleEvents ! VehicleServiceMessage(factionChannel, val empire = VehicleLockState.Empire.id
VehicleAction.SeatPermissions(Service.defaultPlayerGUID, guid, group, empire) val factionChannel = s"${vehicle.Faction}"
) (0 to 2).foreach(group => {
}) vehicle.PermissionGroup(group, empire)
ReloadAccessPermissions(vehicle, player.Name) vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
Some(vehicle) factionChannel,
case _ => VehicleAction.SeatPermissions(Service.defaultPlayerGUID, guid, group, empire)
None )
} })
ReloadAccessPermissions(vehicle, player.Name)
Some(vehicle)
case _ =>
None
}
/** /**
* Disassociate a player from a vehicle that he owns. * Disassociate a player from a vehicle that he owns.
@ -76,7 +84,8 @@ object Vehicles {
* This is the player side of vehicle ownership removal. * This is the player side of vehicle ownership removal.
* @param player the player * @param player the player
*/ */
def Disown(player : Player, zone : Zone) : Option[Vehicle] = Disown(player, Some(zone)) def Disown(player: Player, zone: Zone): Option[Vehicle] = Disown(player, Some(zone))
/** /**
* Disassociate a player from a vehicle that he owns. * Disassociate a player from a vehicle that he owns.
* The vehicle must exist in the game world on the specified continent. * The vehicle must exist in the game world on the specified continent.
@ -84,12 +93,12 @@ object Vehicles {
* This is the player side of vehicle ownership removal. * This is the player side of vehicle ownership removal.
* @param player the player * @param player the player
*/ */
def Disown(player : Player, zoneOpt : Option[Zone]) : Option[Vehicle] = { def Disown(player: Player, zoneOpt: Option[Zone]): Option[Vehicle] = {
player.VehicleOwned match { player.VehicleOwned match {
case Some(vehicle_guid) => case Some(vehicle_guid) =>
player.VehicleOwned = None player.VehicleOwned = None
zoneOpt.getOrElse(player.Zone).GUID(vehicle_guid) match { zoneOpt.getOrElse(player.Zone).GUID(vehicle_guid) match {
case Some(vehicle : Vehicle) => case Some(vehicle: Vehicle) =>
Disown(player, vehicle) Disown(player, vehicle)
case _ => case _ =>
None None
@ -106,21 +115,23 @@ object Vehicles {
* This is the vehicle side of vehicle ownership removal. * This is the vehicle side of vehicle ownership removal.
* @param player the player * @param player the player
*/ */
def Disown(player : Player, vehicle : Vehicle) : Option[Vehicle] = { def Disown(player: Player, vehicle: Vehicle): Option[Vehicle] = {
val pguid = player.GUID val pguid = player.GUID
if(vehicle.Owner.contains(pguid)) { if (vehicle.Owner.contains(pguid)) {
vehicle.AssignOwnership(None) vehicle.AssignOwnership(None)
vehicle.Zone.VehicleEvents ! VehicleServiceMessage(player.Name, VehicleAction.Ownership(pguid, PlanetSideGUID(0))) vehicle.Zone.VehicleEvents ! VehicleServiceMessage(player.Name, VehicleAction.Ownership(pguid, PlanetSideGUID(0)))
val vguid = vehicle.GUID val vguid = vehicle.GUID
val empire = VehicleLockState.Empire.id val empire = VehicleLockState.Empire.id
(0 to 2).foreach(group => { (0 to 2).foreach(group => {
vehicle.PermissionGroup(group, empire) vehicle.PermissionGroup(group, empire)
vehicle.Zone.VehicleEvents ! VehicleServiceMessage(s"${vehicle.Faction}", VehicleAction.SeatPermissions(pguid, vguid, group, empire)) vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
s"${vehicle.Faction}",
VehicleAction.SeatPermissions(pguid, vguid, group, empire)
)
}) })
ReloadAccessPermissions(vehicle, player.Name) ReloadAccessPermissions(vehicle, player.Name)
Some(vehicle) Some(vehicle)
} } else {
else {
None None
} }
} }
@ -134,7 +145,7 @@ object Vehicles {
* The most important examples include either the player or the vehicle itself spawning in for the first time. * The most important examples include either the player or the vehicle itself spawning in for the first time.
* @param vehicle the `Vehicle` * @param vehicle the `Vehicle`
*/ */
def ReloadAccessPermissions(vehicle : Vehicle, toChannel : String) : Unit = { def ReloadAccessPermissions(vehicle: Vehicle, toChannel: String): Unit = {
val vehicle_guid = vehicle.GUID val vehicle_guid = vehicle.GUID
(0 to 3).foreach(group => { (0 to 3).foreach(group => {
vehicle.Zone.AvatarEvents ! AvatarServiceMessage( vehicle.Zone.AvatarEvents ! AvatarServiceMessage(
@ -170,16 +181,16 @@ object Vehicles {
* @return `true`, if all passengers of the vehicle, and its cargo vehicles, etc., have reported being in the same zone; * @return `true`, if all passengers of the vehicle, and its cargo vehicles, etc., have reported being in the same zone;
* `false`, if no manifest entry exists, or if the vehicle is moving to the same zone * `false`, if no manifest entry exists, or if the vehicle is moving to the same zone
*/ */
def AllGatedOccupantsInSameZone(vehicle : Vehicle) : Boolean = { def AllGatedOccupantsInSameZone(vehicle: Vehicle): Boolean = {
val vzone = vehicle.Zone val vzone = vehicle.Zone
vehicle.PreviousGatingManifest() match { vehicle.PreviousGatingManifest() match {
case Some(manifest) if vzone != manifest.origin => case Some(manifest) if vzone != manifest.origin =>
val manifestPassengers = manifest.passengers.collect { case (name, _) => name } :+ manifest.driverName val manifestPassengers = manifest.passengers.collect { case (name, _) => name } :+ manifest.driverName
val manifestPassengerResults = manifestPassengers.map { name => vzone.Players.exists(_.name.equals(name)) } val manifestPassengerResults = manifestPassengers.map { name => vzone.Players.exists(_.name.equals(name)) }
manifestPassengerResults.forall(_ == true) && manifestPassengerResults.forall(_ == true) &&
vehicle.CargoHolds.values vehicle.CargoHolds.values
.collect { case hold if hold.isOccupied => AllGatedOccupantsInSameZone(hold.Occupant.get) } .collect { case hold if hold.isOccupied => AllGatedOccupantsInSameZone(hold.Occupant.get) }
.forall(_ == true) .forall(_ == true)
case _ => case _ =>
false false
} }
@ -192,11 +203,10 @@ object Vehicles {
* @return the orientation as an `Integer` value; * @return the orientation as an `Integer` value;
* `0` for almost all cases * `0` for almost all cases
*/ */
def CargoOrientation(vehicle : Vehicle) : Int = { def CargoOrientation(vehicle: Vehicle): Int = {
if(vehicle.Definition == GlobalDefinitions.router) { if (vehicle.Definition == GlobalDefinitions.router) {
1 1
} } else {
else {
0 0
} }
} }
@ -208,17 +218,22 @@ object Vehicles {
* @param hacker the one whoi performed the hack and will inherit ownership of the target vehicle * @param hacker the one whoi performed the hack and will inherit ownership of the target vehicle
* @param unk na; used by `HackMessage` as `unk5` * @param unk na; used by `HackMessage` as `unk5`
*/ */
def FinishHackingVehicle(target : Vehicle, hacker : Player, unk : Long)(): Unit = { def FinishHackingVehicle(target: Vehicle, hacker: Player, unk: Long)(): Unit = {
log.info(s"Vehicle guid: ${target.GUID} has been jacked") log.info(s"Vehicle guid: ${target.GUID} has been jacked")
import scala.concurrent.duration._
val zone = target.Zone val zone = target.Zone
// Forcefully dismount any cargo // Forcefully dismount any cargo
target.CargoHolds.values.foreach(cargoHold => { target.CargoHolds.values.foreach(cargoHold => {
cargoHold.Occupant match { cargoHold.Occupant match {
case Some(cargo : Vehicle) => { case Some(cargo: Vehicle) => {
cargo.Seats(0).Occupant match { cargo.Seats(0).Occupant match {
case Some(cargoDriver: Player) => case Some(cargoDriver: Player) =>
CargoBehavior.HandleVehicleCargoDismount(target.Zone, cargo.GUID, bailed = target.Flying, requestedByPassenger = false, kicked = true ) CargoBehavior.HandleVehicleCargoDismount(
target.Zone,
cargo.GUID,
bailed = target.Flying,
requestedByPassenger = false,
kicked = true
)
case None => case None =>
log.error("FinishHackingVehicle: vehicle in cargo hold missing driver") log.error("FinishHackingVehicle: vehicle in cargo hold missing driver")
CargoBehavior.HandleVehicleCargoDismount(cargo.GUID, cargo, target.GUID, target, false, false, true) CargoBehavior.HandleVehicleCargoDismount(cargo.GUID, cargo, target.GUID, target, false, false, true)
@ -233,20 +248,23 @@ object Vehicles {
case Some(tplayer) => case Some(tplayer) =>
seat.Occupant = None seat.Occupant = None
tplayer.VehicleSeated = None tplayer.VehicleSeated = None
if(tplayer.HasGUID) { if (tplayer.HasGUID) {
zone.VehicleEvents ! VehicleServiceMessage(zone.Id, VehicleAction.KickPassenger(tplayer.GUID, 4, unk2 = false, target.GUID)) zone.VehicleEvents ! VehicleServiceMessage(
zone.Id,
VehicleAction.KickPassenger(tplayer.GUID, 4, unk2 = false, target.GUID)
)
} }
case None => ; case None => ;
} }
}) })
// If the vehicle can fly and is flying deconstruct it, and well played to whomever managed to hack a plane in mid air. I'm impressed. // If the vehicle can fly and is flying deconstruct it, and well played to whomever managed to hack a plane in mid air. I'm impressed.
if(target.Definition.CanFly && target.Flying) { if (target.Definition.CanFly && target.Flying) {
// todo: Should this force the vehicle to land in the same way as when a pilot bails with passengers on board? // todo: Should this force the vehicle to land in the same way as when a pilot bails with passengers on board?
target.Actor ! Vehicle.Deconstruct() target.Actor ! Vehicle.Deconstruct()
} else { // Otherwise handle ownership transfer as normal } else { // Otherwise handle ownership transfer as normal
// Remove ownership of our current vehicle, if we have one // Remove ownership of our current vehicle, if we have one
hacker.VehicleOwned match { hacker.VehicleOwned match {
case Some(guid : PlanetSideGUID) => case Some(guid: PlanetSideGUID) =>
zone.GUID(guid) match { zone.GUID(guid) match {
case Some(vehicle: Vehicle) => case Some(vehicle: Vehicle) =>
Vehicles.Disown(hacker, vehicle) Vehicles.Disown(hacker, vehicle)
@ -270,9 +288,15 @@ object Vehicles {
Vehicles.Own(target, hacker) Vehicles.Own(target, hacker)
//todo: Send HackMessage -> HackCleared to vehicle? can be found in packet captures. Not sure if necessary. //todo: Send HackMessage -> HackCleared to vehicle? can be found in packet captures. Not sure if necessary.
// And broadcast the faction change to other clients // And broadcast the faction change to other clients
zone.AvatarEvents ! AvatarServiceMessage(zone.Id, AvatarAction.SetEmpire(Service.defaultPlayerGUID, target.GUID, hacker.Faction)) zone.AvatarEvents ! AvatarServiceMessage(
zone.Id,
AvatarAction.SetEmpire(Service.defaultPlayerGUID, target.GUID, hacker.Faction)
)
} }
zone.LocalEvents ! LocalServiceMessage(zone.Id, LocalAction.TriggerSound(hacker.GUID, TriggeredSound.HackVehicle, target.Position, 30, 0.49803925f)) zone.LocalEvents ! LocalServiceMessage(
zone.Id,
LocalAction.TriggerSound(hacker.GUID, TriggeredSound.HackVehicle, target.Position, 30, 0.49803925f)
)
// Clean up after specific vehicles, e.g. remove router telepads // Clean up after specific vehicles, e.g. remove router telepads
// If AMS is deployed, swap it to the new faction // If AMS is deployed, swap it to the new faction
target.Definition match { target.Definition match {

View file

@ -6,14 +6,14 @@ package net.psforever.objects.avatar
* #121 is the most important. * #121 is the most important.
*/ */
object Avatars extends Enumeration { object Avatars extends Enumeration {
final val avatar = Value(121) final val avatar = Value(121)
final val avatar_bot = Value(122) final val avatar_bot = Value(122)
final val avatar_bot_agile = Value(123) final val avatar_bot_agile = Value(123)
final val avatar_bot_agile_no_weapon = Value(124) final val avatar_bot_agile_no_weapon = Value(124)
final val avatar_bot_max = Value(125) final val avatar_bot_max = Value(125)
final val avatar_bot_max_no_weapon = Value(126) final val avatar_bot_max_no_weapon = Value(126)
final val avatar_bot_reinforced = Value(127) final val avatar_bot_reinforced = Value(127)
final val avatar_bot_reinforced_no_weapon = Value(128) final val avatar_bot_reinforced_no_weapon = Value(128)
final val avatar_bot_standard = Value(129) final val avatar_bot_standard = Value(129)
final val avatar_bot_standard_no_weapon = Value(130) final val avatar_bot_standard_no_weapon = Value(130)
} }

View file

@ -7,13 +7,14 @@ import scala.collection.mutable
object Certification { object Certification {
object Dependencies { object Dependencies {
/** /**
* Find the certifications that are immediately dependent on the target certification. * Find the certifications that are immediately dependent on the target certification.
* (For `A`, find all `B` that are `B ⇒ A`.) * (For `A`, find all `B` that are `B ⇒ A`.)
* @param certification the target certification * @param certification the target certification
* @return all connected certifications * @return all connected certifications
*/ */
def From(certification : CertificationType.Value) : Set[CertificationType.Value] = dependencies(certification).toSet def From(certification: CertificationType.Value): Set[CertificationType.Value] = dependencies(certification).toSet
/** /**
* Find all certifications that are dependent on the target certification. * Find all certifications that are dependent on the target certification.
@ -21,14 +22,13 @@ object Certification {
* @param certification the target certification * @param certification the target certification
* @return all connected certifications * @return all connected certifications
*/ */
def FromAll(certification : CertificationType.Value) : Set[CertificationType.Value] = { def FromAll(certification: CertificationType.Value): Set[CertificationType.Value] = {
var available : List[CertificationType.Value] = List(certification) var available: List[CertificationType.Value] = List(certification)
var allocated : mutable.ListBuffer[CertificationType.Value] = mutable.ListBuffer.empty[CertificationType.Value] var allocated: mutable.ListBuffer[CertificationType.Value] = mutable.ListBuffer.empty[CertificationType.Value]
do { do {
available = available.flatMap(cert => dependencies(cert)) available = available.flatMap(cert => dependencies(cert))
allocated ++= available allocated ++= available
} } while (available.nonEmpty)
while(available.nonEmpty)
allocated.toSet allocated.toSet
} }
@ -38,7 +38,7 @@ object Certification {
* @param certification the target certification * @param certification the target certification
* @return all connected certifications * @return all connected certifications
*/ */
def For(certification : CertificationType.Value) : Set[CertificationType.Value] = { def For(certification: CertificationType.Value): Set[CertificationType.Value] = {
(for { (for {
(cert, certs) <- dependencies (cert, certs) <- dependencies
if certs contains certification if certs contains certification
@ -51,16 +51,15 @@ object Certification {
* @param certification the target certification * @param certification the target certification
* @return all connected certifications * @return all connected certifications
*/ */
def ForAll(certification : CertificationType.Value) : Set[CertificationType.Value] = { def ForAll(certification: CertificationType.Value): Set[CertificationType.Value] = {
var available : List[CertificationType.Value] = List(certification) var available: List[CertificationType.Value] = List(certification)
var allocated : mutable.ListBuffer[CertificationType.Value] = mutable.ListBuffer.empty[CertificationType.Value] var allocated: mutable.ListBuffer[CertificationType.Value] = mutable.ListBuffer.empty[CertificationType.Value]
do { do {
available = available.flatMap { available = available.flatMap {
For For
} }
allocated ++= available allocated ++= available
} } while (available.nonEmpty)
while(available.nonEmpty)
allocated.toSet allocated.toSet
} }
@ -72,83 +71,80 @@ object Certification {
* @param certification the target certification * @param certification the target certification
* @return all connected certifications * @return all connected certifications
*/ */
def Like(certification : CertificationType.Value) : Set[CertificationType.Value] = certification match { def Like(certification: CertificationType.Value): Set[CertificationType.Value] =
case AssaultBuggy => certification match {
Set(Harasser) case AssaultBuggy =>
case LightScout => Set(Harasser)
Set(AirCavalryScout, AssaultBuggy, Harasser) case LightScout =>
case UniMAX => Set(AirCavalryScout, AssaultBuggy, Harasser)
Set(AAMAX, AIMAX, AVMAX) case UniMAX =>
case AdvancedEngineering => Set(AAMAX, AIMAX, AVMAX)
Set(AssaultEngineering, FortificationEngineering) case AdvancedEngineering =>
case ElectronicsExpert => Set(AssaultEngineering, FortificationEngineering)
Set(DataCorruption, ExpertHacking) case ElectronicsExpert =>
case _ => Set(DataCorruption, ExpertHacking)
Set.empty[CertificationType.Value] case _ =>
} Set.empty[CertificationType.Value]
}
private val dependencies : Map[CertificationType.Value, List[CertificationType.Value]] = Map( private val dependencies: Map[CertificationType.Value, List[CertificationType.Value]] = Map(
StandardAssault -> List(), StandardAssault -> List(),
AgileExoSuit -> List(), AgileExoSuit -> List(),
ReinforcedExoSuit -> List(), ReinforcedExoSuit -> List(),
InfiltrationSuit -> List(Phantasm), InfiltrationSuit -> List(Phantasm),
AIMAX -> List(), AIMAX -> List(),
AVMAX -> List(), AVMAX -> List(),
AAMAX -> List(), AAMAX -> List(),
UniMAX -> List(), UniMAX -> List(),
StandardAssault -> List(),
StandardAssault -> List(), MediumAssault -> List(AntiVehicular, HeavyAssault, Sniping, SpecialAssault),
MediumAssault -> List(AntiVehicular, HeavyAssault, Sniping, SpecialAssault), AntiVehicular -> List(),
AntiVehicular -> List(), HeavyAssault -> List(),
HeavyAssault -> List(), Sniping -> List(),
Sniping -> List(), SpecialAssault -> List(EliteAssault),
SpecialAssault -> List(EliteAssault), EliteAssault -> List(),
EliteAssault -> List(), ATV -> List(Switchblade),
Switchblade -> List(),
ATV -> List(Switchblade), Harasser -> List(),
Switchblade -> List(), AssaultBuggy -> List(),
Harasser -> List(), LightScout -> List(AirCavalryAssault),
AssaultBuggy -> List(), GroundSupport -> List(),
LightScout -> List(AirCavalryAssault), GroundTransport -> List(),
GroundSupport -> List(), ArmoredAssault1 -> List(ArmoredAssault2),
GroundTransport -> List(), ArmoredAssault2 -> List(BattleFrameRobotics, Flail),
ArmoredAssault1 -> List(ArmoredAssault2), Flail -> List(),
ArmoredAssault2 -> List(BattleFrameRobotics, Flail), AirCavalryScout -> List(AirCavalryAssault),
Flail -> List(), AirCavalryAssault -> List(AirCavalryInterceptor),
AirCavalryInterceptor -> List(),
AirCavalryScout -> List(AirCavalryAssault), AirSupport -> List(GalaxyGunship),
AirCavalryAssault -> List(AirCavalryInterceptor), GalaxyGunship -> List(),
AirCavalryInterceptor -> List(), Phantasm -> List(),
AirSupport -> List(GalaxyGunship), BattleFrameRobotics -> List(BFRAntiInfantry, BFRAntiAircraft),
GalaxyGunship -> List(), BFRAntiInfantry -> List(),
Phantasm -> List(), BFRAntiAircraft -> List(),
Medical -> List(AdvancedMedical),
BattleFrameRobotics -> List(BFRAntiInfantry, BFRAntiAircraft), AdvancedMedical -> List(),
BFRAntiInfantry -> List(), Engineering -> List(CombatEngineering),
BFRAntiAircraft -> List(), CombatEngineering -> List(AdvancedEngineering, AssaultEngineering, FortificationEngineering),
AdvancedEngineering -> List(),
Medical -> List(AdvancedMedical), AssaultEngineering -> List(),
AdvancedMedical -> List(),
Engineering -> List(CombatEngineering),
CombatEngineering -> List(AdvancedEngineering, AssaultEngineering, FortificationEngineering),
AdvancedEngineering -> List(),
AssaultEngineering -> List(),
FortificationEngineering -> List(), FortificationEngineering -> List(),
Hacking -> List(AdvancedHacking), Hacking -> List(AdvancedHacking),
AdvancedHacking -> List(DataCorruption, ElectronicsExpert, ExpertHacking), AdvancedHacking -> List(DataCorruption, ElectronicsExpert, ExpertHacking),
DataCorruption -> List(), DataCorruption -> List(),
ElectronicsExpert -> List(), ElectronicsExpert -> List(),
ExpertHacking -> List() ExpertHacking -> List()
) )
} }
object Cost { object Cost {
/** /**
* For a certification, get its point cost. * For a certification, get its point cost.
* @param certification the certification * @param certification the certification
* @return the cost * @return the cost
*/ */
def Of(certification : CertificationType.Value) : Int = points(certification) def Of(certification: CertificationType.Value): Int = points(certification)
/** /**
* For a list of certifications, find the point cost of all unique certifications. * For a list of certifications, find the point cost of all unique certifications.
@ -156,7 +152,7 @@ object Certification {
* @param certifications the certification list * @param certifications the certification list
* @return the total cost * @return the total cost
*/ */
def Of(certifications : List[CertificationType.Value]) : Int = Of(certifications.toSet) def Of(certifications: List[CertificationType.Value]): Int = Of(certifications.toSet)
/** /**
* For a set of certifications, find the point cost of all certifications. * For a set of certifications, find the point cost of all certifications.
@ -164,70 +160,65 @@ object Certification {
* @param certifications the certification list * @param certifications the certification list
* @return the total cost * @return the total cost
*/ */
def Of(certifications : Set[CertificationType.Value]) : Int = OfAll(certifications.toList) def Of(certifications: Set[CertificationType.Value]): Int = OfAll(certifications.toList)
/** /**
* For a list of certifications, find the point cost of all certifications, counting any duplicates. * For a list of certifications, find the point cost of all certifications, counting any duplicates.
* @param certifications the certification list * @param certifications the certification list
* @return the total cost * @return the total cost
*/ */
def OfAll(certifications : List[CertificationType.Value]) : Int = { def OfAll(certifications: List[CertificationType.Value]): Int = {
certifications map points sum certifications map points sum
} }
import CertificationType._ import CertificationType._
private val points : Map[CertificationType.Value, Int] = Map( private val points: Map[CertificationType.Value, Int] = Map(
StandardExoSuit -> 0, StandardExoSuit -> 0,
AgileExoSuit -> 0, AgileExoSuit -> 0,
ReinforcedExoSuit -> 3, ReinforcedExoSuit -> 3,
InfiltrationSuit -> 2, InfiltrationSuit -> 2,
AAMAX -> 2, AAMAX -> 2,
AIMAX -> 3, AIMAX -> 3,
AVMAX -> 3, AVMAX -> 3,
UniMAX -> 6, UniMAX -> 6,
StandardAssault -> 0,
StandardAssault -> 0, MediumAssault -> 2,
MediumAssault -> 2, AntiVehicular -> 3,
AntiVehicular -> 3, HeavyAssault -> 4,
HeavyAssault -> 4, Sniping -> 3,
Sniping -> 3, SpecialAssault -> 3,
SpecialAssault -> 3, EliteAssault -> 1,
EliteAssault -> 1, ATV -> 1,
Switchblade -> 1,
ATV -> 1, Harasser -> 1,
Switchblade -> 1, AssaultBuggy -> 3,
Harasser -> 1, LightScout -> 5,
AssaultBuggy -> 3, GroundSupport -> 2,
LightScout -> 5, GroundTransport -> 2,
GroundSupport -> 2, ArmoredAssault1 -> 2,
GroundTransport -> 2, ArmoredAssault2 -> 3,
ArmoredAssault1 -> 2, Flail -> 1,
ArmoredAssault2 -> 3, AirCavalryScout -> 3,
Flail -> 1, AirCavalryAssault -> 2,
AirCavalryInterceptor -> 2,
AirCavalryScout -> 3, AirSupport -> 3,
AirCavalryAssault -> 2, GalaxyGunship -> 2,
AirCavalryInterceptor -> 2, Phantasm -> 3,
AirSupport -> 3, BattleFrameRobotics -> 4,
GalaxyGunship -> 2, BFRAntiInfantry -> 1,
Phantasm -> 3, BFRAntiAircraft -> 1,
Medical -> 3,
BattleFrameRobotics -> 4, AdvancedMedical -> 2,
BFRAntiInfantry -> 1, Engineering -> 3,
BFRAntiAircraft -> 1, CombatEngineering -> 2,
AdvancedEngineering -> 5,
Medical -> 3, AssaultEngineering -> 3,
AdvancedMedical -> 2,
Engineering -> 3,
CombatEngineering -> 2,
AdvancedEngineering -> 5,
AssaultEngineering -> 3,
FortificationEngineering -> 3, FortificationEngineering -> 3,
Hacking -> 3, Hacking -> 3,
AdvancedHacking -> 2, AdvancedHacking -> 2,
DataCorruption -> 3, DataCorruption -> 3,
ElectronicsExpert -> 4, ElectronicsExpert -> 4,
ExpertHacking -> 2 ExpertHacking -> 2
) )
} }
} }

View file

@ -11,15 +11,14 @@ import net.psforever.types.{PlanetSideEmpire, Vector3}
import services.Service import services.Service
import services.avatar.{AvatarAction, AvatarServiceMessage} import services.avatar.{AvatarAction, AvatarServiceMessage}
class CorpseControl(player : Player) extends Actor class CorpseControl(player: Player) extends Actor with ContainableBehavior {
with ContainableBehavior {
def ContainerObject = player def ContainerObject = player
//private [this] val log = org.log4s.getLogger(player.Name) //private [this] val log = org.log4s.getLogger(player.Name)
def receive : Receive = containerBehavior.orElse { case _ => ; } def receive: Receive = containerBehavior.orElse { case _ => ; }
def MessageDeferredCallback(msg : Any) : Unit = { def MessageDeferredCallback(msg: Any): Unit = {
msg match { msg match {
case Containable.MoveItem(_, item, _) => case Containable.MoveItem(_, item, _) =>
//momentarily put item back where it was originally //momentarily put item back where it was originally
@ -36,18 +35,18 @@ class CorpseControl(player : Player) extends Actor
} }
} }
def RemoveItemFromSlotCallback(item : Equipment, slot : Int) : Unit = { def RemoveItemFromSlotCallback(item: Equipment, slot: Int): Unit = {
val obj = ContainerObject val obj = ContainerObject
val zone = obj.Zone val zone = obj.Zone
val events = zone.AvatarEvents val events = zone.AvatarEvents
item.Faction = PlanetSideEmpire.NEUTRAL item.Faction = PlanetSideEmpire.NEUTRAL
events ! AvatarServiceMessage(zone.Id, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, item.GUID)) events ! AvatarServiceMessage(zone.Id, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, item.GUID))
} }
def PutItemInSlotCallback(item : Equipment, slot : Int) : Unit = { def PutItemInSlotCallback(item: Equipment, slot: Int): Unit = {
val obj = ContainerObject val obj = ContainerObject
val zone = obj.Zone val zone = obj.Zone
val events = zone.AvatarEvents val events = zone.AvatarEvents
val definition = item.Definition val definition = item.Definition
events ! AvatarServiceMessage( events ! AvatarServiceMessage(
zone.Id, zone.Id,
@ -63,10 +62,11 @@ class CorpseControl(player : Player) extends Actor
) )
} }
def SwapItemCallback(item : Equipment) : Unit = { def SwapItemCallback(item: Equipment): Unit = {
val obj = ContainerObject val obj = ContainerObject
val zone = obj.Zone val zone = obj.Zone
zone.AvatarEvents ! AvatarServiceMessage(zone.Id, zone.AvatarEvents ! AvatarServiceMessage(
zone.Id,
AvatarAction.SendResponse( AvatarAction.SendResponse(
Service.defaultPlayerGUID, Service.defaultPlayerGUID,
ObjectDetachMessage(obj.GUID, item.GUID, Vector3.Zero, 0f) ObjectDetachMessage(obj.GUID, item.GUID, Vector3.Zero, 0f)

View file

@ -23,29 +23,36 @@ import scala.collection.mutable
* these structures are updated to reflect proper count. * these structures are updated to reflect proper count.
*/ */
class DeployableToolbox { class DeployableToolbox {
/** /**
* a map of bins for keeping track of the quantities of deployables in a category * a map of bins for keeping track of the quantities of deployables in a category
* keys: categories, values: quantity storage object * keys: categories, values: quantity storage object
*/ */
private val categoryCounts = DeployableCategory.values.toSeq.map(value => { value -> new DeployableToolbox.Bin }).toMap private val categoryCounts =
DeployableCategory.values.toSeq.map(value => { value -> new DeployableToolbox.Bin }).toMap
categoryCounts(DeployableCategory.Telepads).Max = 1024 categoryCounts(DeployableCategory.Telepads).Max = 1024
/** /**
* a map of bins for keeping track of the quantities of individual deployables * a map of bins for keeping track of the quantities of individual deployables
* keys: deployable types, values: quantity storage object * keys: deployable types, values: quantity storage object
*/ */
private val deployableCounts = DeployedItem.values.toSeq.map(value => { value -> new DeployableToolbox.Bin }).toMap private val deployableCounts = DeployedItem.values.toSeq.map(value => { value -> new DeployableToolbox.Bin }).toMap
deployableCounts(DeployedItem.router_telepad_deployable).Max = 1024 deployableCounts(DeployedItem.router_telepad_deployable).Max = 1024
/** /**
* a map of tracked/owned individual deployables * a map of tracked/owned individual deployables
* keys: categories, values: deployable objects * keys: categories, values: deployable objects
*/ */
private val deployableLists = private val deployableLists =
DeployableCategory.values.toSeq.map(value => { value -> mutable.ListBuffer[DeployableToolbox.AcceptableDeployable]() }).toMap DeployableCategory.values.toSeq
.map(value => { value -> mutable.ListBuffer[DeployableToolbox.AcceptableDeployable]() })
.toMap
/** /**
* can only be initialized once * can only be initialized once
* set during the `Initialization` method primarily, and in `Add` and in `Remove` if not * set during the `Initialization` method primarily, and in `Add` and in `Remove` if not
*/ */
private var initialized : Boolean = false private var initialized: Boolean = false
/** /**
* Set up the initial deployable counts by providing certification values to be used in category and unit selection. * Set up the initial deployable counts by providing certification values to be used in category and unit selection.
@ -53,13 +60,12 @@ class DeployableToolbox {
* @return `true`, if this is the first time and actual "initialization" is performed; * @return `true`, if this is the first time and actual "initialization" is performed;
* `false`, otherwise * `false`, otherwise
*/ */
def Initialize(certifications : Set[CertificationType.Value]) : Boolean = { def Initialize(certifications: Set[CertificationType.Value]): Boolean = {
if(!initialized) { if (!initialized) {
DeployableToolbox.Initialize(deployableCounts, categoryCounts, certifications) DeployableToolbox.Initialize(deployableCounts, categoryCounts, certifications)
initialized = true initialized = true
true true
} } else {
else {
false false
} }
} }
@ -72,7 +78,10 @@ class DeployableToolbox {
* occasionally, important former certification values are required for additional configuration; * occasionally, important former certification values are required for additional configuration;
* the new certification should already have been added to this group * the new certification should already have been added to this group
*/ */
def AddToDeployableQuantities(certification : CertificationType.Value, certificationSet : Set[CertificationType.Value]) : Unit = { def AddToDeployableQuantities(
certification: CertificationType.Value,
certificationSet: Set[CertificationType.Value]
): Unit = {
initialized = true initialized = true
DeployableToolbox.AddToDeployableQuantities(deployableCounts, categoryCounts, certification, certificationSet) DeployableToolbox.AddToDeployableQuantities(deployableCounts, categoryCounts, certification, certificationSet)
} }
@ -86,7 +95,10 @@ class DeployableToolbox {
* occasionally, important former certification values are required for additional configuration; * occasionally, important former certification values are required for additional configuration;
* the new certification should already have been excluded from this group * the new certification should already have been excluded from this group
*/ */
def RemoveFromDeployableQuantities(certification : CertificationType.Value, certificationSet : Set[CertificationType.Value]) : Unit = { def RemoveFromDeployableQuantities(
certification: CertificationType.Value,
certificationSet: Set[CertificationType.Value]
): Unit = {
initialized = true initialized = true
DeployableToolbox.RemoveFromDeployablesQuantities(deployableCounts, categoryCounts, certification, certificationSet) DeployableToolbox.RemoveFromDeployablesQuantities(deployableCounts, categoryCounts, certification, certificationSet)
} }
@ -100,7 +112,7 @@ class DeployableToolbox {
* @return `true`, if it can be managed under the current conditions; * @return `true`, if it can be managed under the current conditions;
* `false`, otherwise * `false`, otherwise
*/ */
def Accept(obj : DeployableToolbox.AcceptableDeployable) : Boolean = { def Accept(obj: DeployableToolbox.AcceptableDeployable): Boolean = {
Valid(obj) && Available(obj) && !Contains(obj) Valid(obj) && Available(obj) && !Contains(obj)
} }
@ -111,9 +123,9 @@ class DeployableToolbox {
* @return `true`, if both category maximum and deployable type maximum are positive non-zero integers; * @return `true`, if both category maximum and deployable type maximum are positive non-zero integers;
* `false`, otherwise * `false`, otherwise
*/ */
def Valid(obj : DeployableToolbox.AcceptableDeployable) : Boolean = { def Valid(obj: DeployableToolbox.AcceptableDeployable): Boolean = {
deployableCounts(DeployableToolbox.UnifiedType(obj.Definition.Item)).Max > 0 && deployableCounts(DeployableToolbox.UnifiedType(obj.Definition.Item)).Max > 0 &&
categoryCounts(obj.Definition.DeployCategory).Max > 0 categoryCounts(obj.Definition.DeployCategory).Max > 0
} }
/** /**
@ -124,9 +136,9 @@ class DeployableToolbox {
* @return `true`, if the deployable can be added to the support lists and counted; * @return `true`, if the deployable can be added to the support lists and counted;
* `false`, otherwise * `false`, otherwise
*/ */
def Available(obj : DeployableToolbox.AcceptableDeployable) : Boolean = { def Available(obj: DeployableToolbox.AcceptableDeployable): Boolean = {
deployableCounts(DeployableToolbox.UnifiedType(obj.Definition.Item)).Available && deployableCounts(DeployableToolbox.UnifiedType(obj.Definition.Item)).Available &&
categoryCounts(obj.Definition.DeployCategory).Available categoryCounts(obj.Definition.DeployCategory).Available
} }
/** /**
@ -136,7 +148,7 @@ class DeployableToolbox {
* @return `true`, if the deployable can be found in one of the lists; * @return `true`, if the deployable can be found in one of the lists;
* `false`, otherwise * `false`, otherwise
*/ */
def Contains(obj : DeployableToolbox.AcceptableDeployable) : Boolean = { def Contains(obj: DeployableToolbox.AcceptableDeployable): Boolean = {
deployableLists(obj.Definition.DeployCategory).contains(obj) deployableLists(obj.Definition.DeployCategory).contains(obj)
} }
@ -152,18 +164,17 @@ class DeployableToolbox {
* @return `true`, if the deployable is added; * @return `true`, if the deployable is added;
* `false`, otherwise * `false`, otherwise
*/ */
def Add(obj : DeployableToolbox.AcceptableDeployable) : Boolean = { def Add(obj: DeployableToolbox.AcceptableDeployable): Boolean = {
val category = obj.Definition.DeployCategory val category = obj.Definition.DeployCategory
val dCategory = categoryCounts(category) val dCategory = categoryCounts(category)
val dType = deployableCounts(DeployableToolbox.UnifiedType(obj.Definition.Item)) val dType = deployableCounts(DeployableToolbox.UnifiedType(obj.Definition.Item))
val dList = deployableLists(category) val dList = deployableLists(category)
if(dCategory.Available() && dType.Available() && !dList.contains(obj)) { if (dCategory.Available() && dType.Available() && !dList.contains(obj)) {
dCategory.Current += 1 dCategory.Current += 1
dType.Current += 1 dType.Current += 1
dList += obj dList += obj
true true
} } else {
else {
false false
} }
} }
@ -179,16 +190,15 @@ class DeployableToolbox {
* @return `true`, if the deployable is added; * @return `true`, if the deployable is added;
* `false`, otherwise * `false`, otherwise
*/ */
def Remove(obj : DeployableToolbox.AcceptableDeployable) : Boolean = { def Remove(obj: DeployableToolbox.AcceptableDeployable): Boolean = {
val category = obj.Definition.DeployCategory val category = obj.Definition.DeployCategory
val deployables = deployableLists(category) val deployables = deployableLists(category)
if(deployables.contains(obj)) { if (deployables.contains(obj)) {
categoryCounts(category).Current -= 1 categoryCounts(category).Current -= 1
deployableCounts(DeployableToolbox.UnifiedType(obj.Definition.Item)).Current -= 1 deployableCounts(DeployableToolbox.UnifiedType(obj.Definition.Item)).Current -= 1
deployables -= obj deployables -= obj
true true
} } else {
else {
false false
} }
} }
@ -199,7 +209,7 @@ class DeployableToolbox {
* @param obj the example deployable * @param obj the example deployable
* @return any deployable that is found * @return any deployable that is found
*/ */
def DisplaceFirst(obj : DeployableToolbox.AcceptableDeployable) : Option[DeployableToolbox.AcceptableDeployable] = { def DisplaceFirst(obj: DeployableToolbox.AcceptableDeployable): Option[DeployableToolbox.AcceptableDeployable] = {
DisplaceFirst(obj, { d => d.Definition.Item == obj.Definition.Item }) DisplaceFirst(obj, { d => d.Definition.Item == obj.Definition.Item })
} }
@ -213,11 +223,14 @@ class DeployableToolbox {
* @param rule the testing rule for determining a valid deployable * @param rule the testing rule for determining a valid deployable
* @return any deployable that is found * @return any deployable that is found
*/ */
def DisplaceFirst(obj : DeployableToolbox.AcceptableDeployable, rule : (Deployable)=> Boolean) : Option[DeployableToolbox.AcceptableDeployable] = { def DisplaceFirst(
val definition = obj.Definition obj: DeployableToolbox.AcceptableDeployable,
val category = definition.DeployCategory rule: (Deployable) => Boolean
): Option[DeployableToolbox.AcceptableDeployable] = {
val definition = obj.Definition
val category = definition.DeployCategory
val categoryList = deployableLists(category) val categoryList = deployableLists(category)
if(categoryList.nonEmpty) { if (categoryList.nonEmpty) {
val found = categoryList.find(rule) match { val found = categoryList.find(rule) match {
case Some(target) => case Some(target) =>
categoryList.remove(categoryList.indexOf(target)) categoryList.remove(categoryList.indexOf(target))
@ -227,8 +240,7 @@ class DeployableToolbox {
categoryCounts(category).Current -= 1 categoryCounts(category).Current -= 1
deployableCounts(DeployableToolbox.UnifiedType(found.Definition.Item)).Current -= 1 deployableCounts(DeployableToolbox.UnifiedType(found.Definition.Item)).Current -= 1
Some(found) Some(found)
} } else {
else {
None None
} }
} }
@ -239,15 +251,14 @@ class DeployableToolbox {
* @param category the target category * @param category the target category
* @return any deployable that is found * @return any deployable that is found
*/ */
def DisplaceFirst(category : DeployableCategory.Value) : Option[DeployableToolbox.AcceptableDeployable] = { def DisplaceFirst(category: DeployableCategory.Value): Option[DeployableToolbox.AcceptableDeployable] = {
val categoryList = deployableLists(category) val categoryList = deployableLists(category)
if(categoryList.nonEmpty) { if (categoryList.nonEmpty) {
val found = categoryList.remove(0) val found = categoryList.remove(0)
categoryCounts(category).Current -= 1 categoryCounts(category).Current -= 1
deployableCounts(DeployableToolbox.UnifiedType(found.Definition.Item)).Current -= 1 deployableCounts(DeployableToolbox.UnifiedType(found.Definition.Item)).Current -= 1
Some(found) Some(found)
} } else {
else {
None None
} }
} }
@ -257,7 +268,7 @@ class DeployableToolbox {
* @param filter the example deployable * @param filter the example deployable
* @return a list of globally unique identifiers that should be valid for the current zone * @return a list of globally unique identifiers that should be valid for the current zone
*/ */
def Deployables(filter : DeployableToolbox.AcceptableDeployable) : List[PlanetSideGUID] = { def Deployables(filter: DeployableToolbox.AcceptableDeployable): List[PlanetSideGUID] = {
Deployables(filter.Definition.Item) Deployables(filter.Definition.Item)
} }
@ -266,10 +277,11 @@ class DeployableToolbox {
* @param filter the type of deployable * @param filter the type of deployable
* @return a list of globally unique identifiers that should be valid for the current zone * @return a list of globally unique identifiers that should be valid for the current zone
*/ */
def Deployables(filter : DeployedItem.Value) : List[PlanetSideGUID] = { def Deployables(filter: DeployedItem.Value): List[PlanetSideGUID] = {
deployableLists(Deployable.Category.Of(filter)) deployableLists(Deployable.Category.Of(filter))
.filter(entry => { entry.Definition.Item == filter }) .filter(entry => { entry.Definition.Item == filter })
.map(_.GUID).toList .map(_.GUID)
.toList
} }
/** /**
@ -277,7 +289,7 @@ class DeployableToolbox {
* @param filter the example deployable * @param filter the example deployable
* @return a list of globally unique identifiers that should be valid for the current zone * @return a list of globally unique identifiers that should be valid for the current zone
*/ */
def Category(filter : DeployableToolbox.AcceptableDeployable) : List[PlanetSideGUID] = { def Category(filter: DeployableToolbox.AcceptableDeployable): List[PlanetSideGUID] = {
Category(filter.Definition.DeployCategory) Category(filter.Definition.DeployCategory)
} }
@ -286,7 +298,7 @@ class DeployableToolbox {
* @param filter the type of deployable * @param filter the type of deployable
* @return a list of globally unique identifiers that should be valid for the current zone * @return a list of globally unique identifiers that should be valid for the current zone
*/ */
def Category(filter : DeployableCategory.Value) : List[PlanetSideGUID] = { def Category(filter: DeployableCategory.Value): List[PlanetSideGUID] = {
deployableLists(filter).map(_.GUID).toList deployableLists(filter).map(_.GUID).toList
} }
@ -295,7 +307,7 @@ class DeployableToolbox {
* @param item the example deployable * @param item the example deployable
* @return the current quantity of deployables and the maximum number * @return the current quantity of deployables and the maximum number
*/ */
def CountDeployable(item : DeployedItem.Value) : (Int, Int) = { def CountDeployable(item: DeployedItem.Value): (Int, Int) = {
val dType = deployableCounts(DeployableToolbox.UnifiedType(item)) val dType = deployableCounts(DeployableToolbox.UnifiedType(item))
(dType.Current, dType.Max) (dType.Current, dType.Max)
} }
@ -305,21 +317,21 @@ class DeployableToolbox {
* @param item the example deployable * @param item the example deployable
* @return the current quantity of deployables and the maximum number * @return the current quantity of deployables and the maximum number
*/ */
def CountCategory(item : DeployedItem.Value) : (Int, Int) = { def CountCategory(item: DeployedItem.Value): (Int, Int) = {
val dCat = categoryCounts(Deployable.Category.Of(DeployableToolbox.UnifiedType(item))) val dCat = categoryCounts(Deployable.Category.Of(DeployableToolbox.UnifiedType(item)))
(dCat.Current, dCat.Max) (dCat.Current, dCat.Max)
} }
def UpdateUIElement(entry : DeployedItem.Value) : List[(Int,Int,Int,Int)] = { def UpdateUIElement(entry: DeployedItem.Value): List[(Int, Int, Int, Int)] = {
val toEntry = DeployableToolbox.UnifiedType(entry) val toEntry = DeployableToolbox.UnifiedType(entry)
val (curr, max) = Deployable.UI(toEntry) val (curr, max) = Deployable.UI(toEntry)
val dType = deployableCounts(toEntry) val dType = deployableCounts(toEntry)
List((curr, dType.Current, max, dType.Max)) List((curr, dType.Current, max, dType.Max))
} }
def UpdateUI() : List[(Int,Int,Int,Int)] = DeployedItem.values flatMap UpdateUIElement toList def UpdateUI(): List[(Int, Int, Int, Int)] = DeployedItem.values flatMap UpdateUIElement toList
def UpdateUI(entry : CertificationType.Value) : List[(Int,Int,Int,Int)] = { def UpdateUI(entry: CertificationType.Value): List[(Int, Int, Int, Int)] = {
import CertificationType._ import CertificationType._
entry match { entry match {
case AdvancedHacking => case AdvancedHacking =>
@ -327,19 +339,26 @@ class DeployableToolbox {
case CombatEngineering => case CombatEngineering =>
List( List(
DeployedItem.boomer, DeployedItem.he_mine, DeployedItem.spitfire_turret, DeployedItem.motionalarmsensor DeployedItem.boomer,
DeployedItem.he_mine,
DeployedItem.spitfire_turret,
DeployedItem.motionalarmsensor
) flatMap UpdateUIElement ) flatMap UpdateUIElement
case AssaultEngineering => case AssaultEngineering =>
List( List(
DeployedItem.jammer_mine, DeployedItem.portable_manned_turret, DeployedItem.deployable_shield_generator DeployedItem.jammer_mine,
DeployedItem.portable_manned_turret,
DeployedItem.deployable_shield_generator
) flatMap UpdateUIElement ) flatMap UpdateUIElement
case FortificationEngineering => case FortificationEngineering =>
List( List(
DeployedItem.boomer, DeployedItem.boomer,
DeployedItem.he_mine, DeployedItem.he_mine,
DeployedItem.spitfire_turret, DeployedItem.spitfire_cloaked, DeployedItem.spitfire_aa, DeployedItem.spitfire_turret,
DeployedItem.spitfire_cloaked,
DeployedItem.spitfire_aa,
DeployedItem.motionalarmsensor, DeployedItem.motionalarmsensor,
DeployedItem.tank_traps DeployedItem.tank_traps
) flatMap UpdateUIElement ) flatMap UpdateUIElement
@ -352,7 +371,7 @@ class DeployableToolbox {
} }
} }
def UpdateUI(certifications : List[CertificationType.Value]) : List[(Int,Int,Int,Int)] = { def UpdateUI(certifications: List[CertificationType.Value]): List[(Int, Int, Int, Int)] = {
certifications flatMap UpdateUI certifications flatMap UpdateUI
} }
@ -361,11 +380,11 @@ class DeployableToolbox {
* @param item the deployable type * @param item the deployable type
* @return a list of globally unique identifiers that should be valid for the current zone * @return a list of globally unique identifiers that should be valid for the current zone
*/ */
def ClearDeployable(item : DeployedItem.Value) : List[PlanetSideGUID] = { def ClearDeployable(item: DeployedItem.Value): List[PlanetSideGUID] = {
val uitem = DeployableToolbox.UnifiedType(item) val uitem = DeployableToolbox.UnifiedType(item)
val category = Deployable.Category.Of(uitem) val category = Deployable.Category.Of(uitem)
val categoryList = deployableLists(category) val categoryList = deployableLists(category)
val (out, in) = categoryList.partition(_.Definition.Item == item) val (out, in) = categoryList.partition(_.Definition.Item == item)
categoryList.clear() categoryList.clear()
categoryList ++= in categoryList ++= in
@ -379,13 +398,13 @@ class DeployableToolbox {
* @param item the deployable type belonging to a category * @param item the deployable type belonging to a category
* @return a list of globally unique identifiers that should be valid for the current zone * @return a list of globally unique identifiers that should be valid for the current zone
*/ */
def ClearCategory(item : DeployedItem.Value) : List[PlanetSideGUID] = { def ClearCategory(item: DeployedItem.Value): List[PlanetSideGUID] = {
val category = Deployable.Category.Of(DeployableToolbox.UnifiedType(item)) val category = Deployable.Category.Of(DeployableToolbox.UnifiedType(item))
val out = deployableLists(category).map(_.GUID).toList val out = deployableLists(category).map(_.GUID).toList
deployableLists(category).clear() deployableLists(category).clear()
categoryCounts(category).Current = 0 categoryCounts(category).Current = 0
(Deployable.Category.Includes(category) map DeployableToolbox.UnifiedType toSet) (Deployable.Category.Includes(category) map DeployableToolbox.UnifiedType toSet)
.foreach({item : DeployedItem.Value => deployableCounts(item).Current = 0 }) .foreach({ item: DeployedItem.Value => deployableCounts(item).Current = 0 })
out out
} }
@ -393,7 +412,7 @@ class DeployableToolbox {
* Remove all managed deployables. * Remove all managed deployables.
* @return a list of globally unique identifiers that should be valid for the current zone * @return a list of globally unique identifiers that should be valid for the current zone
*/ */
def Clear() : List[PlanetSideGUID] = { def Clear(): List[PlanetSideGUID] = {
val out = deployableLists.values.flatten.map(_.GUID).toList val out = deployableLists.values.flatten.map(_.GUID).toList
deployableLists.values.foreach(_.clear()) deployableLists.values.foreach(_.clear())
deployableCounts.values.foreach(_.Current = 0) deployableCounts.values.foreach(_.Current = 0)
@ -403,6 +422,7 @@ class DeployableToolbox {
} }
object DeployableToolbox { object DeployableToolbox {
/** /**
* A `type` intended to properly define the minimum acceptable conditions for a `Deployable` object. * A `type` intended to properly define the minimum acceptable conditions for a `Deployable` object.
*/ */
@ -413,26 +433,28 @@ object DeployableToolbox {
* There are deployable numbers organized by deploybale type and by deployable category. * There are deployable numbers organized by deploybale type and by deployable category.
*/ */
private class Bin { private class Bin {
/** the maximum number of deployables for this criteria that can be managed */ /** the maximum number of deployables for this criteria that can be managed */
private var max : Int = 0 private var max: Int = 0
/** the current number of deployables for this criteria that are being managed */ /** the current number of deployables for this criteria that are being managed */
private var current : Int = 0 private var current: Int = 0
def Current : Int = current def Current: Int = current
def Current_=(curr : Int) : Int = { def Current_=(curr: Int): Int = {
current = curr current = curr
Current Current
} }
def Max : Int = max def Max: Int = max
def Max_=(mx : Int) : Int = { def Max_=(mx: Int): Int = {
max = mx max = mx
Max Max
} }
def Available() : Boolean = current < max def Available(): Boolean = current < max
} }
/** /**
@ -441,12 +463,14 @@ object DeployableToolbox {
* @param item the type of deployable * @param item the type of deployable
* @return the corrected deployable type * @return the corrected deployable type
*/ */
def UnifiedType(item : DeployedItem.Value) : DeployedItem.Value = item match { def UnifiedType(item: DeployedItem.Value): DeployedItem.Value =
case DeployedItem.portable_manned_turret_nc | DeployedItem.portable_manned_turret_tr | DeployedItem.portable_manned_turret_vs => item match {
DeployedItem.portable_manned_turret case DeployedItem.portable_manned_turret_nc | DeployedItem.portable_manned_turret_tr |
case _ => DeployedItem.portable_manned_turret_vs =>
item DeployedItem.portable_manned_turret
} case _ =>
item
}
/** /**
* Hardcoded maximum values for the category and type initialization. * Hardcoded maximum values for the category and type initialization.
@ -454,9 +478,13 @@ object DeployableToolbox {
* @param categories a reference to the category `Bin` object * @param categories a reference to the category `Bin` object
* @param certifications a group of certifications for the initial values * @param certifications a group of certifications for the initial values
*/ */
private def Initialize(counts : Map[DeployedItem.Value, DeployableToolbox.Bin], categories : Map[DeployableCategory.Value, DeployableToolbox.Bin], certifications : Set[CertificationType.Value]) : Unit = { private def Initialize(
counts: Map[DeployedItem.Value, DeployableToolbox.Bin],
categories: Map[DeployableCategory.Value, DeployableToolbox.Bin],
certifications: Set[CertificationType.Value]
): Unit = {
import CertificationType._ import CertificationType._
if(certifications.contains(AdvancedEngineering)) { if (certifications.contains(AdvancedEngineering)) {
counts(DeployedItem.boomer).Max = 25 counts(DeployedItem.boomer).Max = 25
counts(DeployedItem.he_mine).Max = 25 counts(DeployedItem.he_mine).Max = 25
counts(DeployedItem.jammer_mine).Max = 20 counts(DeployedItem.jammer_mine).Max = 20
@ -478,12 +506,11 @@ object DeployableToolbox {
categories(DeployableCategory.FieldTurrets).Max = 1 categories(DeployableCategory.FieldTurrets).Max = 1
categories(DeployableCategory.ShieldGenerators).Max = 1 categories(DeployableCategory.ShieldGenerators).Max = 1
if(certifications.contains(AdvancedHacking)) { if (certifications.contains(AdvancedHacking)) {
counts(DeployedItem.sensor_shield).Max = 25 counts(DeployedItem.sensor_shield).Max = 25
} }
} } else if (certifications.contains(CombatEngineering)) {
else if(certifications.contains(CombatEngineering)) { if (certifications.contains(AssaultEngineering)) {
if(certifications.contains(AssaultEngineering)) {
counts(DeployedItem.jammer_mine).Max = 20 counts(DeployedItem.jammer_mine).Max = 20
counts(DeployedItem.portable_manned_turret).Max = 1 //the below turret types are unified counts(DeployedItem.portable_manned_turret).Max = 1 //the below turret types are unified
//counts(DeployedItem.portable_manned_turret_nc).Max = 1 //counts(DeployedItem.portable_manned_turret_nc).Max = 1
@ -493,7 +520,7 @@ object DeployableToolbox {
categories(DeployableCategory.FieldTurrets).Max = 1 categories(DeployableCategory.FieldTurrets).Max = 1
categories(DeployableCategory.ShieldGenerators).Max = 1 categories(DeployableCategory.ShieldGenerators).Max = 1
} }
if(certifications.contains(FortificationEngineering)) { if (certifications.contains(FortificationEngineering)) {
counts(DeployedItem.boomer).Max = 25 counts(DeployedItem.boomer).Max = 25
counts(DeployedItem.he_mine).Max = 25 counts(DeployedItem.he_mine).Max = 25
counts(DeployedItem.spitfire_turret).Max = 15 counts(DeployedItem.spitfire_turret).Max = 15
@ -506,8 +533,7 @@ object DeployableToolbox {
categories(DeployableCategory.SmallTurrets).Max = 15 categories(DeployableCategory.SmallTurrets).Max = 15
categories(DeployableCategory.Sensors).Max = 25 categories(DeployableCategory.Sensors).Max = 25
categories(DeployableCategory.TankTraps).Max = 5 categories(DeployableCategory.TankTraps).Max = 5
} } else {
else {
counts(DeployedItem.boomer).Max = 20 counts(DeployedItem.boomer).Max = 20
counts(DeployedItem.he_mine).Max = 20 counts(DeployedItem.he_mine).Max = 20
counts(DeployedItem.spitfire_turret).Max = 10 counts(DeployedItem.spitfire_turret).Max = 10
@ -518,11 +544,11 @@ object DeployableToolbox {
categories(DeployableCategory.Sensors).Max = 20 categories(DeployableCategory.Sensors).Max = 20
} }
if(certifications.contains(AdvancedHacking)) { if (certifications.contains(AdvancedHacking)) {
counts(DeployedItem.sensor_shield).Max = 20 counts(DeployedItem.sensor_shield).Max = 20
} }
} }
if(certifications.contains(CertificationType.GroundSupport)) { if (certifications.contains(CertificationType.GroundSupport)) {
counts(DeployedItem.router_telepad_deployable).Max = 1024 counts(DeployedItem.router_telepad_deployable).Max = 1024
categories(DeployableCategory.Telepads).Max = 1024 categories(DeployableCategory.Telepads).Max = 1024
} }
@ -535,12 +561,17 @@ object DeployableToolbox {
* @param certification the new certification * @param certification the new certification
* @param certificationSet the group of previous certifications being tracked * @param certificationSet the group of previous certifications being tracked
*/ */
def AddToDeployableQuantities(counts : Map[DeployedItem.Value, DeployableToolbox.Bin], categories : Map[DeployableCategory.Value, DeployableToolbox.Bin], certification : CertificationType.Value, certificationSet : Set[CertificationType.Value]) : Unit = { def AddToDeployableQuantities(
counts: Map[DeployedItem.Value, DeployableToolbox.Bin],
categories: Map[DeployableCategory.Value, DeployableToolbox.Bin],
certification: CertificationType.Value,
certificationSet: Set[CertificationType.Value]
): Unit = {
import CertificationType._ import CertificationType._
if(certificationSet contains certification) { if (certificationSet contains certification) {
certification match { certification match {
case AdvancedHacking => case AdvancedHacking =>
if(certificationSet contains CombatEngineering) { if (certificationSet contains CombatEngineering) {
counts(DeployedItem.sensor_shield).Max = 20 counts(DeployedItem.sensor_shield).Max = 20
} }
@ -553,7 +584,7 @@ object DeployableToolbox {
categories(DeployableCategory.Mines).Max = 20 categories(DeployableCategory.Mines).Max = 20
categories(DeployableCategory.SmallTurrets).Max = 10 categories(DeployableCategory.SmallTurrets).Max = 10
categories(DeployableCategory.Sensors).Max = 20 categories(DeployableCategory.Sensors).Max = 20
if(certificationSet contains AdvancedHacking) { if (certificationSet contains AdvancedHacking) {
counts(DeployedItem.sensor_shield).Max = 20 counts(DeployedItem.sensor_shield).Max = 20
} }
@ -582,11 +613,21 @@ object DeployableToolbox {
categories(DeployableCategory.TankTraps).Max = 5 categories(DeployableCategory.TankTraps).Max = 5
case AdvancedEngineering => case AdvancedEngineering =>
if(!certificationSet.contains(AssaultEngineering)) { if (!certificationSet.contains(AssaultEngineering)) {
AddToDeployableQuantities(counts, categories, AssaultEngineering, certificationSet ++ Set(AssaultEngineering)) AddToDeployableQuantities(
counts,
categories,
AssaultEngineering,
certificationSet ++ Set(AssaultEngineering)
)
} }
if(!certificationSet.contains(FortificationEngineering)) { if (!certificationSet.contains(FortificationEngineering)) {
AddToDeployableQuantities(counts, categories, FortificationEngineering, certificationSet ++ Set(FortificationEngineering)) AddToDeployableQuantities(
counts,
categories,
FortificationEngineering,
certificationSet ++ Set(FortificationEngineering)
)
} }
// case GroundSupport => // case GroundSupport =>
@ -605,9 +646,14 @@ object DeployableToolbox {
* @param certification the new certification * @param certification the new certification
* @param certificationSet the group of previous certifications being tracked * @param certificationSet the group of previous certifications being tracked
*/ */
def RemoveFromDeployablesQuantities(counts : Map[DeployedItem.Value, DeployableToolbox.Bin], categories : Map[DeployableCategory.Value, DeployableToolbox.Bin], certification : CertificationType.Value, certificationSet : Set[CertificationType.Value]) : Unit = { def RemoveFromDeployablesQuantities(
counts: Map[DeployedItem.Value, DeployableToolbox.Bin],
categories: Map[DeployableCategory.Value, DeployableToolbox.Bin],
certification: CertificationType.Value,
certificationSet: Set[CertificationType.Value]
): Unit = {
import CertificationType._ import CertificationType._
if(!certificationSet.contains(certification)) { if (!certificationSet.contains(certification)) {
certification match { certification match {
case AdvancedHacking => case AdvancedHacking =>
counts(DeployedItem.sensor_shield).Max = 0 counts(DeployedItem.sensor_shield).Max = 0
@ -625,17 +671,17 @@ object DeployableToolbox {
case AssaultEngineering => case AssaultEngineering =>
counts(DeployedItem.jammer_mine).Max = 0 counts(DeployedItem.jammer_mine).Max = 0
counts(DeployedItem.portable_manned_turret).Max = 0 //the below turret types are unified counts(DeployedItem.portable_manned_turret).Max = 0 //the below turret types are unified
//counts(DeployedItem.portable_manned_turret_nc).Max = 0 //counts(DeployedItem.portable_manned_turret_nc).Max = 0
//counts(DeployedItem.portable_manned_turret_tr).Max = 0 //counts(DeployedItem.portable_manned_turret_tr).Max = 0
//counts(DeployedItem.portable_manned_turret_vs).Max = 0 //counts(DeployedItem.portable_manned_turret_vs).Max = 0
counts(DeployedItem.deployable_shield_generator).Max = 0 counts(DeployedItem.deployable_shield_generator).Max = 0
categories(DeployableCategory.Sensors).Max = if(certificationSet contains CombatEngineering) 20 else 0 categories(DeployableCategory.Sensors).Max = if (certificationSet contains CombatEngineering) 20 else 0
categories(DeployableCategory.FieldTurrets).Max = 0 categories(DeployableCategory.FieldTurrets).Max = 0
categories(DeployableCategory.ShieldGenerators).Max = 0 categories(DeployableCategory.ShieldGenerators).Max = 0
case FortificationEngineering => case FortificationEngineering =>
val ce : Int = if(certificationSet contains CombatEngineering) 1 else 0 //true = 1, false = 0 val ce: Int = if (certificationSet contains CombatEngineering) 1 else 0 //true = 1, false = 0
counts(DeployedItem.boomer).Max = ce * 20 counts(DeployedItem.boomer).Max = ce * 20
counts(DeployedItem.he_mine).Max = ce * 20 counts(DeployedItem.he_mine).Max = ce * 20
counts(DeployedItem.spitfire_turret).Max = ce * 10 counts(DeployedItem.spitfire_turret).Max = ce * 10
@ -650,10 +696,10 @@ object DeployableToolbox {
categories(DeployableCategory.TankTraps).Max = 0 categories(DeployableCategory.TankTraps).Max = 0
case AdvancedEngineering => case AdvancedEngineering =>
if(!certificationSet.contains(AssaultEngineering)) { if (!certificationSet.contains(AssaultEngineering)) {
RemoveFromDeployablesQuantities(counts, categories, AssaultEngineering, certificationSet) RemoveFromDeployablesQuantities(counts, categories, AssaultEngineering, certificationSet)
} }
if(!certificationSet.contains(FortificationEngineering)) { if (!certificationSet.contains(FortificationEngineering)) {
RemoveFromDeployablesQuantities(counts, categories, FortificationEngineering, certificationSet) RemoveFromDeployablesQuantities(counts, categories, FortificationEngineering, certificationSet)
} }

View file

@ -3,12 +3,16 @@ package net.psforever.objects.avatar
object FirstTimeEvents { object FirstTimeEvents {
object TR { object TR {
val InfantryWeapons : Set[String] = Set( val InfantryWeapons: Set[String] = Set(
"used_chainblade","used_repeater","used_cycler","used_mini_chaingun","used_striker", "used_chainblade",
"used_repeater",
"used_cycler",
"used_mini_chaingun",
"used_striker",
"used_anniversary_guna" "used_anniversary_guna"
) )
val Vehicles : Set[String] = Set( val Vehicles: Set[String] = Set(
"used_heavy_grenade_launcher", "used_heavy_grenade_launcher",
"used_apc_tr_weapon", "used_apc_tr_weapon",
"used_15mm_chaingun", "used_15mm_chaingun",
@ -18,27 +22,38 @@ object FirstTimeEvents {
"used_colossus_cluster_bomb_pod", "used_colossus_cluster_bomb_pod",
"used_colossus_dual_100mm_cannons", "used_colossus_dual_100mm_cannons",
"used_colossus_tank_cannon", "used_colossus_tank_cannon",
"visited_threemanheavybuggy","visited_battlewagon","visited_apc_tr","visited_prowler", "visited_threemanheavybuggy",
"visited_colossus_flight","visited_colossus_gunner" "visited_battlewagon",
"visited_apc_tr",
"visited_prowler",
"visited_colossus_flight",
"visited_colossus_gunner"
) )
val Other : Set[String] = Set( val Other: Set[String] = Set(
"used_trhev_dualcycler","used_trhev_pounder","used_trhev_burster", "used_trhev_dualcycler",
"used_colossus_dual_100mm_cannons","used_colossus_tank_cannon", "used_trhev_pounder",
"used_trhev_burster",
"used_colossus_dual_100mm_cannons",
"used_colossus_tank_cannon",
"used_energy_gun_tr", "used_energy_gun_tr",
"visited_portable_manned_turret_tr" "visited_portable_manned_turret_tr"
) )
val All : Set[String] = InfantryWeapons ++ Vehicles ++ Other val All: Set[String] = InfantryWeapons ++ Vehicles ++ Other
} }
object NC { object NC {
val InfantryWeapons : Set[String] = Set( val InfantryWeapons: Set[String] = Set(
"used_magcutter","used_isp","used_gauss","used_r_shotgun","used_hunterseeker", "used_magcutter",
"used_isp",
"used_gauss",
"used_r_shotgun",
"used_hunterseeker",
"used_anniversary_gun" "used_anniversary_gun"
) )
val Vehicles : Set[String] = Set( val Vehicles: Set[String] = Set(
"used_firebird", "used_firebird",
"used_gauss_cannon", "used_gauss_cannon",
"used_apc_nc_weapon", "used_apc_nc_weapon",
@ -48,26 +63,36 @@ object FirstTimeEvents {
"used_peregrine_mechhammer", "used_peregrine_mechhammer",
"used_peregrine_particle_cannon", "used_peregrine_particle_cannon",
"used_peregrine_sparrow", "used_peregrine_sparrow",
"visited_twomanheavybuggy","visited_thunderer","visited_apc_nc","visited_vanguard", "visited_twomanheavybuggy",
"visited_peregrine_flight","visited_peregrine_gunner" "visited_thunderer",
"visited_apc_nc",
"visited_vanguard",
"visited_peregrine_flight",
"visited_peregrine_gunner"
) )
val Other : Set[String] = Set( val Other: Set[String] = Set(
"used_nchev_scattercannon","used_nchev_falcon","used_nchev_sparrow", "used_nchev_scattercannon",
"used_nchev_falcon",
"used_nchev_sparrow",
"used_energy_gun_nc", "used_energy_gun_nc",
"visited_portable_manned_turret_nc" "visited_portable_manned_turret_nc"
) )
val All : Set[String] = InfantryWeapons ++ Vehicles ++ Other val All: Set[String] = InfantryWeapons ++ Vehicles ++ Other
} }
object VS { object VS {
val InfantryWeapons : Set[String] = Set( val InfantryWeapons: Set[String] = Set(
"used_forceblade","used_beamer","used_pulsar","used_lasher","used_lancer", "used_forceblade",
"used_beamer",
"used_pulsar",
"used_lasher",
"used_lancer",
"used_anniversary_gunb" "used_anniversary_gunb"
) )
val Vehicles : Set[String] = Set( val Vehicles: Set[String] = Set(
"used_fluxpod", "used_fluxpod",
"used_apc_vs_weapon", "used_apc_vs_weapon",
"used_heavy_rail_beam", "used_heavy_rail_beam",
@ -78,27 +103,45 @@ object FirstTimeEvents {
"used_aphelion_immolation_cannon", "used_aphelion_immolation_cannon",
"used_aphelion_plasma_rocket_pod", "used_aphelion_plasma_rocket_pod",
"used_aphelion_ppa", "used_aphelion_ppa",
"visited_twomanhoverbuggy","visited_aurora","visited_apc_vs","visited_magrider", "visited_twomanhoverbuggy",
"visited_aphelion_flight","visited_aphelion_gunner" "visited_aurora",
"visited_apc_vs",
"visited_magrider",
"visited_aphelion_flight",
"visited_aphelion_gunner"
) )
val Other : Set[String] = Set( val Other: Set[String] = Set(
"used_vshev_quasar","used_vshev_comet","used_vshev_starfire", "used_vshev_quasar",
"used_vshev_comet",
"used_vshev_starfire",
"used_energy_gun_vs", "used_energy_gun_vs",
"visited_portable_manned_turret_vs" "visited_portable_manned_turret_vs"
) )
val All : Set[String] = InfantryWeapons ++ Vehicles ++ Other val All: Set[String] = InfantryWeapons ++ Vehicles ++ Other
} }
object Standard { object Standard {
val InfantryWeapons : Set[String] = Set( val InfantryWeapons: Set[String] = Set(
"used_grenade_plasma","used_grenade_jammer","used_grenade_frag", "used_grenade_plasma",
"used_grenade_jammer",
"used_grenade_frag",
"used_katana", "used_katana",
"used_ilc9","used_suppressor","used_punisher","used_flechette","used_phoenix","used_thumper","used_rocklet","used_bolt_driver","used_heavy_sniper","used_oicw","used_flamethrower" "used_ilc9",
"used_suppressor",
"used_punisher",
"used_flechette",
"used_phoenix",
"used_thumper",
"used_rocklet",
"used_bolt_driver",
"used_heavy_sniper",
"used_oicw",
"used_flamethrower"
) )
val Vehicles : Set[String] = Set( val Vehicles: Set[String] = Set(
"used_armor_siphon", "used_armor_siphon",
"used_ntu_siphon", "used_ntu_siphon",
"used_ballgun", "used_ballgun",
@ -116,50 +159,95 @@ object FirstTimeEvents {
"used_vulture_nose_cannon", "used_vulture_nose_cannon",
"used_vulture_tail_cannon", "used_vulture_tail_cannon",
"used_liberator_bombardier", "used_liberator_bombardier",
"visited_ams","visited_ant", "visited_ams",
"visited_quadassault","visited_fury","visited_quadstealth", "visited_ant",
"visited_two_man_assault_buggy","visited_skyguard", "visited_quadassault",
"visited_mediumtransport","visited_apc","visited_lightning", "visited_fury",
"visited_mosquito","visited_lightgunship","visited_wasp", "visited_quadstealth",
"visited_liberator","visited_vulture","visited_dropship","visited_galaxy_gunship", "visited_two_man_assault_buggy",
"visited_phantasm","visited_lodestar" "visited_skyguard",
"visited_mediumtransport",
"visited_apc",
"visited_lightning",
"visited_mosquito",
"visited_lightgunship",
"visited_wasp",
"visited_liberator",
"visited_vulture",
"visited_dropship",
"visited_galaxy_gunship",
"visited_phantasm",
"visited_lodestar"
) )
val Facilities : Set[String] = Set( val Facilities: Set[String] = Set(
"visited_broadcast_warpgate","visited_warpgate_small", "visited_broadcast_warpgate",
"visited_respawn_terminal","visited_deconstruction_terminal", "visited_warpgate_small",
"visited_capture_terminal","visited_secondary_capture","visited_LLU_socket","visited_resource_silo", "visited_respawn_terminal",
"visited_med_terminal","visited_adv_med_terminal","visited_repair_silo", "visited_deconstruction_terminal",
"visited_order_terminal","visited_certification_terminal","visited_implant_terminal","visited_locker", "visited_capture_terminal",
"visited_ground_vehicle_terminal","visited_bfr_terminal","visited_air_vehicle_terminal","visited_galaxy_terminal", "visited_secondary_capture",
"visited_generator","visited_generator_terminal", "visited_LLU_socket",
"visited_wall_turret","used_phalanx","used_phalanx_avcombo","used_phalanx_flakcombo", "visited_resource_silo",
"visited_med_terminal",
"visited_adv_med_terminal",
"visited_repair_silo",
"visited_order_terminal",
"visited_certification_terminal",
"visited_implant_terminal",
"visited_locker",
"visited_ground_vehicle_terminal",
"visited_bfr_terminal",
"visited_air_vehicle_terminal",
"visited_galaxy_terminal",
"visited_generator",
"visited_generator_terminal",
"visited_wall_turret",
"used_phalanx",
"used_phalanx_avcombo",
"used_phalanx_flakcombo",
"visited_external_door_lock" "visited_external_door_lock"
) )
val Other : Set[String] = Set( val Other: Set[String] = Set(
"used_command_uplink", "used_command_uplink",
"used_med_app","used_nano_dispenser","used_bank","used_ace","used_advanced_ace","used_rek","used_trek","used_laze_pointer","used_telepad", "used_med_app",
"visited_motion_sensor","visited_sensor_shield", "used_nano_dispenser",
"visited_spitfire_turret","visited_spitfire_cloaked","visited_spitfire_aa", "used_bank",
"visited_shield_generator","visited_tank_traps" "used_ace",
"used_advanced_ace",
"used_rek",
"used_trek",
"used_laze_pointer",
"used_telepad",
"visited_motion_sensor",
"visited_sensor_shield",
"visited_spitfire_turret",
"visited_spitfire_cloaked",
"visited_spitfire_aa",
"visited_shield_generator",
"visited_tank_traps"
) )
val All : Set[String] = InfantryWeapons ++ Vehicles ++ Facilities ++ Other val All: Set[String] = InfantryWeapons ++ Vehicles ++ Facilities ++ Other
} }
object Cavern { object Cavern {
val InfantryWeapons : Set[String] = Set( val InfantryWeapons: Set[String] = Set(
"used_spiker","used_radiator","used_maelstrom" "used_spiker",
"used_radiator",
"used_maelstrom"
) )
val Vehicles : Set[String] = Set( val Vehicles: Set[String] = Set(
"used_scythe", "used_scythe",
"used_flail_weapon", "used_flail_weapon",
"visited_switchblade","visited_flail","visited_router" "visited_switchblade",
"visited_flail",
"visited_router"
) )
val Facilities : Set[String] = Set( val Facilities: Set[String] = Set(
"used_ancient_turret_weapon", "used_ancient_turret_weapon",
"visited_vanu_control_console", "visited_vanu_control_console",
"visited_ancient_air_vehicle_terminal", "visited_ancient_air_vehicle_terminal",
@ -172,21 +260,43 @@ object FirstTimeEvents {
"visited_energy_crystal" "visited_energy_crystal"
) )
val Other : Set[String] = Set( val Other: Set[String] = Set(
"visited_vanu_module" "visited_vanu_module"
) )
val All : Set[String] = InfantryWeapons ++ Vehicles ++ Facilities ++ Other val All: Set[String] = InfantryWeapons ++ Vehicles ++ Facilities ++ Other
} }
val Maps : Set[String] = Set( val Maps: Set[String] = Set(
"map01","map02","map03","map04","map05","map06","map07","map08","map09","map10", "map01",
"map11","map12","map13","map14","map15","map16", "map02",
"ugd01","ugd02","ugd03","ugd04","ugd05","ugd06", "map03",
"map96","map97","map98","map99" "map04",
"map05",
"map06",
"map07",
"map08",
"map09",
"map10",
"map11",
"map12",
"map13",
"map14",
"map15",
"map16",
"ugd01",
"ugd02",
"ugd03",
"ugd04",
"ugd05",
"ugd06",
"map96",
"map97",
"map98",
"map99"
) )
val Monoliths : Set[String] = Set( val Monoliths: Set[String] = Set(
"visited_monolith_amerish", "visited_monolith_amerish",
"visited_monolith_ceryshen", "visited_monolith_ceryshen",
"visited_monolith_cyssor", "visited_monolith_cyssor",
@ -198,7 +308,7 @@ object FirstTimeEvents {
"visited_monolith_solsar" "visited_monolith_solsar"
) )
val Gingerman : Set[String] = Set( val Gingerman: Set[String] = Set(
"visited_gingerman_atar", "visited_gingerman_atar",
"visited_gingerman_dahaka", "visited_gingerman_dahaka",
"visited_gingerman_hvar", "visited_gingerman_hvar",
@ -211,7 +321,7 @@ object FirstTimeEvents {
"visited_gingerman_zal" "visited_gingerman_zal"
) )
val Sled : Set[String] = Set( val Sled: Set[String] = Set(
"visited_sled01", "visited_sled01",
"visited_sled02", "visited_sled02",
"visited_sled04", "visited_sled04",
@ -222,7 +332,7 @@ object FirstTimeEvents {
"visited_sled09" "visited_sled09"
) )
val Snowman : Set[String] = Set( val Snowman: Set[String] = Set(
"visited_snowman_amerish", "visited_snowman_amerish",
"visited_snowman_ceryshen", "visited_snowman_ceryshen",
"visited_snowman_cyssor", "visited_snowman_cyssor",
@ -234,7 +344,7 @@ object FirstTimeEvents {
"visited_snowman_solsar" "visited_snowman_solsar"
) )
val Charlie : Set[String] = Set( val Charlie: Set[String] = Set(
"visited_charlie01", "visited_charlie01",
"visited_charlie02", "visited_charlie02",
"visited_charlie03", "visited_charlie03",
@ -246,22 +356,58 @@ object FirstTimeEvents {
"visited_charlie09" "visited_charlie09"
) )
val BattleRanks : Set[String] = Set( val BattleRanks: Set[String] = Set(
"xpe_battle_rank_1","xpe_battle_rank_2","xpe_battle_rank_3","xpe_battle_rank_4","xpe_battle_rank_5", "xpe_battle_rank_1",
"xpe_battle_rank_6","xpe_battle_rank_7","xpe_battle_rank_8","xpe_battle_rank_9","xpe_battle_rank_10", "xpe_battle_rank_2",
"xpe_battle_rank_11","xpe_battle_rank_12","xpe_battle_rank_13","xpe_battle_rank_14","xpe_battle_rank_15", "xpe_battle_rank_3",
"xpe_battle_rank_16","xpe_battle_rank_17","xpe_battle_rank_18","xpe_battle_rank_19","xpe_battle_rank_20", "xpe_battle_rank_4",
"xpe_battle_rank_21","xpe_battle_rank_22","xpe_battle_rank_23","xpe_battle_rank_24","xpe_battle_rank_25", "xpe_battle_rank_5",
"xpe_battle_rank_26","xpe_battle_rank_27","xpe_battle_rank_28","xpe_battle_rank_29","xpe_battle_rank_30", "xpe_battle_rank_6",
"xpe_battle_rank_31","xpe_battle_rank_32","xpe_battle_rank_33","xpe_battle_rank_34","xpe_battle_rank_35", "xpe_battle_rank_7",
"xpe_battle_rank_36","xpe_battle_rank_37","xpe_battle_rank_38","xpe_battle_rank_39","xpe_battle_rank_40" "xpe_battle_rank_8",
"xpe_battle_rank_9",
"xpe_battle_rank_10",
"xpe_battle_rank_11",
"xpe_battle_rank_12",
"xpe_battle_rank_13",
"xpe_battle_rank_14",
"xpe_battle_rank_15",
"xpe_battle_rank_16",
"xpe_battle_rank_17",
"xpe_battle_rank_18",
"xpe_battle_rank_19",
"xpe_battle_rank_20",
"xpe_battle_rank_21",
"xpe_battle_rank_22",
"xpe_battle_rank_23",
"xpe_battle_rank_24",
"xpe_battle_rank_25",
"xpe_battle_rank_26",
"xpe_battle_rank_27",
"xpe_battle_rank_28",
"xpe_battle_rank_29",
"xpe_battle_rank_30",
"xpe_battle_rank_31",
"xpe_battle_rank_32",
"xpe_battle_rank_33",
"xpe_battle_rank_34",
"xpe_battle_rank_35",
"xpe_battle_rank_36",
"xpe_battle_rank_37",
"xpe_battle_rank_38",
"xpe_battle_rank_39",
"xpe_battle_rank_40"
) )
val CommandRanks : Set[String] = Set( val CommandRanks: Set[String] = Set(
"xpe_command_rank_1","xpe_command_rank_2","xpe_command_rank_3","xpe_command_rank_4","xpe_command_rank_5" "xpe_command_rank_1",
"xpe_command_rank_2",
"xpe_command_rank_3",
"xpe_command_rank_4",
"xpe_command_rank_5"
) )
val Training : Set[String] = Set( val Training: Set[String] = Set(
"training_welcome", "training_welcome",
"training_map", "training_map",
"training_hart", "training_hart",
@ -275,13 +421,13 @@ object FirstTimeEvents {
"training_implants" "training_implants"
) )
val OldTraining : Set[String] = Set( val OldTraining: Set[String] = Set(
"training_start_tr", "training_start_tr",
"training_start_nc", "training_start_nc",
"training_start_vs" "training_start_vs"
) )
val Generic : Set[String] = Set( val Generic: Set[String] = Set(
"xpe_overhead_map", "xpe_overhead_map",
"xpe_mail_alert", "xpe_mail_alert",
"xpe_join_platoon", "xpe_join_platoon",

View file

@ -2,14 +2,13 @@
package net.psforever.objects.avatar package net.psforever.objects.avatar
import net.psforever.objects.loadouts.Loadout import net.psforever.objects.loadouts.Loadout
import net.psforever.types.LoadoutType
import scala.util.Success import scala.util.Success
class LoadoutManager(size : Int) { class LoadoutManager(size: Int) {
private val entries : Array[Option[Loadout]] = Array.fill[Option[Loadout]](size)(None) private val entries: Array[Option[Loadout]] = Array.fill[Option[Loadout]](size)(None)
def SaveLoadout(owner : Any, label : String, line : Int) : Unit = { def SaveLoadout(owner: Any, label: String, line: Int): Unit = {
Loadout.Create(owner, label) match { Loadout.Create(owner, label) match {
case Success(loadout) if entries.length > line => case Success(loadout) if entries.length > line =>
entries(line) = Some(loadout) entries(line) = Some(loadout)
@ -17,13 +16,14 @@ class LoadoutManager(size : Int) {
} }
} }
def LoadLoadout(line : Int) : Option[Loadout] = entries.lift(line).flatten def LoadLoadout(line: Int): Option[Loadout] = entries.lift(line).flatten
def DeleteLoadout(line : Int) : Unit = { def DeleteLoadout(line: Int): Unit = {
if(entries.length > line) { if (entries.length > line) {
entries(line) = None entries(line) = None
} }
} }
def Loadouts : Seq[(Int, Loadout)] = entries.zipWithIndex.collect { case(Some(loadout), index) => (index, loadout) } toSeq def Loadouts: Seq[(Int, Loadout)] =
entries.zipWithIndex.collect { case (Some(loadout), index) => (index, loadout) } toSeq
} }

View file

@ -7,27 +7,29 @@ import net.psforever.objects.definition.{BaseDeployableDefinition, ObjectDefinit
import net.psforever.objects.vital.resistance.ResistanceProfile import net.psforever.objects.vital.resistance.ResistanceProfile
import net.psforever.types.{PlanetSideEmpire, Vector3} import net.psforever.types.{PlanetSideEmpire, Vector3}
final case class ComplexDeployableSource(obj_def : ObjectDefinition with BaseDeployableDefinition, final case class ComplexDeployableSource(
faction : PlanetSideEmpire.Value, obj_def: ObjectDefinition with BaseDeployableDefinition,
health : Int, faction: PlanetSideEmpire.Value,
shields : Int, health: Int,
ownerName : String, shields: Int,
position : Vector3, ownerName: String,
orientation : Vector3) extends SourceEntry { position: Vector3,
override def Name = SourceEntry.NameFormat(obj_def.Name) orientation: Vector3
override def Faction = faction ) extends SourceEntry {
def Definition : ObjectDefinition with BaseDeployableDefinition = obj_def override def Name = SourceEntry.NameFormat(obj_def.Name)
def Health = health override def Faction = faction
def Shields = shields def Definition: ObjectDefinition with BaseDeployableDefinition = obj_def
def OwnerName = ownerName def Health = health
def Position = position def Shields = shields
def Orientation = orientation def OwnerName = ownerName
def Velocity = None def Position = position
def Modifiers = obj_def.asInstanceOf[ResistanceProfile] def Orientation = orientation
def Velocity = None
def Modifiers = obj_def.asInstanceOf[ResistanceProfile]
} }
object ComplexDeployableSource { object ComplexDeployableSource {
def apply(obj : ComplexDeployable) : ComplexDeployableSource = { def apply(obj: ComplexDeployable): ComplexDeployableSource = {
ComplexDeployableSource( ComplexDeployableSource(
obj.Definition, obj.Definition,
obj.Faction, obj.Faction,
@ -39,7 +41,7 @@ object ComplexDeployableSource {
) )
} }
def apply(obj : TurretDeployable) : ComplexDeployableSource = { def apply(obj: TurretDeployable): ComplexDeployableSource = {
ComplexDeployableSource( ComplexDeployableSource(
obj.Definition, obj.Definition,
obj.Faction, obj.Faction,

View file

@ -7,25 +7,27 @@ import net.psforever.objects.definition.{BaseDeployableDefinition, ObjectDefinit
import net.psforever.objects.vital.resistance.ResistanceProfile import net.psforever.objects.vital.resistance.ResistanceProfile
import net.psforever.types.{PlanetSideEmpire, Vector3} import net.psforever.types.{PlanetSideEmpire, Vector3}
final case class DeployableSource(obj_def : ObjectDefinition with BaseDeployableDefinition, final case class DeployableSource(
faction : PlanetSideEmpire.Value, obj_def: ObjectDefinition with BaseDeployableDefinition,
health : Int, faction: PlanetSideEmpire.Value,
ownerName : String, health: Int,
position : Vector3, ownerName: String,
orientation : Vector3) extends SourceEntry { position: Vector3,
override def Name = SourceEntry.NameFormat(obj_def.Name) orientation: Vector3
override def Faction = faction ) extends SourceEntry {
def Definition : ObjectDefinition with BaseDeployableDefinition = obj_def override def Name = SourceEntry.NameFormat(obj_def.Name)
def Health = health override def Faction = faction
def OwnerName = ownerName def Definition: ObjectDefinition with BaseDeployableDefinition = obj_def
def Position = position def Health = health
def Orientation = orientation def OwnerName = ownerName
def Velocity = None def Position = position
def Modifiers = obj_def.asInstanceOf[ResistanceProfile] def Orientation = orientation
def Velocity = None
def Modifiers = obj_def.asInstanceOf[ResistanceProfile]
} }
object DeployableSource { object DeployableSource {
def apply(obj : PlanetSideGameObject with Deployable) : DeployableSource = { def apply(obj: PlanetSideGameObject with Deployable): DeployableSource = {
DeployableSource( DeployableSource(
obj.Definition, obj.Definition,
obj.Faction, obj.Faction,

View file

@ -6,22 +6,24 @@ import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.vital.resistance.ResistanceProfileMutators import net.psforever.objects.vital.resistance.ResistanceProfileMutators
import net.psforever.types.{PlanetSideEmpire, Vector3} import net.psforever.types.{PlanetSideEmpire, Vector3}
final case class ObjectSource(obj : PlanetSideGameObject with FactionAffinity, final case class ObjectSource(
faction : PlanetSideEmpire.Value, obj: PlanetSideGameObject with FactionAffinity,
position : Vector3, faction: PlanetSideEmpire.Value,
orientation : Vector3, position: Vector3,
velocity : Option[Vector3]) extends SourceEntry { orientation: Vector3,
override def Name = SourceEntry.NameFormat(obj.Definition.Name) velocity: Option[Vector3]
) extends SourceEntry {
override def Name = SourceEntry.NameFormat(obj.Definition.Name)
override def Faction = faction override def Faction = faction
def Definition = obj.Definition def Definition = obj.Definition
def Position = position def Position = position
def Orientation = orientation def Orientation = orientation
def Velocity = velocity def Velocity = velocity
def Modifiers = new ResistanceProfileMutators { } def Modifiers = new ResistanceProfileMutators {}
} }
object ObjectSource { object ObjectSource {
def apply(obj : PlanetSideGameObject with FactionAffinity) : ObjectSource = { def apply(obj: PlanetSideGameObject with FactionAffinity): ObjectSource = {
ObjectSource( ObjectSource(
obj, obj,
obj.Faction, obj.Faction,

View file

@ -6,36 +6,49 @@ import net.psforever.objects.definition.{ExoSuitDefinition, ObjectDefinition}
import net.psforever.objects.vital.resistance.ResistanceProfile import net.psforever.objects.vital.resistance.ResistanceProfile
import net.psforever.types.{ExoSuitType, PlanetSideEmpire, Vector3} import net.psforever.types.{ExoSuitType, PlanetSideEmpire, Vector3}
final case class PlayerSource(name : String, final case class PlayerSource(
char_id : Long, name: String,
obj_def : ObjectDefinition, char_id: Long,
faction : PlanetSideEmpire.Value, obj_def: ObjectDefinition,
exosuit : ExoSuitType.Value, faction: PlanetSideEmpire.Value,
seated : Boolean, exosuit: ExoSuitType.Value,
health : Int, seated: Boolean,
armor : Int, health: Int,
position : Vector3, armor: Int,
orientation : Vector3, position: Vector3,
velocity : Option[Vector3], orientation: Vector3,
modifiers : ResistanceProfile) extends SourceEntry { velocity: Option[Vector3],
override def Name = name modifiers: ResistanceProfile
) extends SourceEntry {
override def Name = name
override def Faction = faction override def Faction = faction
override def CharId = char_id override def CharId = char_id
def Definition = obj_def def Definition = obj_def
def ExoSuit = exosuit def ExoSuit = exosuit
def Seated = seated def Seated = seated
def Health = health def Health = health
def Armor = armor def Armor = armor
def Position = position def Position = position
def Orientation = orientation def Orientation = orientation
def Velocity = velocity def Velocity = velocity
def Modifiers = modifiers def Modifiers = modifiers
} }
object PlayerSource { object PlayerSource {
def apply(tplayer : Player) : PlayerSource = { def apply(tplayer: Player): PlayerSource = {
PlayerSource(tplayer.Name, tplayer.CharId, tplayer.Definition, tplayer.Faction, tplayer.ExoSuit, tplayer.VehicleSeated.nonEmpty, PlayerSource(
tplayer.Health, tplayer.Armor, tplayer.Position, tplayer.Orientation, tplayer.Velocity, tplayer.Name,
ExoSuitDefinition.Select(tplayer.ExoSuit, tplayer.Faction)) tplayer.CharId,
tplayer.Definition,
tplayer.Faction,
tplayer.ExoSuit,
tplayer.VehicleSeated.nonEmpty,
tplayer.Health,
tplayer.Armor,
tplayer.Position,
tplayer.Orientation,
tplayer.Velocity,
ExoSuitDefinition.Select(tplayer.ExoSuit, tplayer.Faction)
)
} }
} }

View file

@ -28,51 +28,57 @@ import net.psforever.types.Vector3
* @param fire_time when the weapon discharged was recorded; * @param fire_time when the weapon discharged was recorded;
* defaults to `System.nanoTime` * defaults to `System.nanoTime`
*/ */
final case class Projectile(profile : ProjectileDefinition, final case class Projectile(
tool_def : ToolDefinition, profile: ProjectileDefinition,
fire_mode : FireModeDefinition, tool_def: ToolDefinition,
owner : SourceEntry, fire_mode: FireModeDefinition,
attribute_to : Int, owner: SourceEntry,
shot_origin : Vector3, attribute_to: Int,
shot_angle : Vector3, shot_origin: Vector3,
fire_time: Long = System.nanoTime) extends PlanetSideGameObject { shot_angle: Vector3,
fire_time: Long = System.nanoTime
) extends PlanetSideGameObject {
Position = shot_origin Position = shot_origin
Orientation = shot_angle Orientation = shot_angle
Velocity = { Velocity = {
val initVel : Int = profile.InitialVelocity //initial velocity val initVel: Int = profile.InitialVelocity //initial velocity
val radAngle : Double = math.toRadians(shot_angle.y) //angle of elevation val radAngle: Double = math.toRadians(shot_angle.y) //angle of elevation
val rise : Float = initVel * math.sin(radAngle).toFloat //z val rise: Float = initVel * math.sin(radAngle).toFloat //z
val ground : Float = initVel * math.cos(radAngle).toFloat //base val ground: Float = initVel * math.cos(radAngle).toFloat //base
Vector3.Rz(Vector3(0, -ground, 0), shot_angle.z) + Vector3.z(rise) Vector3.Rz(Vector3(0, -ground, 0), shot_angle.z) + Vector3.z(rise)
} }
/** Information about the current world coordinates and orientation of the projectile */ /** Information about the current world coordinates and orientation of the projectile */
val current : SimpleWorldEntity = new SimpleWorldEntity() val current: SimpleWorldEntity = new SimpleWorldEntity()
private var resolved : ProjectileResolution.Value = ProjectileResolution.Unresolved private var resolved: ProjectileResolution.Value = ProjectileResolution.Unresolved
/** /**
* Mark the projectile as being "encountered" or "managed" at least once. * Mark the projectile as being "encountered" or "managed" at least once.
*/ */
def Resolve() : Unit = { def Resolve(): Unit = {
resolved = ProjectileResolution.Resolved resolved = ProjectileResolution.Resolved
} }
def Miss() : Unit = { def Miss(): Unit = {
resolved = ProjectileResolution.MissedShot resolved = ProjectileResolution.MissedShot
} }
def isResolved : Boolean = resolved == ProjectileResolution.Resolved || resolved == ProjectileResolution.MissedShot def isResolved: Boolean = resolved == ProjectileResolution.Resolved || resolved == ProjectileResolution.MissedShot
def isMiss : Boolean = resolved == ProjectileResolution.MissedShot def isMiss: Boolean = resolved == ProjectileResolution.MissedShot
def Definition = profile def Definition = profile
} }
object Projectile { object Projectile {
/** the first projectile GUID used by all clients internally */ /** the first projectile GUID used by all clients internally */
final val BaseUID : Int = 40100 final val BaseUID: Int = 40100
/** all clients progress through 40100 to 40124 normally, skipping only for long-lived projectiles /** all clients progress through 40100 to 40124 normally, skipping only for long-lived projectiles
* 40125 to 40149 are being reserved as a guard against undetected overflow */ * 40125 to 40149 are being reserved as a guard against undetected overflow
final val RangeUID : Int = 40150 */
final val RangeUID: Int = 40150
/** /**
* Overloaded constructor for an `Unresolved` projectile. * Overloaded constructor for an `Unresolved` projectile.
@ -84,7 +90,14 @@ object Projectile {
* @param shot_angle in which direction the projectile was aimed when it was discharged * @param shot_angle in which direction the projectile was aimed when it was discharged
* @return the `Projectile` object * @return the `Projectile` object
*/ */
def apply(profile : ProjectileDefinition, tool_def : ToolDefinition, fire_mode : FireModeDefinition, owner : PlanetSideGameObject with FactionAffinity, shot_origin : Vector3, shot_angle : Vector3) : Projectile = { def apply(
profile: ProjectileDefinition,
tool_def: ToolDefinition,
fire_mode: FireModeDefinition,
owner: PlanetSideGameObject with FactionAffinity,
shot_origin: Vector3,
shot_angle: Vector3
): Projectile = {
Projectile(profile, tool_def, fire_mode, SourceEntry(owner), tool_def.ObjectId, shot_origin, shot_angle) Projectile(profile, tool_def, fire_mode, SourceEntry(owner), tool_def.ObjectId, shot_origin, shot_angle)
} }
@ -99,7 +112,15 @@ object Projectile {
* @param shot_angle in which direction the projectile was aimed when it was discharged * @param shot_angle in which direction the projectile was aimed when it was discharged
* @return the `Projectile` object * @return the `Projectile` object
*/ */
def apply(profile : ProjectileDefinition, tool_def : ToolDefinition, fire_mode : FireModeDefinition, owner : PlanetSideGameObject with FactionAffinity, attribute_to : Int, shot_origin : Vector3, shot_angle : Vector3) : Projectile = { def apply(
profile: ProjectileDefinition,
tool_def: ToolDefinition,
fire_mode: FireModeDefinition,
owner: PlanetSideGameObject with FactionAffinity,
attribute_to: Int,
shot_origin: Vector3,
shot_angle: Vector3
): Projectile = {
Projectile(profile, tool_def, fire_mode, SourceEntry(owner), attribute_to, shot_origin, shot_angle) Projectile(profile, tool_def, fire_mode, SourceEntry(owner), attribute_to, shot_origin, shot_angle)
} }
} }

View file

@ -7,12 +7,11 @@ package net.psforever.objects.ballistics
object ProjectileResolution extends Enumeration { object ProjectileResolution extends Enumeration {
type Type = Value type Type = Value
val val Unresolved, //original basic non-resolution
Unresolved, //original basic non-resolution MissedShot, //projectile did not encounter any collision object and was despawned
MissedShot, //projectile did not encounter any collision object and was despawned Resolved, //a general "projectile encountered something" status with a more specific resolution
Resolved, //a general "projectile encountered something" status with a more specific resolution Hit, //direct hit, one target
Hit, //direct hit, one target Splash, //area of effect damage, potentially multiple targets
Splash, //area of effect damage, potentially multiple targets Lash //lashing damage, potentially multiple targets
Lash //lashing damage, potentially multiple targets
= Value = Value
} }

View file

@ -7,143 +7,143 @@ package net.psforever.objects.ballistics
object Projectiles extends Enumeration { object Projectiles extends Enumeration {
final val no_projectile = Value(0) final val no_projectile = Value(0)
final val bullet_105mm_projectile = Value(1) final val bullet_105mm_projectile = Value(1)
final val bullet_12mm_projectile = Value(4) final val bullet_12mm_projectile = Value(4)
final val bullet_12mm_projectileb = Value(5) final val bullet_12mm_projectileb = Value(5)
final val bullet_150mm_projectile = Value(7) final val bullet_150mm_projectile = Value(7)
final val bullet_15mm_apc_projectile = Value(10) final val bullet_15mm_apc_projectile = Value(10)
final val bullet_15mm_projectile = Value(11) final val bullet_15mm_projectile = Value(11)
final val bullet_20mm_apc_projectile = Value(17) final val bullet_20mm_apc_projectile = Value(17)
final val bullet_20mm_projectile = Value(18) final val bullet_20mm_projectile = Value(18)
final val bullet_25mm_projectile = Value(20) final val bullet_25mm_projectile = Value(20)
final val bullet_35mm_projectile = Value(22) final val bullet_35mm_projectile = Value(22)
final val bullet_75mm_apc_projectile = Value(26) final val bullet_75mm_apc_projectile = Value(26)
final val bullet_75mm_projectile = Value(27) final val bullet_75mm_projectile = Value(27)
final val bullet_9mm_AP_projectile = Value(30) final val bullet_9mm_AP_projectile = Value(30)
final val bullet_9mm_projectile = Value(31) final val bullet_9mm_projectile = Value(31)
final val anniversary_projectilea = Value(58) final val anniversary_projectilea = Value(58)
final val anniversary_projectileb = Value(59) final val anniversary_projectileb = Value(59)
final val aphelion_immolation_cannon_projectile = Value(87) final val aphelion_immolation_cannon_projectile = Value(87)
final val aphelion_laser_projectile = Value(91) final val aphelion_laser_projectile = Value(91)
final val aphelion_plasma_rocket_projectile = Value(99) final val aphelion_plasma_rocket_projectile = Value(99)
final val aphelion_ppa_projectile = Value(103) final val aphelion_ppa_projectile = Value(103)
final val aphelion_starfire_projectile = Value(108) final val aphelion_starfire_projectile = Value(108)
final val bolt_projectile = Value(147) final val bolt_projectile = Value(147)
final val burster_projectile = Value(155) final val burster_projectile = Value(155)
final val chainblade_projectile = Value(176) final val chainblade_projectile = Value(176)
final val colossus_100mm_projectile = Value(181) final val colossus_100mm_projectile = Value(181)
final val colossus_burster_projectile = Value(188) final val colossus_burster_projectile = Value(188)
final val colossus_chaingun_projectile = Value(193) final val colossus_chaingun_projectile = Value(193)
final val colossus_cluster_bomb_projectile = Value(197) final val colossus_cluster_bomb_projectile = Value(197)
final val colossus_tank_cannon_projectile = Value(207) final val colossus_tank_cannon_projectile = Value(207)
final val comet_projectile = Value(210) final val comet_projectile = Value(210)
final val dualcycler_projectile = Value(266) final val dualcycler_projectile = Value(266)
final val dynomite_projectile = Value(268) final val dynomite_projectile = Value(268)
final val energy_cell_projectile = Value(273) final val energy_cell_projectile = Value(273)
final val energy_gun_nc_projectile = Value(277) final val energy_gun_nc_projectile = Value(277)
final val energy_gun_tr_projectile = Value(279) final val energy_gun_tr_projectile = Value(279)
final val energy_gun_vs_projectile = Value(281) final val energy_gun_vs_projectile = Value(281)
final val enhanced_energy_cell_projectile = Value(282) final val enhanced_energy_cell_projectile = Value(282)
final val enhanced_quasar_projectile = Value(283) final val enhanced_quasar_projectile = Value(283)
final val falcon_projectile = Value(286) final val falcon_projectile = Value(286)
final val firebird_missile_projectile = Value(288) final val firebird_missile_projectile = Value(288)
final val flail_projectile = Value(296) final val flail_projectile = Value(296)
final val flamethrower_fireball = Value(302) final val flamethrower_fireball = Value(302)
final val flamethrower_projectile = Value(303) final val flamethrower_projectile = Value(303)
final val flux_cannon_apc_projectile = Value(305) final val flux_cannon_apc_projectile = Value(305)
final val flux_cannon_thresher_projectile = Value(308) final val flux_cannon_thresher_projectile = Value(308)
final val fluxpod_projectile = Value(311) final val fluxpod_projectile = Value(311)
final val forceblade_projectile = Value(325) final val forceblade_projectile = Value(325)
final val frag_cartridge_projectile = Value(328) final val frag_cartridge_projectile = Value(328)
final val frag_cartridge_projectile_b = Value(329) final val frag_cartridge_projectile_b = Value(329)
final val frag_grenade_projectile = Value(332) final val frag_grenade_projectile = Value(332)
final val frag_grenade_projectile_enh = Value(333) final val frag_grenade_projectile_enh = Value(333)
final val galaxy_gunship_gun_projectile = Value(341) final val galaxy_gunship_gun_projectile = Value(341)
final val gauss_cannon_projectile = Value(348) final val gauss_cannon_projectile = Value(348)
final val grenade_projectile = Value(372) final val grenade_projectile = Value(372)
final val heavy_grenade_projectile = Value(392) final val heavy_grenade_projectile = Value(392)
final val heavy_rail_beam_projectile = Value(395) final val heavy_rail_beam_projectile = Value(395)
final val heavy_sniper_projectile = Value(397) final val heavy_sniper_projectile = Value(397)
final val hellfire_projectile = Value(400) final val hellfire_projectile = Value(400)
final val hunter_seeker_missile_dumbfire = Value(404) final val hunter_seeker_missile_dumbfire = Value(404)
final val hunter_seeker_missile_projectile = Value(405) final val hunter_seeker_missile_projectile = Value(405)
final val jammer_cartridge_projectile = Value(414) final val jammer_cartridge_projectile = Value(414)
final val jammer_cartridge_projectile_b = Value(415) final val jammer_cartridge_projectile_b = Value(415)
final val jammer_grenade_projectile = Value(418) final val jammer_grenade_projectile = Value(418)
final val jammer_grenade_projectile_enh = Value(419) final val jammer_grenade_projectile_enh = Value(419)
final val katana_projectile = Value(422) final val katana_projectile = Value(422)
final val katana_projectileb = Value(423) final val katana_projectileb = Value(423)
final val lancer_projectile = Value(427) final val lancer_projectile = Value(427)
final val lasher_projectile = Value(430) final val lasher_projectile = Value(430)
final val lasher_projectile_ap = Value(431) final val lasher_projectile_ap = Value(431)
final val liberator_bomb_cluster_bomblet_projectile = Value(436) final val liberator_bomb_cluster_bomblet_projectile = Value(436)
final val liberator_bomb_cluster_projectile = Value(437) final val liberator_bomb_cluster_projectile = Value(437)
final val liberator_bomb_projectile = Value(438) final val liberator_bomb_projectile = Value(438)
final val maelstrom_grenade_projectile = Value(465) final val maelstrom_grenade_projectile = Value(465)
final val maelstrom_grenade_projectile_contact = Value(466) final val maelstrom_grenade_projectile_contact = Value(466)
final val maelstrom_stream_projectile = Value(467) final val maelstrom_stream_projectile = Value(467)
final val magcutter_projectile = Value(469) final val magcutter_projectile = Value(469)
final val melee_ammo_projectile = Value(541) final val melee_ammo_projectile = Value(541)
final val meteor_common = Value(543) final val meteor_common = Value(543)
final val meteor_projectile_b_large = Value(544) final val meteor_projectile_b_large = Value(544)
final val meteor_projectile_b_medium = Value(545) final val meteor_projectile_b_medium = Value(545)
final val meteor_projectile_b_small = Value(546) final val meteor_projectile_b_small = Value(546)
final val meteor_projectile_large = Value(547) final val meteor_projectile_large = Value(547)
final val meteor_projectile_medium = Value(548) final val meteor_projectile_medium = Value(548)
final val meteor_projectile_small = Value(549) final val meteor_projectile_small = Value(549)
final val mine_projectile = Value(551) final val mine_projectile = Value(551)
final val mine_sweeper_projectile = Value(554) final val mine_sweeper_projectile = Value(554)
final val mine_sweeper_projectile_enh = Value(555) final val mine_sweeper_projectile_enh = Value(555)
final val oicw_little_buddy = Value(601) final val oicw_little_buddy = Value(601)
final val oicw_projectile = Value(602) final val oicw_projectile = Value(602)
final val pellet_gun_projectile = Value(631) final val pellet_gun_projectile = Value(631)
final val peregrine_dual_machine_gun_projectile = Value(639) final val peregrine_dual_machine_gun_projectile = Value(639)
final val peregrine_mechhammer_projectile = Value(647) final val peregrine_mechhammer_projectile = Value(647)
final val peregrine_particle_cannon_projectile = Value(654) final val peregrine_particle_cannon_projectile = Value(654)
final val peregrine_rocket_pod_projectile = Value(657) final val peregrine_rocket_pod_projectile = Value(657)
final val peregrine_sparrow_projectile = Value(661) final val peregrine_sparrow_projectile = Value(661)
final val phalanx_av_projectile = Value(665) final val phalanx_av_projectile = Value(665)
final val phalanx_flak_projectile = Value(667) final val phalanx_flak_projectile = Value(667)
final val phalanx_projectile = Value(669) final val phalanx_projectile = Value(669)
final val phoenix_missile_guided_projectile = Value(675) final val phoenix_missile_guided_projectile = Value(675)
final val phoenix_missile_projectile = Value(676) final val phoenix_missile_projectile = Value(676)
final val plasma_cartridge_projectile = Value(678) final val plasma_cartridge_projectile = Value(678)
final val plasma_cartridge_projectile_b = Value(679) final val plasma_cartridge_projectile_b = Value(679)
final val plasma_grenade_projectile = Value(682) final val plasma_grenade_projectile = Value(682)
final val plasma_grenade_projectile_B = Value(683) final val plasma_grenade_projectile_B = Value(683)
final val pounder_projectile = Value(694) final val pounder_projectile = Value(694)
final val pounder_projectile_enh = Value(695) final val pounder_projectile_enh = Value(695)
final val ppa_projectile = Value(696) final val ppa_projectile = Value(696)
final val pulsar_ap_projectile = Value(702) final val pulsar_ap_projectile = Value(702)
final val pulsar_projectile = Value(703) final val pulsar_projectile = Value(703)
final val quasar_projectile = Value(713) final val quasar_projectile = Value(713)
final val radiator_grenade_projectile = Value(718) final val radiator_grenade_projectile = Value(718)
final val radiator_sticky_projectile = Value(719) final val radiator_sticky_projectile = Value(719)
final val reaver_rocket_projectile = Value(723) final val reaver_rocket_projectile = Value(723)
final val rocket_projectile = Value(735) final val rocket_projectile = Value(735)
final val rocklet_flak_projectile = Value(738) final val rocklet_flak_projectile = Value(738)
final val rocklet_jammer_projectile = Value(739) final val rocklet_jammer_projectile = Value(739)
final val scattercannon_projectile = Value(746) final val scattercannon_projectile = Value(746)
final val scythe_projectile = Value(748) final val scythe_projectile = Value(748)
final val scythe_projectile_slave = Value(749) final val scythe_projectile_slave = Value(749)
final val shotgun_shell_AP_projectile = Value(757) final val shotgun_shell_AP_projectile = Value(757)
final val shotgun_shell_projectile = Value(758) final val shotgun_shell_projectile = Value(758)
final val six_shooter_projectile = Value(763) final val six_shooter_projectile = Value(763)
final val skyguard_flak_cannon_projectile = Value(787) final val skyguard_flak_cannon_projectile = Value(787)
final val sparrow_projectile = Value(792) final val sparrow_projectile = Value(792)
final val sparrow_secondary_projectile = Value(793) final val sparrow_secondary_projectile = Value(793)
final val spiker_projectile = Value(818) final val spiker_projectile = Value(818)
final val spitfire_aa_ammo_projectile = Value(821) final val spitfire_aa_ammo_projectile = Value(821)
final val spitfire_ammo_projectile = Value(824) final val spitfire_ammo_projectile = Value(824)
final val starfire_projectile = Value(831) final val starfire_projectile = Value(831)
final val striker_missile_projectile = Value(840) final val striker_missile_projectile = Value(840)
final val striker_missile_targeting_projectile = Value(841) final val striker_missile_targeting_projectile = Value(841)
final val trek_projectile = Value(878) final val trek_projectile = Value(878)
final val vanu_sentry_turret_projectile = Value(944) final val vanu_sentry_turret_projectile = Value(944)
final val vulture_bomb_projectile = Value(988) final val vulture_bomb_projectile = Value(988)
final val vulture_nose_bullet_projectile = Value(989) final val vulture_nose_bullet_projectile = Value(989)
final val vulture_tail_bullet_projectile = Value(991) final val vulture_tail_bullet_projectile = Value(991)
final val wasp_gun_projectile = Value(999) final val wasp_gun_projectile = Value(999)
final val wasp_rocket_projectile = Value(1001) final val wasp_rocket_projectile = Value(1001)
final val winchester_projectile = Value(1005) final val winchester_projectile = Value(1005)
} }

View file

@ -15,10 +15,12 @@ import net.psforever.types.Vector3
* @param damage_model the kind of damage model to which the `target` is/was subject * @param damage_model the kind of damage model to which the `target` is/was subject
* @param hit_pos where the projectile hit * @param hit_pos where the projectile hit
*/ */
final case class ResolvedProjectile(resolution : ProjectileResolution.Value, final case class ResolvedProjectile(
projectile : Projectile, resolution: ProjectileResolution.Value,
target : SourceEntry, projectile: Projectile,
damage_model : DamageResistanceModel, target: SourceEntry,
hit_pos : Vector3) { damage_model: DamageResistanceModel,
val hit_time : Long = System.nanoTime hit_pos: Vector3
) {
val hit_time: Long = System.nanoTime
} }

View file

@ -10,37 +10,38 @@ import net.psforever.objects.vital.resistance.ResistanceProfile
import net.psforever.types.{PlanetSideEmpire, Vector3} import net.psforever.types.{PlanetSideEmpire, Vector3}
trait SourceEntry extends WorldEntity { trait SourceEntry extends WorldEntity {
def Name : String = "" def Name: String = ""
def Definition : ObjectDefinition def Definition: ObjectDefinition
def CharId : Long = 0L def CharId: Long = 0L
def Faction : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL def Faction: PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
def Position_=(pos : Vector3) = Position def Position_=(pos: Vector3) = Position
def Orientation_=(pos : Vector3) = Position def Orientation_=(pos: Vector3) = Position
def Velocity_=(pos : Option[Vector3]) = Velocity def Velocity_=(pos: Option[Vector3]) = Velocity
def Modifiers : ResistanceProfile def Modifiers: ResistanceProfile
} }
object SourceEntry { object SourceEntry {
final val None = new SourceEntry() { final val None = new SourceEntry() {
def Definition = null def Definition = null
def Position = Vector3.Zero def Position = Vector3.Zero
def Orientation = Vector3.Zero def Orientation = Vector3.Zero
def Velocity = Some(Vector3.Zero) def Velocity = Some(Vector3.Zero)
def Modifiers = null def Modifiers = null
} }
def apply(target : PlanetSideGameObject with FactionAffinity) : SourceEntry = { def apply(target: PlanetSideGameObject with FactionAffinity): SourceEntry = {
target match { target match {
case obj : Player => PlayerSource(obj) case obj: Player => PlayerSource(obj)
case obj : Vehicle => VehicleSource(obj) case obj: Vehicle => VehicleSource(obj)
case obj : ComplexDeployable => ComplexDeployableSource(obj) case obj: ComplexDeployable => ComplexDeployableSource(obj)
case obj : SimpleDeployable => DeployableSource(obj) case obj: SimpleDeployable => DeployableSource(obj)
case _ => ObjectSource(target) case _ => ObjectSource(target)
} }
} }
def NameFormat(name : String) : String = { def NameFormat(name: String): String = {
name.replace("_", " ") name
.replace("_", " ")
.split(" ") .split(" ")
.map(_.capitalize) .map(_.capitalize)
.mkString(" ") .mkString(" ")

View file

@ -6,27 +6,29 @@ import net.psforever.objects.definition.VehicleDefinition
import net.psforever.objects.vital.resistance.ResistanceProfile import net.psforever.objects.vital.resistance.ResistanceProfile
import net.psforever.types.{PlanetSideEmpire, Vector3} import net.psforever.types.{PlanetSideEmpire, Vector3}
final case class VehicleSource(obj_def : VehicleDefinition, final case class VehicleSource(
faction : PlanetSideEmpire.Value, obj_def: VehicleDefinition,
health : Int, faction: PlanetSideEmpire.Value,
shields : Int, health: Int,
position : Vector3, shields: Int,
orientation : Vector3, position: Vector3,
velocity : Option[Vector3], orientation: Vector3,
modifiers : ResistanceProfile) extends SourceEntry { velocity: Option[Vector3],
override def Name = SourceEntry.NameFormat(obj_def.Name) modifiers: ResistanceProfile
override def Faction = faction ) extends SourceEntry {
def Definition : VehicleDefinition = obj_def override def Name = SourceEntry.NameFormat(obj_def.Name)
def Health = health override def Faction = faction
def Shields = shields def Definition: VehicleDefinition = obj_def
def Position = position def Health = health
def Orientation = orientation def Shields = shields
def Velocity = velocity def Position = position
def Modifiers = modifiers def Orientation = orientation
def Velocity = velocity
def Modifiers = modifiers
} }
object VehicleSource { object VehicleSource {
def apply(obj : Vehicle) : VehicleSource = { def apply(obj: Vehicle): VehicleSource = {
VehicleSource( VehicleSource(
obj.Definition, obj.Definition,
obj.Faction, obj.Faction,

View file

@ -4,19 +4,18 @@ package net.psforever.objects.ce
import net.psforever.objects.definition.ComplexDeployableDefinition import net.psforever.objects.definition.ComplexDeployableDefinition
import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.PlanetSideServerObject
abstract class ComplexDeployable(cdef : ComplexDeployableDefinition) extends PlanetSideServerObject abstract class ComplexDeployable(cdef: ComplexDeployableDefinition) extends PlanetSideServerObject with Deployable {
with Deployable { private var shields: Int = 0
private var shields : Int = 0
def Shields : Int = shields def Shields: Int = shields
def Shields_=(toShields : Int) : Int = { def Shields_=(toShields: Int): Int = {
shields = math.min(math.max(0, toShields), MaxShields) shields = math.min(math.max(0, toShields), MaxShields)
Shields Shields
} }
def MaxShields : Int = { def MaxShields: Int = {
0//Definition.MaxShields 0 //Definition.MaxShields
} }
def Definition = cdef def Definition = cdef

View file

@ -9,83 +9,80 @@ import net.psforever.objects.zones.ZoneAware
import net.psforever.packet.game.DeployableIcon import net.psforever.packet.game.DeployableIcon
import net.psforever.types.PlanetSideEmpire import net.psforever.types.PlanetSideEmpire
trait Deployable extends FactionAffinity trait Deployable extends FactionAffinity with Vitality with OwnableByPlayer with ZoneAware {
with Vitality this: PlanetSideGameObject =>
with OwnableByPlayer private var faction: PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
with ZoneAware {
this : PlanetSideGameObject =>
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
def MaxHealth : Int def MaxHealth: Int
def Faction : PlanetSideEmpire.Value = faction def Faction: PlanetSideEmpire.Value = faction
override def Faction_=(toFaction : PlanetSideEmpire.Value) : PlanetSideEmpire.Value = { override def Faction_=(toFaction: PlanetSideEmpire.Value): PlanetSideEmpire.Value = {
faction = toFaction faction = toFaction
Faction Faction
} }
def DamageModel : DamageResistanceModel = Definition.asInstanceOf[DamageResistanceModel] def DamageModel: DamageResistanceModel = Definition.asInstanceOf[DamageResistanceModel]
def Definition : DeployableDefinition def Definition: DeployableDefinition
} }
object Deployable { object Deployable {
object Category { object Category {
def Of(item : DeployedItem.Value) : DeployableCategory.Value = deployablesToCategories(item) def Of(item: DeployedItem.Value): DeployableCategory.Value = deployablesToCategories(item)
def Includes(category : DeployableCategory.Value) : List[DeployedItem.Value] = { def Includes(category: DeployableCategory.Value): List[DeployedItem.Value] = {
(for { (for {
(ce, cat) <- deployablesToCategories (ce, cat) <- deployablesToCategories
if cat == category if cat == category
} yield ce) toList } yield ce) toList
} }
def OfAll() : Map[DeployedItem.Value, DeployableCategory.Value] = deployablesToCategories def OfAll(): Map[DeployedItem.Value, DeployableCategory.Value] = deployablesToCategories
private val deployablesToCategories : Map[DeployedItem.Value, DeployableCategory.Value] = Map( private val deployablesToCategories: Map[DeployedItem.Value, DeployableCategory.Value] = Map(
DeployedItem.boomer -> DeployableCategory.Boomers, DeployedItem.boomer -> DeployableCategory.Boomers,
DeployedItem.he_mine -> DeployableCategory.Mines, DeployedItem.he_mine -> DeployableCategory.Mines,
DeployedItem.jammer_mine -> DeployableCategory.Mines, DeployedItem.jammer_mine -> DeployableCategory.Mines,
DeployedItem.spitfire_turret -> DeployableCategory.SmallTurrets, DeployedItem.spitfire_turret -> DeployableCategory.SmallTurrets,
DeployedItem.motionalarmsensor -> DeployableCategory.Sensors, DeployedItem.motionalarmsensor -> DeployableCategory.Sensors,
DeployedItem.spitfire_cloaked -> DeployableCategory.SmallTurrets, DeployedItem.spitfire_cloaked -> DeployableCategory.SmallTurrets,
DeployedItem.spitfire_aa -> DeployableCategory.SmallTurrets, DeployedItem.spitfire_aa -> DeployableCategory.SmallTurrets,
DeployedItem.deployable_shield_generator -> DeployableCategory.ShieldGenerators, DeployedItem.deployable_shield_generator -> DeployableCategory.ShieldGenerators,
DeployedItem.tank_traps -> DeployableCategory.TankTraps, DeployedItem.tank_traps -> DeployableCategory.TankTraps,
DeployedItem.portable_manned_turret -> DeployableCategory.FieldTurrets, DeployedItem.portable_manned_turret -> DeployableCategory.FieldTurrets,
DeployedItem.portable_manned_turret_nc -> DeployableCategory.FieldTurrets, DeployedItem.portable_manned_turret_nc -> DeployableCategory.FieldTurrets,
DeployedItem.portable_manned_turret_tr -> DeployableCategory.FieldTurrets, DeployedItem.portable_manned_turret_tr -> DeployableCategory.FieldTurrets,
DeployedItem.portable_manned_turret_vs -> DeployableCategory.FieldTurrets, DeployedItem.portable_manned_turret_vs -> DeployableCategory.FieldTurrets,
DeployedItem.sensor_shield -> DeployableCategory.Sensors, DeployedItem.sensor_shield -> DeployableCategory.Sensors,
DeployedItem.router_telepad_deployable -> DeployableCategory.Telepads DeployedItem.router_telepad_deployable -> DeployableCategory.Telepads
) )
} }
object Icon { object Icon {
def apply(item : DeployedItem.Value) : DeployableIcon.Value = ceicon(item.id) def apply(item: DeployedItem.Value): DeployableIcon.Value = ceicon(item.id)
private val ceicon : Map[Int, DeployableIcon.Value] = Map( private val ceicon: Map[Int, DeployableIcon.Value] = Map(
DeployedItem.boomer.id -> DeployableIcon.Boomer, DeployedItem.boomer.id -> DeployableIcon.Boomer,
DeployedItem.he_mine.id -> DeployableIcon.HEMine, DeployedItem.he_mine.id -> DeployableIcon.HEMine,
DeployedItem.jammer_mine.id -> DeployableIcon.DisruptorMine, DeployedItem.jammer_mine.id -> DeployableIcon.DisruptorMine,
DeployedItem.spitfire_turret.id -> DeployableIcon.SpitfireTurret, DeployedItem.spitfire_turret.id -> DeployableIcon.SpitfireTurret,
DeployedItem.spitfire_cloaked.id -> DeployableIcon.ShadowTurret, DeployedItem.spitfire_cloaked.id -> DeployableIcon.ShadowTurret,
DeployedItem.spitfire_aa.id -> DeployableIcon.CerebusTurret, DeployedItem.spitfire_aa.id -> DeployableIcon.CerebusTurret,
DeployedItem.motionalarmsensor.id -> DeployableIcon.MotionAlarmSensor, DeployedItem.motionalarmsensor.id -> DeployableIcon.MotionAlarmSensor,
DeployedItem.sensor_shield.id -> DeployableIcon.SensorDisruptor, DeployedItem.sensor_shield.id -> DeployableIcon.SensorDisruptor,
DeployedItem.tank_traps.id -> DeployableIcon.TRAP, DeployedItem.tank_traps.id -> DeployableIcon.TRAP,
DeployedItem.portable_manned_turret.id -> DeployableIcon.FieldTurret, DeployedItem.portable_manned_turret.id -> DeployableIcon.FieldTurret,
DeployedItem.portable_manned_turret_tr.id -> DeployableIcon.FieldTurret, DeployedItem.portable_manned_turret_tr.id -> DeployableIcon.FieldTurret,
DeployedItem.portable_manned_turret_nc.id -> DeployableIcon.FieldTurret, DeployedItem.portable_manned_turret_nc.id -> DeployableIcon.FieldTurret,
DeployedItem.portable_manned_turret_vs.id -> DeployableIcon.FieldTurret, DeployedItem.portable_manned_turret_vs.id -> DeployableIcon.FieldTurret,
DeployedItem.deployable_shield_generator.id -> DeployableIcon.AegisShieldGenerator, DeployedItem.deployable_shield_generator.id -> DeployableIcon.AegisShieldGenerator,
DeployedItem.router_telepad_deployable.id -> DeployableIcon.RouterTelepad DeployedItem.router_telepad_deployable.id -> DeployableIcon.RouterTelepad
).withDefaultValue(DeployableIcon.Boomer) ).withDefaultValue(DeployableIcon.Boomer)
} }
object UI { object UI {
def apply(item : DeployedItem.Value) : (Int, Int) = planetsideAttribute(item) def apply(item: DeployedItem.Value): (Int, Int) = planetsideAttribute(item)
/** /**
* The attribute values to be invoked in `PlanetsideAttributeMessage` packets * The attribute values to be invoked in `PlanetsideAttributeMessage` packets
@ -93,21 +90,21 @@ object Deployable {
* The first number is for the actual count field. * The first number is for the actual count field.
* The second number is for the maximum count field. * The second number is for the maximum count field.
*/ */
private val planetsideAttribute : Map[DeployedItem.Value, (Int, Int)] = Map( private val planetsideAttribute: Map[DeployedItem.Value, (Int, Int)] = Map(
DeployedItem.boomer -> (94, 83), DeployedItem.boomer -> (94, 83),
DeployedItem.he_mine -> (95, 84), DeployedItem.he_mine -> (95, 84),
DeployedItem.jammer_mine -> (96, 85), DeployedItem.jammer_mine -> (96, 85),
DeployedItem.spitfire_turret -> (97, 86), DeployedItem.spitfire_turret -> (97, 86),
DeployedItem.motionalarmsensor -> (98, 87), DeployedItem.motionalarmsensor -> (98, 87),
DeployedItem.spitfire_cloaked -> (99, 88), DeployedItem.spitfire_cloaked -> (99, 88),
DeployedItem.spitfire_aa -> (100, 89), DeployedItem.spitfire_aa -> (100, 89),
DeployedItem.deployable_shield_generator -> (101, 90), DeployedItem.deployable_shield_generator -> (101, 90),
DeployedItem.tank_traps -> (102, 91), DeployedItem.tank_traps -> (102, 91),
DeployedItem.portable_manned_turret -> (103, 92), DeployedItem.portable_manned_turret -> (103, 92),
DeployedItem.portable_manned_turret_nc -> (103, 92), DeployedItem.portable_manned_turret_nc -> (103, 92),
DeployedItem.portable_manned_turret_tr -> (103, 92), DeployedItem.portable_manned_turret_tr -> (103, 92),
DeployedItem.portable_manned_turret_vs -> (103, 92), DeployedItem.portable_manned_turret_vs -> (103, 92),
DeployedItem.sensor_shield -> (104, 93) DeployedItem.sensor_shield -> (104, 93)
).withDefaultValue((0,0)) ).withDefaultValue((0, 0))
} }
} }

View file

@ -4,14 +4,5 @@ package net.psforever.objects.ce
object DeployableCategory extends Enumeration { object DeployableCategory extends Enumeration {
type Type = Value type Type = Value
val val Boomers, Mines, SmallTurrets, Sensors, TankTraps, FieldTurrets, ShieldGenerators, Telepads = Value
Boomers,
Mines,
SmallTurrets,
Sensors,
TankTraps,
FieldTurrets,
ShieldGenerators,
Telepads
= Value
} }

View file

@ -4,19 +4,19 @@ package net.psforever.objects.ce
object DeployedItem extends Enumeration { object DeployedItem extends Enumeration {
type Type = Value type Type = Value
final val boomer = Value(148) final val boomer = Value(148)
final val deployable_shield_generator = Value(240) final val deployable_shield_generator = Value(240)
final val he_mine = Value(388) final val he_mine = Value(388)
final val jammer_mine = Value(420) //disruptor mine final val jammer_mine = Value(420) //disruptor mine
final val motionalarmsensor = Value(575) final val motionalarmsensor = Value(575)
final val sensor_shield = Value(752) //sensor disruptor final val sensor_shield = Value(752) //sensor disruptor
final val spitfire_aa = Value(819) //cerebus turret final val spitfire_aa = Value(819) //cerebus turret
final val spitfire_cloaked = Value(825) //shadow turret final val spitfire_cloaked = Value(825) //shadow turret
final val spitfire_turret = Value(826) final val spitfire_turret = Value(826)
final val tank_traps = Value(849) //trap final val tank_traps = Value(849) //trap
final val portable_manned_turret = Value(685) final val portable_manned_turret = Value(685)
final val portable_manned_turret_nc = Value(686) final val portable_manned_turret_nc = Value(686)
final val portable_manned_turret_tr = Value(687) final val portable_manned_turret_tr = Value(687)
final val portable_manned_turret_vs = Value(688) final val portable_manned_turret_vs = Value(688)
final val router_telepad_deployable = Value(744) final val router_telepad_deployable = Value(744)
} }

View file

@ -4,8 +4,7 @@ package net.psforever.objects.ce
import net.psforever.objects.PlanetSideGameObject import net.psforever.objects.PlanetSideGameObject
import net.psforever.objects.definition.SimpleDeployableDefinition import net.psforever.objects.definition.SimpleDeployableDefinition
abstract class SimpleDeployable(cdef : SimpleDeployableDefinition) extends PlanetSideGameObject abstract class SimpleDeployable(cdef: SimpleDeployableDefinition) extends PlanetSideGameObject with Deployable {
with Deployable {
Health = Definition.MaxHealth Health = Definition.MaxHealth
def Definition = cdef def Definition = cdef

View file

@ -10,37 +10,37 @@ import net.psforever.objects.zones.Zone
import net.psforever.types.PlanetSideGUID import net.psforever.types.PlanetSideGUID
trait TelepadLike { trait TelepadLike {
private var router : Option[PlanetSideGUID] = None private var router: Option[PlanetSideGUID] = None
private var activated : Boolean = false private var activated: Boolean = false
def Router : Option[PlanetSideGUID] = router def Router: Option[PlanetSideGUID] = router
def Router_=(rguid : PlanetSideGUID) : Option[PlanetSideGUID] = Router_=(Some(rguid)) def Router_=(rguid: PlanetSideGUID): Option[PlanetSideGUID] = Router_=(Some(rguid))
def Router_=(rguid : Option[PlanetSideGUID]) : Option[PlanetSideGUID] = { def Router_=(rguid: Option[PlanetSideGUID]): Option[PlanetSideGUID] = {
router match { router match {
case None => case None =>
router = rguid router = rguid
case Some(_) => case Some(_) =>
if(rguid.isEmpty || rguid.contains(PlanetSideGUID(0))) { if (rguid.isEmpty || rguid.contains(PlanetSideGUID(0))) {
router = None router = None
} }
} }
Router Router
} }
def Active : Boolean = activated def Active: Boolean = activated
def Active_=(state : Boolean) : Boolean = { def Active_=(state: Boolean): Boolean = {
activated = state activated = state
Active Active
} }
} }
object TelepadLike { object TelepadLike {
final case class Activate(obj : PlanetSideGameObject with TelepadLike) final case class Activate(obj: PlanetSideGameObject with TelepadLike)
final case class Deactivate(obj : PlanetSideGameObject with TelepadLike) final case class Deactivate(obj: PlanetSideGameObject with TelepadLike)
/** /**
* Assemble some logic for a provided object. * Assemble some logic for a provided object.
@ -48,10 +48,10 @@ object TelepadLike {
* anticipating a `Terminal` object using this same definition * anticipating a `Terminal` object using this same definition
* @param context hook to the local `Actor` system * @param context hook to the local `Actor` system
*/ */
def Setup(obj : Amenity, context : ActorContext) : Unit = { def Setup(obj: Amenity, context: ActorContext): Unit = {
obj.asInstanceOf[TelepadLike].Router = obj.Owner.GUID obj.asInstanceOf[TelepadLike].Router = obj.Owner.GUID
import akka.actor.Props import akka.actor.Props
if(obj.Actor == Default.Actor) { if (obj.Actor == Default.Actor) {
obj.Actor = context.actorOf(Props(classOf[TelepadControl], obj), PlanetSideServerObject.UniqueActorName(obj)) obj.Actor = context.actorOf(Props(classOf[TelepadControl], obj), PlanetSideServerObject.UniqueActorName(obj))
} }
} }
@ -64,20 +64,19 @@ object TelepadLike {
* @param zone where the router is located * @param zone where the router is located
* @return the pair of units that compose the teleportation system * @return the pair of units that compose the teleportation system
*/ */
def AppraiseTeleportationSystem(router : Vehicle, zone : Zone) : Option[(Utility.InternalTelepad, TelepadDeployable)] = { def AppraiseTeleportationSystem(router: Vehicle, zone: Zone): Option[(Utility.InternalTelepad, TelepadDeployable)] = {
import net.psforever.objects.vehicles.UtilityType import net.psforever.objects.vehicles.UtilityType
import net.psforever.types.DriveState import net.psforever.types.DriveState
router.Utility(UtilityType.internal_router_telepad_deployable) match { router.Utility(UtilityType.internal_router_telepad_deployable) match {
//if the vehicle has an internal telepad, it is allowed to be a Router (that's a weird way of saying it) //if the vehicle has an internal telepad, it is allowed to be a Router (that's a weird way of saying it)
case Some(util : Utility.InternalTelepad) => case Some(util: Utility.InternalTelepad) =>
//check for a readied remote telepad //check for a readied remote telepad
zone.GUID(util.Telepad) match { zone.GUID(util.Telepad) match {
case Some(telepad : TelepadDeployable) => case Some(telepad: TelepadDeployable) =>
//determine whether to activate both the Router's internal telepad and the deployed remote telepad //determine whether to activate both the Router's internal telepad and the deployed remote telepad
if(router.DeploymentState == DriveState.Deployed && util.Active && telepad.Active) { if (router.DeploymentState == DriveState.Deployed && util.Active && telepad.Active) {
Some((util, telepad)) Some((util, telepad))
} } else {
else {
None None
} }
case _ => case _ =>
@ -96,8 +95,8 @@ object TelepadLike {
* a placeholder like this is easy to reason around. * a placeholder like this is easy to reason around.
* @param obj an entity that extends `TelepadLike` * @param obj an entity that extends `TelepadLike`
*/ */
class TelepadControl(obj : TelepadLike) extends akka.actor.Actor { class TelepadControl(obj: TelepadLike) extends akka.actor.Actor {
def receive : akka.actor.Actor.Receive = { def receive: akka.actor.Actor.Receive = {
case _ => ; case _ => ;
} }
} }

View file

@ -4,19 +4,19 @@ package net.psforever.objects.definition
import net.psforever.objects.definition.converter.AmmoBoxConverter import net.psforever.objects.definition.converter.AmmoBoxConverter
import net.psforever.objects.equipment.Ammo import net.psforever.objects.equipment.Ammo
class AmmoBoxDefinition(objectId : Int) extends EquipmentDefinition(objectId) { class AmmoBoxDefinition(objectId: Int) extends EquipmentDefinition(objectId) {
import net.psforever.objects.equipment.EquipmentSize import net.psforever.objects.equipment.EquipmentSize
private val ammoType : Ammo.Value = Ammo(objectId) //let throw NoSuchElementException private val ammoType: Ammo.Value = Ammo(objectId) //let throw NoSuchElementException
private var capacity : Int = 1 private var capacity: Int = 1
Name = "ammo box" Name = "ammo box"
Size = EquipmentSize.Inventory Size = EquipmentSize.Inventory
Packet = AmmoBoxDefinition.converter Packet = AmmoBoxDefinition.converter
def AmmoType : Ammo.Value = ammoType def AmmoType: Ammo.Value = ammoType
def Capacity : Int = capacity def Capacity: Int = capacity
def Capacity_=(capacity : Int) : Int = { def Capacity_=(capacity: Int): Int = {
this.capacity = capacity this.capacity = capacity
Capacity Capacity
} }
@ -25,11 +25,11 @@ class AmmoBoxDefinition(objectId : Int) extends EquipmentDefinition(objectId) {
object AmmoBoxDefinition { object AmmoBoxDefinition {
private val converter = new AmmoBoxConverter() private val converter = new AmmoBoxConverter()
def apply(objectId: Int) : AmmoBoxDefinition = { def apply(objectId: Int): AmmoBoxDefinition = {
new AmmoBoxDefinition(objectId) new AmmoBoxDefinition(objectId)
} }
def apply(ammoType : Ammo.Value) : AmmoBoxDefinition = { def apply(ammoType: Ammo.Value): AmmoBoxDefinition = {
new AmmoBoxDefinition(ammoType.id) new AmmoBoxDefinition(ammoType.id)
} }
} }

View file

@ -9,8 +9,7 @@ import net.psforever.objects.vital.VitalityDefinition
* The definition for game objects that look like other people, and also for players. * The definition for game objects that look like other people, and also for players.
* @param objectId the object's identifier number * @param objectId the object's identifier number
*/ */
class AvatarDefinition(objectId : Int) extends ObjectDefinition(objectId) class AvatarDefinition(objectId: Int) extends ObjectDefinition(objectId) with VitalityDefinition {
with VitalityDefinition {
Avatars(objectId) //let throw NoSuchElementException Avatars(objectId) //let throw NoSuchElementException
Packet = AvatarDefinition.converter Packet = AvatarDefinition.converter
} }
@ -18,11 +17,11 @@ class AvatarDefinition(objectId : Int) extends ObjectDefinition(objectId)
object AvatarDefinition { object AvatarDefinition {
private val converter = new AvatarConverter() private val converter = new AvatarConverter()
def apply(objectId: Int) : AvatarDefinition = { def apply(objectId: Int): AvatarDefinition = {
new AvatarDefinition(objectId) new AvatarDefinition(objectId)
} }
def apply(avatar : Avatars.Value) : AvatarDefinition = { def apply(avatar: Avatars.Value): AvatarDefinition = {
new AvatarDefinition(avatar.id) new AvatarDefinition(avatar.id)
} }
} }

View file

@ -2,21 +2,21 @@
package net.psforever.objects.definition package net.psforever.objects.definition
abstract class BasicDefinition { abstract class BasicDefinition {
private var name : String = "definition" private var name: String = "definition"
private var descriptor : Option[String] = None private var descriptor: Option[String] = None
def Name : String = name def Name: String = name
def Name_=(name : String) : String = { def Name_=(name: String): String = {
this.name = name this.name = name
Name Name
} }
def Descriptor : String = descriptor.getOrElse(Name) def Descriptor: String = descriptor.getOrElse(Name)
def Descriptor_=(description : String) : String = Descriptor_=(Some(description)) def Descriptor_=(description: String): String = Descriptor_=(Some(description))
def Descriptor_=(description : Option[String]) : String = { def Descriptor_=(description: Option[String]): String = {
descriptor = description descriptor = description
Descriptor Descriptor
} }

View file

@ -7,26 +7,28 @@ import net.psforever.objects.vehicles.CargoVehicleRestriction
* The definition for a cargo hold. * The definition for a cargo hold.
*/ */
class CargoDefinition extends BasicDefinition { class CargoDefinition extends BasicDefinition {
/** a restriction on the type of exo-suit a person can wear */ /** a restriction on the type of exo-suit a person can wear */
private var vehicleRestriction : CargoVehicleRestriction.Value = CargoVehicleRestriction.Small private var vehicleRestriction: CargoVehicleRestriction.Value = CargoVehicleRestriction.Small
/** the user can escape while the vehicle is moving */ /** the user can escape while the vehicle is moving */
private var bailable : Boolean = true private var bailable: Boolean = true
Name = "cargo" Name = "cargo"
def CargoRestriction : CargoVehicleRestriction.Value = { def CargoRestriction: CargoVehicleRestriction.Value = {
this.vehicleRestriction this.vehicleRestriction
} }
def CargoRestriction_=(restriction : CargoVehicleRestriction.Value) : CargoVehicleRestriction.Value = { def CargoRestriction_=(restriction: CargoVehicleRestriction.Value): CargoVehicleRestriction.Value = {
this.vehicleRestriction = restriction this.vehicleRestriction = restriction
restriction restriction
} }
def Bailable : Boolean = { def Bailable: Boolean = {
this.bailable this.bailable
} }
def Bailable_=(canBail : Boolean) : Boolean = { def Bailable_=(canBail: Boolean): Boolean = {
this.bailable = canBail this.bailable = canBail
canBail canBail
} }

View file

@ -8,39 +8,39 @@ import net.psforever.types.CertificationType
import scala.collection.mutable.ListBuffer import scala.collection.mutable.ListBuffer
class ConstructionItemDefinition(objectId : Int) extends EquipmentDefinition(objectId) { class ConstructionItemDefinition(objectId: Int) extends EquipmentDefinition(objectId) {
CItem(objectId) //let throw NoSuchElementException CItem(objectId) //let throw NoSuchElementException
private val modes : ListBuffer[ConstructionFireMode] = ListBuffer() private val modes: ListBuffer[ConstructionFireMode] = ListBuffer()
Packet = new ACEConverter Packet = new ACEConverter
def Modes : ListBuffer[ConstructionFireMode] = modes def Modes: ListBuffer[ConstructionFireMode] = modes
} }
object ConstructionItemDefinition { object ConstructionItemDefinition {
def apply(objectId : Int) : ConstructionItemDefinition = { def apply(objectId: Int): ConstructionItemDefinition = {
new ConstructionItemDefinition(objectId) new ConstructionItemDefinition(objectId)
} }
def apply(cItem : CItem.Value) : ConstructionItemDefinition = { def apply(cItem: CItem.Value): ConstructionItemDefinition = {
new ConstructionItemDefinition(cItem.id) new ConstructionItemDefinition(cItem.id)
} }
} }
class ConstructionFireMode { class ConstructionFireMode {
private val deployables : ListBuffer[DeployedItem.Value] = ListBuffer.empty private val deployables: ListBuffer[DeployedItem.Value] = ListBuffer.empty
private val permissions : ListBuffer[Set[CertificationType.Value]] = ListBuffer.empty private val permissions: ListBuffer[Set[CertificationType.Value]] = ListBuffer.empty
def Permissions : ListBuffer[Set[CertificationType.Value]] = permissions def Permissions: ListBuffer[Set[CertificationType.Value]] = permissions
def Deployables : ListBuffer[DeployedItem.Value] = deployables def Deployables: ListBuffer[DeployedItem.Value] = deployables
def Item(deployable : DeployedItem.Value) : ListBuffer[DeployedItem.Value] = { def Item(deployable: DeployedItem.Value): ListBuffer[DeployedItem.Value] = {
deployables += deployable deployables += deployable
permissions += Set.empty[CertificationType.Value] permissions += Set.empty[CertificationType.Value]
deployables deployables
} }
def Item(deployPair : (DeployedItem.Value, Set[CertificationType.Value])) : ListBuffer[DeployedItem.Value] = { def Item(deployPair: (DeployedItem.Value, Set[CertificationType.Value])): ListBuffer[DeployedItem.Value] = {
val (deployable, permission) = deployPair val (deployable, permission) = deployPair
deployables += deployable deployables += deployable
permissions += permission permissions += permission

View file

@ -8,31 +8,34 @@ import net.psforever.objects.inventory.InventoryTile
* The definition for any piece of `Equipment`. * The definition for any piece of `Equipment`.
* @param objectId the object's identifier number * @param objectId the object's identifier number
*/ */
abstract class EquipmentDefinition(objectId : Int) extends ObjectDefinition(objectId) { abstract class EquipmentDefinition(objectId: Int) extends ObjectDefinition(objectId) {
/** the size of the item when placed in an EquipmentSlot / holster / mounting */ /** the size of the item when placed in an EquipmentSlot / holster / mounting */
private var size : EquipmentSize.Value = EquipmentSize.Blocked private var size: EquipmentSize.Value = EquipmentSize.Blocked
/** the size of the item when placed in the grid inventory space */ /** the size of the item when placed in the grid inventory space */
private var tile : InventoryTile = InventoryTile.Tile11 private var tile: InventoryTile = InventoryTile.Tile11
/** a correction for the z-coordinate for some dropped items to avoid sinking into the ground */ /** a correction for the z-coordinate for some dropped items to avoid sinking into the ground */
private var dropOffset : Float = 0f private var dropOffset: Float = 0f
def Size : EquipmentSize.Value = size def Size: EquipmentSize.Value = size
def Size_=(newSize : EquipmentSize.Value) : EquipmentSize.Value = { def Size_=(newSize: EquipmentSize.Value): EquipmentSize.Value = {
size = newSize size = newSize
Size Size
} }
def Tile : InventoryTile = tile def Tile: InventoryTile = tile
def Tile_=(newTile : InventoryTile) : InventoryTile = { def Tile_=(newTile: InventoryTile): InventoryTile = {
tile = newTile tile = newTile
Tile Tile
} }
def DropOffset : Float = dropOffset def DropOffset: Float = dropOffset
def DropOffset(offset : Float) : Float = { def DropOffset(offset: Float): Float = {
dropOffset = offset dropOffset = offset
DropOffset DropOffset
} }

View file

@ -13,112 +13,112 @@ import net.psforever.types.{CertificationType, ExoSuitType, PlanetSideEmpire}
* Players are influenced by the exo-suit they wear in a variety of ways, with speed and available equipment slots being major differences. * Players are influenced by the exo-suit they wear in a variety of ways, with speed and available equipment slots being major differences.
* @param suitType the `Enumeration` corresponding to this exo-suit * @param suitType the `Enumeration` corresponding to this exo-suit
*/ */
class ExoSuitDefinition(private val suitType : ExoSuitType.Value) extends BasicDefinition class ExoSuitDefinition(private val suitType: ExoSuitType.Value)
with ResistanceProfileMutators extends BasicDefinition
with DamageResistanceModel { with ResistanceProfileMutators
protected var permissions : List[CertificationType.Value] = List.empty with DamageResistanceModel {
protected var maxArmor : Int = 0 protected var permissions: List[CertificationType.Value] = List.empty
protected val holsters : Array[EquipmentSize.Value] = Array.fill[EquipmentSize.Value](5)(EquipmentSize.Blocked) protected var maxArmor: Int = 0
protected var inventoryScale : InventoryTile = InventoryTile.Tile11 //override with custom InventoryTile protected val holsters: Array[EquipmentSize.Value] = Array.fill[EquipmentSize.Value](5)(EquipmentSize.Blocked)
protected var inventoryOffset : Int = 0 protected var inventoryScale: InventoryTile = InventoryTile.Tile11 //override with custom InventoryTile
protected var maxCapacitor : Int = 0 protected var inventoryOffset: Int = 0
protected var capacitorRechargeDelayMillis : Int = 0 protected var maxCapacitor: Int = 0
protected var capacitorRechargePerSecond : Int = 0 protected var capacitorRechargeDelayMillis: Int = 0
protected var capacitorDrainPerSecond : Int = 0 protected var capacitorRechargePerSecond: Int = 0
protected var capacitorDrainPerSecond: Int = 0
Name = "exo-suit" Name = "exo-suit"
DamageUsing = StandardInfantryDamage DamageUsing = StandardInfantryDamage
ResistUsing = StandardInfantryResistance ResistUsing = StandardInfantryResistance
Model = StandardResolutions.Infantry Model = StandardResolutions.Infantry
def SuitType : ExoSuitType.Value = suitType def SuitType: ExoSuitType.Value = suitType
def MaxArmor : Int = maxArmor def MaxArmor: Int = maxArmor
def MaxArmor_=(armor : Int) : Int = { def MaxArmor_=(armor: Int): Int = {
maxArmor = math.min(math.max(0, armor), 65535) maxArmor = math.min(math.max(0, armor), 65535)
MaxArmor MaxArmor
} }
def MaxCapacitor : Int = maxCapacitor def MaxCapacitor: Int = maxCapacitor
def MaxCapacitor_=(value : Int) : Int = { def MaxCapacitor_=(value: Int): Int = {
maxCapacitor = value maxCapacitor = value
maxCapacitor maxCapacitor
} }
def CapacitorRechargeDelayMillis : Int = capacitorRechargeDelayMillis def CapacitorRechargeDelayMillis: Int = capacitorRechargeDelayMillis
def CapacitorRechargeDelayMillis_=(value : Int) : Int = { def CapacitorRechargeDelayMillis_=(value: Int): Int = {
capacitorRechargeDelayMillis = value capacitorRechargeDelayMillis = value
capacitorRechargeDelayMillis capacitorRechargeDelayMillis
} }
def CapacitorRechargePerSecond : Int = capacitorRechargePerSecond def CapacitorRechargePerSecond: Int = capacitorRechargePerSecond
def CapacitorRechargePerSecond_=(value : Int) : Int = { def CapacitorRechargePerSecond_=(value: Int): Int = {
capacitorRechargePerSecond = value capacitorRechargePerSecond = value
capacitorRechargePerSecond capacitorRechargePerSecond
} }
def CapacitorDrainPerSecond : Int = capacitorDrainPerSecond def CapacitorDrainPerSecond: Int = capacitorDrainPerSecond
def CapacitorDrainPerSecond_=(value : Int) : Int = { def CapacitorDrainPerSecond_=(value: Int): Int = {
capacitorDrainPerSecond = value capacitorDrainPerSecond = value
capacitorDrainPerSecond capacitorDrainPerSecond
} }
def InventoryScale : InventoryTile = inventoryScale def InventoryScale: InventoryTile = inventoryScale
def InventoryScale_=(scale : InventoryTile) : InventoryTile = { def InventoryScale_=(scale: InventoryTile): InventoryTile = {
inventoryScale = scale inventoryScale = scale
InventoryScale InventoryScale
} }
def InventoryOffset : Int = inventoryOffset def InventoryOffset: Int = inventoryOffset
def InventoryOffset_=(offset : Int) : Int = { def InventoryOffset_=(offset: Int): Int = {
inventoryOffset = math.min(math.max(0, offset), 65535) inventoryOffset = math.min(math.max(0, offset), 65535)
InventoryOffset InventoryOffset
} }
def Holsters : Array[EquipmentSize.Value] = holsters def Holsters: Array[EquipmentSize.Value] = holsters
def Holster(slot : Int) : EquipmentSize.Value = { def Holster(slot: Int): EquipmentSize.Value = {
if(slot >= 0 && slot < 5) { if (slot >= 0 && slot < 5) {
holsters(slot) holsters(slot)
} } else {
else {
EquipmentSize.Blocked EquipmentSize.Blocked
} }
} }
def Holster(slot : Int, value : EquipmentSize.Value) : EquipmentSize.Value = { def Holster(slot: Int, value: EquipmentSize.Value): EquipmentSize.Value = {
if(slot >= 0 && slot < 5) { if (slot >= 0 && slot < 5) {
holsters(slot) = value holsters(slot) = value
holsters(slot) holsters(slot)
} } else {
else {
EquipmentSize.Blocked EquipmentSize.Blocked
} }
} }
def Permissions : List[CertificationType.Value] = permissions def Permissions: List[CertificationType.Value] = permissions
def Permissions_=(certs : List[CertificationType.Value]) : List[CertificationType.Value] = { def Permissions_=(certs: List[CertificationType.Value]): List[CertificationType.Value] = {
permissions = certs permissions = certs
Permissions Permissions
} }
def Use : ExoSuitDefinition = this def Use: ExoSuitDefinition = this
def canEqual(other: Any): Boolean = other.isInstanceOf[ExoSuitDefinition] def canEqual(other: Any): Boolean = other.isInstanceOf[ExoSuitDefinition]
override def equals(other: Any): Boolean = other match { override def equals(other: Any): Boolean =
case that: ExoSuitDefinition => other match {
(that canEqual this) && case that: ExoSuitDefinition =>
suitType == that.suitType (that canEqual this) &&
case _ => false suitType == that.suitType
} case _ => false
}
override def hashCode(): Int = { override def hashCode(): Int = {
val state = Seq(suitType) val state = Seq(suitType)
@ -126,20 +126,20 @@ class ExoSuitDefinition(private val suitType : ExoSuitType.Value) extends BasicD
} }
} }
class SpecialExoSuitDefinition(private val suitType : ExoSuitType.Value) extends ExoSuitDefinition(suitType) { class SpecialExoSuitDefinition(private val suitType: ExoSuitType.Value) extends ExoSuitDefinition(suitType) {
Name = "heavy_armor" Name = "heavy_armor"
Descriptor = "heavy_armor" Descriptor = "heavy_armor"
private var activatedSpecial : SpecialExoSuitDefinition.Mode.Value = SpecialExoSuitDefinition.Mode.Normal private var activatedSpecial: SpecialExoSuitDefinition.Mode.Value = SpecialExoSuitDefinition.Mode.Normal
def UsingSpecial : SpecialExoSuitDefinition.Mode.Value = activatedSpecial def UsingSpecial: SpecialExoSuitDefinition.Mode.Value = activatedSpecial
def UsingSpecial_=(state : SpecialExoSuitDefinition.Mode.Value) : SpecialExoSuitDefinition.Mode.Value = { def UsingSpecial_=(state: SpecialExoSuitDefinition.Mode.Value): SpecialExoSuitDefinition.Mode.Value = {
activatedSpecial = state activatedSpecial = state
UsingSpecial UsingSpecial
} }
override def Use : ExoSuitDefinition = { override def Use: ExoSuitDefinition = {
val obj = new SpecialExoSuitDefinition(SuitType) val obj = new SpecialExoSuitDefinition(SuitType)
obj.Permissions = Permissions obj.Permissions = Permissions
obj.MaxArmor = MaxArmor obj.MaxArmor = MaxArmor
@ -165,24 +165,19 @@ class SpecialExoSuitDefinition(private val suitType : ExoSuitType.Value) extends
} }
object SpecialExoSuitDefinition { object SpecialExoSuitDefinition {
def apply(suitType : ExoSuitType.Value) : SpecialExoSuitDefinition = { def apply(suitType: ExoSuitType.Value): SpecialExoSuitDefinition = {
new SpecialExoSuitDefinition(suitType) new SpecialExoSuitDefinition(suitType)
} }
object Mode extends Enumeration { object Mode extends Enumeration {
type Type = Value type Type = Value
val val Normal, Anchored, Overdrive, Shielded = Value
Normal,
Anchored,
Overdrive,
Shielded
= Value
} }
} }
object ExoSuitDefinition { object ExoSuitDefinition {
def apply(suitType : ExoSuitType.Value) : ExoSuitDefinition = { def apply(suitType: ExoSuitType.Value): ExoSuitDefinition = {
new ExoSuitDefinition(suitType) new ExoSuitDefinition(suitType)
} }
@ -192,16 +187,17 @@ object ExoSuitDefinition {
* @param faction the faction the player belongs to for this exosuit * @param faction the faction the player belongs to for this exosuit
* @return the exo-suit definition * @return the exo-suit definition
*/ */
def Select(suit : ExoSuitType.Value, faction : PlanetSideEmpire.Value) : ExoSuitDefinition = { def Select(suit: ExoSuitType.Value, faction: PlanetSideEmpire.Value): ExoSuitDefinition = {
suit match { suit match {
case ExoSuitType.Infiltration => GlobalDefinitions.Infiltration.Use case ExoSuitType.Infiltration => GlobalDefinitions.Infiltration.Use
case ExoSuitType.Agile => GlobalDefinitions.Agile.Use case ExoSuitType.Agile => GlobalDefinitions.Agile.Use
case ExoSuitType.Reinforced => GlobalDefinitions.Reinforced.Use case ExoSuitType.Reinforced => GlobalDefinitions.Reinforced.Use
case ExoSuitType.MAX => faction match { case ExoSuitType.MAX =>
case PlanetSideEmpire.TR => GlobalDefinitions.TRMAX.Use faction match {
case PlanetSideEmpire.NC => GlobalDefinitions.NCMAX.Use case PlanetSideEmpire.TR => GlobalDefinitions.TRMAX.Use
case PlanetSideEmpire.VS => GlobalDefinitions.VSMAX.Use case PlanetSideEmpire.NC => GlobalDefinitions.NCMAX.Use
} case PlanetSideEmpire.VS => GlobalDefinitions.VSMAX.Use
}
case _ => GlobalDefinitions.Standard.Use case _ => GlobalDefinitions.Standard.Use
} }
} }

View file

@ -17,16 +17,20 @@ import scala.collection.mutable
* @param implantType the type of implant that is defined * @param implantType the type of implant that is defined
* @see `ImplantType` * @see `ImplantType`
*/ */
class ImplantDefinition(private val implantType : Int) extends BasicDefinition { class ImplantDefinition(private val implantType: Int) extends BasicDefinition {
ImplantType(implantType) ImplantType(implantType)
/** how long it takes the implant to become ready for activation; is milliseconds */ /** how long it takes the implant to become ready for activation; is milliseconds */
private var initializationDuration : Long = 0L private var initializationDuration: Long = 0L
/** a passive certification is activated as soon as it is ready (or other condition) */ /** a passive certification is activated as soon as it is ready (or other condition) */
private var passive : Boolean = false private var passive: Boolean = false
/** how much turning on the implant costs */ /** how much turning on the implant costs */
private var activationStaminaCost : Int = 0 private var activationStaminaCost: Int = 0
/** how much energy does this implant cost to remain activate per interval tick */ /** how much energy does this implant cost to remain activate per interval tick */
private var staminaCost : Int = 0 private var staminaCost: Int = 0
/** /**
* How often in milliseconds the stamina cost will be applied, per exo-suit type * How often in milliseconds the stamina cost will be applied, per exo-suit type
@ -37,59 +41,59 @@ class ImplantDefinition(private val implantType : Int) extends BasicDefinition {
* stamina_consumption_interval3 = Rexo * stamina_consumption_interval3 = Rexo
* stamina_consumption_interval4 = MAX? * stamina_consumption_interval4 = MAX?
*/ */
private var costIntervalDefault : Int = 0 private var costIntervalDefault: Int = 0
private val costIntervalByExoSuit = mutable.HashMap[ExoSuitType.Value, Int]().withDefaultValue(CostIntervalDefault) private val costIntervalByExoSuit = mutable.HashMap[ExoSuitType.Value, Int]().withDefaultValue(CostIntervalDefault)
Name = "implant" Name = "implant"
def InitializationDuration : Long = initializationDuration def InitializationDuration: Long = initializationDuration
def InitializationDuration_=(time : Long) : Long = { def InitializationDuration_=(time: Long): Long = {
initializationDuration = math.max(0, time) initializationDuration = math.max(0, time)
InitializationDuration InitializationDuration
} }
def Passive : Boolean = passive def Passive: Boolean = passive
def Passive_=(isPassive : Boolean) : Boolean = { def Passive_=(isPassive: Boolean): Boolean = {
passive = isPassive passive = isPassive
Passive Passive
} }
def ActivationStaminaCost : Int = activationStaminaCost def ActivationStaminaCost: Int = activationStaminaCost
def ActivationStaminaCost_=(charge : Int) : Int = { def ActivationStaminaCost_=(charge: Int): Int = {
activationStaminaCost = math.max(0, charge) activationStaminaCost = math.max(0, charge)
ActivationStaminaCost ActivationStaminaCost
} }
def StaminaCost : Int = staminaCost def StaminaCost: Int = staminaCost
def StaminaCost_=(charge : Int) : Int = { def StaminaCost_=(charge: Int): Int = {
staminaCost = math.max(0, charge) staminaCost = math.max(0, charge)
StaminaCost StaminaCost
} }
def CostIntervalDefault: Int = {
def CostIntervalDefault : Int = {
costIntervalDefault costIntervalDefault
} }
def CostIntervalDefault_=(interval : Int) : Int = { def CostIntervalDefault_=(interval: Int): Int = {
costIntervalDefault = interval costIntervalDefault = interval
CostIntervalDefault CostIntervalDefault
} }
def GetCostIntervalByExoSuit(exosuit : ExoSuitType.Value) : Int = costIntervalByExoSuit.getOrElse(exosuit, CostIntervalDefault) def GetCostIntervalByExoSuit(exosuit: ExoSuitType.Value): Int =
def CostIntervalByExoSuitHashMap : mutable.Map[ExoSuitType.Value, Int] = costIntervalByExoSuit costIntervalByExoSuit.getOrElse(exosuit, CostIntervalDefault)
def CostIntervalByExoSuitHashMap: mutable.Map[ExoSuitType.Value, Int] = costIntervalByExoSuit
def Type : ImplantType.Value = ImplantType(implantType) def Type: ImplantType.Value = ImplantType(implantType)
} }
object ImplantDefinition { object ImplantDefinition {
def apply(implantType : Int) : ImplantDefinition = { def apply(implantType: Int): ImplantDefinition = {
new ImplantDefinition(implantType) new ImplantDefinition(implantType)
} }
def apply(implantType : ImplantType.Value) : ImplantDefinition = { def apply(implantType: ImplantType.Value): ImplantDefinition = {
new ImplantDefinition(implantType.id) new ImplantDefinition(implantType.id)
} }
} }

View file

@ -8,7 +8,7 @@ import net.psforever.objects.equipment.Kits
* The definition for a personal one-time-use recovery item. * The definition for a personal one-time-use recovery item.
* @param objectId the object's identifier number * @param objectId the object's identifier number
*/ */
class KitDefinition(objectId : Int) extends EquipmentDefinition(objectId) { class KitDefinition(objectId: Int) extends EquipmentDefinition(objectId) {
import net.psforever.objects.equipment.EquipmentSize import net.psforever.objects.equipment.EquipmentSize
import net.psforever.objects.inventory.InventoryTile import net.psforever.objects.inventory.InventoryTile
Kits(objectId) //let throw NoSuchElementException Kits(objectId) //let throw NoSuchElementException
@ -21,11 +21,11 @@ class KitDefinition(objectId : Int) extends EquipmentDefinition(objectId) {
object KitDefinition { object KitDefinition {
private val converter = new KitConverter() private val converter = new KitConverter()
def apply(objectId: Int) : KitDefinition = { def apply(objectId: Int): KitDefinition = {
new KitDefinition(objectId) new KitDefinition(objectId)
} }
def apply(kit : Kits.Value) : KitDefinition = { def apply(kit: Kits.Value): KitDefinition = {
new KitDefinition(kit.id) new KitDefinition(kit.id)
} }
} }

View file

@ -17,26 +17,28 @@ import net.psforever.objects.definition.converter.{ObjectCreateConverter, Packet
* So long as it is an `ObjectCreatePacket`, those methods can be called correctly for a game object of the desired type. * So long as it is an `ObjectCreatePacket`, those methods can be called correctly for a game object of the desired type.
* @param objectId the object's identifier number * @param objectId the object's identifier number
*/ */
abstract class ObjectDefinition(private val objectId : Int) extends BasicDefinition { abstract class ObjectDefinition(private val objectId: Int) extends BasicDefinition {
/** a data converter for this type of object */ /** a data converter for this type of object */
protected var packet : PacketConverter = new ObjectCreateConverter[PlanetSideGameObject]() { } protected var packet: PacketConverter = new ObjectCreateConverter[PlanetSideGameObject]() {}
Name = "object definition" Name = "object definition"
/** /**
* Get the conversion object. * Get the conversion object.
* @return * @return
*/ */
final def Packet : ObjectCreateConverter[PlanetSideGameObject] = packet.asInstanceOf[ObjectCreateConverter[PlanetSideGameObject]] final def Packet: ObjectCreateConverter[PlanetSideGameObject] =
packet.asInstanceOf[ObjectCreateConverter[PlanetSideGameObject]]
/** /**
* Assign this definition a conversion object. * Assign this definition a conversion object.
* @param pkt the new converter * @param pkt the new converter
* @return the current converter, after assignment * @return the current converter, after assignment
*/ */
final def Packet_=(pkt : ObjectCreateConverter[_]) : PacketConverter = { final def Packet_=(pkt: ObjectCreateConverter[_]): PacketConverter = {
packet = pkt packet = pkt
Packet Packet
} }
def ObjectId : Int = objectId def ObjectId: Int = objectId
} }

View file

@ -10,168 +10,170 @@ import net.psforever.objects.vital.{DamageType, StandardDamageProfile}
* `Tool` objects emit `ProjectileDefinition` objects and that is later wrapped into a `Projectile` object. * `Tool` objects emit `ProjectileDefinition` objects and that is later wrapped into a `Projectile` object.
* @param objectId the object's identifier number * @param objectId the object's identifier number
*/ */
class ProjectileDefinition(objectId : Int) extends ObjectDefinition(objectId) class ProjectileDefinition(objectId: Int)
with JammingUnit extends ObjectDefinition(objectId)
with StandardDamageProfile { with JammingUnit
private val projectileType : Projectiles.Value = Projectiles(objectId) //let throw NoSuchElementException with StandardDamageProfile {
private var acceleration : Int = 0 private val projectileType: Projectiles.Value = Projectiles(objectId) //let throw NoSuchElementException
private var accelerationUntil : Float = 0f private var acceleration: Int = 0
private var damageType : DamageType.Value = DamageType.None private var accelerationUntil: Float = 0f
private var damageTypeSecondary : DamageType.Value = DamageType.None private var damageType: DamageType.Value = DamageType.None
private var degradeDelay : Float = 1f private var damageTypeSecondary: DamageType.Value = DamageType.None
private var degradeMultiplier : Float = 1f private var degradeDelay: Float = 1f
private var initialVelocity : Int = 1 private var degradeMultiplier: Float = 1f
private var lifespan : Float = 1f private var initialVelocity: Int = 1
private var damageAtEdge : Float = 1f private var lifespan: Float = 1f
private var damageRadius : Float = 1f private var damageAtEdge: Float = 1f
private var useDamage1Subtract : Boolean = false private var damageRadius: Float = 1f
private var existsOnRemoteClients : Boolean = false //`true` spawns a server-managed object private var useDamage1Subtract: Boolean = false
private var remoteClientData : (Int, Int) = (0, 0) //artificial values; for ObjectCreateMessage packet (oicw_little_buddy is undefined) private var existsOnRemoteClients: Boolean = false //`true` spawns a server-managed object
private var autoLock : Boolean = false private var remoteClientData: (Int, Int) =
private var additionalEffect : Boolean = false (0, 0) //artificial values; for ObjectCreateMessage packet (oicw_little_buddy is undefined)
private var jammerProjectile : Boolean = false private var autoLock: Boolean = false
private var additionalEffect: Boolean = false
private var jammerProjectile: Boolean = false
//derived calculations //derived calculations
private var distanceMax : Float = 0f private var distanceMax: Float = 0f
private var distanceFromAcceleration : Float = 0f private var distanceFromAcceleration: Float = 0f
private var distanceNoDegrade : Float = 0f private var distanceNoDegrade: Float = 0f
private var finalVelocity : Float = 0f private var finalVelocity: Float = 0f
Name = "projectile" Name = "projectile"
def ProjectileType : Projectiles.Value = projectileType def ProjectileType: Projectiles.Value = projectileType
def UseDamage1Subtract : Boolean = useDamage1Subtract def UseDamage1Subtract: Boolean = useDamage1Subtract
def UseDamage1Subtract_=(useDamage1Subtract : Boolean) : Boolean = { def UseDamage1Subtract_=(useDamage1Subtract: Boolean): Boolean = {
this.useDamage1Subtract = useDamage1Subtract this.useDamage1Subtract = useDamage1Subtract
UseDamage1Subtract UseDamage1Subtract
} }
def Acceleration : Int = acceleration def Acceleration: Int = acceleration
def Acceleration_=(accel : Int) : Int = { def Acceleration_=(accel: Int): Int = {
acceleration = accel acceleration = accel
Acceleration Acceleration
} }
def AccelerationUntil : Float = accelerationUntil def AccelerationUntil: Float = accelerationUntil
def AccelerationUntil_=(accelUntil : Float) : Float = { def AccelerationUntil_=(accelUntil: Float): Float = {
accelerationUntil = accelUntil accelerationUntil = accelUntil
AccelerationUntil AccelerationUntil
} }
def ProjectileDamageType : DamageType.Value = damageType def ProjectileDamageType: DamageType.Value = damageType
def ProjectileDamageType_=(damageType1 : DamageType.Value) : DamageType.Value = { def ProjectileDamageType_=(damageType1: DamageType.Value): DamageType.Value = {
damageType = damageType1 damageType = damageType1
ProjectileDamageType ProjectileDamageType
} }
def ProjectileDamageTypeSecondary : DamageType.Value = damageTypeSecondary def ProjectileDamageTypeSecondary: DamageType.Value = damageTypeSecondary
def ProjectileDamageTypeSecondary_=(damageTypeSecondary1 : DamageType.Value) : DamageType.Value = { def ProjectileDamageTypeSecondary_=(damageTypeSecondary1: DamageType.Value): DamageType.Value = {
damageTypeSecondary = damageTypeSecondary1 damageTypeSecondary = damageTypeSecondary1
ProjectileDamageTypeSecondary ProjectileDamageTypeSecondary
} }
def DegradeDelay : Float = degradeDelay def DegradeDelay: Float = degradeDelay
def DegradeDelay_=(degradeDelay : Float) : Float = { def DegradeDelay_=(degradeDelay: Float): Float = {
this.degradeDelay = degradeDelay this.degradeDelay = degradeDelay
DegradeDelay DegradeDelay
} }
def DegradeMultiplier : Float = degradeMultiplier def DegradeMultiplier: Float = degradeMultiplier
def DegradeMultiplier_=(degradeMultiplier : Float) : Float = { def DegradeMultiplier_=(degradeMultiplier: Float): Float = {
this.degradeMultiplier = degradeMultiplier this.degradeMultiplier = degradeMultiplier
DegradeMultiplier DegradeMultiplier
} }
def InitialVelocity : Int = initialVelocity def InitialVelocity: Int = initialVelocity
def InitialVelocity_=(initialVelocity : Int) : Int = { def InitialVelocity_=(initialVelocity: Int): Int = {
this.initialVelocity = initialVelocity this.initialVelocity = initialVelocity
InitialVelocity InitialVelocity
} }
def Lifespan : Float = lifespan def Lifespan: Float = lifespan
def Lifespan_=(lifespan : Float) : Float = { def Lifespan_=(lifespan: Float): Float = {
this.lifespan = lifespan this.lifespan = lifespan
Lifespan Lifespan
} }
def DamageAtEdge : Float = damageAtEdge def DamageAtEdge: Float = damageAtEdge
def DamageAtEdge_=(damageAtEdge : Float) : Float = { def DamageAtEdge_=(damageAtEdge: Float): Float = {
this.damageAtEdge = damageAtEdge this.damageAtEdge = damageAtEdge
DamageAtEdge DamageAtEdge
} }
def DamageRadius : Float = damageRadius def DamageRadius: Float = damageRadius
def DamageRadius_=(damageRadius : Float) : Float = { def DamageRadius_=(damageRadius: Float): Float = {
this.damageRadius = damageRadius this.damageRadius = damageRadius
DamageRadius DamageRadius
} }
def ExistsOnRemoteClients : Boolean = existsOnRemoteClients def ExistsOnRemoteClients: Boolean = existsOnRemoteClients
def ExistsOnRemoteClients_=(existsOnRemoteClients : Boolean) : Boolean = { def ExistsOnRemoteClients_=(existsOnRemoteClients: Boolean): Boolean = {
this.existsOnRemoteClients = existsOnRemoteClients this.existsOnRemoteClients = existsOnRemoteClients
ExistsOnRemoteClients ExistsOnRemoteClients
} }
def RemoteClientData : (Int, Int) = remoteClientData def RemoteClientData: (Int, Int) = remoteClientData
def RemoteClientData_=(remoteClientData : (Int, Int)) : (Int, Int) = { def RemoteClientData_=(remoteClientData: (Int, Int)): (Int, Int) = {
this.remoteClientData = remoteClientData this.remoteClientData = remoteClientData
RemoteClientData RemoteClientData
} }
def AutoLock : Boolean = autoLock def AutoLock: Boolean = autoLock
def AutoLock_=(lockState : Boolean) : Boolean = { def AutoLock_=(lockState: Boolean): Boolean = {
autoLock = lockState autoLock = lockState
AutoLock AutoLock
} }
def AdditionalEffect : Boolean = additionalEffect def AdditionalEffect: Boolean = additionalEffect
def AdditionalEffect_=(effect : Boolean) : Boolean = { def AdditionalEffect_=(effect: Boolean): Boolean = {
additionalEffect = effect additionalEffect = effect
AdditionalEffect AdditionalEffect
} }
def JammerProjectile : Boolean = jammerProjectile def JammerProjectile: Boolean = jammerProjectile
def JammerProjectile_=(effect : Boolean) : Boolean = { def JammerProjectile_=(effect: Boolean): Boolean = {
jammerProjectile = effect jammerProjectile = effect
JammerProjectile JammerProjectile
} }
def DistanceMax : Float = distanceMax //accessor only def DistanceMax: Float = distanceMax //accessor only
def DistanceFromAcceleration : Float = distanceFromAcceleration //accessor only def DistanceFromAcceleration: Float = distanceFromAcceleration //accessor only
def DistanceNoDegrade : Float = distanceNoDegrade //accessor only def DistanceNoDegrade: Float = distanceNoDegrade //accessor only
def FinalVelocity : Float = finalVelocity //accessor only def FinalVelocity: Float = finalVelocity //accessor only
} }
object ProjectileDefinition { object ProjectileDefinition {
def apply(projectileType : Projectiles.Value) : ProjectileDefinition = { def apply(projectileType: Projectiles.Value): ProjectileDefinition = {
new ProjectileDefinition(projectileType.id) new ProjectileDefinition(projectileType.id)
} }
def CalculateDerivedFields(pdef : ProjectileDefinition) : Unit = { def CalculateDerivedFields(pdef: ProjectileDefinition): Unit = {
val (distanceMax, distanceFromAcceleration, finalVelocity) : (Float, Float, Float) = if(pdef.Acceleration == 0) { val (distanceMax, distanceFromAcceleration, finalVelocity): (Float, Float, Float) = if (pdef.Acceleration == 0) {
(pdef.InitialVelocity * pdef.Lifespan, 0, pdef.InitialVelocity.toFloat) (pdef.InitialVelocity * pdef.Lifespan, 0, pdef.InitialVelocity.toFloat)
} } else {
else { val distanceFromAcceleration =
val distanceFromAcceleration = (pdef.AccelerationUntil * pdef.InitialVelocity) + (0.5f * pdef.Acceleration * pdef.AccelerationUntil * pdef.AccelerationUntil) (pdef.AccelerationUntil * pdef.InitialVelocity) + (0.5f * pdef.Acceleration * pdef.AccelerationUntil * pdef.AccelerationUntil)
val finalVelocity = pdef.InitialVelocity + pdef.Acceleration * pdef.AccelerationUntil val finalVelocity = pdef.InitialVelocity + pdef.Acceleration * pdef.AccelerationUntil
val distanceAfterAcceleration = finalVelocity * (pdef.Lifespan - pdef.AccelerationUntil) val distanceAfterAcceleration = finalVelocity * (pdef.Lifespan - pdef.AccelerationUntil)
(distanceFromAcceleration + distanceAfterAcceleration, distanceFromAcceleration, finalVelocity) (distanceFromAcceleration + distanceAfterAcceleration, distanceFromAcceleration, finalVelocity)
} }
@ -179,13 +181,11 @@ object ProjectileDefinition {
pdef.distanceFromAcceleration = distanceFromAcceleration pdef.distanceFromAcceleration = distanceFromAcceleration
pdef.finalVelocity = finalVelocity pdef.finalVelocity = finalVelocity
pdef.distanceNoDegrade = if(pdef.DegradeDelay == 0f) { pdef.distanceNoDegrade = if (pdef.DegradeDelay == 0f) {
pdef.distanceMax pdef.distanceMax
} } else if (pdef.DegradeDelay < pdef.AccelerationUntil) {
else if(pdef.DegradeDelay < pdef.AccelerationUntil) {
(pdef.DegradeDelay * pdef.InitialVelocity) + (0.5f * pdef.Acceleration * pdef.DegradeDelay * pdef.DegradeDelay) (pdef.DegradeDelay * pdef.InitialVelocity) + (0.5f * pdef.Acceleration * pdef.DegradeDelay * pdef.DegradeDelay)
} } else {
else {
pdef.distanceFromAcceleration + pdef.finalVelocity * (pdef.DegradeDelay - pdef.AccelerationUntil) pdef.distanceFromAcceleration + pdef.finalVelocity * (pdef.DegradeDelay - pdef.AccelerationUntil)
} }
} }

View file

@ -7,41 +7,44 @@ import net.psforever.objects.vehicles.SeatArmorRestriction
* The definition for a seat. * The definition for a seat.
*/ */
class SeatDefinition extends BasicDefinition { class SeatDefinition extends BasicDefinition {
/** a restriction on the type of exo-suit a person can wear */ /** a restriction on the type of exo-suit a person can wear */
private var armorRestriction : SeatArmorRestriction.Value = SeatArmorRestriction.NoMax private var armorRestriction: SeatArmorRestriction.Value = SeatArmorRestriction.NoMax
/** the user can escape while the vehicle is moving */ /** the user can escape while the vehicle is moving */
private var bailable : Boolean = false private var bailable: Boolean = false
/** any controlled weapon */ /** any controlled weapon */
private var weaponMount : Option[Int] = None private var weaponMount: Option[Int] = None
Name = "seat" Name = "seat"
def ArmorRestriction : SeatArmorRestriction.Value = { def ArmorRestriction: SeatArmorRestriction.Value = {
this.armorRestriction this.armorRestriction
} }
def ArmorRestriction_=(restriction : SeatArmorRestriction.Value) : SeatArmorRestriction.Value = { def ArmorRestriction_=(restriction: SeatArmorRestriction.Value): SeatArmorRestriction.Value = {
this.armorRestriction = restriction this.armorRestriction = restriction
restriction restriction
} }
def Bailable : Boolean = { def Bailable: Boolean = {
this.bailable this.bailable
} }
def Bailable_=(canBail : Boolean) : Boolean = { def Bailable_=(canBail: Boolean): Boolean = {
this.bailable = canBail this.bailable = canBail
canBail canBail
} }
def ControlledWeapon : Option[Int] = { def ControlledWeapon: Option[Int] = {
this.weaponMount this.weaponMount
} }
def ControlledWeapon_=(wep : Int) : Option[Int] = { def ControlledWeapon_=(wep: Int): Option[Int] = {
ControlledWeapon_=(Some(wep)) ControlledWeapon_=(Some(wep))
} }
def ControlledWeapon_=(wep : Option[Int]) : Option[Int] = { def ControlledWeapon_=(wep: Option[Int]): Option[Int] = {
this.weaponMount = wep this.weaponMount = wep
ControlledWeapon ControlledWeapon
} }

View file

@ -7,66 +7,72 @@ import net.psforever.objects.ce.{Deployable, DeployableCategory, DeployedItem}
import net.psforever.objects.definition.converter.SmallDeployableConverter import net.psforever.objects.definition.converter.SmallDeployableConverter
import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.vital.resistance.ResistanceProfileMutators import net.psforever.objects.vital.resistance.ResistanceProfileMutators
import net.psforever.objects.vital.{DamageResistanceModel, NoResistanceSelection, StandardDeployableDamage, VitalityDefinition} import net.psforever.objects.vital.{
DamageResistanceModel,
NoResistanceSelection,
StandardDeployableDamage,
VitalityDefinition
}
import scala.concurrent.duration._ import scala.concurrent.duration._
trait BaseDeployableDefinition { trait BaseDeployableDefinition {
private var category : DeployableCategory.Value = DeployableCategory.Boomers private var category: DeployableCategory.Value = DeployableCategory.Boomers
private var deployTime : Long = (1 second).toMillis //ms private var deployTime: Long = (1 second).toMillis //ms
def Item : DeployedItem.Value def Item: DeployedItem.Value
def DeployCategory : DeployableCategory.Value = category def DeployCategory: DeployableCategory.Value = category
def DeployCategory_=(cat : DeployableCategory.Value) : DeployableCategory.Value = { def DeployCategory_=(cat: DeployableCategory.Value): DeployableCategory.Value = {
category = cat category = cat
DeployCategory DeployCategory
} }
def DeployTime : Long = deployTime def DeployTime: Long = deployTime
def DeployTime_=(time : FiniteDuration) : Long = DeployTime_=(time.toMillis) def DeployTime_=(time: FiniteDuration): Long = DeployTime_=(time.toMillis)
def DeployTime_=(time: Long) : Long = { def DeployTime_=(time: Long): Long = {
deployTime = time deployTime = time
DeployTime DeployTime
} }
def Initialize(obj : PlanetSideGameObject with Deployable, context : ActorContext) : Unit = { } def Initialize(obj: PlanetSideGameObject with Deployable, context: ActorContext): Unit = {}
def Initialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) : Unit = { } def Initialize(obj: PlanetSideServerObject with Deployable, context: ActorContext): Unit = {}
def Uninitialize(obj : PlanetSideGameObject with Deployable, context : ActorContext) : Unit = { } def Uninitialize(obj: PlanetSideGameObject with Deployable, context: ActorContext): Unit = {}
def Uninitialize(obj : PlanetSideServerObject with Deployable, context : ActorContext) : Unit = { } def Uninitialize(obj: PlanetSideServerObject with Deployable, context: ActorContext): Unit = {}
} }
abstract class DeployableDefinition(objectId : Int) extends ObjectDefinition(objectId) abstract class DeployableDefinition(objectId: Int)
with DamageResistanceModel extends ObjectDefinition(objectId)
with ResistanceProfileMutators with DamageResistanceModel
with VitalityDefinition with ResistanceProfileMutators
with BaseDeployableDefinition { with VitalityDefinition
with BaseDeployableDefinition {
private val item = DeployedItem(objectId) //let throw NoSuchElementException private val item = DeployedItem(objectId) //let throw NoSuchElementException
DamageUsing = StandardDeployableDamage DamageUsing = StandardDeployableDamage
ResistUsing = NoResistanceSelection ResistUsing = NoResistanceSelection
def Item : DeployedItem.Value = item def Item: DeployedItem.Value = item
} }
class SimpleDeployableDefinition(objectId : Int) extends DeployableDefinition(objectId) { class SimpleDeployableDefinition(objectId: Int) extends DeployableDefinition(objectId) {
Packet = new SmallDeployableConverter Packet = new SmallDeployableConverter
} }
abstract class ComplexDeployableDefinition(objectId : Int) extends DeployableDefinition(objectId) abstract class ComplexDeployableDefinition(objectId: Int) extends DeployableDefinition(objectId)
object SimpleDeployableDefinition { object SimpleDeployableDefinition {
def apply(item : DeployedItem.Value) : SimpleDeployableDefinition = def apply(item: DeployedItem.Value): SimpleDeployableDefinition =
new SimpleDeployableDefinition(item.id) new SimpleDeployableDefinition(item.id)
def SimpleUninitialize(obj : PlanetSideGameObject, context : ActorContext) : Unit = { } def SimpleUninitialize(obj: PlanetSideGameObject, context: ActorContext): Unit = {}
def SimpleUninitialize(obj : PlanetSideServerObject, context : ActorContext) : Unit = { def SimpleUninitialize(obj: PlanetSideServerObject, context: ActorContext): Unit = {
context.stop(obj.Actor) context.stop(obj.Actor)
obj.Actor = Default.Actor obj.Actor = Default.Actor
} }

View file

@ -3,7 +3,7 @@ package net.psforever.objects.definition
import net.psforever.objects.equipment.SItem import net.psforever.objects.equipment.SItem
class SimpleItemDefinition(objectId : Int) extends EquipmentDefinition(objectId) { class SimpleItemDefinition(objectId: Int) extends EquipmentDefinition(objectId) {
import net.psforever.objects.equipment.EquipmentSize import net.psforever.objects.equipment.EquipmentSize
SItem(objectId) //let throw NoSuchElementException SItem(objectId) //let throw NoSuchElementException
Name = "tool" Name = "tool"
@ -11,11 +11,11 @@ class SimpleItemDefinition(objectId : Int) extends EquipmentDefinition(objectId)
} }
object SimpleItemDefinition { object SimpleItemDefinition {
def apply(objectId : Int) : SimpleItemDefinition = { def apply(objectId: Int): SimpleItemDefinition = {
new SimpleItemDefinition(objectId) new SimpleItemDefinition(objectId)
} }
def apply(simpItem : SItem.Value) : SimpleItemDefinition = { def apply(simpItem: SItem.Value): SimpleItemDefinition = {
new SimpleItemDefinition(simpItem.id) new SimpleItemDefinition(simpItem.id)
} }
} }

View file

@ -6,27 +6,27 @@ import net.psforever.objects.equipment.FireModeDefinition
import scala.collection.mutable import scala.collection.mutable
class ToolDefinition(objectId : Int) extends EquipmentDefinition(objectId) { class ToolDefinition(objectId: Int) extends EquipmentDefinition(objectId) {
private val ammoTypes : mutable.ListBuffer[AmmoBoxDefinition] = new mutable.ListBuffer[AmmoBoxDefinition] private val ammoTypes: mutable.ListBuffer[AmmoBoxDefinition] = new mutable.ListBuffer[AmmoBoxDefinition]
private val projectileTypes : mutable.ListBuffer[ProjectileDefinition] = new mutable.ListBuffer[ProjectileDefinition] private val projectileTypes: mutable.ListBuffer[ProjectileDefinition] = new mutable.ListBuffer[ProjectileDefinition]
private val fireModes : mutable.ListBuffer[FireModeDefinition] = new mutable.ListBuffer[FireModeDefinition] private val fireModes: mutable.ListBuffer[FireModeDefinition] = new mutable.ListBuffer[FireModeDefinition]
private var defaultFireModeIndex : Option[Int] = None private var defaultFireModeIndex: Option[Int] = None
Name = "tool" Name = "tool"
Packet = ToolDefinition.converter Packet = ToolDefinition.converter
def AmmoTypes : mutable.ListBuffer[AmmoBoxDefinition] = ammoTypes def AmmoTypes: mutable.ListBuffer[AmmoBoxDefinition] = ammoTypes
def ProjectileTypes : mutable.ListBuffer[ProjectileDefinition] = projectileTypes def ProjectileTypes: mutable.ListBuffer[ProjectileDefinition] = projectileTypes
def FireModes : mutable.ListBuffer[FireModeDefinition] = fireModes def FireModes: mutable.ListBuffer[FireModeDefinition] = fireModes
def NextFireModeIndex(index : Int) : Int = index + 1 def NextFireModeIndex(index: Int): Int = index + 1
def DefaultFireModeIndex : Int = defaultFireModeIndex.getOrElse(0) def DefaultFireModeIndex: Int = defaultFireModeIndex.getOrElse(0)
def DefaultFireModeIndex_=(index : Int) : Int = DefaultFireModeIndex_=(Some(index)) def DefaultFireModeIndex_=(index: Int): Int = DefaultFireModeIndex_=(Some(index))
def DefaultFireModeIndex_=(index : Option[Int]) : Int = { def DefaultFireModeIndex_=(index: Option[Int]): Int = {
defaultFireModeIndex = index defaultFireModeIndex = index
DefaultFireModeIndex DefaultFireModeIndex
} }
@ -35,7 +35,7 @@ class ToolDefinition(objectId : Int) extends EquipmentDefinition(objectId) {
object ToolDefinition { object ToolDefinition {
private val converter = new ToolConverter() private val converter = new ToolConverter()
def apply(objectId : Int) : ToolDefinition = { def apply(objectId: Int): ToolDefinition = {
new ToolDefinition(objectId) new ToolDefinition(objectId)
} }
} }

View file

@ -15,37 +15,39 @@ import scala.concurrent.duration._
* An object definition system used to construct and retain the parameters of various vehicles. * An object definition system used to construct and retain the parameters of various vehicles.
* @param objectId the object id that is associated with this sort of `Vehicle` * @param objectId the object id that is associated with this sort of `Vehicle`
*/ */
class VehicleDefinition(objectId : Int) extends ObjectDefinition(objectId) class VehicleDefinition(objectId: Int)
with VitalityDefinition extends ObjectDefinition(objectId)
with ResistanceProfileMutators with VitalityDefinition
with DamageResistanceModel { with ResistanceProfileMutators
/** vehicle shields offered through amp station facility benefits (generally: 20% of health + 1) */ with DamageResistanceModel {
private var maxShields : Int = 0
/* key - seat index, value - seat object */
private val seats : mutable.HashMap[Int, SeatDefinition] = mutable.HashMap[Int, SeatDefinition]()
private val cargo : mutable.HashMap[Int, CargoDefinition] = mutable.HashMap[Int, CargoDefinition]()
/* key - entry point index, value - seat index */
private val mountPoints : mutable.HashMap[Int, Int] = mutable.HashMap()
/* key - seat index (where this weapon attaches during object construction), value - the weapon on an EquipmentSlot */
private val weapons : mutable.HashMap[Int, ToolDefinition] = mutable.HashMap[Int, ToolDefinition]()
private var deployment : Boolean = false
private val utilities : mutable.HashMap[Int, UtilityType.Value] = mutable.HashMap()
private val utilityOffsets : mutable.HashMap[Int, Vector3] = mutable.HashMap()
private var deploymentTime_Deploy : Int = 0 //ms
private var deploymentTime_Undeploy : Int = 0 //ms
private var trunkSize : InventoryTile = InventoryTile.None
private var trunkOffset : Int = 0
/** The position offset of the trunk, orientation as East = 0 */ /** vehicle shields offered through amp station facility benefits (generally: 20% of health + 1) */
private var trunkLocation : Vector3 = Vector3.Zero private var maxShields: Int = 0
private var canCloak : Boolean = false /* key - seat index, value - seat object */
private var canFly : Boolean = false private val seats: mutable.HashMap[Int, SeatDefinition] = mutable.HashMap[Int, SeatDefinition]()
private var canBeOwned : Boolean = true private val cargo: mutable.HashMap[Int, CargoDefinition] = mutable.HashMap[Int, CargoDefinition]()
private var serverVehicleOverrideSpeeds : (Int, Int) = (0, 0) /* key - entry point index, value - seat index */
private var deconTime : Option[FiniteDuration] = None private val mountPoints: mutable.HashMap[Int, Int] = mutable.HashMap()
private var maxCapacitor : Int = 0 /* key - seat index (where this weapon attaches during object construction), value - the weapon on an EquipmentSlot */
private var maxNtuCapacitor : Int = 0 private val weapons: mutable.HashMap[Int, ToolDefinition] = mutable.HashMap[Int, ToolDefinition]()
private var destroyedModel : Option[DestroyedVehicle.Value] = None private var deployment: Boolean = false
private val utilities: mutable.HashMap[Int, UtilityType.Value] = mutable.HashMap()
private val utilityOffsets: mutable.HashMap[Int, Vector3] = mutable.HashMap()
private var deploymentTime_Deploy: Int = 0 //ms
private var deploymentTime_Undeploy: Int = 0 //ms
private var trunkSize: InventoryTile = InventoryTile.None
private var trunkOffset: Int = 0
/** The position offset of the trunk, orientation as East = 0 */
private var trunkLocation: Vector3 = Vector3.Zero
private var canCloak: Boolean = false
private var canFly: Boolean = false
private var canBeOwned: Boolean = true
private var serverVehicleOverrideSpeeds: (Int, Int) = (0, 0)
private var deconTime: Option[FiniteDuration] = None
private var maxCapacitor: Int = 0
private var maxNtuCapacitor: Int = 0
private var destroyedModel: Option[DestroyedVehicle.Value] = None
Name = "vehicle" Name = "vehicle"
Packet = VehicleDefinition.converter Packet = VehicleDefinition.converter
DamageUsing = StandardVehicleDamage DamageUsing = StandardVehicleDamage
@ -54,135 +56,135 @@ class VehicleDefinition(objectId : Int) extends ObjectDefinition(objectId)
RepairDistance = 10 RepairDistance = 10
RepairRestoresAt = 1 RepairRestoresAt = 1
def MaxShields : Int = maxShields def MaxShields: Int = maxShields
def MaxShields_=(shields : Int) : Int = { def MaxShields_=(shields: Int): Int = {
maxShields = shields maxShields = shields
MaxShields MaxShields
} }
def Seats : mutable.HashMap[Int, SeatDefinition] = seats def Seats: mutable.HashMap[Int, SeatDefinition] = seats
def Cargo : mutable.HashMap[Int, CargoDefinition] = cargo def Cargo: mutable.HashMap[Int, CargoDefinition] = cargo
def MountPoints : mutable.HashMap[Int, Int] = mountPoints def MountPoints: mutable.HashMap[Int, Int] = mountPoints
def CanBeOwned : Boolean = canBeOwned def CanBeOwned: Boolean = canBeOwned
def CanBeOwned_=(ownable : Boolean) : Boolean = { def CanBeOwned_=(ownable: Boolean): Boolean = {
canBeOwned = ownable canBeOwned = ownable
CanBeOwned CanBeOwned
} }
def CanCloak : Boolean = canCloak def CanCloak: Boolean = canCloak
def CanCloak_=(cloakable : Boolean) : Boolean = { def CanCloak_=(cloakable: Boolean): Boolean = {
canCloak = cloakable canCloak = cloakable
CanCloak CanCloak
} }
def CanFly : Boolean = canFly def CanFly: Boolean = canFly
def CanFly_=(flying : Boolean) : Boolean = { def CanFly_=(flying: Boolean): Boolean = {
canFly = flying canFly = flying
CanFly CanFly
} }
def Weapons : mutable.HashMap[Int, ToolDefinition] = weapons def Weapons: mutable.HashMap[Int, ToolDefinition] = weapons
def Deployment : Boolean = deployment def Deployment: Boolean = deployment
def Deployment_=(deployable : Boolean) : Boolean = { def Deployment_=(deployable: Boolean): Boolean = {
deployment = deployable deployment = deployable
Deployment Deployment
} }
def Utilities : mutable.HashMap[Int, UtilityType.Value] = utilities def Utilities: mutable.HashMap[Int, UtilityType.Value] = utilities
def UtilityOffset : mutable.HashMap[Int, Vector3] = utilityOffsets def UtilityOffset: mutable.HashMap[Int, Vector3] = utilityOffsets
def DeployTime : Int = deploymentTime_Deploy def DeployTime: Int = deploymentTime_Deploy
def DeployTime_=(dtime : Int) : Int = { def DeployTime_=(dtime: Int): Int = {
deploymentTime_Deploy = dtime deploymentTime_Deploy = dtime
DeployTime DeployTime
} }
def DeconstructionTime : Option[FiniteDuration] = deconTime def DeconstructionTime: Option[FiniteDuration] = deconTime
def DeconstructionTime_=(time : FiniteDuration) : Option[FiniteDuration] = { def DeconstructionTime_=(time: FiniteDuration): Option[FiniteDuration] = {
deconTime_=(Some(time)) deconTime_=(Some(time))
DeconstructionTime DeconstructionTime
} }
def DeconstructionTime_=(time : Option[FiniteDuration]) : Option[FiniteDuration] = { def DeconstructionTime_=(time: Option[FiniteDuration]): Option[FiniteDuration] = {
deconTime = time deconTime = time
DeconstructionTime DeconstructionTime
} }
def UndeployTime : Int = deploymentTime_Undeploy def UndeployTime: Int = deploymentTime_Undeploy
def UndeployTime_=(dtime : Int) : Int = { def UndeployTime_=(dtime: Int): Int = {
deploymentTime_Undeploy = dtime deploymentTime_Undeploy = dtime
UndeployTime UndeployTime
} }
def TrunkSize : InventoryTile = trunkSize def TrunkSize: InventoryTile = trunkSize
def TrunkSize_=(tile : InventoryTile) : InventoryTile = { def TrunkSize_=(tile: InventoryTile): InventoryTile = {
trunkSize = tile trunkSize = tile
TrunkSize TrunkSize
} }
def TrunkOffset : Int = trunkOffset def TrunkOffset: Int = trunkOffset
def TrunkOffset_=(offset : Int) : Int = { def TrunkOffset_=(offset: Int): Int = {
trunkOffset = offset trunkOffset = offset
TrunkOffset TrunkOffset
} }
def TrunkLocation : Vector3 = trunkLocation def TrunkLocation: Vector3 = trunkLocation
def TrunkLocation_=(location : Vector3) : Vector3 = { def TrunkLocation_=(location: Vector3): Vector3 = {
trunkLocation = location trunkLocation = location
TrunkLocation TrunkLocation
} }
def AutoPilotSpeeds : (Int, Int) = serverVehicleOverrideSpeeds def AutoPilotSpeeds: (Int, Int) = serverVehicleOverrideSpeeds
def AutoPilotSpeeds_=(speeds : (Int, Int)) : (Int, Int) = { def AutoPilotSpeeds_=(speeds: (Int, Int)): (Int, Int) = {
serverVehicleOverrideSpeeds = speeds serverVehicleOverrideSpeeds = speeds
AutoPilotSpeeds AutoPilotSpeeds
} }
def AutoPilotSpeed1 : Int = serverVehicleOverrideSpeeds._1 def AutoPilotSpeed1: Int = serverVehicleOverrideSpeeds._1
def AutoPilotSpeed2 : Int = serverVehicleOverrideSpeeds._2 def AutoPilotSpeed2: Int = serverVehicleOverrideSpeeds._2
def MaxNtuCapacitor : Int = maxNtuCapacitor def MaxNtuCapacitor: Int = maxNtuCapacitor
def MaxNtuCapacitor_=(max: Int) : Int = { def MaxNtuCapacitor_=(max: Int): Int = {
maxNtuCapacitor = max maxNtuCapacitor = max
MaxNtuCapacitor MaxNtuCapacitor
} }
def MaxCapacitor : Int = maxCapacitor def MaxCapacitor: Int = maxCapacitor
def MaxCapacitor_=(max: Int) : Int = { def MaxCapacitor_=(max: Int): Int = {
maxCapacitor = max maxCapacitor = max
MaxCapacitor MaxCapacitor
} }
private var jackDuration = Array(0, 0, 0, 0) private var jackDuration = Array(0, 0, 0, 0)
def JackingDuration: Array[Int] = jackDuration def JackingDuration: Array[Int] = jackDuration
def JackingDuration_=(arr: Array[Int]) : Array[Int] = { def JackingDuration_=(arr: Array[Int]): Array[Int] = {
jackDuration = arr jackDuration = arr
arr arr
} }
def DestroyedModel : Option[DestroyedVehicle.Value] = destroyedModel def DestroyedModel: Option[DestroyedVehicle.Value] = destroyedModel
def DestroyedModel_=(model : Option[DestroyedVehicle.Value]) : Option[DestroyedVehicle.Value] = { def DestroyedModel_=(model: Option[DestroyedVehicle.Value]): Option[DestroyedVehicle.Value] = {
destroyedModel = model destroyedModel = model
DestroyedModel DestroyedModel
} }
@ -191,7 +193,7 @@ class VehicleDefinition(objectId : Int) extends ObjectDefinition(objectId)
object VehicleDefinition { object VehicleDefinition {
private val converter = new VehicleConverter private val converter = new VehicleConverter
def apply(objectId: Int) : VehicleDefinition = { def apply(objectId: Int): VehicleDefinition = {
new VehicleDefinition(objectId) new VehicleDefinition(objectId)
} }
} }

View file

@ -8,7 +8,7 @@ import net.psforever.types.PlanetSideGUID
import scala.util.{Success, Try} import scala.util.{Success, Try}
class ACEConverter extends ObjectCreateConverter[ConstructionItem]() { class ACEConverter extends ObjectCreateConverter[ConstructionItem]() {
override def ConstructorData(obj : ConstructionItem) : Try[HandheldData] = { override def ConstructorData(obj: ConstructionItem): Try[HandheldData] = {
Success( Success(
HandheldData( HandheldData(
CommonFieldData( CommonFieldData(
@ -27,7 +27,7 @@ class ACEConverter extends ObjectCreateConverter[ConstructionItem]() {
) )
} }
override def DetailedConstructorData(obj : ConstructionItem) : Try[DetailedConstructionToolData] = { override def DetailedConstructorData(obj: ConstructionItem): Try[DetailedConstructionToolData] = {
Success( Success(
DetailedConstructionToolData( DetailedConstructionToolData(
CommonFieldData( CommonFieldData(

View file

@ -8,11 +8,11 @@ import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
import scala.util.{Success, Try} import scala.util.{Success, Try}
class AmmoBoxConverter extends ObjectCreateConverter[AmmoBox] { class AmmoBoxConverter extends ObjectCreateConverter[AmmoBox] {
override def ConstructorData(obj : AmmoBox) : Try[CommonFieldData] = { override def ConstructorData(obj: AmmoBox): Try[CommonFieldData] = {
Success(CommonFieldData()(false)) Success(CommonFieldData()(false))
} }
override def DetailedConstructorData(obj : AmmoBox) : Try[DetailedAmmoBoxData] = { override def DetailedConstructorData(obj: AmmoBox): Try[DetailedAmmoBoxData] = {
Success( Success(
DetailedAmmoBoxData( DetailedAmmoBoxData(
CommonFieldData( CommonFieldData(

View file

@ -10,10 +10,10 @@ import scala.annotation.tailrec
import scala.util.{Success, Try} import scala.util.{Success, Try}
class AvatarConverter extends ObjectCreateConverter[Player]() { class AvatarConverter extends ObjectCreateConverter[Player]() {
override def ConstructorData(obj : Player) : Try[PlayerData] = { override def ConstructorData(obj: Player): Try[PlayerData] = {
import AvatarConverter._ import AvatarConverter._
Success( Success(
if(obj.VehicleSeated.isEmpty) { if (obj.VehicleSeated.isEmpty) {
PlayerData( PlayerData(
PlacementData(obj.Position, obj.Orientation, obj.Velocity), PlacementData(obj.Position, obj.Orientation, obj.Velocity),
MakeAppearanceData(obj), MakeAppearanceData(obj),
@ -21,8 +21,7 @@ class AvatarConverter extends ObjectCreateConverter[Player]() {
MakeInventoryData(obj), MakeInventoryData(obj),
GetDrawnSlot(obj) GetDrawnSlot(obj)
) )
} } else {
else {
PlayerData( PlayerData(
MakeAppearanceData(obj), MakeAppearanceData(obj),
MakeCharacterData(obj), MakeCharacterData(obj),
@ -33,10 +32,10 @@ class AvatarConverter extends ObjectCreateConverter[Player]() {
) )
} }
override def DetailedConstructorData(obj : Player) : Try[DetailedPlayerData] = { override def DetailedConstructorData(obj: Player): Try[DetailedPlayerData] = {
import AvatarConverter._ import AvatarConverter._
Success( Success(
if(obj.VehicleSeated.isEmpty) { if (obj.VehicleSeated.isEmpty) {
DetailedPlayerData.apply( DetailedPlayerData.apply(
PlacementData(obj.Position, obj.Orientation, obj.Velocity), PlacementData(obj.Position, obj.Orientation, obj.Velocity),
MakeAppearanceData(obj), MakeAppearanceData(obj),
@ -44,8 +43,7 @@ class AvatarConverter extends ObjectCreateConverter[Player]() {
MakeDetailedInventoryData(obj), MakeDetailedInventoryData(obj),
GetDrawnSlot(obj) GetDrawnSlot(obj)
) )
} } else {
else {
DetailedPlayerData.apply( DetailedPlayerData.apply(
MakeAppearanceData(obj), MakeAppearanceData(obj),
MakeDetailedCharacterData(obj), MakeDetailedCharacterData(obj),
@ -58,14 +56,15 @@ class AvatarConverter extends ObjectCreateConverter[Player]() {
} }
object AvatarConverter { object AvatarConverter {
/** /**
* Compose some data from a `Player` into a representation common to both `CharacterData` and `DetailedCharacterData`. * Compose some data from a `Player` into a representation common to both `CharacterData` and `DetailedCharacterData`.
* @param obj the `Player` game object * @param obj the `Player` game object
* @return the resulting `CharacterAppearanceData` * @return the resulting `CharacterAppearanceData`
*/ */
def MakeAppearanceData(obj : Player) : Int=>CharacterAppearanceData = { def MakeAppearanceData(obj: Player): Int => CharacterAppearanceData = {
val alt_model_flag : Boolean = obj.isBackpack val alt_model_flag: Boolean = obj.isBackpack
val aa : Int=>CharacterAppearanceA = CharacterAppearanceA( val aa: Int => CharacterAppearanceA = CharacterAppearanceA(
BasicCharacterData(obj.Name, obj.Faction, obj.Sex, obj.Head, obj.Voice), BasicCharacterData(obj.Name, obj.Faction, obj.Sex, obj.Head, obj.Voice),
CommonFieldData( CommonFieldData(
obj.Faction, obj.Faction,
@ -86,7 +85,7 @@ object AvatarConverter {
0, 0,
0 0
) )
val ab : (Boolean,Int)=>CharacterAppearanceB = CharacterAppearanceB( val ab: (Boolean, Int) => CharacterAppearanceB = CharacterAppearanceB(
0L, 0L,
outfit_name = "", outfit_name = "",
outfit_logo = 0, outfit_logo = 0,
@ -109,14 +108,13 @@ object AvatarConverter {
CharacterAppearanceData(aa, ab, RibbonBars()) CharacterAppearanceData(aa, ab, RibbonBars())
} }
def MakeCharacterData(obj : Player) : (Boolean,Boolean)=>CharacterData = { def MakeCharacterData(obj: Player): (Boolean, Boolean) => CharacterData = {
val MaxArmor = obj.MaxArmor val MaxArmor = obj.MaxArmor
CharacterData( CharacterData(
StatConverter.Health(obj.Health, obj.MaxHealth), StatConverter.Health(obj.Health, obj.MaxHealth),
if(MaxArmor == 0) { if (MaxArmor == 0) {
0 0
} } else {
else {
StatConverter.Health(obj.Armor, MaxArmor) StatConverter.Health(obj.Armor, MaxArmor)
}, },
DressBattleRank(obj), DressBattleRank(obj),
@ -127,43 +125,59 @@ object AvatarConverter {
) )
} }
def MakeDetailedCharacterData(obj : Player) : Option[Int]=>DetailedCharacterData = { def MakeDetailedCharacterData(obj: Player): Option[Int] => DetailedCharacterData = {
val bep : Long = obj.BEP val bep: Long = obj.BEP
val maxOpt : Option[Long] = if(obj.ExoSuit == ExoSuitType.MAX) { Some(0L) } else { None } val maxOpt: Option[Long] = if (obj.ExoSuit == ExoSuitType.MAX) { Some(0L) }
val ba : DetailedCharacterA = DetailedCharacterA( else { None }
val ba: DetailedCharacterA = DetailedCharacterA(
bep, bep,
obj.CEP, obj.CEP,
0L, 0L, 0L, 0L,
obj.MaxHealth, obj.Health, 0L,
0L,
obj.MaxHealth,
obj.Health,
false, false,
obj.Armor, obj.Armor,
0L, 0L,
obj.MaxStamina, obj.Stamina, obj.MaxStamina,
obj.Stamina,
maxOpt, maxOpt,
0, 0, 0L, 0,
0,
0L,
List(0, 0, 0, 0, 0, 0), List(0, 0, 0, 0, 0, 0),
obj.Certifications.toList.sortBy(_.id) //TODO is sorting necessary? obj.Certifications.toList.sortBy(_.id) //TODO is sorting necessary?
) )
val bb : (Long, Option[Int])=>DetailedCharacterB = DetailedCharacterB( val bb: (Long, Option[Int]) => DetailedCharacterB = DetailedCharacterB(
None, None,
MakeImplantEntries(obj), MakeImplantEntries(obj),
Nil, Nil, Nil,
Nil,
obj.FirstTimeEvents, obj.FirstTimeEvents,
tutorials = List.empty[String], //TODO tutorial list tutorials = List.empty[String], //TODO tutorial list
0L, 0L, 0L, 0L, 0L, 0L,
0L,
0L,
0L,
0L,
Some(DCDExtra2(0, 0)), Some(DCDExtra2(0, 0)),
Nil, Nil, false, Nil,
Nil,
false,
MakeCosmetics(obj) MakeCosmetics(obj)
) )
pad_length : Option[Int] => DetailedCharacterData(ba, bb(bep, pad_length))(pad_length) pad_length: Option[Int] => DetailedCharacterData(ba, bb(bep, pad_length))(pad_length)
} }
def MakeInventoryData(obj : Player) : InventoryData = { def MakeInventoryData(obj: Player): InventoryData = {
InventoryData(MakeHolsters(obj, BuildEquipment).sortBy(_.parentSlot)) InventoryData(MakeHolsters(obj, BuildEquipment).sortBy(_.parentSlot))
} }
def MakeDetailedInventoryData(obj : Player) : InventoryData = { def MakeDetailedInventoryData(obj: Player): InventoryData = {
InventoryData((MakeHolsters(obj, BuildDetailedEquipment) ++ MakeFifthSlot(obj) ++ MakeInventory(obj)).sortBy(_.parentSlot)) InventoryData(
(MakeHolsters(obj, BuildDetailedEquipment) ++ MakeFifthSlot(obj) ++ MakeInventory(obj)).sortBy(_.parentSlot)
)
} }
/** /**
@ -172,18 +186,15 @@ object AvatarConverter {
* @param obj the `Player` game object * @param obj the `Player` game object
* @return the resulting uniform upgrade level * @return the resulting uniform upgrade level
*/ */
private def DressBattleRank(obj : Player) : UniformStyle.Value = { private def DressBattleRank(obj: Player): UniformStyle.Value = {
val bep : Long = obj.BEP val bep: Long = obj.BEP
if(bep > 2583440) { //BR25+ if (bep > 2583440) { //BR25+
UniformStyle.ThirdUpgrade UniformStyle.ThirdUpgrade
} } else if (bep > 308989) { //BR14+
else if(bep > 308989) { //BR14+
UniformStyle.SecondUpgrade UniformStyle.SecondUpgrade
} } else if (bep > 44999) { //BR7+
else if(bep > 44999) { //BR7+
UniformStyle.FirstUpgrade UniformStyle.FirstUpgrade
} } else { //BR1+
else { //BR1+
UniformStyle.Normal UniformStyle.Normal
} }
} }
@ -194,24 +205,19 @@ object AvatarConverter {
* @param obj the `Player` game object * @param obj the `Player` game object
* @return the resulting uniform upgrade level * @return the resulting uniform upgrade level
*/ */
private def DressCommandRank(obj : Player) : Int = { private def DressCommandRank(obj: Player): Int = {
val cep = obj.CEP val cep = obj.CEP
if(cep > 599999) { if (cep > 599999) {
5 5
} } else if (cep > 299999) {
else if(cep > 299999) {
4 4
} } else if (cep > 149999) {
else if(cep > 149999) {
3 3
} } else if (cep > 49999) {
else if(cep > 49999) {
2 2
} } else if (cep > 9999) {
else if(cep > 9999) {
1 1
} } else {
else {
0 0
} }
} }
@ -222,17 +228,19 @@ object AvatarConverter {
* @return the resulting implant `List` * @return the resulting implant `List`
* @see `ImplantEntry` in `DetailedCharacterData` * @see `ImplantEntry` in `DetailedCharacterData`
*/ */
private def MakeImplantEntries(obj : Player) : List[ImplantEntry] = { private def MakeImplantEntries(obj: Player): List[ImplantEntry] = {
//val numImplants : Int = DetailedCharacterData.numberOfImplantSlots(obj.BEP) //val numImplants : Int = DetailedCharacterData.numberOfImplantSlots(obj.BEP)
//val implants = obj.Implants //val implants = obj.Implants
obj.Implants.map({ case(implant, initialization, _) => obj.Implants
if(initialization == 0) { .map({
ImplantEntry(implant, None) case (implant, initialization, _) =>
} if (initialization == 0) {
else { ImplantEntry(implant, None)
ImplantEntry(implant, Some(math.max(0,initialization).toInt)) } else {
} ImplantEntry(implant, Some(math.max(0, initialization).toInt))
}).toList }
})
.toList
} }
/** /**
@ -240,12 +248,12 @@ object AvatarConverter {
* @param implants a `Sequence` of `ImplantSlot` objects * @param implants a `Sequence` of `ImplantSlot` objects
* @return the effect of an active implant * @return the effect of an active implant
*/ */
private def MakeImplantEffectList(implants : Seq[(ImplantType.Value, Long, Boolean)]) : List[ImplantEffects.Value] = { private def MakeImplantEffectList(implants: Seq[(ImplantType.Value, Long, Boolean)]): List[ImplantEffects.Value] = {
implants.collect { implants.collect {
case (ImplantType.AdvancedRegen,_,true) => ImplantEffects.RegenEffects case (ImplantType.AdvancedRegen, _, true) => ImplantEffects.RegenEffects
case (ImplantType.DarklightVision,_,true) => ImplantEffects.DarklightEffects case (ImplantType.DarklightVision, _, true) => ImplantEffects.DarklightEffects
case (ImplantType.PersonalShield,_,true) => ImplantEffects.PersonalShieldEffects case (ImplantType.PersonalShield, _, true) => ImplantEffects.PersonalShieldEffects
case (ImplantType.Surge,_,true) => ImplantEffects.SurgeEffects case (ImplantType.Surge, _, true) => ImplantEffects.SurgeEffects
}.toList }.toList
} }
@ -257,11 +265,10 @@ object AvatarConverter {
* @see `Cosmetics` * @see `Cosmetics`
* @return the `Cosmetics` options * @return the `Cosmetics` options
*/ */
def MakeCosmetics(obj : Player) : Option[Cosmetics] = def MakeCosmetics(obj: Player): Option[Cosmetics] =
if(DetailedCharacterData.isBR24(obj.BEP)) { if (DetailedCharacterData.isBR24(obj.BEP)) {
obj.PersonalStyleFeatures.orElse(Some(Cosmetics())) obj.PersonalStyleFeatures.orElse(Some(Cosmetics()))
} } else {
else {
None None
} }
@ -272,11 +279,16 @@ object AvatarConverter {
* @param obj the `Player` game object * @param obj the `Player` game object
* @return a list of all items that were in the inventory in decoded packet form * @return a list of all items that were in the inventory in decoded packet form
*/ */
private def MakeInventory(obj : Player) : List[InternalSlot] = { private def MakeInventory(obj: Player): List[InternalSlot] = {
obj.Inventory.Items obj.Inventory.Items
.map(item => { .map(item => {
val equip : Equipment = item.obj val equip: Equipment = item.obj
InternalSlot(equip.Definition.ObjectId, equip.GUID, item.start, equip.Definition.Packet.DetailedConstructorData(equip).get) InternalSlot(
equip.Definition.ObjectId,
equip.GUID,
item.start,
equip.Definition.Packet.DetailedConstructorData(equip).get
)
}) })
} }
@ -289,7 +301,7 @@ object AvatarConverter {
* @param builder the function used to transform to the decoded packet form * @param builder the function used to transform to the decoded packet form
* @return a list of all items that were in the holsters in decoded packet form * @return a list of all items that were in the holsters in decoded packet form
*/ */
private def MakeHolsters(obj : Player, builder : (Int, Equipment) => InternalSlot) : List[InternalSlot] = { private def MakeHolsters(obj: Player, builder: (Int, Equipment) => InternalSlot): List[InternalSlot] = {
recursiveMakeHolsters(obj.Holsters().iterator, builder) recursiveMakeHolsters(obj.Holsters().iterator, builder)
} }
@ -300,7 +312,7 @@ object AvatarConverter {
* @param obj the `Player` game object * @param obj the `Player` game object
* @return a list of any item that was in the fifth holster in decoded packet form * @return a list of any item that was in the fifth holster in decoded packet form
*/ */
private def MakeFifthSlot(obj : Player) : List[InternalSlot] = { private def MakeFifthSlot(obj: Player): List[InternalSlot] = {
obj.Slot(5).Equipment match { obj.Slot(5).Equipment match {
case Some(equip) => case Some(equip) =>
BuildDetailedEquipment(5, equip) :: Nil BuildDetailedEquipment(5, equip) :: Nil
@ -315,7 +327,7 @@ object AvatarConverter {
* @param equip the game object * @param equip the game object
* @return the game object in decoded packet form * @return the game object in decoded packet form
*/ */
private def BuildEquipment(index : Int, equip : Equipment) : InternalSlot = { private def BuildEquipment(index: Int, equip: Equipment): InternalSlot = {
InternalSlot(equip.Definition.ObjectId, equip.GUID, index, equip.Definition.Packet.ConstructorData(equip).get) InternalSlot(equip.Definition.ObjectId, equip.GUID, index, equip.Definition.Packet.ConstructorData(equip).get)
} }
@ -325,8 +337,13 @@ object AvatarConverter {
* @param equip the game object * @param equip the game object
* @return the game object in decoded packet form * @return the game object in decoded packet form
*/ */
def BuildDetailedEquipment(index : Int, equip : Equipment) : InternalSlot = { def BuildDetailedEquipment(index: Int, equip: Equipment): InternalSlot = {
InternalSlot(equip.Definition.ObjectId, equip.GUID, index, equip.Definition.Packet.DetailedConstructorData(equip).get) InternalSlot(
equip.Definition.ObjectId,
equip.GUID,
index,
equip.Definition.Packet.DetailedConstructorData(equip).get
)
} }
/** /**
@ -337,22 +354,25 @@ object AvatarConverter {
* @param index which holster is currently being explored * @param index which holster is currently being explored
* @return the `List` of inventory data created from the holsters * @return the `List` of inventory data created from the holsters
*/ */
@tailrec private def recursiveMakeHolsters(iter : Iterator[EquipmentSlot], builder : (Int, Equipment) => InternalSlot, list : List[InternalSlot] = Nil, index : Int = 0) : List[InternalSlot] = { @tailrec private def recursiveMakeHolsters(
if(!iter.hasNext) { iter: Iterator[EquipmentSlot],
builder: (Int, Equipment) => InternalSlot,
list: List[InternalSlot] = Nil,
index: Int = 0
): List[InternalSlot] = {
if (!iter.hasNext) {
list list
} } else {
else { val slot: EquipmentSlot = iter.next
val slot : EquipmentSlot = iter.next if (slot.Equipment.isDefined) {
if(slot.Equipment.isDefined) { val equip: Equipment = slot.Equipment.get
val equip : Equipment = slot.Equipment.get
recursiveMakeHolsters( recursiveMakeHolsters(
iter, iter,
builder, builder,
list :+ builder(index, equip), list :+ builder(index, equip),
index + 1 index + 1
) )
} } else {
else {
recursiveMakeHolsters(iter, builder, list, index + 1) recursiveMakeHolsters(iter, builder, list, index + 1)
} }
} }
@ -363,10 +383,10 @@ object AvatarConverter {
* @param obj the `Player` game object * @param obj the `Player` game object
* @return the holster's Enumeration value * @return the holster's Enumeration value
*/ */
def GetDrawnSlot(obj : Player) : DrawnSlot.Value = { def GetDrawnSlot(obj: Player): DrawnSlot.Value = {
obj.DrawnSlot match { obj.DrawnSlot match {
case Player.HandsDownSlot | Player.FreeHandSlot => DrawnSlot.None case Player.HandsDownSlot | Player.FreeHandSlot => DrawnSlot.None
case n => DrawnSlot(n) case n => DrawnSlot(n)
} }
} }
} }

View file

@ -8,13 +8,15 @@ import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
import scala.util.{Success, Try} import scala.util.{Success, Try}
class BoomerTriggerConverter extends ObjectCreateConverter[SimpleItem]() { class BoomerTriggerConverter extends ObjectCreateConverter[SimpleItem]() {
override def ConstructorData(obj : SimpleItem) : Try[HandheldData] = { override def ConstructorData(obj: SimpleItem): Try[HandheldData] = {
Success(HandheldData(CommonFieldData())) Success(HandheldData(CommonFieldData()))
} }
override def DetailedConstructorData(obj : SimpleItem) : Try[DetailedConstructionToolData] = { override def DetailedConstructorData(obj: SimpleItem): Try[DetailedConstructionToolData] = {
Success(DetailedConstructionToolData( Success(
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)) DetailedConstructionToolData(
)) CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0))
)
)
} }
} }

View file

@ -2,7 +2,7 @@
package net.psforever.objects.definition.converter package net.psforever.objects.definition.converter
import net.psforever.objects.{Player, Tool} import net.psforever.objects.{Player, Tool}
import net.psforever.objects.equipment.{Equipment, EquipmentSlot} import net.psforever.objects.equipment.EquipmentSlot
import net.psforever.packet.game.objectcreate._ import net.psforever.packet.game.objectcreate._
import net.psforever.types.{PlanetSideGUID, _} import net.psforever.types.{PlanetSideGUID, _}
@ -15,9 +15,10 @@ import scala.util.{Failure, Success, Try}
* Details that would not be apparent on that screen such as implants or certifications are ignored. * Details that would not be apparent on that screen such as implants or certifications are ignored.
*/ */
class CharacterSelectConverter extends AvatarConverter { class CharacterSelectConverter extends AvatarConverter {
override def ConstructorData(obj : Player) : Try[PlayerData] = Failure(new Exception("CharacterSelectConverter should not be used to generate CharacterData")) override def ConstructorData(obj: Player): Try[PlayerData] =
Failure(new Exception("CharacterSelectConverter should not be used to generate CharacterData"))
override def DetailedConstructorData(obj : Player) : Try[DetailedPlayerData] = { override def DetailedConstructorData(obj: Player): Try[DetailedPlayerData] = {
Success( Success(
DetailedPlayerData.apply( DetailedPlayerData.apply(
PlacementData(0, 0, 0), PlacementData(0, 0, 0),
@ -35,8 +36,8 @@ class CharacterSelectConverter extends AvatarConverter {
* @see `AvatarConverter.MakeAppearanceData` * @see `AvatarConverter.MakeAppearanceData`
* @return the resulting `CharacterAppearanceData` * @return the resulting `CharacterAppearanceData`
*/ */
private def MakeAppearanceData(obj : Player) : Int=>CharacterAppearanceData = { private def MakeAppearanceData(obj: Player): Int => CharacterAppearanceData = {
val aa : Int=>CharacterAppearanceA = CharacterAppearanceA( val aa: Int => CharacterAppearanceA = CharacterAppearanceA(
BasicCharacterData(obj.Name, obj.Faction, obj.Sex, obj.Head, CharacterVoice.Mute), BasicCharacterData(obj.Name, obj.Faction, obj.Sex, obj.Head, CharacterVoice.Mute),
CommonFieldData( CommonFieldData(
obj.Faction, obj.Faction,
@ -57,7 +58,7 @@ class CharacterSelectConverter extends AvatarConverter {
0, 0,
0 0
) )
val ab : (Boolean,Int)=>CharacterAppearanceB = CharacterAppearanceB( val ab: (Boolean, Int) => CharacterAppearanceB = CharacterAppearanceB(
0L, 0L,
outfit_name = "", outfit_name = "",
outfit_logo = 0, outfit_logo = 0,
@ -80,35 +81,49 @@ class CharacterSelectConverter extends AvatarConverter {
CharacterAppearanceData(aa, ab, RibbonBars()) CharacterAppearanceData(aa, ab, RibbonBars())
} }
private def MakeDetailedCharacterData(obj : Player) : Option[Int]=>DetailedCharacterData = { private def MakeDetailedCharacterData(obj: Player): Option[Int] => DetailedCharacterData = {
val bep : Long = obj.BEP val bep: Long = obj.BEP
val maxOpt : Option[Long] = if(obj.ExoSuit == ExoSuitType.MAX) { Some(0L) } else { None } val maxOpt: Option[Long] = if (obj.ExoSuit == ExoSuitType.MAX) { Some(0L) }
val ba : DetailedCharacterA = DetailedCharacterA( else { None }
val ba: DetailedCharacterA = DetailedCharacterA(
bep, bep,
obj.CEP, obj.CEP,
0L, 0L, 0L, 0L,
1, 1, 0L,
0L,
1,
1,
false, false,
0, 0,
0L, 0L,
1, 1, 1,
1,
maxOpt, maxOpt,
0, 0, 0L, 0,
0,
0L,
List(0, 0, 0, 0, 0, 0), List(0, 0, 0, 0, 0, 0),
certs = List.empty[CertificationType.Value] certs = List.empty[CertificationType.Value]
) )
val bb : (Long, Option[Int])=>DetailedCharacterB = DetailedCharacterB( val bb: (Long, Option[Int]) => DetailedCharacterB = DetailedCharacterB(
None, None,
MakeImplantEntries(obj), //necessary for correct stream length MakeImplantEntries(obj), //necessary for correct stream length
Nil, Nil, Nil,
Nil,
firstTimeEvents = List.empty[String], firstTimeEvents = List.empty[String],
tutorials = List.empty[String], tutorials = List.empty[String],
0L, 0L, 0L, 0L, 0L, 0L,
0L,
0L,
0L,
0L,
Some(DCDExtra2(0, 0)), Some(DCDExtra2(0, 0)),
Nil, Nil, false, Nil,
Nil,
false,
AvatarConverter.MakeCosmetics(obj) AvatarConverter.MakeCosmetics(obj)
) )
pad_length : Option[Int] => DetailedCharacterData(ba, bb(bep, pad_length))(pad_length) pad_length: Option[Int] => DetailedCharacterData(ba, bb(bep, pad_length))(pad_length)
} }
/** /**
@ -117,7 +132,7 @@ class CharacterSelectConverter extends AvatarConverter {
* @return the resulting implant `List` * @return the resulting implant `List`
* @see `ImplantEntry` in `DetailedCharacterData` * @see `ImplantEntry` in `DetailedCharacterData`
*/ */
private def MakeImplantEntries(obj : Player) : List[ImplantEntry] = { private def MakeImplantEntries(obj: Player): List[ImplantEntry] = {
List.fill[ImplantEntry](DetailedCharacterData.numberOfImplantSlots(obj.BEP))(ImplantEntry(ImplantType.None, None)) List.fill[ImplantEntry](DetailedCharacterData.numberOfImplantSlots(obj.BEP))(ImplantEntry(ImplantType.None, None))
} }
@ -129,14 +144,17 @@ class CharacterSelectConverter extends AvatarConverter {
* @see `AvatarConverter.recursiveMakeHolsters` * @see `AvatarConverter.recursiveMakeHolsters`
* @return the `List` of inventory data created from the holsters * @return the `List` of inventory data created from the holsters
*/ */
@tailrec private def recursiveMakeHolsters(iter : Iterator[EquipmentSlot], list : List[InternalSlot] = Nil, index : Int = 0) : List[InternalSlot] = { @tailrec private def recursiveMakeHolsters(
if(!iter.hasNext) { iter: Iterator[EquipmentSlot],
list: List[InternalSlot] = Nil,
index: Int = 0
): List[InternalSlot] = {
if (!iter.hasNext) {
list list
} } else {
else { val slot: EquipmentSlot = iter.next
val slot : EquipmentSlot = iter.next
slot.Equipment match { slot.Equipment match {
case Some(equip : Tool) => case Some(equip: Tool) =>
val jammed = equip.Jammed val jammed = equip.Jammed
equip.Jammed = false equip.Jammed = false
val slot = AvatarConverter.BuildDetailedEquipment(index, equip) val slot = AvatarConverter.BuildDetailedEquipment(index, equip)

View file

@ -3,12 +3,12 @@ package net.psforever.objects.definition.converter
import net.psforever.objects.SimpleItem import net.psforever.objects.SimpleItem
import net.psforever.packet.game.objectcreate.{CommonFieldData, DetailedCommandDetonaterData, HandheldData} import net.psforever.packet.game.objectcreate.{CommonFieldData, DetailedCommandDetonaterData, HandheldData}
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID} import net.psforever.types.PlanetSideGUID
import scala.util.{Success, Try} import scala.util.{Success, Try}
class CommandDetonaterConverter extends ObjectCreateConverter[SimpleItem]() { class CommandDetonaterConverter extends ObjectCreateConverter[SimpleItem]() {
override def ConstructorData(obj : SimpleItem) : Try[HandheldData] = { override def ConstructorData(obj: SimpleItem): Try[HandheldData] = {
Success( Success(
HandheldData( HandheldData(
CommonFieldData( CommonFieldData(
@ -26,7 +26,7 @@ class CommandDetonaterConverter extends ObjectCreateConverter[SimpleItem]() {
) )
} }
override def DetailedConstructorData(obj : SimpleItem) : Try[DetailedCommandDetonaterData] = { override def DetailedConstructorData(obj: SimpleItem): Try[DetailedCommandDetonaterData] = {
Success( Success(
DetailedCommandDetonaterData( DetailedCommandDetonaterData(
CommonFieldData( CommonFieldData(

View file

@ -10,13 +10,13 @@ import scala.annotation.tailrec
import scala.util.{Failure, Success, Try} import scala.util.{Failure, Success, Try}
class CorpseConverter extends AvatarConverter { class CorpseConverter extends AvatarConverter {
override def ConstructorData(obj : Player) : Try[PlayerData] = override def ConstructorData(obj: Player): Try[PlayerData] =
Failure(new Exception("CorpseConverter should not be used to generate CharacterData")) Failure(new Exception("CorpseConverter should not be used to generate CharacterData"))
override def DetailedConstructorData(obj : Player) : Try[DetailedPlayerData] = { override def DetailedConstructorData(obj: Player): Try[DetailedPlayerData] = {
Success( Success(
DetailedPlayerData.apply( DetailedPlayerData.apply(
PlacementData(obj.Position, Vector3(0,0, obj.Orientation.z)), PlacementData(obj.Position, Vector3(0, 0, obj.Orientation.z)),
MakeAppearanceData(obj), MakeAppearanceData(obj),
MakeDetailedCharacterData(obj), MakeDetailedCharacterData(obj),
InventoryData((MakeHolsters(obj) ++ MakeInventory(obj)).sortBy(_.parentSlot)), InventoryData((MakeHolsters(obj) ++ MakeInventory(obj)).sortBy(_.parentSlot)),
@ -30,8 +30,8 @@ class CorpseConverter extends AvatarConverter {
* @param obj the `Player` game object * @param obj the `Player` game object
* @return the resulting `CharacterAppearanceData` * @return the resulting `CharacterAppearanceData`
*/ */
private def MakeAppearanceData(obj : Player) : Int=>CharacterAppearanceData = { private def MakeAppearanceData(obj: Player): Int => CharacterAppearanceData = {
val aa : Int=>CharacterAppearanceA = CharacterAppearanceA( val aa: Int => CharacterAppearanceA = CharacterAppearanceA(
BasicCharacterData(obj.Name, obj.Faction, CharacterGender.Male, 0, CharacterVoice.Mute), BasicCharacterData(obj.Name, obj.Faction, CharacterGender.Male, 0, CharacterVoice.Mute),
CommonFieldData( CommonFieldData(
obj.Faction, obj.Faction,
@ -52,7 +52,7 @@ class CorpseConverter extends AvatarConverter {
0, 0,
0 0
) )
val ab : (Boolean,Int)=>CharacterAppearanceB = CharacterAppearanceB( val ab: (Boolean, Int) => CharacterAppearanceB = CharacterAppearanceB(
0L, 0L,
outfit_name = "", outfit_name = "",
outfit_logo = 0, outfit_logo = 0,
@ -75,34 +75,48 @@ class CorpseConverter extends AvatarConverter {
CharacterAppearanceData(aa, ab, RibbonBars()) CharacterAppearanceData(aa, ab, RibbonBars())
} }
private def MakeDetailedCharacterData(obj : Player) : Option[Int]=>DetailedCharacterData = { private def MakeDetailedCharacterData(obj: Player): Option[Int] => DetailedCharacterData = {
val maxOpt : Option[Long] = if(obj.ExoSuit == ExoSuitType.MAX) { Some(0L) } else { None } val maxOpt: Option[Long] = if (obj.ExoSuit == ExoSuitType.MAX) { Some(0L) }
val ba : DetailedCharacterA = DetailedCharacterA( else { None }
val ba: DetailedCharacterA = DetailedCharacterA(
bep = 0L, bep = 0L,
cep = 0L, cep = 0L,
0L, 0L, 0L, 0L,
0, 0, 0L,
0L,
0,
0,
false, false,
0, 0,
0L, 0L,
0, 0, 0,
0,
maxOpt, maxOpt,
0, 0, 0L, 0,
0,
0L,
List(0, 0, 0, 0, 0, 0), List(0, 0, 0, 0, 0, 0),
certs = List.empty[CertificationType.Value] certs = List.empty[CertificationType.Value]
) )
val bb : (Long, Option[Int])=>DetailedCharacterB = DetailedCharacterB( val bb: (Long, Option[Int]) => DetailedCharacterB = DetailedCharacterB(
None, None,
implants = List.empty[ImplantEntry], implants = List.empty[ImplantEntry],
Nil, Nil, Nil,
Nil,
firstTimeEvents = List.empty[String], firstTimeEvents = List.empty[String],
tutorials = List.empty[String], tutorials = List.empty[String],
0L, 0L, 0L, 0L, 0L, 0L,
0L,
0L,
0L,
0L,
Some(DCDExtra2(0, 0)), Some(DCDExtra2(0, 0)),
Nil, Nil, false, Nil,
Nil,
false,
cosmetics = None cosmetics = None
) )
(pad_length : Option[Int]) => DetailedCharacterData(ba, bb(0, pad_length))(pad_length) (pad_length: Option[Int]) => DetailedCharacterData(ba, bb(0, pad_length))(pad_length)
} }
/** /**
@ -112,11 +126,11 @@ class CorpseConverter extends AvatarConverter {
* @param obj the `Player` game object * @param obj the `Player` game object
* @return a list of all items that were in the inventory in decoded packet form * @return a list of all items that were in the inventory in decoded packet form
*/ */
private def MakeInventory(obj : Player) : List[InternalSlot] = { private def MakeInventory(obj: Player): List[InternalSlot] = {
obj.Inventory.Items obj.Inventory.Items
.map(item => { .map(item => {
val equip : Equipment = item.obj val equip: Equipment = item.obj
BuildEquipment(item.start, equip) BuildEquipment(item.start, equip)
}) })
} }
@ -128,7 +142,7 @@ class CorpseConverter extends AvatarConverter {
* @param obj the `Player` game object * @param obj the `Player` game object
* @return a list of all items that were in the holsters in decoded packet form * @return a list of all items that were in the holsters in decoded packet form
*/ */
private def MakeHolsters(obj : Player) : List[InternalSlot] = { private def MakeHolsters(obj: Player): List[InternalSlot] = {
recursiveMakeHolsters(obj.Holsters().iterator) recursiveMakeHolsters(obj.Holsters().iterator)
} }
@ -139,21 +153,23 @@ class CorpseConverter extends AvatarConverter {
* @param index which holster is currently being explored * @param index which holster is currently being explored
* @return the `List` of inventory data created from the holsters * @return the `List` of inventory data created from the holsters
*/ */
@tailrec private def recursiveMakeHolsters(iter : Iterator[EquipmentSlot], list : List[InternalSlot] = Nil, index : Int = 0) : List[InternalSlot] = { @tailrec private def recursiveMakeHolsters(
if(!iter.hasNext) { iter: Iterator[EquipmentSlot],
list: List[InternalSlot] = Nil,
index: Int = 0
): List[InternalSlot] = {
if (!iter.hasNext) {
list list
} } else {
else { val slot: EquipmentSlot = iter.next
val slot : EquipmentSlot = iter.next if (slot.Equipment.isDefined) {
if(slot.Equipment.isDefined) { val equip: Equipment = slot.Equipment.get
val equip : Equipment = slot.Equipment.get
recursiveMakeHolsters( recursiveMakeHolsters(
iter, iter,
list :+ BuildEquipment(index, equip), list :+ BuildEquipment(index, equip),
index + 1 index + 1
) )
} } else {
else {
recursiveMakeHolsters(iter, list, index + 1) recursiveMakeHolsters(iter, list, index + 1)
} }
} }
@ -165,8 +181,13 @@ class CorpseConverter extends AvatarConverter {
* @param equip the game object * @param equip the game object
* @return the game object in decoded packet form * @return the game object in decoded packet form
*/ */
private def BuildEquipment(index : Int, equip : Equipment) : InternalSlot = { private def BuildEquipment(index: Int, equip: Equipment): InternalSlot = {
InternalSlot(equip.Definition.ObjectId, equip.GUID, index, equip.Definition.Packet.DetailedConstructorData(equip).get) InternalSlot(
equip.Definition.ObjectId,
equip.GUID,
index,
equip.Definition.Packet.DetailedConstructorData(equip).get
)
} }
} }

View file

@ -7,14 +7,17 @@ import net.psforever.packet.game.objectcreate.{DestroyedVehicleData, PlacementDa
import scala.util.{Failure, Success, Try} import scala.util.{Failure, Success, Try}
class DestroyedVehicleConverter extends ObjectCreateConverter[Vehicle]() { class DestroyedVehicleConverter extends ObjectCreateConverter[Vehicle]() {
override def DetailedConstructorData(obj : Vehicle) : Try[DestroyedVehicleData] = override def DetailedConstructorData(obj: Vehicle): Try[DestroyedVehicleData] =
Failure(new Exception("DestroyedVehicleConverter should not be used to generate detailed DestroyedVehicleData (nothing should)")) Failure(
new Exception(
"DestroyedVehicleConverter should not be used to generate detailed DestroyedVehicleData (nothing should)"
)
)
override def ConstructorData(obj : Vehicle) : Try[DestroyedVehicleData] = { override def ConstructorData(obj: Vehicle): Try[DestroyedVehicleData] = {
if(obj.Health > 0) { if (obj.Health > 0) {
Failure(new Exception("Vehicle used on DestroyedVehicleConverter has not yet been destroyed (Health == 0)")) Failure(new Exception("Vehicle used on DestroyedVehicleConverter has not yet been destroyed (Health == 0)"))
} } else {
else {
Success(DestroyedVehicleData(PlacementData(obj.Position, obj.Orientation))) Success(DestroyedVehicleData(PlacementData(obj.Position, obj.Orientation)))
} }
} }

View file

@ -8,12 +8,12 @@ import net.psforever.types.PlanetSideGUID
import scala.util.{Failure, Success, Try} import scala.util.{Failure, Success, Try}
class DroppodConverter extends ObjectCreateConverter[Vehicle]() { class DroppodConverter extends ObjectCreateConverter[Vehicle]() {
override def DetailedConstructorData(obj : Vehicle) : Try[DroppodData] = override def DetailedConstructorData(obj: Vehicle): Try[DroppodData] =
Failure(new Exception("DroppodConverter should not be used to generate detailed DroppodData (nothing should)")) Failure(new Exception("DroppodConverter should not be used to generate detailed DroppodData (nothing should)"))
override def ConstructorData(obj : Vehicle) : Try[DroppodData] = { override def ConstructorData(obj: Vehicle): Try[DroppodData] = {
val health = StatConverter.Health(obj.Health, obj.MaxHealth) val health = StatConverter.Health(obj.Health, obj.MaxHealth)
if(health > 0) { //active if (health > 0) { //active
Success( Success(
DroppodData( DroppodData(
CommonFieldDataWithPlacement( CommonFieldDataWithPlacement(
@ -29,7 +29,7 @@ class DroppodConverter extends ObjectCreateConverter[Vehicle]() {
v5 = None, v5 = None,
obj.Owner match { obj.Owner match {
case Some(owner) => owner case Some(owner) => owner
case None => PlanetSideGUID(0) case None => PlanetSideGUID(0)
} }
) )
), ),
@ -38,8 +38,7 @@ class DroppodConverter extends ObjectCreateConverter[Vehicle]() {
unk = false unk = false
) )
) )
} } else { //destroyed
else { //destroyed
Success( Success(
DroppodData( DroppodData(
CommonFieldDataWithPlacement( CommonFieldDataWithPlacement(

View file

@ -10,9 +10,9 @@ import net.psforever.types.PlanetSideGUID
import scala.util.{Failure, Success, Try} import scala.util.{Failure, Success, Try}
class FieldTurretConverter extends ObjectCreateConverter[TurretDeployable]() { class FieldTurretConverter extends ObjectCreateConverter[TurretDeployable]() {
override def ConstructorData(obj : TurretDeployable) : Try[OneMannedFieldTurretData] = { override def ConstructorData(obj: TurretDeployable): Try[OneMannedFieldTurretData] = {
val health = StatConverter.Health(obj.Health, obj.MaxHealth) val health = StatConverter.Health(obj.Health, obj.MaxHealth)
if(health > 3) { if (health > 3) {
Success( Success(
OneMannedFieldTurretData( OneMannedFieldTurretData(
CommonFieldDataWithPlacement( CommonFieldDataWithPlacement(
@ -28,7 +28,7 @@ class FieldTurretConverter extends ObjectCreateConverter[TurretDeployable]() {
None, None,
obj.Owner match { obj.Owner match {
case Some(owner) => owner case Some(owner) => owner
case None => PlanetSideGUID(0) case None => PlanetSideGUID(0)
} }
) )
), ),
@ -36,8 +36,7 @@ class FieldTurretConverter extends ObjectCreateConverter[TurretDeployable]() {
Some(InventoryData(FieldTurretConverter.MakeMountings(obj))) Some(InventoryData(FieldTurretConverter.MakeMountings(obj)))
) )
) )
} } else {
else {
Success( Success(
OneMannedFieldTurretData( OneMannedFieldTurretData(
CommonFieldDataWithPlacement( CommonFieldDataWithPlacement(
@ -60,17 +59,19 @@ class FieldTurretConverter extends ObjectCreateConverter[TurretDeployable]() {
} }
} }
override def DetailedConstructorData(obj : TurretDeployable) : Try[OneMannedFieldTurretData] = override def DetailedConstructorData(obj: TurretDeployable): Try[OneMannedFieldTurretData] =
Failure(new Exception("converter should not be used to generate detailed OneMannedFieldTurretData")) Failure(new Exception("converter should not be used to generate detailed OneMannedFieldTurretData"))
} }
object FieldTurretConverter { object FieldTurretConverter {
private def MakeMountings(obj : WeaponTurret) : List[InventoryItemData.InventoryItem] = { private def MakeMountings(obj: WeaponTurret): List[InventoryItemData.InventoryItem] = {
obj.Weapons.map({ obj.Weapons
case(index, slot) => .map({
val equip : Equipment = slot.Equipment.get case (index, slot) =>
val equipDef = equip.Definition val equip: Equipment = slot.Equipment.get
InventoryItemData(equipDef.ObjectId, equip.GUID, index, equipDef.Packet.ConstructorData(equip).get) val equipDef = equip.Definition
}).toList InventoryItemData(equipDef.ObjectId, equip.GUID, index, equipDef.Packet.ConstructorData(equip).get)
})
.toList
} }
} }

View file

@ -9,7 +9,7 @@ import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
import scala.util.{Failure, Success, Try} import scala.util.{Failure, Success, Try}
class InternalTelepadDeployableConverter extends ObjectCreateConverter[PlanetSideGameObject with TelepadLike]() { class InternalTelepadDeployableConverter extends ObjectCreateConverter[PlanetSideGameObject with TelepadLike]() {
override def ConstructorData(obj : PlanetSideGameObject with TelepadLike) : Try[TelepadDeployableData] = { override def ConstructorData(obj: PlanetSideGameObject with TelepadLike): Try[TelepadDeployableData] = {
obj.Router match { obj.Router match {
case Some(PlanetSideGUID(0)) => case Some(PlanetSideGUID(0)) =>
Failure(new IllegalStateException("InternalTelepadDeployableConverter: knowledge of parent Router is null")) Failure(new IllegalStateException("InternalTelepadDeployableConverter: knowledge of parent Router is null"))
@ -34,7 +34,9 @@ class InternalTelepadDeployableConverter extends ObjectCreateConverter[PlanetSid
) )
case None => case None =>
Failure(new IllegalStateException("InternalTelepadDeployableConverter: telepad needs to know id of its parent Router")) Failure(
new IllegalStateException("InternalTelepadDeployableConverter: telepad needs to know id of its parent Router")
)
} }
} }
} }

View file

@ -7,11 +7,11 @@ import net.psforever.packet.game.objectcreate.{CommonFieldData, DetailedAmmoBoxD
import scala.util.{Success, Try} import scala.util.{Success, Try}
class KitConverter extends ObjectCreateConverter[Kit]() { class KitConverter extends ObjectCreateConverter[Kit]() {
override def ConstructorData(obj : Kit) : Try[CommonFieldData] = { override def ConstructorData(obj: Kit): Try[CommonFieldData] = {
Success(CommonFieldData()(false)) Success(CommonFieldData()(false))
} }
override def DetailedConstructorData(obj : Kit) : Try[DetailedAmmoBoxData] = { override def DetailedConstructorData(obj: Kit): Try[DetailedAmmoBoxData] = {
Success(DetailedAmmoBoxData(0, 1)) Success(DetailedAmmoBoxData(0, 1))
} }
} }

View file

@ -10,7 +10,7 @@ import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
import scala.util.{Success, Try} import scala.util.{Success, Try}
class LockerContainerConverter extends ObjectCreateConverter[LockerEquipment]() { class LockerContainerConverter extends ObjectCreateConverter[LockerEquipment]() {
override def ConstructorData(obj : LockerEquipment) : Try[LockerContainerData] = { override def ConstructorData(obj: LockerEquipment): Try[LockerContainerData] = {
MakeInventory(obj.Inventory) match { MakeInventory(obj.Inventory) match {
case Nil => case Nil =>
Success(LockerContainerData(None)) Success(LockerContainerData(None))
@ -19,18 +19,21 @@ class LockerContainerConverter extends ObjectCreateConverter[LockerEquipment]()
} }
} }
override def DetailedConstructorData(obj : LockerEquipment) : Try[DetailedLockerContainerData] = { override def DetailedConstructorData(obj: LockerEquipment): Try[DetailedLockerContainerData] = {
if(obj.Inventory.Size > 0) { if (obj.Inventory.Size > 0) {
Success(DetailedLockerContainerData( Success(
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), DetailedLockerContainerData(
Some(InventoryData(MakeDetailedInventory(obj.Inventory))) CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)),
)) Some(InventoryData(MakeDetailedInventory(obj.Inventory)))
} )
else { )
Success(DetailedLockerContainerData( } else {
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), Success(
None DetailedLockerContainerData(
)) CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)),
None
)
)
} }
} }
@ -40,13 +43,18 @@ class LockerContainerConverter extends ObjectCreateConverter[LockerEquipment]()
* @param inv the inventory container * @param inv the inventory container
* @return a list of all items that were in the inventory in decoded packet form * @return a list of all items that were in the inventory in decoded packet form
*/ */
private def MakeInventory(inv : GridInventory) : List[InternalSlot] = { private def MakeInventory(inv: GridInventory): List[InternalSlot] = {
inv.Items inv.Items
.map(item => { .map(item => {
val equip : Equipment = item.obj val equip: Equipment = item.obj
InternalSlot(equip.Definition.ObjectId, equip.GUID, item.start, equip.Definition.Packet.ConstructorData(equip).get) InternalSlot(
equip.Definition.ObjectId,
equip.GUID,
item.start,
equip.Definition.Packet.ConstructorData(equip).get
)
}) })
} }
/** /**
* Transform a list of contained items into a list of contained `InternalSlot` objects. * Transform a list of contained items into a list of contained `InternalSlot` objects.
@ -54,11 +62,16 @@ class LockerContainerConverter extends ObjectCreateConverter[LockerEquipment]()
* @param inv the inventory container * @param inv the inventory container
* @return a list of all items that were in the inventory in decoded packet form * @return a list of all items that were in the inventory in decoded packet form
*/ */
private def MakeDetailedInventory(inv : GridInventory) : List[InternalSlot] = { private def MakeDetailedInventory(inv: GridInventory): List[InternalSlot] = {
inv.Items inv.Items
.map(item => { .map(item => {
val equip : Equipment = item.obj val equip: Equipment = item.obj
InternalSlot(equip.Definition.ObjectId, equip.GUID, item.start, equip.Definition.Packet.DetailedConstructorData(equip).get) InternalSlot(
equip.Definition.ObjectId,
equip.GUID,
item.start,
equip.Definition.Packet.DetailedConstructorData(equip).get
)
}) })
} }
} }

Some files were not shown because too many files have changed in this diff Show more