mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-15 08:24:39 +00:00
* 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:
parent
88b194fde2
commit
e0defe8240
850 changed files with 144487 additions and 47476 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -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
6
.scalafix.conf
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
rules = [
|
||||||
|
RemoveUnused
|
||||||
|
]
|
||||||
|
RemoveUnused.imports = true
|
||||||
|
RemoveUnused.privates = false
|
||||||
|
RemoveUnused.locals = false
|
||||||
3
.scalafmt.conf
Normal file
3
.scalafmt.conf
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
version = 2.6.1
|
||||||
|
preset = defaultWithAlign
|
||||||
|
maxColumn = 120
|
||||||
66
README.md
66
README.md
|
|
@ -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.
|
||||||
|
|
|
||||||
122
build.sbt
122
build.sbt
|
|
@ -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,22 +24,31 @@ 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.akka" %% "akka-protobuf-v3" % "2.6.6",
|
||||||
|
"com.typesafe.akka" %% "akka-stream" % "2.6.6",
|
||||||
|
"com.typesafe.akka" %% "akka-testkit" % "2.6.6" % "test",
|
||||||
|
"com.typesafe.akka" %% "akka-actor-typed" % "2.6.6",
|
||||||
|
"com.typesafe.akka" %% "akka-cluster-typed" % "2.6.6",
|
||||||
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.2",
|
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.2",
|
||||||
"org.specs2" %% "specs2-core" % "4.9.4" % "test",
|
"org.specs2" %% "specs2-core" % "4.9.4" % "test",
|
||||||
"org.scalatest" %% "scalatest" % "3.1.2" % "test",
|
"org.scalatest" %% "scalatest" % "3.1.2" % "test",
|
||||||
|
|
@ -41,14 +60,20 @@ lazy val commonSettings = Seq(
|
||||||
"org.fusesource.jansi" % "jansi" % "1.12",
|
"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.ini4j" % "ini4j" % "0.5.4",
|
|
||||||
"org.scala-graph" %% "graph-core" % "1.13.1",
|
"org.scala-graph" %% "graph-core" % "1.13.1",
|
||||||
"io.kamon" %% "kamon-bundle" % "2.1.0",
|
"io.kamon" %% "kamon-bundle" % "2.1.0",
|
||||||
"io.kamon" %% "kamon-apm-reporter" % "2.1.0",
|
"io.kamon" %% "kamon-apm-reporter" % "2.1.0",
|
||||||
"org.json4s" %% "json4s-native" % "3.6.8",
|
"org.json4s" %% "json4s-native" % "3.6.8",
|
||||||
"com.typesafe.akka" %% "akka-stream" % "2.6.5"
|
"com.typesafe.akka" %% "akka-stream" % "2.6.5",
|
||||||
|
"io.getquill" %% "quill-jasync-postgres" % "3.5.2",
|
||||||
|
"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)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// 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
|
||||||
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,7 +12,9 @@ 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() = {
|
||||||
|
|
|
||||||
|
|
@ -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: _*)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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 string’s 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 string’s 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: _*)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -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:_*)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -4,7 +4,7 @@ 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 {
|
||||||
|
|
@ -14,18 +14,18 @@ object CryptoInterface {
|
||||||
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)
|
||||||
|
|
||||||
|
|
@ -61,8 +61,10 @@ 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"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -213,8 +215,7 @@ 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
|
||||||
|
|
@ -267,10 +268,13 @@ object CryptoInterface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CryptoStateWithMAC(decryptionKey : ByteVector,
|
class CryptoStateWithMAC(
|
||||||
|
decryptionKey: ByteVector,
|
||||||
encryptionKey: ByteVector,
|
encryptionKey: ByteVector,
|
||||||
val decryptionMACKey: ByteVector,
|
val decryptionMACKey: ByteVector,
|
||||||
val encryptionMACKey : ByteVector) extends CryptoState(decryptionKey, encryptionKey) {
|
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
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
// 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
|
||||||
|
|
||||||
|
|
@ -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)"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,17 @@ 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 =
|
||||||
|
limit match {
|
||||||
case None => SizeBound.unknown
|
case None => SizeBound.unknown
|
||||||
case Some(lim) => codec.sizeBound * lim.toLong
|
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
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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]](
|
||||||
|
{
|
||||||
|
case (cnt, xs) =>
|
||||||
if (xs.size == cnt) Attempt.successful(xs)
|
if (xs.size == cnt) Attempt.successful(xs)
|
||||||
else Attempt.failure(Err(s"Insufficient number of elements: decoded ${xs.size} but should have decoded $cnt"))
|
else
|
||||||
}, xs => (xs.size, xs)).
|
Attempt.failure(Err(s"Insufficient number of elements: decoded ${xs.size} but should have decoded $cnt"))
|
||||||
withToString(s"vectorOfN($countCodec, $valueCodec)")
|
},
|
||||||
|
xs => (xs.size, xs)
|
||||||
|
)
|
||||||
|
.withToString(s"vectorOfN($countCodec, $valueCodec)")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,9 @@ 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
|
||||||
|
|
||||||
|
|
@ -54,12 +53,12 @@ object AmmoBox {
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 * */
|
/** Cosmetics * */
|
||||||
private var pStyle: Option[Cosmetics] = None
|
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.
|
||||||
|
|
@ -29,15 +41,18 @@ class Avatar(private val char_id : Long, val name : String, val faction : Planet
|
||||||
* @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 = {
|
||||||
|
|
@ -57,24 +72,28 @@ class Avatar(private val char_id : Long, val name : String, val faction : Planet
|
||||||
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.
|
||||||
|
|
@ -123,7 +142,8 @@ class Avatar(private val char_id : Long, val name : String, val faction : Planet
|
||||||
* @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 }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -137,7 +157,8 @@ class Avatar(private val char_id : Long, val name : String, val faction : Planet
|
||||||
* @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) =>
|
||||||
|
|
@ -183,16 +204,18 @@ 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(
|
||||||
|
iter: Iterator[ImplantSlot],
|
||||||
|
implantType: ImplantType.Value,
|
||||||
|
index: Int = 0
|
||||||
|
): Option[Int] = {
|
||||||
if (!iter.hasNext) {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -264,8 +287,7 @@ class Avatar(private val char_id : Long, val name : String, val faction : Planet
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -326,7 +348,8 @@ 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 =
|
||||||
|
other match {
|
||||||
case that: Avatar =>
|
case that: Avatar =>
|
||||||
(that canEqual this) &&
|
(that canEqual this) &&
|
||||||
name == that.name &&
|
name == that.name &&
|
||||||
|
|
@ -347,7 +370,13 @@ 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ 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)
|
||||||
|
extends Equipment
|
||||||
with FireModeSwitch[ConstructionFireMode] {
|
with FireModeSwitch[ConstructionFireMode] {
|
||||||
private var fireModeIndex: Int = 0
|
private var fireModeIndex: Int = 0
|
||||||
private var ammoTypeIndex: Int = 0
|
private var ammoTypeIndex: Int = 0
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ object Default {
|
||||||
|
|
||||||
//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.
|
||||||
|
|
@ -31,6 +32,7 @@ object Default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -30,11 +30,21 @@ object Deployables {
|
||||||
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)
|
||||||
|
},
|
||||||
|
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) })
|
).withDefaultValue({ () => new ExplosiveDeployable(GlobalDefinitions.boomer) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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(
|
||||||
|
s"${target.Faction}",
|
||||||
|
LocalAction.DeployableMapIcon(
|
||||||
PlanetSideGUID(0),
|
PlanetSideGUID(0),
|
||||||
DeploymentAction.Dismiss,
|
DeploymentAction.Dismiss,
|
||||||
DeployableInfo(target.GUID, Deployable.Icon(target.Definition.Item), target.Position, PlanetSideGUID(0)))
|
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))
|
||||||
|
|
@ -88,13 +101,18 @@ object Deployables {
|
||||||
*/
|
*/
|
||||||
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 =>
|
||||||
|
zone.LocalEvents.tell(
|
||||||
|
LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, zone, Some(0 seconds))),
|
||||||
|
replyTo
|
||||||
|
) //near-instant
|
||||||
obj.Owner = None
|
obj.Owner = None
|
||||||
obj.Trigger = None
|
obj.Trigger = None
|
||||||
})
|
})
|
||||||
|
|
@ -124,8 +142,6 @@ object Deployables {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the deployables backend information.
|
* Initialize the deployables backend information.
|
||||||
* @param avatar the player's core
|
* @param avatar the player's core
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,7 @@ 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
|
||||||
}
|
}
|
||||||
|
|
@ -40,7 +39,8 @@ class ExplosiveDeployableDefinition(private val objectId : Int) extends ComplexD
|
||||||
}
|
}
|
||||||
|
|
||||||
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) = {
|
||||||
|
|
@ -54,11 +54,11 @@ object ExplosiveDeployableDefinition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 =
|
||||||
|
takesDamage
|
||||||
.orElse {
|
.orElse {
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
@ -71,8 +71,7 @@ class ExplosiveDeployableControl(mine : ExplosiveDeployable) extends Actor
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -84,12 +83,13 @@ object ExplosiveDeployableControl {
|
||||||
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)
|
||||||
|
|
@ -113,9 +113,15 @@ object ExplosiveDeployableControl {
|
||||||
}
|
}
|
||||||
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(
|
||||||
|
zone.Id,
|
||||||
|
AvatarAction.Destroy(target.GUID, attribution, Service.defaultPlayerGUID, target.Position)
|
||||||
|
)
|
||||||
if (target.Health == 0) {
|
if (target.Health == 0) {
|
||||||
zone.LocalEvents ! LocalServiceMessage(zone.Id, LocalAction.TriggerEffect(Service.defaultPlayerGUID, "detonate_damaged_mine", target.GUID))
|
zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
zone.Id,
|
||||||
|
LocalAction.TriggerEffect(Service.defaultPlayerGUID, "detonate_damaged_mine", target.GUID)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -242,7 +242,9 @@ object GlobalDefinitions {
|
||||||
|
|
||||||
val lasher_projectile_ap = ProjectileDefinition(Projectiles.lasher_projectile_ap)
|
val lasher_projectile_ap = ProjectileDefinition(Projectiles.lasher_projectile_ap)
|
||||||
|
|
||||||
val liberator_bomb_cluster_bomblet_projectile = ProjectileDefinition(Projectiles.liberator_bomb_cluster_bomblet_projectile)
|
val liberator_bomb_cluster_bomblet_projectile = ProjectileDefinition(
|
||||||
|
Projectiles.liberator_bomb_cluster_bomblet_projectile
|
||||||
|
)
|
||||||
|
|
||||||
val liberator_bomb_cluster_projectile = ProjectileDefinition(Projectiles.liberator_bomb_cluster_projectile)
|
val liberator_bomb_cluster_projectile = ProjectileDefinition(Projectiles.liberator_bomb_cluster_projectile)
|
||||||
|
|
||||||
|
|
@ -653,20 +655,16 @@ object GlobalDefinitions {
|
||||||
if (index == 0 || index == 3) {
|
if (index == 0 || index == 3) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
3 //3-second fuse
|
3 //3-second fuse
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
0 //explode on contact
|
0 //explode on contact
|
||||||
}
|
}
|
||||||
}
|
} else if (index == 1 || index == 4) {
|
||||||
else if(index == 1 || index == 4) {
|
|
||||||
if (index == 1) {
|
if (index == 1) {
|
||||||
4 //3-second fuse, anchored
|
4 //3-second fuse, anchored
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
1 //explode on contact, anchored
|
1 //explode on contact, anchored
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
index
|
index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1157,7 +1155,6 @@ object GlobalDefinitions {
|
||||||
val vt_spawn = new BuildingDefinition(984) { Name = "vt_spawn" }
|
val vt_spawn = new BuildingDefinition(984) { Name = "vt_spawn" }
|
||||||
val vt_vehicle = new BuildingDefinition(985) { Name = "vt_vehicle" }
|
val vt_vehicle = new BuildingDefinition(985) { Name = "vt_vehicle" }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a faction, provide the standard assault melee weapon.
|
* Given a faction, provide the standard assault melee weapon.
|
||||||
* @param faction the faction
|
* @param faction the faction
|
||||||
|
|
@ -1247,6 +1244,7 @@ object GlobalDefinitions {
|
||||||
case PlanetSideEmpire.NEUTRAL => bullet_9mm
|
case PlanetSideEmpire.NEUTRAL => bullet_9mm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For a given faction, provide the AP ammunition for the medium assault rifle.
|
* For a given faction, provide the AP ammunition for the medium assault rifle.
|
||||||
* The ammunition value here must work with the result of obtaining the rifle using the faction.
|
* The ammunition value here must work with the result of obtaining the rifle using the faction.
|
||||||
|
|
@ -1343,23 +1341,19 @@ object GlobalDefinitions {
|
||||||
def MAXArms(subtype: Int, faction: PlanetSideEmpire.Value): ToolDefinition = {
|
def MAXArms(subtype: Int, faction: PlanetSideEmpire.Value): ToolDefinition = {
|
||||||
if (subtype == 1) {
|
if (subtype == 1) {
|
||||||
AI_MAX(faction)
|
AI_MAX(faction)
|
||||||
}
|
} else if (subtype == 2) {
|
||||||
else if(subtype == 2) {
|
|
||||||
AV_MAX(faction)
|
AV_MAX(faction)
|
||||||
}
|
} else if (subtype == 3) {
|
||||||
else if(subtype == 3) {
|
|
||||||
AA_MAX(faction)
|
AA_MAX(faction)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
suppressor //there are no common pool MAX arms
|
suppressor //there are no common pool MAX arms
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def isMaxArms(tdef: ToolDefinition): Boolean = {
|
def isMaxArms(tdef: ToolDefinition): Boolean = {
|
||||||
tdef match {
|
tdef match {
|
||||||
case `trhev_dualcycler` | `nchev_scattercannon` | `vshev_quasar`
|
case `trhev_dualcycler` | `nchev_scattercannon` | `vshev_quasar` | `trhev_pounder` | `nchev_falcon` |
|
||||||
| `trhev_pounder` | `nchev_falcon` | `vshev_comet`
|
`vshev_comet` | `trhev_burster` | `nchev_sparrow` | `vshev_starfire` =>
|
||||||
| `trhev_burster` | `nchev_sparrow` | `vshev_starfire` =>
|
|
||||||
true
|
true
|
||||||
case _ =>
|
case _ =>
|
||||||
false
|
false
|
||||||
|
|
@ -1468,11 +1462,14 @@ object GlobalDefinitions {
|
||||||
*/
|
*/
|
||||||
def isFactionWeapon(edef: EquipmentDefinition): PlanetSideEmpire.Value = {
|
def isFactionWeapon(edef: EquipmentDefinition): PlanetSideEmpire.Value = {
|
||||||
edef match {
|
edef match {
|
||||||
case `chainblade` | `repeater` | `anniversary_guna` | `cycler` | `mini_chaingun` | `striker` | `trhev_dualcycler` | `trhev_pounder` | `trhev_burster` =>
|
case `chainblade` | `repeater` | `anniversary_guna` | `cycler` | `mini_chaingun` | `striker` |
|
||||||
|
`trhev_dualcycler` | `trhev_pounder` | `trhev_burster` =>
|
||||||
PlanetSideEmpire.TR
|
PlanetSideEmpire.TR
|
||||||
case `magcutter` | `isp` | `anniversary_gun` | `gauss` | `r_shotgun` | `hunterseeker` | `nchev_scattercannon` | `nchev_falcon` | `nchev_sparrow` =>
|
case `magcutter` | `isp` | `anniversary_gun` | `gauss` | `r_shotgun` | `hunterseeker` | `nchev_scattercannon` |
|
||||||
|
`nchev_falcon` | `nchev_sparrow` =>
|
||||||
PlanetSideEmpire.NC
|
PlanetSideEmpire.NC
|
||||||
case `forceblade` | `beamer` | `anniversary_gunb` | `pulsar` | `lasher` | `lancer` | `vshev_quasar` | `vshev_comet` | `vshev_starfire` =>
|
case `forceblade` | `beamer` | `anniversary_gunb` | `pulsar` | `lasher` | `lancer` | `vshev_quasar` |
|
||||||
|
`vshev_comet` | `vshev_starfire` =>
|
||||||
PlanetSideEmpire.VS
|
PlanetSideEmpire.VS
|
||||||
case _ =>
|
case _ =>
|
||||||
PlanetSideEmpire.NEUTRAL
|
PlanetSideEmpire.NEUTRAL
|
||||||
|
|
@ -1487,11 +1484,17 @@ object GlobalDefinitions {
|
||||||
*/
|
*/
|
||||||
def isFactionEquipment(edef: EquipmentDefinition): PlanetSideEmpire.Value = {
|
def isFactionEquipment(edef: EquipmentDefinition): PlanetSideEmpire.Value = {
|
||||||
edef match {
|
edef match {
|
||||||
case `chainblade` | `repeater` | `anniversary_guna` | `cycler` | `mini_chaingun` | `striker` | `striker_missile_ammo` | `trhev_dualcycler` | `trhev_pounder` | `trhev_burster` | `dualcycler_ammo` | `pounder_ammo` | `burster_ammo` =>
|
case `chainblade` | `repeater` | `anniversary_guna` | `cycler` | `mini_chaingun` | `striker` |
|
||||||
|
`striker_missile_ammo` | `trhev_dualcycler` | `trhev_pounder` | `trhev_burster` | `dualcycler_ammo` |
|
||||||
|
`pounder_ammo` | `burster_ammo` =>
|
||||||
PlanetSideEmpire.TR
|
PlanetSideEmpire.TR
|
||||||
case `magcutter` | `isp` | `anniversary_gun` | `gauss` | `r_shotgun` | `hunterseeker` | `hunter_seeker_missile` | `nchev_scattercannon` | `nchev_falcon` | `nchev_sparrow` | `scattercannon_ammo` | `falcon_ammo` | `sparrow_ammo` =>
|
case `magcutter` | `isp` | `anniversary_gun` | `gauss` | `r_shotgun` | `hunterseeker` | `hunter_seeker_missile` |
|
||||||
|
`nchev_scattercannon` | `nchev_falcon` | `nchev_sparrow` | `scattercannon_ammo` | `falcon_ammo` |
|
||||||
|
`sparrow_ammo` =>
|
||||||
PlanetSideEmpire.NC
|
PlanetSideEmpire.NC
|
||||||
case `forceblade` | `beamer` | `anniversary_gunb` | `pulsar` | `lasher` | `lancer` | `energy_cell` | `lancer_cartridge` | `vshev_quasar` | `vshev_comet` | `vshev_starfire` | `quasar_ammo` | `comet_ammo` | `starfire_ammo` =>
|
case `forceblade` | `beamer` | `anniversary_gunb` | `pulsar` | `lasher` | `lancer` | `energy_cell` |
|
||||||
|
`lancer_cartridge` | `vshev_quasar` | `vshev_comet` | `vshev_starfire` | `quasar_ammo` | `comet_ammo` |
|
||||||
|
`starfire_ammo` =>
|
||||||
PlanetSideEmpire.VS
|
PlanetSideEmpire.VS
|
||||||
case _ =>
|
case _ =>
|
||||||
PlanetSideEmpire.NEUTRAL
|
PlanetSideEmpire.NEUTRAL
|
||||||
|
|
@ -1546,7 +1549,8 @@ object GlobalDefinitions {
|
||||||
*/
|
*/
|
||||||
def isFlightVehicle(vdef: VehicleDefinition): Boolean = {
|
def isFlightVehicle(vdef: VehicleDefinition): Boolean = {
|
||||||
vdef match {
|
vdef match {
|
||||||
case `mosquito` | `lightgunship` | `wasp` | `liberator` | `vulture` | `phantasm` | `lodestar` | `dropship` | `galaxy_gunship` =>
|
case `mosquito` | `lightgunship` | `wasp` | `liberator` | `vulture` | `phantasm` | `lodestar` | `dropship` |
|
||||||
|
`galaxy_gunship` =>
|
||||||
true
|
true
|
||||||
case _ =>
|
case _ =>
|
||||||
false
|
false
|
||||||
|
|
@ -1575,8 +1579,7 @@ object GlobalDefinitions {
|
||||||
def canStationaryRotate(vdef: VehicleDefinition): Boolean = {
|
def canStationaryRotate(vdef: VehicleDefinition): Boolean = {
|
||||||
if (isFlightVehicle(vdef) || isHoverVehicle(vdef)) {
|
if (isFlightVehicle(vdef) || isHoverVehicle(vdef)) {
|
||||||
true
|
true
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
vdef match {
|
vdef match {
|
||||||
case `lightning` | `prowler` | `vanguard` =>
|
case `lightning` | `prowler` | `vanguard` =>
|
||||||
true
|
true
|
||||||
|
|
@ -1651,7 +1654,8 @@ object GlobalDefinitions {
|
||||||
Infiltration.Holster(4, EquipmentSize.Melee)
|
Infiltration.Holster(4, EquipmentSize.Melee)
|
||||||
|
|
||||||
def CommonMaxConfig(max: SpecialExoSuitDefinition): Unit = {
|
def CommonMaxConfig(max: SpecialExoSuitDefinition): Unit = {
|
||||||
max.Permissions = List(CertificationType.AIMAX,CertificationType.AVMAX, CertificationType.AAMAX, CertificationType.UniMAX)
|
max.Permissions =
|
||||||
|
List(CertificationType.AIMAX, CertificationType.AVMAX, CertificationType.AAMAX, CertificationType.UniMAX)
|
||||||
max.MaxArmor = 650
|
max.MaxArmor = 650
|
||||||
max.InventoryScale = InventoryTile.Tile1612
|
max.InventoryScale = InventoryTile.Tile1612
|
||||||
max.InventoryOffset = 6
|
max.InventoryOffset = 6
|
||||||
|
|
@ -1687,6 +1691,7 @@ object GlobalDefinitions {
|
||||||
NCMAX.CapacitorDrainPerSecond = 4
|
NCMAX.CapacitorDrainPerSecond = 4
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize `AmmoBoxDefinition` globals.
|
* Initialize `AmmoBoxDefinition` globals.
|
||||||
*/
|
*/
|
||||||
|
|
@ -2772,12 +2777,30 @@ object GlobalDefinitions {
|
||||||
jammer_cartridge_projectile.Lifespan = 15f
|
jammer_cartridge_projectile.Lifespan = 15f
|
||||||
jammer_cartridge_projectile.AdditionalEffect = true
|
jammer_cartridge_projectile.AdditionalEffect = true
|
||||||
jammer_cartridge_projectile.JammerProjectile = true
|
jammer_cartridge_projectile.JammerProjectile = true
|
||||||
jammer_cartridge_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Player, EffectTarget.Validation.Player) -> 1000
|
jammer_cartridge_projectile.JammedEffectDuration += TargetValidation(
|
||||||
jammer_cartridge_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Vehicle, EffectTarget.Validation.AMS) -> 5000
|
EffectTarget.Category.Player,
|
||||||
jammer_cartridge_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Deployable, EffectTarget.Validation.MotionSensor) -> 30000
|
EffectTarget.Validation.Player
|
||||||
jammer_cartridge_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Deployable, EffectTarget.Validation.Spitfire) -> 30000
|
) -> 1000
|
||||||
jammer_cartridge_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Turret, EffectTarget.Validation.Turret) -> 30000
|
jammer_cartridge_projectile.JammedEffectDuration += TargetValidation(
|
||||||
jammer_cartridge_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Vehicle, EffectTarget.Validation.VehicleNotAMS) -> 10000
|
EffectTarget.Category.Vehicle,
|
||||||
|
EffectTarget.Validation.AMS
|
||||||
|
) -> 5000
|
||||||
|
jammer_cartridge_projectile.JammedEffectDuration += TargetValidation(
|
||||||
|
EffectTarget.Category.Deployable,
|
||||||
|
EffectTarget.Validation.MotionSensor
|
||||||
|
) -> 30000
|
||||||
|
jammer_cartridge_projectile.JammedEffectDuration += TargetValidation(
|
||||||
|
EffectTarget.Category.Deployable,
|
||||||
|
EffectTarget.Validation.Spitfire
|
||||||
|
) -> 30000
|
||||||
|
jammer_cartridge_projectile.JammedEffectDuration += TargetValidation(
|
||||||
|
EffectTarget.Category.Turret,
|
||||||
|
EffectTarget.Validation.Turret
|
||||||
|
) -> 30000
|
||||||
|
jammer_cartridge_projectile.JammedEffectDuration += TargetValidation(
|
||||||
|
EffectTarget.Category.Vehicle,
|
||||||
|
EffectTarget.Validation.VehicleNotAMS
|
||||||
|
) -> 10000
|
||||||
ProjectileDefinition.CalculateDerivedFields(jammer_cartridge_projectile)
|
ProjectileDefinition.CalculateDerivedFields(jammer_cartridge_projectile)
|
||||||
|
|
||||||
jammer_cartridge_projectile_b.Name = "jammer_cartridge_projectile_b"
|
jammer_cartridge_projectile_b.Name = "jammer_cartridge_projectile_b"
|
||||||
|
|
@ -2791,12 +2814,30 @@ object GlobalDefinitions {
|
||||||
jammer_cartridge_projectile_b.Lifespan = 2f
|
jammer_cartridge_projectile_b.Lifespan = 2f
|
||||||
jammer_cartridge_projectile_b.AdditionalEffect = true
|
jammer_cartridge_projectile_b.AdditionalEffect = true
|
||||||
jammer_cartridge_projectile_b.JammerProjectile = true
|
jammer_cartridge_projectile_b.JammerProjectile = true
|
||||||
jammer_cartridge_projectile_b.JammedEffectDuration += TargetValidation(EffectTarget.Category.Player, EffectTarget.Validation.Player) -> 1000
|
jammer_cartridge_projectile_b.JammedEffectDuration += TargetValidation(
|
||||||
jammer_cartridge_projectile_b.JammedEffectDuration += TargetValidation(EffectTarget.Category.Vehicle, EffectTarget.Validation.AMS) -> 5000
|
EffectTarget.Category.Player,
|
||||||
jammer_cartridge_projectile_b.JammedEffectDuration += TargetValidation(EffectTarget.Category.Deployable, EffectTarget.Validation.MotionSensor) -> 30000
|
EffectTarget.Validation.Player
|
||||||
jammer_cartridge_projectile_b.JammedEffectDuration += TargetValidation(EffectTarget.Category.Deployable, EffectTarget.Validation.Spitfire) -> 30000
|
) -> 1000
|
||||||
jammer_cartridge_projectile_b.JammedEffectDuration += TargetValidation(EffectTarget.Category.Turret, EffectTarget.Validation.Turret) -> 30000
|
jammer_cartridge_projectile_b.JammedEffectDuration += TargetValidation(
|
||||||
jammer_cartridge_projectile_b.JammedEffectDuration += TargetValidation(EffectTarget.Category.Vehicle, EffectTarget.Validation.VehicleNotAMS) -> 10000
|
EffectTarget.Category.Vehicle,
|
||||||
|
EffectTarget.Validation.AMS
|
||||||
|
) -> 5000
|
||||||
|
jammer_cartridge_projectile_b.JammedEffectDuration += TargetValidation(
|
||||||
|
EffectTarget.Category.Deployable,
|
||||||
|
EffectTarget.Validation.MotionSensor
|
||||||
|
) -> 30000
|
||||||
|
jammer_cartridge_projectile_b.JammedEffectDuration += TargetValidation(
|
||||||
|
EffectTarget.Category.Deployable,
|
||||||
|
EffectTarget.Validation.Spitfire
|
||||||
|
) -> 30000
|
||||||
|
jammer_cartridge_projectile_b.JammedEffectDuration += TargetValidation(
|
||||||
|
EffectTarget.Category.Turret,
|
||||||
|
EffectTarget.Validation.Turret
|
||||||
|
) -> 30000
|
||||||
|
jammer_cartridge_projectile_b.JammedEffectDuration += TargetValidation(
|
||||||
|
EffectTarget.Category.Vehicle,
|
||||||
|
EffectTarget.Validation.VehicleNotAMS
|
||||||
|
) -> 10000
|
||||||
ProjectileDefinition.CalculateDerivedFields(jammer_cartridge_projectile_b)
|
ProjectileDefinition.CalculateDerivedFields(jammer_cartridge_projectile_b)
|
||||||
|
|
||||||
jammer_grenade_projectile.Name = "jammer_grenade_projectile"
|
jammer_grenade_projectile.Name = "jammer_grenade_projectile"
|
||||||
|
|
@ -2809,12 +2850,30 @@ object GlobalDefinitions {
|
||||||
jammer_grenade_projectile.Lifespan = 15f
|
jammer_grenade_projectile.Lifespan = 15f
|
||||||
jammer_grenade_projectile.AdditionalEffect = true
|
jammer_grenade_projectile.AdditionalEffect = true
|
||||||
jammer_grenade_projectile.JammerProjectile = true
|
jammer_grenade_projectile.JammerProjectile = true
|
||||||
jammer_grenade_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Player, EffectTarget.Validation.Player) -> 1000
|
jammer_grenade_projectile.JammedEffectDuration += TargetValidation(
|
||||||
jammer_grenade_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Vehicle, EffectTarget.Validation.AMS) -> 5000
|
EffectTarget.Category.Player,
|
||||||
jammer_grenade_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Deployable, EffectTarget.Validation.MotionSensor) -> 30000
|
EffectTarget.Validation.Player
|
||||||
jammer_grenade_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Deployable, EffectTarget.Validation.Spitfire) -> 30000
|
) -> 1000
|
||||||
jammer_grenade_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Turret, EffectTarget.Validation.Turret) -> 30000
|
jammer_grenade_projectile.JammedEffectDuration += TargetValidation(
|
||||||
jammer_grenade_projectile.JammedEffectDuration += TargetValidation(EffectTarget.Category.Vehicle, EffectTarget.Validation.VehicleNotAMS) -> 10000
|
EffectTarget.Category.Vehicle,
|
||||||
|
EffectTarget.Validation.AMS
|
||||||
|
) -> 5000
|
||||||
|
jammer_grenade_projectile.JammedEffectDuration += TargetValidation(
|
||||||
|
EffectTarget.Category.Deployable,
|
||||||
|
EffectTarget.Validation.MotionSensor
|
||||||
|
) -> 30000
|
||||||
|
jammer_grenade_projectile.JammedEffectDuration += TargetValidation(
|
||||||
|
EffectTarget.Category.Deployable,
|
||||||
|
EffectTarget.Validation.Spitfire
|
||||||
|
) -> 30000
|
||||||
|
jammer_grenade_projectile.JammedEffectDuration += TargetValidation(
|
||||||
|
EffectTarget.Category.Turret,
|
||||||
|
EffectTarget.Validation.Turret
|
||||||
|
) -> 30000
|
||||||
|
jammer_grenade_projectile.JammedEffectDuration += TargetValidation(
|
||||||
|
EffectTarget.Category.Vehicle,
|
||||||
|
EffectTarget.Validation.VehicleNotAMS
|
||||||
|
) -> 10000
|
||||||
ProjectileDefinition.CalculateDerivedFields(jammer_grenade_projectile)
|
ProjectileDefinition.CalculateDerivedFields(jammer_grenade_projectile)
|
||||||
|
|
||||||
jammer_grenade_projectile_enh.Name = "jammer_grenade_projectile_enh"
|
jammer_grenade_projectile_enh.Name = "jammer_grenade_projectile_enh"
|
||||||
|
|
@ -2828,12 +2887,30 @@ object GlobalDefinitions {
|
||||||
jammer_grenade_projectile_enh.Lifespan = 3f
|
jammer_grenade_projectile_enh.Lifespan = 3f
|
||||||
jammer_grenade_projectile_enh.AdditionalEffect = true
|
jammer_grenade_projectile_enh.AdditionalEffect = true
|
||||||
jammer_grenade_projectile_enh.JammerProjectile = true
|
jammer_grenade_projectile_enh.JammerProjectile = true
|
||||||
jammer_grenade_projectile_enh.JammedEffectDuration += TargetValidation(EffectTarget.Category.Player, EffectTarget.Validation.Player) -> 1000
|
jammer_grenade_projectile_enh.JammedEffectDuration += TargetValidation(
|
||||||
jammer_grenade_projectile_enh.JammedEffectDuration += TargetValidation(EffectTarget.Category.Vehicle, EffectTarget.Validation.AMS) -> 5000
|
EffectTarget.Category.Player,
|
||||||
jammer_grenade_projectile_enh.JammedEffectDuration += TargetValidation(EffectTarget.Category.Deployable, EffectTarget.Validation.MotionSensor) -> 30000
|
EffectTarget.Validation.Player
|
||||||
jammer_grenade_projectile_enh.JammedEffectDuration += TargetValidation(EffectTarget.Category.Deployable, EffectTarget.Validation.Spitfire) -> 30000
|
) -> 1000
|
||||||
jammer_grenade_projectile_enh.JammedEffectDuration += TargetValidation(EffectTarget.Category.Turret, EffectTarget.Validation.Turret) -> 30000
|
jammer_grenade_projectile_enh.JammedEffectDuration += TargetValidation(
|
||||||
jammer_grenade_projectile_enh.JammedEffectDuration += TargetValidation(EffectTarget.Category.Vehicle, EffectTarget.Validation.VehicleNotAMS) -> 10000
|
EffectTarget.Category.Vehicle,
|
||||||
|
EffectTarget.Validation.AMS
|
||||||
|
) -> 5000
|
||||||
|
jammer_grenade_projectile_enh.JammedEffectDuration += TargetValidation(
|
||||||
|
EffectTarget.Category.Deployable,
|
||||||
|
EffectTarget.Validation.MotionSensor
|
||||||
|
) -> 30000
|
||||||
|
jammer_grenade_projectile_enh.JammedEffectDuration += TargetValidation(
|
||||||
|
EffectTarget.Category.Deployable,
|
||||||
|
EffectTarget.Validation.Spitfire
|
||||||
|
) -> 30000
|
||||||
|
jammer_grenade_projectile_enh.JammedEffectDuration += TargetValidation(
|
||||||
|
EffectTarget.Category.Turret,
|
||||||
|
EffectTarget.Validation.Turret
|
||||||
|
) -> 30000
|
||||||
|
jammer_grenade_projectile_enh.JammedEffectDuration += TargetValidation(
|
||||||
|
EffectTarget.Category.Vehicle,
|
||||||
|
EffectTarget.Validation.VehicleNotAMS
|
||||||
|
) -> 10000
|
||||||
ProjectileDefinition.CalculateDerivedFields(jammer_grenade_projectile_enh)
|
ProjectileDefinition.CalculateDerivedFields(jammer_grenade_projectile_enh)
|
||||||
|
|
||||||
katana_projectile.Name = "katana_projectile"
|
katana_projectile.Name = "katana_projectile"
|
||||||
|
|
@ -4569,7 +4646,9 @@ object GlobalDefinitions {
|
||||||
ace.Modes(2).Item(DeployedItem.spitfire_aa -> Set(CertificationType.FortificationEngineering))
|
ace.Modes(2).Item(DeployedItem.spitfire_aa -> Set(CertificationType.FortificationEngineering))
|
||||||
ace.Modes += new ConstructionFireMode
|
ace.Modes += new ConstructionFireMode
|
||||||
ace.Modes(3).Item(DeployedItem.motionalarmsensor -> Set(CertificationType.CombatEngineering))
|
ace.Modes(3).Item(DeployedItem.motionalarmsensor -> Set(CertificationType.CombatEngineering))
|
||||||
ace.Modes(3).Item(DeployedItem.sensor_shield -> Set(CertificationType.AdvancedHacking, CertificationType.CombatEngineering))
|
ace
|
||||||
|
.Modes(3)
|
||||||
|
.Item(DeployedItem.sensor_shield -> Set(CertificationType.AdvancedHacking, CertificationType.CombatEngineering))
|
||||||
ace.Tile = InventoryTile.Tile33
|
ace.Tile = InventoryTile.Tile33
|
||||||
|
|
||||||
advanced_ace.Name = "advanced_ace"
|
advanced_ace.Name = "advanced_ace"
|
||||||
|
|
@ -4619,7 +4698,8 @@ object GlobalDefinitions {
|
||||||
scythe.FireModes += new FireModeDefinition
|
scythe.FireModes += new FireModeDefinition
|
||||||
scythe.FireModes(1).AmmoTypeIndices += 0
|
scythe.FireModes(1).AmmoTypeIndices += 0
|
||||||
scythe.FireModes(1).ProjectileTypeIndices += 0
|
scythe.FireModes(1).ProjectileTypeIndices += 0
|
||||||
scythe.FireModes(1).AmmoSlotIndex = 1 //note: the scythe has two magazines using a single pool; however, it can not ammo-switch or mode-switch
|
scythe.FireModes(1).AmmoSlotIndex =
|
||||||
|
1 //note: the scythe has two magazines using a single pool; however, it can not ammo-switch or mode-switch
|
||||||
scythe.FireModes(1).Magazine = 250
|
scythe.FireModes(1).Magazine = 250
|
||||||
|
|
||||||
chaingun_p.Name = "chaingun_p"
|
chaingun_p.Name = "chaingun_p"
|
||||||
|
|
@ -5957,7 +6037,8 @@ object GlobalDefinitions {
|
||||||
vulture.TrunkLocation = Vector3(-0.76f, -1.88f, 0f)
|
vulture.TrunkLocation = Vector3(-0.76f, -1.88f, 0f)
|
||||||
vulture.AutoPilotSpeeds = (0, 4)
|
vulture.AutoPilotSpeeds = (0, 4)
|
||||||
vulture.Packet = variantConverter
|
vulture.Packet = variantConverter
|
||||||
vulture.DestroyedModel = Some(DestroyedVehicle.Liberator) //add_property vulture destroyedphysics liberator_destroyed
|
vulture.DestroyedModel =
|
||||||
|
Some(DestroyedVehicle.Liberator) //add_property vulture destroyedphysics liberator_destroyed
|
||||||
vulture.Subtract.Damage1 = 5
|
vulture.Subtract.Damage1 = 5
|
||||||
vulture.JackingDuration = Array(0, 30, 10, 5)
|
vulture.JackingDuration = Array(0, 30, 10, 5)
|
||||||
|
|
||||||
|
|
@ -6058,7 +6139,8 @@ object GlobalDefinitions {
|
||||||
galaxy_gunship.TrunkLocation = Vector3(-9.85f, 0f, 0f)
|
galaxy_gunship.TrunkLocation = Vector3(-9.85f, 0f, 0f)
|
||||||
galaxy_gunship.AutoPilotSpeeds = (0, 4)
|
galaxy_gunship.AutoPilotSpeeds = (0, 4)
|
||||||
galaxy_gunship.Packet = variantConverter
|
galaxy_gunship.Packet = variantConverter
|
||||||
galaxy_gunship.DestroyedModel = Some(DestroyedVehicle.Dropship) //the adb calls out a galaxy_gunship_destroyed but no such asset exists
|
galaxy_gunship.DestroyedModel =
|
||||||
|
Some(DestroyedVehicle.Dropship) //the adb calls out a galaxy_gunship_destroyed but no such asset exists
|
||||||
galaxy_gunship.Subtract.Damage1 = 7
|
galaxy_gunship.Subtract.Damage1 = 7
|
||||||
galaxy_gunship.JackingDuration = Array(0, 60, 20, 10)
|
galaxy_gunship.JackingDuration = Array(0, 60, 20, 10)
|
||||||
|
|
||||||
|
|
@ -6351,9 +6433,16 @@ object GlobalDefinitions {
|
||||||
spawn_terminal.Repairable = false
|
spawn_terminal.Repairable = false
|
||||||
|
|
||||||
order_terminal.Name = "order_terminal"
|
order_terminal.Name = "order_terminal"
|
||||||
order_terminal.Tab += 0 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.infantryAmmunition ++ EquipmentTerminalDefinition.infantryWeapons)
|
order_terminal.Tab += 0 -> OrderTerminalDefinition.EquipmentPage(
|
||||||
order_terminal.Tab += 1 -> OrderTerminalDefinition.ArmorWithAmmoPage(EquipmentTerminalDefinition.suits ++ EquipmentTerminalDefinition.maxSuits, EquipmentTerminalDefinition.maxAmmo)
|
EquipmentTerminalDefinition.infantryAmmunition ++ EquipmentTerminalDefinition.infantryWeapons
|
||||||
order_terminal.Tab += 2 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.supportAmmunition ++ EquipmentTerminalDefinition.supportWeapons)
|
)
|
||||||
|
order_terminal.Tab += 1 -> OrderTerminalDefinition.ArmorWithAmmoPage(
|
||||||
|
EquipmentTerminalDefinition.suits ++ EquipmentTerminalDefinition.maxSuits,
|
||||||
|
EquipmentTerminalDefinition.maxAmmo
|
||||||
|
)
|
||||||
|
order_terminal.Tab += 2 -> OrderTerminalDefinition.EquipmentPage(
|
||||||
|
EquipmentTerminalDefinition.supportAmmunition ++ EquipmentTerminalDefinition.supportWeapons
|
||||||
|
)
|
||||||
order_terminal.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
order_terminal.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
||||||
order_terminal.Tab += 4 -> OrderTerminalDefinition.InfantryLoadoutPage()
|
order_terminal.Tab += 4 -> OrderTerminalDefinition.InfantryLoadoutPage()
|
||||||
order_terminal.SellEquipmentByDefault = true
|
order_terminal.SellEquipmentByDefault = true
|
||||||
|
|
@ -6364,9 +6453,16 @@ object GlobalDefinitions {
|
||||||
order_terminal.Subtract.Damage1 = 8
|
order_terminal.Subtract.Damage1 = 8
|
||||||
|
|
||||||
order_terminala.Name = "order_terminala"
|
order_terminala.Name = "order_terminala"
|
||||||
order_terminala.Tab += 0 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.infantryAmmunition ++ EquipmentTerminalDefinition.infantryWeapons)
|
order_terminala.Tab += 0 -> OrderTerminalDefinition.EquipmentPage(
|
||||||
order_terminala.Tab += 1 -> OrderTerminalDefinition.ArmorWithAmmoPage(EquipmentTerminalDefinition.suits, EquipmentTerminalDefinition.maxAmmo)
|
EquipmentTerminalDefinition.infantryAmmunition ++ EquipmentTerminalDefinition.infantryWeapons
|
||||||
order_terminala.Tab += 2 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.supportAmmunition ++ EquipmentTerminalDefinition.supportWeapons)
|
)
|
||||||
|
order_terminala.Tab += 1 -> OrderTerminalDefinition.ArmorWithAmmoPage(
|
||||||
|
EquipmentTerminalDefinition.suits,
|
||||||
|
EquipmentTerminalDefinition.maxAmmo
|
||||||
|
)
|
||||||
|
order_terminala.Tab += 2 -> OrderTerminalDefinition.EquipmentPage(
|
||||||
|
EquipmentTerminalDefinition.supportAmmunition ++ EquipmentTerminalDefinition.supportWeapons
|
||||||
|
)
|
||||||
order_terminala.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
order_terminala.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
||||||
order_terminala.Tab += 4 -> OrderTerminalDefinition.InfantryLoadoutPage()
|
order_terminala.Tab += 4 -> OrderTerminalDefinition.InfantryLoadoutPage()
|
||||||
order_terminala.Tab(4).asInstanceOf[OrderTerminalDefinition.InfantryLoadoutPage].Exclude = ExoSuitType.MAX
|
order_terminala.Tab(4).asInstanceOf[OrderTerminalDefinition.InfantryLoadoutPage].Exclude = ExoSuitType.MAX
|
||||||
|
|
@ -6375,9 +6471,16 @@ object GlobalDefinitions {
|
||||||
order_terminala.Repairable = false
|
order_terminala.Repairable = false
|
||||||
|
|
||||||
order_terminalb.Name = "order_terminalb"
|
order_terminalb.Name = "order_terminalb"
|
||||||
order_terminalb.Tab += 0 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.infantryAmmunition ++ EquipmentTerminalDefinition.infantryWeapons)
|
order_terminalb.Tab += 0 -> OrderTerminalDefinition.EquipmentPage(
|
||||||
order_terminalb.Tab += 1 -> OrderTerminalDefinition.ArmorWithAmmoPage(EquipmentTerminalDefinition.suits, EquipmentTerminalDefinition.maxAmmo)
|
EquipmentTerminalDefinition.infantryAmmunition ++ EquipmentTerminalDefinition.infantryWeapons
|
||||||
order_terminalb.Tab += 2 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.supportAmmunition ++ EquipmentTerminalDefinition.supportWeapons)
|
)
|
||||||
|
order_terminalb.Tab += 1 -> OrderTerminalDefinition.ArmorWithAmmoPage(
|
||||||
|
EquipmentTerminalDefinition.suits,
|
||||||
|
EquipmentTerminalDefinition.maxAmmo
|
||||||
|
)
|
||||||
|
order_terminalb.Tab += 2 -> OrderTerminalDefinition.EquipmentPage(
|
||||||
|
EquipmentTerminalDefinition.supportAmmunition ++ EquipmentTerminalDefinition.supportWeapons
|
||||||
|
)
|
||||||
order_terminalb.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
order_terminalb.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
||||||
order_terminalb.Tab += 4 -> OrderTerminalDefinition.InfantryLoadoutPage()
|
order_terminalb.Tab += 4 -> OrderTerminalDefinition.InfantryLoadoutPage()
|
||||||
order_terminalb.Tab(4).asInstanceOf[OrderTerminalDefinition.InfantryLoadoutPage].Exclude = ExoSuitType.MAX
|
order_terminalb.Tab(4).asInstanceOf[OrderTerminalDefinition.InfantryLoadoutPage].Exclude = ExoSuitType.MAX
|
||||||
|
|
@ -6386,9 +6489,16 @@ object GlobalDefinitions {
|
||||||
order_terminalb.Repairable = false
|
order_terminalb.Repairable = false
|
||||||
|
|
||||||
vanu_equipment_term.Name = "vanu_equipment_term"
|
vanu_equipment_term.Name = "vanu_equipment_term"
|
||||||
vanu_equipment_term.Tab += 0 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.infantryAmmunition ++ EquipmentTerminalDefinition.infantryWeapons)
|
vanu_equipment_term.Tab += 0 -> OrderTerminalDefinition.EquipmentPage(
|
||||||
vanu_equipment_term.Tab += 1 -> OrderTerminalDefinition.ArmorWithAmmoPage(EquipmentTerminalDefinition.suits ++ EquipmentTerminalDefinition.maxSuits, EquipmentTerminalDefinition.maxAmmo)
|
EquipmentTerminalDefinition.infantryAmmunition ++ EquipmentTerminalDefinition.infantryWeapons
|
||||||
vanu_equipment_term.Tab += 2 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.supportAmmunition ++ EquipmentTerminalDefinition.supportWeapons)
|
)
|
||||||
|
vanu_equipment_term.Tab += 1 -> OrderTerminalDefinition.ArmorWithAmmoPage(
|
||||||
|
EquipmentTerminalDefinition.suits ++ EquipmentTerminalDefinition.maxSuits,
|
||||||
|
EquipmentTerminalDefinition.maxAmmo
|
||||||
|
)
|
||||||
|
vanu_equipment_term.Tab += 2 -> OrderTerminalDefinition.EquipmentPage(
|
||||||
|
EquipmentTerminalDefinition.supportAmmunition ++ EquipmentTerminalDefinition.supportWeapons
|
||||||
|
)
|
||||||
vanu_equipment_term.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
vanu_equipment_term.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
||||||
vanu_equipment_term.Tab += 4 -> OrderTerminalDefinition.InfantryLoadoutPage()
|
vanu_equipment_term.Tab += 4 -> OrderTerminalDefinition.InfantryLoadoutPage()
|
||||||
vanu_equipment_term.SellEquipmentByDefault = true
|
vanu_equipment_term.SellEquipmentByDefault = true
|
||||||
|
|
@ -6417,7 +6527,10 @@ object GlobalDefinitions {
|
||||||
implant_terminal_interface.RepairIfDestroyed = true
|
implant_terminal_interface.RepairIfDestroyed = true
|
||||||
|
|
||||||
ground_vehicle_terminal.Name = "ground_vehicle_terminal"
|
ground_vehicle_terminal.Name = "ground_vehicle_terminal"
|
||||||
ground_vehicle_terminal.Tab += 46769 -> OrderTerminalDefinition.VehiclePage(VehicleTerminalDefinition.groundVehicles, VehicleTerminalDefinition.trunk)
|
ground_vehicle_terminal.Tab += 46769 -> OrderTerminalDefinition.VehiclePage(
|
||||||
|
VehicleTerminalDefinition.groundVehicles,
|
||||||
|
VehicleTerminalDefinition.trunk
|
||||||
|
)
|
||||||
ground_vehicle_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
ground_vehicle_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
||||||
ground_vehicle_terminal.MaxHealth = 500
|
ground_vehicle_terminal.MaxHealth = 500
|
||||||
ground_vehicle_terminal.Damageable = true
|
ground_vehicle_terminal.Damageable = true
|
||||||
|
|
@ -6426,7 +6539,10 @@ object GlobalDefinitions {
|
||||||
ground_vehicle_terminal.Subtract.Damage1 = 8
|
ground_vehicle_terminal.Subtract.Damage1 = 8
|
||||||
|
|
||||||
air_vehicle_terminal.Name = "air_vehicle_terminal"
|
air_vehicle_terminal.Name = "air_vehicle_terminal"
|
||||||
air_vehicle_terminal.Tab += 46769 -> OrderTerminalDefinition.VehiclePage(VehicleTerminalDefinition.flight1Vehicles, VehicleTerminalDefinition.trunk)
|
air_vehicle_terminal.Tab += 46769 -> OrderTerminalDefinition.VehiclePage(
|
||||||
|
VehicleTerminalDefinition.flight1Vehicles,
|
||||||
|
VehicleTerminalDefinition.trunk
|
||||||
|
)
|
||||||
air_vehicle_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
air_vehicle_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
||||||
air_vehicle_terminal.MaxHealth = 500
|
air_vehicle_terminal.MaxHealth = 500
|
||||||
air_vehicle_terminal.Damageable = true
|
air_vehicle_terminal.Damageable = true
|
||||||
|
|
@ -6435,7 +6551,10 @@ object GlobalDefinitions {
|
||||||
air_vehicle_terminal.Subtract.Damage1 = 8
|
air_vehicle_terminal.Subtract.Damage1 = 8
|
||||||
|
|
||||||
dropship_vehicle_terminal.Name = "dropship_vehicle_terminal"
|
dropship_vehicle_terminal.Name = "dropship_vehicle_terminal"
|
||||||
dropship_vehicle_terminal.Tab += 46769 -> OrderTerminalDefinition.VehiclePage(VehicleTerminalDefinition.flight1Vehicles ++ VehicleTerminalDefinition.flight2Vehicles, VehicleTerminalDefinition.trunk)
|
dropship_vehicle_terminal.Tab += 46769 -> OrderTerminalDefinition.VehiclePage(
|
||||||
|
VehicleTerminalDefinition.flight1Vehicles ++ VehicleTerminalDefinition.flight2Vehicles,
|
||||||
|
VehicleTerminalDefinition.trunk
|
||||||
|
)
|
||||||
dropship_vehicle_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
dropship_vehicle_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
||||||
dropship_vehicle_terminal.MaxHealth = 500
|
dropship_vehicle_terminal.MaxHealth = 500
|
||||||
dropship_vehicle_terminal.Damageable = true
|
dropship_vehicle_terminal.Damageable = true
|
||||||
|
|
@ -6444,7 +6563,10 @@ object GlobalDefinitions {
|
||||||
dropship_vehicle_terminal.Subtract.Damage1 = 8
|
dropship_vehicle_terminal.Subtract.Damage1 = 8
|
||||||
|
|
||||||
vehicle_terminal_combined.Name = "vehicle_terminal_combined"
|
vehicle_terminal_combined.Name = "vehicle_terminal_combined"
|
||||||
vehicle_terminal_combined.Tab += 46769 -> OrderTerminalDefinition.VehiclePage(VehicleTerminalDefinition.flight1Vehicles ++ VehicleTerminalDefinition.groundVehicles, VehicleTerminalDefinition.trunk)
|
vehicle_terminal_combined.Tab += 46769 -> OrderTerminalDefinition.VehiclePage(
|
||||||
|
VehicleTerminalDefinition.flight1Vehicles ++ VehicleTerminalDefinition.groundVehicles,
|
||||||
|
VehicleTerminalDefinition.trunk
|
||||||
|
)
|
||||||
vehicle_terminal_combined.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
vehicle_terminal_combined.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
||||||
vehicle_terminal_combined.MaxHealth = 500
|
vehicle_terminal_combined.MaxHealth = 500
|
||||||
vehicle_terminal_combined.Damageable = true
|
vehicle_terminal_combined.Damageable = true
|
||||||
|
|
@ -6453,7 +6575,10 @@ object GlobalDefinitions {
|
||||||
vehicle_terminal_combined.Subtract.Damage1 = 8
|
vehicle_terminal_combined.Subtract.Damage1 = 8
|
||||||
|
|
||||||
vanu_air_vehicle_term.Name = "vanu_air_vehicle_term"
|
vanu_air_vehicle_term.Name = "vanu_air_vehicle_term"
|
||||||
vanu_air_vehicle_term.Tab += 46769 -> OrderTerminalDefinition.VehiclePage(VehicleTerminalDefinition.flight1Vehicles, VehicleTerminalDefinition.trunk)
|
vanu_air_vehicle_term.Tab += 46769 -> OrderTerminalDefinition.VehiclePage(
|
||||||
|
VehicleTerminalDefinition.flight1Vehicles,
|
||||||
|
VehicleTerminalDefinition.trunk
|
||||||
|
)
|
||||||
vanu_air_vehicle_term.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
vanu_air_vehicle_term.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
||||||
vanu_air_vehicle_term.MaxHealth = 500
|
vanu_air_vehicle_term.MaxHealth = 500
|
||||||
vanu_air_vehicle_term.Damageable = true
|
vanu_air_vehicle_term.Damageable = true
|
||||||
|
|
@ -6462,7 +6587,10 @@ object GlobalDefinitions {
|
||||||
vanu_air_vehicle_term.Subtract.Damage1 = 8
|
vanu_air_vehicle_term.Subtract.Damage1 = 8
|
||||||
|
|
||||||
vanu_vehicle_term.Name = "vanu_vehicle_term"
|
vanu_vehicle_term.Name = "vanu_vehicle_term"
|
||||||
vanu_vehicle_term.Tab += 46769 -> OrderTerminalDefinition.VehiclePage(VehicleTerminalDefinition.groundVehicles, VehicleTerminalDefinition.trunk)
|
vanu_vehicle_term.Tab += 46769 -> OrderTerminalDefinition.VehiclePage(
|
||||||
|
VehicleTerminalDefinition.groundVehicles,
|
||||||
|
VehicleTerminalDefinition.trunk
|
||||||
|
)
|
||||||
vanu_vehicle_term.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
vanu_vehicle_term.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
||||||
vanu_vehicle_term.MaxHealth = 500
|
vanu_vehicle_term.MaxHealth = 500
|
||||||
vanu_vehicle_term.Damageable = true
|
vanu_vehicle_term.Damageable = true
|
||||||
|
|
@ -6471,7 +6599,10 @@ object GlobalDefinitions {
|
||||||
vanu_vehicle_term.Subtract.Damage1 = 8
|
vanu_vehicle_term.Subtract.Damage1 = 8
|
||||||
|
|
||||||
bfr_terminal.Name = "bfr_terminal"
|
bfr_terminal.Name = "bfr_terminal"
|
||||||
bfr_terminal.Tab += 46769 -> OrderTerminalDefinition.VehiclePage(VehicleTerminalDefinition.bfrVehicles, VehicleTerminalDefinition.trunk)
|
bfr_terminal.Tab += 46769 -> OrderTerminalDefinition.VehiclePage(
|
||||||
|
VehicleTerminalDefinition.bfrVehicles,
|
||||||
|
VehicleTerminalDefinition.trunk
|
||||||
|
)
|
||||||
bfr_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
bfr_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
||||||
bfr_terminal.MaxHealth = 500
|
bfr_terminal.MaxHealth = 500
|
||||||
bfr_terminal.Damageable = true
|
bfr_terminal.Damageable = true
|
||||||
|
|
@ -6632,14 +6763,18 @@ object GlobalDefinitions {
|
||||||
lodestar_repair_terminal.Repairable = false
|
lodestar_repair_terminal.Repairable = false
|
||||||
|
|
||||||
multivehicle_rearm_terminal.Name = "multivehicle_rearm_terminal"
|
multivehicle_rearm_terminal.Name = "multivehicle_rearm_terminal"
|
||||||
multivehicle_rearm_terminal.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
multivehicle_rearm_terminal.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(
|
||||||
|
EquipmentTerminalDefinition.vehicleAmmunition
|
||||||
|
)
|
||||||
multivehicle_rearm_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
multivehicle_rearm_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
||||||
multivehicle_rearm_terminal.SellEquipmentByDefault = true //TODO ?
|
multivehicle_rearm_terminal.SellEquipmentByDefault = true //TODO ?
|
||||||
multivehicle_rearm_terminal.Damageable = false
|
multivehicle_rearm_terminal.Damageable = false
|
||||||
multivehicle_rearm_terminal.Repairable = false
|
multivehicle_rearm_terminal.Repairable = false
|
||||||
|
|
||||||
bfr_rearm_terminal.Name = "bfr_rearm_terminal"
|
bfr_rearm_terminal.Name = "bfr_rearm_terminal"
|
||||||
bfr_rearm_terminal.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(Map.empty[String, ()=>Equipment]) //TODO add stock to page
|
bfr_rearm_terminal.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(
|
||||||
|
Map.empty[String, () => Equipment]
|
||||||
|
) //TODO add stock to page
|
||||||
bfr_rearm_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
bfr_rearm_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
||||||
bfr_rearm_terminal.SellEquipmentByDefault = true //TODO ?
|
bfr_rearm_terminal.SellEquipmentByDefault = true //TODO ?
|
||||||
bfr_rearm_terminal.Damageable = false
|
bfr_rearm_terminal.Damageable = false
|
||||||
|
|
@ -6653,7 +6788,9 @@ object GlobalDefinitions {
|
||||||
air_rearm_terminal.Repairable = false
|
air_rearm_terminal.Repairable = false
|
||||||
|
|
||||||
ground_rearm_terminal.Name = "ground_rearm_terminal"
|
ground_rearm_terminal.Name = "ground_rearm_terminal"
|
||||||
ground_rearm_terminal.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(EquipmentTerminalDefinition.vehicleAmmunition)
|
ground_rearm_terminal.Tab += 3 -> OrderTerminalDefinition.EquipmentPage(
|
||||||
|
EquipmentTerminalDefinition.vehicleAmmunition
|
||||||
|
)
|
||||||
ground_rearm_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
ground_rearm_terminal.Tab += 4 -> OrderTerminalDefinition.VehicleLoadoutPage()
|
||||||
ground_rearm_terminal.SellEquipmentByDefault = true //TODO ?
|
ground_rearm_terminal.SellEquipmentByDefault = true //TODO ?
|
||||||
ground_rearm_terminal.Damageable = false
|
ground_rearm_terminal.Damageable = false
|
||||||
|
|
|
||||||
|
|
@ -14,14 +14,20 @@ 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
|
||||||
|
|
||||||
|
|
@ -54,7 +60,8 @@ class ImplantSlot {
|
||||||
Active
|
Active
|
||||||
}
|
}
|
||||||
|
|
||||||
def Implant : ImplantType.Value = Installed match {
|
def Implant: ImplantType.Value =
|
||||||
|
Installed match {
|
||||||
case Some(idef) =>
|
case Some(idef) =>
|
||||||
idef.Type
|
idef.Type
|
||||||
case None =>
|
case None =>
|
||||||
|
|
@ -83,7 +90,8 @@ class ImplantSlot {
|
||||||
|
|
||||||
def Installed: Option[ImplantDefinition] = implant
|
def Installed: Option[ImplantDefinition] = implant
|
||||||
|
|
||||||
def MaxTimer : Long = Implant match {
|
def MaxTimer: Long =
|
||||||
|
Implant match {
|
||||||
case ImplantType.None =>
|
case ImplantType.None =>
|
||||||
-1L
|
-1L
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
@ -93,8 +101,7 @@ class ImplantSlot {
|
||||||
def ActivationCharge: Int = {
|
def ActivationCharge: Int = {
|
||||||
if (Active) {
|
if (Active) {
|
||||||
Installed.get.ActivationStaminaCost
|
Installed.get.ActivationStaminaCost
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -108,8 +115,7 @@ class ImplantSlot {
|
||||||
if (Active) {
|
if (Active) {
|
||||||
val inst = Installed.get
|
val inst = Installed.get
|
||||||
inst.StaminaCost
|
inst.StaminaCost
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ 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 */
|
/** key - the session id; value - a `Player` object */
|
||||||
private val sessionMap: Map[Long, Avatar] = new TrieMap[Long, Avatar]
|
private val sessionMap: Map[Long, Avatar] = new TrieMap[Long, Avatar]
|
||||||
|
|
||||||
|
|
@ -48,6 +49,7 @@ private class LivePlayerList {
|
||||||
* `LivePlayerList.Remove(session)`
|
* `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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,7 @@ 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)
|
||||||
|
|
||||||
|
|
@ -44,8 +43,7 @@ object 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
|
||||||
|
|
@ -65,11 +63,11 @@ class LockerEquipment(locker : LockerContainer) extends Equipment
|
||||||
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 =
|
||||||
|
containerBehavior
|
||||||
.orElse {
|
.orElse {
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
@ -116,6 +114,12 @@ 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)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ class OffhandEquipmentSlot(size : EquipmentSize.Value) extends EquipmentSlot {
|
||||||
}
|
}
|
||||||
|
|
||||||
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.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,8 @@ abstract class PlanetSideGameObject extends IdentifiableEntity with WorldEntity
|
||||||
|
|
||||||
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})"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,7 +21,8 @@ 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)
|
||||||
|
extends PlanetSideServerObject
|
||||||
with FactionAffinity
|
with FactionAffinity
|
||||||
with Vitality
|
with Vitality
|
||||||
with ResistanceProfile
|
with ResistanceProfile
|
||||||
|
|
@ -48,7 +54,8 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
|
||||||
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 =
|
||||||
|
false // If stamina drops to 0, player is fatigued until regenerating at least 20 stamina
|
||||||
private var afk: Boolean = false
|
private var afk: Boolean = false
|
||||||
|
|
||||||
private var vehicleSeated: Option[PlanetSideGUID] = None
|
private var vehicleSeated: Option[PlanetSideGUID] = None
|
||||||
|
|
@ -60,6 +67,7 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
|
||||||
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
|
||||||
|
|
@ -113,8 +121,7 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
|
||||||
if (!isAlive) {
|
if (!isAlive) {
|
||||||
backpack = true
|
backpack = true
|
||||||
true
|
true
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -122,7 +129,8 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,12 +158,10 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
|
||||||
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
|
||||||
|
|
@ -180,27 +186,23 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
|
||||||
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] =
|
||||||
|
if (exosuit.SuitType == ExoSuitType.MAX) {
|
||||||
Set(0)
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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(
|
||||||
|
iter: Iterator[EquipmentSlot],
|
||||||
|
objSize: EquipmentSize.Value,
|
||||||
|
index: Int = 0
|
||||||
|
): Option[Int] = {
|
||||||
if (!iter.hasNext) {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -259,23 +264,24 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
|
||||||
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(
|
||||||
|
iter: Iterator[EquipmentSlot],
|
||||||
|
guid: PlanetSideGUID,
|
||||||
|
index: Int = 0
|
||||||
|
): Option[Int] = {
|
||||||
if (!iter.hasNext) {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -289,16 +295,14 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -309,8 +313,7 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
@ -428,8 +431,7 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
|
||||||
Cosmetics(value)
|
Cosmetics(value)
|
||||||
}
|
}
|
||||||
(original, core.PersonalStyleFeatures)
|
(original, core.PersonalStyleFeatures)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
(None, None)
|
(None, None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -444,12 +446,12 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def BasicFeatureToggle(feature : PersonalStyle.Value) : (Option[Cosmetics], Option[Cosmetics]) = core.PersonalStyleFeatures match {
|
private def BasicFeatureToggle(feature: PersonalStyle.Value): (Option[Cosmetics], Option[Cosmetics]) =
|
||||||
|
core.PersonalStyleFeatures match {
|
||||||
case Some(c: Cosmetics) =>
|
case Some(c: Cosmetics) =>
|
||||||
if (c.Styles.contains(feature)) {
|
if (c.Styles.contains(feature)) {
|
||||||
RemoveFromPersonalStyle(feature)
|
RemoveFromPersonalStyle(feature)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
AddToPersonalStyle(feature)
|
AddToPersonalStyle(feature)
|
||||||
}
|
}
|
||||||
case None =>
|
case None =>
|
||||||
|
|
@ -466,13 +468,10 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
|
||||||
core.PersonalStyleFeatures match {
|
core.PersonalStyleFeatures match {
|
||||||
case Some(c: Cosmetics) =>
|
case Some(c: Cosmetics) =>
|
||||||
if (c.Styles.contains(PersonalStyle.BrimmedCap)) {
|
if (c.Styles.contains(PersonalStyle.BrimmedCap)) {
|
||||||
(RemoveFromPersonalStyle(PersonalStyle.BrimmedCap)._1,
|
(RemoveFromPersonalStyle(PersonalStyle.BrimmedCap)._1, AddToPersonalStyle(PersonalStyle.Beret)._2)
|
||||||
AddToPersonalStyle(PersonalStyle.Beret)._2)
|
} else if (c.Styles.contains(PersonalStyle.Beret)) {
|
||||||
}
|
|
||||||
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,7 +479,8 @@ 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
|
||||||
|
|
||||||
|
|
@ -492,8 +492,7 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
|
||||||
case PlanetSideEmpire.NC => UsingShield
|
case PlanetSideEmpire.NC => UsingShield
|
||||||
case _ => DefaultUsingSpecial
|
case _ => DefaultUsingSpecial
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
usingSpecial = DefaultUsingSpecial
|
usingSpecial = DefaultUsingSpecial
|
||||||
gettingSpecial = DefaultGettingSpecial
|
gettingSpecial = DefaultGettingSpecial
|
||||||
}
|
}
|
||||||
|
|
@ -501,25 +500,26 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
|
||||||
|
|
||||||
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)
|
||||||
|
|
@ -531,15 +531,12 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
|
||||||
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)
|
||||||
|
|
@ -547,25 +544,30 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
|
||||||
|
|
||||||
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 =
|
||||||
|
exosuit match {
|
||||||
case obj: SpecialExoSuitDefinition =>
|
case obj: SpecialExoSuitDefinition =>
|
||||||
obj.UsingSpecial = state
|
obj.UsingSpecial = state
|
||||||
case _ =>
|
case _ =>
|
||||||
SpecialExoSuitDefinition.Mode.Normal
|
SpecialExoSuitDefinition.Mode.Normal
|
||||||
}
|
}
|
||||||
|
|
||||||
private def MAXGettingSpecial() : SpecialExoSuitDefinition.Mode.Value = exosuit match {
|
private def MAXGettingSpecial(): SpecialExoSuitDefinition.Mode.Value =
|
||||||
|
exosuit match {
|
||||||
case obj: SpecialExoSuitDefinition =>
|
case obj: SpecialExoSuitDefinition =>
|
||||||
obj.UsingSpecial
|
obj.UsingSpecial
|
||||||
case _ =>
|
case _ =>
|
||||||
SpecialExoSuitDefinition.Mode.Normal
|
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
|
||||||
|
|
||||||
|
|
@ -631,7 +633,8 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
|
@ -647,7 +650,8 @@ class Player(private val core : Avatar) extends PlanetSideServerObject
|
||||||
|
|
||||||
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 =
|
||||||
|
other match {
|
||||||
case that: Player =>
|
case that: Player =>
|
||||||
(that canEqual this) &&
|
(that canEqual this) &&
|
||||||
core == that.core
|
core == that.core
|
||||||
|
|
@ -697,29 +701,30 @@ object Player {
|
||||||
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}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,16 +26,20 @@ object Players {
|
||||||
* `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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -52,7 +56,13 @@ object Players {
|
||||||
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(
|
||||||
|
iter: Iterator[EquipmentSlot],
|
||||||
|
index: Int = 0,
|
||||||
|
list: List[InventoryItem] = Nil
|
||||||
|
): List[InventoryItem] = {
|
||||||
if (!iter.hasNext) {
|
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) =>
|
||||||
|
|
@ -91,8 +104,7 @@ object Players {
|
||||||
@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 {
|
||||||
|
|
@ -103,8 +115,7 @@ object Players {
|
||||||
case None =>
|
case None =>
|
||||||
fillEmptyHolsters(iter, list)
|
fillEmptyHolsters(iter, list)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
fillEmptyHolsters(iter, list)
|
fillEmptyHolsters(iter, list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,7 @@ 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"
|
||||||
|
|
@ -30,7 +28,8 @@ class SensorDeployableDefinition(private val objectId : Int) extends ComplexDepl
|
||||||
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) = {
|
||||||
|
|
@ -44,7 +43,8 @@ object SensorDeployableDefinition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SensorDeployableControl(sensor : SensorDeployable) extends Actor
|
class SensorDeployableControl(sensor: SensorDeployable)
|
||||||
|
extends Actor
|
||||||
with JammableBehavior
|
with JammableBehavior
|
||||||
with DamageableEntity
|
with DamageableEntity
|
||||||
with RepairableEntity {
|
with RepairableEntity {
|
||||||
|
|
@ -52,7 +52,8 @@ class SensorDeployableControl(sensor : SensorDeployable) extends Actor
|
||||||
def DamageableObject = sensor
|
def DamageableObject = sensor
|
||||||
def RepairableObject = sensor
|
def RepairableObject = sensor
|
||||||
|
|
||||||
def receive : Receive = jammableBehavior
|
def receive: Receive =
|
||||||
|
jammableBehavior
|
||||||
.orElse(takesDamage)
|
.orElse(takesDamage)
|
||||||
.orElse(canBeRepairedByNanoDispenser)
|
.orElse(canBeRepairedByNanoDispenser)
|
||||||
.orElse {
|
.orElse {
|
||||||
|
|
@ -66,17 +67,25 @@ class SensorDeployableControl(sensor : SensorDeployable) extends Actor
|
||||||
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 =
|
||||||
|
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))
|
obj.Zone.VehicleEvents ! VehicleServiceMessage(
|
||||||
|
obj.Zone.Id,
|
||||||
|
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 1)
|
||||||
|
)
|
||||||
super.StartJammeredSound(obj, dur)
|
super.StartJammeredSound(obj, dur)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
override def StartJammeredStatus(target : Any, dur : Int) : Unit = target match {
|
override def StartJammeredStatus(target: Any, dur: Int): Unit =
|
||||||
|
target match {
|
||||||
case obj: PlanetSideServerObject with JammableUnit if !obj.Jammed =>
|
case obj: PlanetSideServerObject with JammableUnit if !obj.Jammed =>
|
||||||
val zone = obj.Zone
|
val zone = obj.Zone
|
||||||
zone.LocalEvents ! LocalServiceMessage(zone.Id, LocalAction.TriggerEffectInfo(Service.defaultPlayerGUID, "on", obj.GUID, false, 1000))
|
zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
zone.Id,
|
||||||
|
LocalAction.TriggerEffectInfo(Service.defaultPlayerGUID, "on", obj.GUID, false, 1000)
|
||||||
|
)
|
||||||
super.StartJammeredStatus(obj, dur)
|
super.StartJammeredStatus(obj, dur)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
@ -85,7 +94,10 @@ class SensorDeployableControl(sensor : SensorDeployable) extends Actor
|
||||||
target match {
|
target match {
|
||||||
case obj: PlanetSideServerObject if jammedSound =>
|
case obj: PlanetSideServerObject if jammedSound =>
|
||||||
val zone = obj.Zone
|
val zone = obj.Zone
|
||||||
zone.VehicleEvents ! VehicleServiceMessage(zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 0))
|
zone.VehicleEvents ! VehicleServiceMessage(
|
||||||
|
zone.Id,
|
||||||
|
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 0)
|
||||||
|
)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
super.CancelJammeredSound(target)
|
super.CancelJammeredSound(target)
|
||||||
|
|
@ -94,7 +106,10 @@ class SensorDeployableControl(sensor : SensorDeployable) extends Actor
|
||||||
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,6 +117,7 @@ class SensorDeployableControl(sensor : SensorDeployable) extends Actor
|
||||||
}
|
}
|
||||||
|
|
||||||
object SensorDeployableControl {
|
object SensorDeployableControl {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* na
|
* na
|
||||||
* @param target na
|
* @param target na
|
||||||
|
|
@ -110,7 +126,8 @@ object SensorDeployableControl {
|
||||||
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
|
||||||
|
|
@ -125,7 +142,8 @@ object SensorDeployableControl {
|
||||||
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)?
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ 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)
|
||||||
|
extends ComplexDeployable(cdef)
|
||||||
with Hackable
|
with Hackable
|
||||||
with JammableUnit
|
with JammableUnit
|
||||||
|
|
||||||
|
|
@ -26,7 +27,8 @@ class ShieldGeneratorDefinition extends ComplexDeployableDefinition(240) {
|
||||||
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) = {
|
||||||
|
|
@ -34,7 +36,8 @@ class ShieldGeneratorDefinition extends ComplexDeployableDefinition(240) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ShieldGeneratorControl(gen : ShieldGeneratorDeployable) extends Actor
|
class ShieldGeneratorControl(gen: ShieldGeneratorDeployable)
|
||||||
|
extends Actor
|
||||||
with JammableBehavior
|
with JammableBehavior
|
||||||
with DamageableEntity
|
with DamageableEntity
|
||||||
with RepairableEntity {
|
with RepairableEntity {
|
||||||
|
|
@ -43,7 +46,8 @@ class ShieldGeneratorControl(gen : ShieldGeneratorDeployable) extends Actor
|
||||||
def RepairableObject = gen
|
def RepairableObject = gen
|
||||||
private var handleDamageToShields: Boolean = false
|
private var handleDamageToShields: Boolean = false
|
||||||
|
|
||||||
def receive : Receive = jammableBehavior
|
def receive: Receive =
|
||||||
|
jammableBehavior
|
||||||
.orElse(takesDamage)
|
.orElse(takesDamage)
|
||||||
.orElse(canBeRepairedByNanoDispenser)
|
.orElse(canBeRepairedByNanoDispenser)
|
||||||
.orElse {
|
.orElse {
|
||||||
|
|
@ -62,14 +66,16 @@ class ShieldGeneratorControl(gen : ShieldGeneratorDeployable) extends Actor
|
||||||
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(
|
||||||
|
target: Damageable.Target,
|
||||||
|
applyDamageTo: ResolutionCalculations.Output
|
||||||
|
): Unit = {
|
||||||
val originalHealth = gen.Health
|
val originalHealth = gen.Health
|
||||||
val originalShields = gen.Shields
|
val originalShields = gen.Shields
|
||||||
val cause = applyDamageTo(target)
|
val cause = applyDamageTo(target)
|
||||||
|
|
@ -80,11 +86,13 @@ class ShieldGeneratorControl(gen : ShieldGeneratorDeployable) extends Actor
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
@ -107,9 +115,13 @@ class ShieldGeneratorControl(gen : ShieldGeneratorDeployable) extends Actor
|
||||||
*/
|
*/
|
||||||
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 =
|
||||||
|
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, 1))
|
obj.Zone.VehicleEvents ! VehicleServiceMessage(
|
||||||
|
obj.Zone.Id,
|
||||||
|
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 27, 1)
|
||||||
|
)
|
||||||
super.StartJammeredStatus(obj, dur)
|
super.StartJammeredStatus(obj, dur)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
@ -119,7 +131,10 @@ class ShieldGeneratorControl(gen : ShieldGeneratorDeployable) extends Actor
|
||||||
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 =>
|
||||||
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, 0)
|
||||||
|
)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
super.CancelJammeredStatus(target)
|
super.CancelJammeredStatus(target)
|
||||||
|
|
@ -127,6 +142,7 @@ class ShieldGeneratorControl(gen : ShieldGeneratorDeployable) extends Actor
|
||||||
}
|
}
|
||||||
|
|
||||||
object ShieldGeneratorControl {
|
object ShieldGeneratorControl {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* na
|
* na
|
||||||
* @param target na
|
* @param target na
|
||||||
|
|
@ -137,7 +153,10 @@ object ShieldGeneratorControl {
|
||||||
//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)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,14 @@ 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.
|
||||||
|
|
@ -22,6 +24,7 @@ trait SpawnPoint {
|
||||||
* @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.
|
||||||
|
|
@ -29,6 +32,7 @@ trait SpawnPoint {
|
||||||
* @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,
|
||||||
|
|
@ -37,6 +41,7 @@ trait SpawnPoint {
|
||||||
* @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.
|
||||||
|
|
@ -66,7 +71,8 @@ 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.Position + Vector3.z(1.5f),
|
||||||
obj.Orientation.xy + Vector3.z(obj.Orientation.z + 90 % 360)
|
obj.Orientation.xy + Vector3.z(obj.Orientation.z + 90 % 360)
|
||||||
)
|
)
|
||||||
|
|
@ -80,18 +86,20 @@ object SpawnPoint {
|
||||||
val z = ori.z
|
val z = ori.z
|
||||||
val zrot = (z + 90) % 360
|
val zrot = (z + 90) % 360
|
||||||
val zrad = math.toRadians(zrot)
|
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
|
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 + shift + (if (x >= 330) { //ams leaning to the left
|
||||||
Vector3.z(xsin)
|
Vector3.z(xsin)
|
||||||
}
|
} else { //ams leaning to the right
|
||||||
else { //ams leaning to the right
|
|
||||||
Vector3.z(-xsin)
|
Vector3.z(-xsin)
|
||||||
}),
|
}),
|
||||||
if (side == 1) {
|
if (side == 1) {
|
||||||
Vector3.z(zrot)
|
Vector3.z(zrot)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Vector3.z((z - 90) % 360)
|
Vector3.z((z - 90) % 360)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -102,7 +110,8 @@ object SpawnPoint {
|
||||||
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 =
|
||||||
|
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 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) =>
|
||||||
|
|
@ -142,8 +151,7 @@ trait SpawnPointDefinition {
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,7 @@ 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 = {
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,14 @@ 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)
|
||||||
|
extends Equipment
|
||||||
with FireModeSwitch[FireModeDefinition]
|
with FireModeSwitch[FireModeDefinition]
|
||||||
with JammableUnit {
|
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
|
||||||
|
|
@ -70,8 +73,7 @@ class Tool(private val toolDef : ToolDefinition) extends Equipment
|
||||||
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
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -134,17 +136,23 @@ object Tool {
|
||||||
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(
|
||||||
|
tdef: ToolDefinition,
|
||||||
|
iter: Iterator[Int],
|
||||||
|
fmodes: List[FireModeDefinition],
|
||||||
|
list: List[FireModeSlot] = Nil
|
||||||
|
): List[FireModeSlot] = {
|
||||||
if (!iter.hasNext) {
|
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"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -167,11 +175,13 @@ object Tool {
|
||||||
* 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
|
||||||
|
|
@ -219,8 +229,7 @@ object Tool {
|
||||||
if (toBox.AmmoType == AmmoType) {
|
if (toBox.AmmoType == AmmoType) {
|
||||||
box = toBox
|
box = toBox
|
||||||
Some(Box)
|
Some(Box)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,12 @@ object TrapDeployableDefinition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 =
|
||||||
|
takesDamage
|
||||||
.orElse(canBeRepairedByNanoDispenser)
|
.orElse(canBeRepairedByNanoDispenser)
|
||||||
.orElse {
|
.orElse {
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ 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)
|
||||||
|
extends ComplexDeployable(tdef)
|
||||||
with WeaponTurret
|
with WeaponTurret
|
||||||
with JammableUnit
|
with JammableUnit
|
||||||
with Hackable {
|
with Hackable {
|
||||||
|
|
@ -28,7 +29,8 @@ class TurretDeployable(tdef : TurretDeployableDefinition) extends ComplexDeploya
|
||||||
override def Definition = tdef
|
override def Definition = tdef
|
||||||
}
|
}
|
||||||
|
|
||||||
class TurretDeployableDefinition(private val objectId : Int) extends ComplexDeployableDefinition(objectId)
|
class TurretDeployableDefinition(private val objectId: Int)
|
||||||
|
extends ComplexDeployableDefinition(objectId)
|
||||||
with TurretDefinition {
|
with TurretDefinition {
|
||||||
Name = "turret_deployable"
|
Name = "turret_deployable"
|
||||||
Packet = new SmallTurretConverter
|
Packet = new SmallTurretConverter
|
||||||
|
|
@ -58,7 +60,8 @@ object TurretDeployableDefinition {
|
||||||
|
|
||||||
/** control actors */
|
/** control actors */
|
||||||
|
|
||||||
class TurretControl(turret : TurretDeployable) extends Actor
|
class TurretControl(turret: TurretDeployable)
|
||||||
|
extends Actor
|
||||||
with FactionAffinityBehavior.Check
|
with FactionAffinityBehavior.Check
|
||||||
with JammableMountedWeapons //note: jammable status is reported as vehicle events, not local events
|
with JammableMountedWeapons //note: jammable status is reported as vehicle events, not local events
|
||||||
with MountableBehavior.TurretMount
|
with MountableBehavior.TurretMount
|
||||||
|
|
@ -71,7 +74,8 @@ class TurretControl(turret : TurretDeployable) extends Actor
|
||||||
def DamageableObject = turret
|
def DamageableObject = turret
|
||||||
def RepairableObject = turret
|
def RepairableObject = turret
|
||||||
|
|
||||||
def receive : Receive = checkBehavior
|
def receive: Receive =
|
||||||
|
checkBehavior
|
||||||
.orElse(jammableBehavior)
|
.orElse(jammableBehavior)
|
||||||
.orElse(mountBehavior)
|
.orElse(mountBehavior)
|
||||||
.orElse(dismountBehavior)
|
.orElse(dismountBehavior)
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,8 @@ 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)
|
||||||
|
extends AmenityOwner
|
||||||
with Hackable
|
with Hackable
|
||||||
with FactionAffinity
|
with FactionAffinity
|
||||||
with Mountable
|
with Mountable
|
||||||
|
|
@ -86,11 +87,13 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
|
||||||
private var flying: Boolean = false
|
private var flying: Boolean = false
|
||||||
private var ntuCapacitor: Int = 0
|
private var ntuCapacitor: Int = 0
|
||||||
private var capacitor: 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] =
|
||||||
|
Array(VehicleLockState.Locked, VehicleLockState.Empire, VehicleLockState.Empire, VehicleLockState.Locked)
|
||||||
private var seats: Map[Int, Seat] = Map.empty
|
private var seats: Map[Int, Seat] = Map.empty
|
||||||
private var cargoHolds: Map[Int, Cargo] = Map.empty
|
private var cargoHolds: Map[Int, Cargo] = Map.empty
|
||||||
private var weapons: Map[Int, EquipmentSlot] = Map.empty
|
private var weapons: Map[Int, EquipmentSlot] = Map.empty
|
||||||
|
|
@ -266,12 +269,13 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
|
||||||
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 =
|
||||||
|
try { VehicleLockState(level.toInt) }
|
||||||
|
catch { case _: Exception => groupPermissions(index) }
|
||||||
if (current != next) {
|
if (current != next) {
|
||||||
groupPermissions(index) = next
|
groupPermissions(index) = next
|
||||||
PermissionGroup(index)
|
PermissionGroup(index)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
case None =>
|
case None =>
|
||||||
|
|
@ -285,13 +289,12 @@ 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] =
|
||||||
|
if (group > 9 && group < 14) {
|
||||||
Some(group - 10)
|
Some(group - 10)
|
||||||
}
|
} else if (group > -1 && group < 4) {
|
||||||
else if(group > -1 && group < 4) {
|
|
||||||
Some(group)
|
Some(group)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -304,8 +307,7 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -317,8 +319,7 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -330,8 +331,7 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
|
||||||
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 {
|
||||||
|
|
@ -377,13 +377,11 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
|
||||||
@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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -404,8 +402,7 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
|
||||||
case None =>
|
case None =>
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -428,7 +425,8 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
|
||||||
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
|
||||||
|
.get(slotNum)
|
||||||
// .orElse(utilities.get(slotNum) match {
|
// .orElse(utilities.get(slotNum) match {
|
||||||
// case Some(_) =>
|
// case Some(_) =>
|
||||||
// //TODO what do now?
|
// //TODO what do now?
|
||||||
|
|
@ -436,17 +434,18 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
|
||||||
// case None => ;
|
// case None => ;
|
||||||
// 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({
|
||||||
|
case (_, obj) =>
|
||||||
obj.Equipment match {
|
obj.Equipment match {
|
||||||
case Some(item) =>
|
case Some(item) =>
|
||||||
if (item.HasGUID && item.GUID == guid) {
|
if (item.HasGUID && item.GUID == guid) {
|
||||||
true
|
true
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
case None =>
|
case None =>
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -569,7 +567,8 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
|
||||||
|
|
||||||
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 =
|
||||||
|
other match {
|
||||||
case that: Vehicle =>
|
case that: Vehicle =>
|
||||||
(that canEqual this) &&
|
(that canEqual this) &&
|
||||||
hashCode() == that.hashCode()
|
hashCode() == that.hashCode()
|
||||||
|
|
@ -589,6 +588,7 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner
|
||||||
}
|
}
|
||||||
|
|
||||||
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.
|
||||||
*/
|
*/
|
||||||
|
|
@ -666,25 +666,30 @@ object Vehicle {
|
||||||
//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
|
||||||
|
.map({
|
||||||
|
case (num, definition) =>
|
||||||
val slot = EquipmentSlot(EquipmentSize.VehicleWeapon)
|
val slot = EquipmentSlot(EquipmentSize.VehicleWeapon)
|
||||||
slot.Equipment = Tool(definition)
|
slot.Equipment = Tool(definition)
|
||||||
num -> slot
|
num -> slot
|
||||||
}).toMap
|
})
|
||||||
|
.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
|
||||||
|
.map({
|
||||||
case (num, util) =>
|
case (num, util) =>
|
||||||
val obj = Utility(util, vehicle)
|
val obj = Utility(util, vehicle)
|
||||||
val utilObj = obj()
|
val utilObj = obj()
|
||||||
vehicle.Amenities = utilObj
|
vehicle.Amenities = utilObj
|
||||||
utilObj.LocationOffset = vdef.UtilityOffset.get(num)
|
utilObj.LocationOffset = vdef.UtilityOffset.get(num)
|
||||||
num -> obj
|
num -> obj
|
||||||
}).toMap
|
})
|
||||||
|
.toMap
|
||||||
//trunk
|
//trunk
|
||||||
vdef.TrunkSize match {
|
vdef.TrunkSize match {
|
||||||
case InventoryTile.None => ;
|
case InventoryTile.None => ;
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,10 @@ object Vehicles {
|
||||||
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,18 +51,23 @@ 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] =
|
||||||
|
vehicle.Zone.GUID(vehicle.Owner) match {
|
||||||
case Some(player: Player) =>
|
case Some(player: Player) =>
|
||||||
if (player.VehicleOwned.contains(guid)) {
|
if (player.VehicleOwned.contains(guid)) {
|
||||||
player.VehicleOwned = None
|
player.VehicleOwned = None
|
||||||
vehicle.Zone.VehicleEvents ! VehicleServiceMessage(player.Name, VehicleAction.Ownership(player.GUID, PlanetSideGUID(0)))
|
vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
|
||||||
|
player.Name,
|
||||||
|
VehicleAction.Ownership(player.GUID, PlanetSideGUID(0))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
vehicle.AssignOwnership(None)
|
vehicle.AssignOwnership(None)
|
||||||
val empire = VehicleLockState.Empire.id
|
val empire = VehicleLockState.Empire.id
|
||||||
val factionChannel = s"${vehicle.Faction}"
|
val factionChannel = s"${vehicle.Faction}"
|
||||||
(0 to 2).foreach(group => {
|
(0 to 2).foreach(group => {
|
||||||
vehicle.PermissionGroup(group, empire)
|
vehicle.PermissionGroup(group, empire)
|
||||||
vehicle.Zone.VehicleEvents ! VehicleServiceMessage(factionChannel,
|
vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
|
||||||
|
factionChannel,
|
||||||
VehicleAction.SeatPermissions(Service.defaultPlayerGUID, guid, group, empire)
|
VehicleAction.SeatPermissions(Service.defaultPlayerGUID, guid, group, empire)
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
@ -77,6 +85,7 @@ object Vehicles {
|
||||||
* @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.
|
||||||
|
|
@ -115,12 +124,14 @@ object Vehicles {
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -195,8 +206,7 @@ object Vehicles {
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -210,7 +220,6 @@ object Vehicles {
|
||||||
*/
|
*/
|
||||||
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 => {
|
||||||
|
|
@ -218,7 +227,13 @@ object Vehicles {
|
||||||
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)
|
||||||
|
|
@ -234,7 +249,10 @@ object Vehicles {
|
||||||
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 => ;
|
||||||
}
|
}
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ 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`.)
|
||||||
|
|
@ -27,8 +28,7 @@ object Certification {
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,8 +59,7 @@ object Certification {
|
||||||
For
|
For
|
||||||
}
|
}
|
||||||
allocated ++= available
|
allocated ++= available
|
||||||
}
|
} while (available.nonEmpty)
|
||||||
while(available.nonEmpty)
|
|
||||||
allocated.toSet
|
allocated.toSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,7 +71,8 @@ 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] =
|
||||||
|
certification match {
|
||||||
case AssaultBuggy =>
|
case AssaultBuggy =>
|
||||||
Set(Harasser)
|
Set(Harasser)
|
||||||
case LightScout =>
|
case LightScout =>
|
||||||
|
|
@ -96,7 +96,6 @@ object Certification {
|
||||||
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(),
|
||||||
|
|
@ -104,7 +103,6 @@ object Certification {
|
||||||
Sniping -> List(),
|
Sniping -> List(),
|
||||||
SpecialAssault -> List(EliteAssault),
|
SpecialAssault -> List(EliteAssault),
|
||||||
EliteAssault -> List(),
|
EliteAssault -> List(),
|
||||||
|
|
||||||
ATV -> List(Switchblade),
|
ATV -> List(Switchblade),
|
||||||
Switchblade -> List(),
|
Switchblade -> List(),
|
||||||
Harasser -> List(),
|
Harasser -> List(),
|
||||||
|
|
@ -115,18 +113,15 @@ object Certification {
|
||||||
ArmoredAssault1 -> List(ArmoredAssault2),
|
ArmoredAssault1 -> List(ArmoredAssault2),
|
||||||
ArmoredAssault2 -> List(BattleFrameRobotics, Flail),
|
ArmoredAssault2 -> List(BattleFrameRobotics, Flail),
|
||||||
Flail -> List(),
|
Flail -> List(),
|
||||||
|
|
||||||
AirCavalryScout -> List(AirCavalryAssault),
|
AirCavalryScout -> List(AirCavalryAssault),
|
||||||
AirCavalryAssault -> List(AirCavalryInterceptor),
|
AirCavalryAssault -> List(AirCavalryInterceptor),
|
||||||
AirCavalryInterceptor -> List(),
|
AirCavalryInterceptor -> List(),
|
||||||
AirSupport -> List(GalaxyGunship),
|
AirSupport -> List(GalaxyGunship),
|
||||||
GalaxyGunship -> List(),
|
GalaxyGunship -> List(),
|
||||||
Phantasm -> List(),
|
Phantasm -> List(),
|
||||||
|
|
||||||
BattleFrameRobotics -> List(BFRAntiInfantry, BFRAntiAircraft),
|
BattleFrameRobotics -> List(BFRAntiInfantry, BFRAntiAircraft),
|
||||||
BFRAntiInfantry -> List(),
|
BFRAntiInfantry -> List(),
|
||||||
BFRAntiAircraft -> List(),
|
BFRAntiAircraft -> List(),
|
||||||
|
|
||||||
Medical -> List(AdvancedMedical),
|
Medical -> List(AdvancedMedical),
|
||||||
AdvancedMedical -> List(),
|
AdvancedMedical -> List(),
|
||||||
Engineering -> List(CombatEngineering),
|
Engineering -> List(CombatEngineering),
|
||||||
|
|
@ -143,6 +138,7 @@ object Certification {
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -185,7 +181,6 @@ object Certification {
|
||||||
AIMAX -> 3,
|
AIMAX -> 3,
|
||||||
AVMAX -> 3,
|
AVMAX -> 3,
|
||||||
UniMAX -> 6,
|
UniMAX -> 6,
|
||||||
|
|
||||||
StandardAssault -> 0,
|
StandardAssault -> 0,
|
||||||
MediumAssault -> 2,
|
MediumAssault -> 2,
|
||||||
AntiVehicular -> 3,
|
AntiVehicular -> 3,
|
||||||
|
|
@ -193,7 +188,6 @@ object Certification {
|
||||||
Sniping -> 3,
|
Sniping -> 3,
|
||||||
SpecialAssault -> 3,
|
SpecialAssault -> 3,
|
||||||
EliteAssault -> 1,
|
EliteAssault -> 1,
|
||||||
|
|
||||||
ATV -> 1,
|
ATV -> 1,
|
||||||
Switchblade -> 1,
|
Switchblade -> 1,
|
||||||
Harasser -> 1,
|
Harasser -> 1,
|
||||||
|
|
@ -204,18 +198,15 @@ object Certification {
|
||||||
ArmoredAssault1 -> 2,
|
ArmoredAssault1 -> 2,
|
||||||
ArmoredAssault2 -> 3,
|
ArmoredAssault2 -> 3,
|
||||||
Flail -> 1,
|
Flail -> 1,
|
||||||
|
|
||||||
AirCavalryScout -> 3,
|
AirCavalryScout -> 3,
|
||||||
AirCavalryAssault -> 2,
|
AirCavalryAssault -> 2,
|
||||||
AirCavalryInterceptor -> 2,
|
AirCavalryInterceptor -> 2,
|
||||||
AirSupport -> 3,
|
AirSupport -> 3,
|
||||||
GalaxyGunship -> 2,
|
GalaxyGunship -> 2,
|
||||||
Phantasm -> 3,
|
Phantasm -> 3,
|
||||||
|
|
||||||
BattleFrameRobotics -> 4,
|
BattleFrameRobotics -> 4,
|
||||||
BFRAntiInfantry -> 1,
|
BFRAntiInfantry -> 1,
|
||||||
BFRAntiAircraft -> 1,
|
BFRAntiAircraft -> 1,
|
||||||
|
|
||||||
Medical -> 3,
|
Medical -> 3,
|
||||||
AdvancedMedical -> 2,
|
AdvancedMedical -> 2,
|
||||||
Engineering -> 3,
|
Engineering -> 3,
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,7 @@ 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)
|
||||||
|
|
@ -66,7 +65,8 @@ 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)
|
||||||
|
|
|
||||||
|
|
@ -23,24 +23,31 @@ 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
|
||||||
|
|
@ -58,8 +65,7 @@ class DeployableToolbox {
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
@ -162,8 +174,7 @@ class DeployableToolbox {
|
||||||
dType.Current += 1
|
dType.Current += 1
|
||||||
dList += obj
|
dList += obj
|
||||||
true
|
true
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -187,8 +198,7 @@ class DeployableToolbox {
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -213,7 +223,10 @@ 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(
|
||||||
|
obj: DeployableToolbox.AcceptableDeployable,
|
||||||
|
rule: (Deployable) => Boolean
|
||||||
|
): Option[DeployableToolbox.AcceptableDeployable] = {
|
||||||
val definition = obj.Definition
|
val definition = obj.Definition
|
||||||
val category = definition.DeployCategory
|
val category = definition.DeployCategory
|
||||||
val categoryList = deployableLists(category)
|
val categoryList = deployableLists(category)
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -246,8 +258,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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -269,7 +280,8 @@ class DeployableToolbox {
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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,8 +433,10 @@ 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
|
||||||
|
|
||||||
|
|
@ -441,8 +463,10 @@ 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 {
|
||||||
|
case DeployedItem.portable_manned_turret_nc | DeployedItem.portable_manned_turret_tr |
|
||||||
|
DeployedItem.portable_manned_turret_vs =>
|
||||||
DeployedItem.portable_manned_turret
|
DeployedItem.portable_manned_turret
|
||||||
case _ =>
|
case _ =>
|
||||||
item
|
item
|
||||||
|
|
@ -454,7 +478,11 @@ 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
|
||||||
|
|
@ -481,8 +509,7 @@ object DeployableToolbox {
|
||||||
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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -535,7 +561,12 @@ 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 {
|
||||||
|
|
@ -583,10 +614,20 @@ object DeployableToolbox {
|
||||||
|
|
||||||
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,7 +646,12 @@ 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 {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,11 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -18,13 +22,20 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
@ -34,7 +45,11 @@ object FirstTimeEvents {
|
||||||
|
|
||||||
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -48,12 +63,18 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
@ -63,7 +84,11 @@ object FirstTimeEvents {
|
||||||
|
|
||||||
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -78,12 +103,18 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
@ -93,9 +124,21 @@ object FirstTimeEvents {
|
||||||
|
|
||||||
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(
|
||||||
|
|
@ -116,33 +159,74 @@ 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
|
||||||
|
|
@ -150,13 +234,17 @@ object FirstTimeEvents {
|
||||||
|
|
||||||
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(
|
||||||
|
|
@ -180,10 +268,32 @@ object FirstTimeEvents {
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
||||||
|
|
@ -247,18 +357,54 @@ object FirstTimeEvents {
|
||||||
)
|
)
|
||||||
|
|
||||||
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(
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
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
|
||||||
|
|
||||||
|
|
@ -25,5 +24,6 @@ class LoadoutManager(size : Int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,7 @@ import scala.concurrent.duration._
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
|
|
||||||
class PlayerControl(player : Player) extends Actor
|
class PlayerControl(player: Player) extends Actor with JammableBehavior with Damageable with ContainableBehavior {
|
||||||
with JammableBehavior
|
|
||||||
with Damageable
|
|
||||||
with ContainableBehavior {
|
|
||||||
def JammableObject = player
|
def JammableObject = player
|
||||||
def DamageableObject = player
|
def DamageableObject = player
|
||||||
def ContainerObject = player
|
def ContainerObject = player
|
||||||
|
|
@ -40,16 +37,22 @@ class PlayerControl(player : Player) extends Actor
|
||||||
|
|
||||||
/** Stamina will be used. Stamina will be restored. */
|
/** Stamina will be used. Stamina will be restored. */
|
||||||
var staminaRegen: Cancellable = Default.Cancellable
|
var staminaRegen: Cancellable = Default.Cancellable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A collection of timers indexed for the implant in each slot.
|
* A collection of timers indexed for the implant in each slot.
|
||||||
* Before an implant is ready, it serves as the initialization timer.
|
* Before an implant is ready, it serves as the initialization timer.
|
||||||
* After being initialized, it is used as the stamina drain interval when the implant is active. */
|
* After being initialized, it is used as the stamina drain interval when the implant is active.
|
||||||
|
*/
|
||||||
val implantSlotTimers = mutable.HashMap(0 -> Default.Cancellable, 1 -> Default.Cancellable, 2 -> Default.Cancellable)
|
val implantSlotTimers = mutable.HashMap(0 -> Default.Cancellable, 1 -> Default.Cancellable, 2 -> Default.Cancellable)
|
||||||
|
|
||||||
/** control agency for the player's locker container (dedicated inventory slot #5) */
|
/** control agency for the player's locker container (dedicated inventory slot #5) */
|
||||||
val lockerControlAgent: ActorRef = {
|
val lockerControlAgent: ActorRef = {
|
||||||
val locker = player.Locker
|
val locker = player.Locker
|
||||||
locker.Zone = player.Zone
|
locker.Zone = player.Zone
|
||||||
locker.Actor = context.actorOf(Props(classOf[LockerContainerControl], locker, player.Name), PlanetSideServerObject.UniqueActorName(locker))
|
locker.Actor = context.actorOf(
|
||||||
|
Props(classOf[LockerContainerControl], locker, player.Name),
|
||||||
|
PlanetSideServerObject.UniqueActorName(locker)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def postStop(): Unit = {
|
override def postStop(): Unit = {
|
||||||
|
|
@ -59,7 +62,8 @@ class PlayerControl(player : Player) extends Actor
|
||||||
implantSlotTimers.values.foreach { _.cancel }
|
implantSlotTimers.values.foreach { _.cancel }
|
||||||
}
|
}
|
||||||
|
|
||||||
def receive : Receive = jammableBehavior
|
def receive: Receive =
|
||||||
|
jammableBehavior
|
||||||
.orElse(takesDamage)
|
.orElse(takesDamage)
|
||||||
.orElse(containerBehavior)
|
.orElse(containerBehavior)
|
||||||
.orElse {
|
.orElse {
|
||||||
|
|
@ -78,7 +82,8 @@ class PlayerControl(player : Player) extends Actor
|
||||||
case Player.StaminaRegen() =>
|
case Player.StaminaRegen() =>
|
||||||
if (staminaRegen == Default.Cancellable) {
|
if (staminaRegen == Default.Cancellable) {
|
||||||
staminaRegen.cancel
|
staminaRegen.cancel
|
||||||
staminaRegen = context.system.scheduler.scheduleOnce(delay = 500 milliseconds, self, PlayerControl.StaminaRegen())
|
staminaRegen =
|
||||||
|
context.system.scheduler.scheduleOnce(delay = 500 milliseconds, self, PlayerControl.StaminaRegen())
|
||||||
}
|
}
|
||||||
|
|
||||||
case PlayerControl.StaminaRegen() =>
|
case PlayerControl.StaminaRegen() =>
|
||||||
|
|
@ -87,13 +92,15 @@ class PlayerControl(player : Player) extends Actor
|
||||||
if (player.skipStaminaRegenForTurns > 0) {
|
if (player.skipStaminaRegenForTurns > 0) {
|
||||||
// Do not renew stamina for a while
|
// Do not renew stamina for a while
|
||||||
player.skipStaminaRegenForTurns -= 1
|
player.skipStaminaRegenForTurns -= 1
|
||||||
}
|
} else if (
|
||||||
else if ((player.VehicleSeated.nonEmpty || !player.isMoving && !player.Jumping) && player.Stamina < player.MaxStamina) {
|
(player.VehicleSeated.nonEmpty || !player.isMoving && !player.Jumping) && player.Stamina < player.MaxStamina
|
||||||
|
) {
|
||||||
// Regen stamina roughly every 500ms
|
// Regen stamina roughly every 500ms
|
||||||
StaminaChanged(changeInStamina = 1)
|
StaminaChanged(changeInStamina = 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
staminaRegen = context.system.scheduler.scheduleOnce(delay = 500 milliseconds, self, PlayerControl.StaminaRegen())
|
staminaRegen =
|
||||||
|
context.system.scheduler.scheduleOnce(delay = 500 milliseconds, self, PlayerControl.StaminaRegen())
|
||||||
|
|
||||||
case Player.StaminaChanged(Some(changeInStamina)) =>
|
case Player.StaminaChanged(Some(changeInStamina)) =>
|
||||||
StaminaChanged(changeInStamina)
|
StaminaChanged(changeInStamina)
|
||||||
|
|
@ -106,14 +113,17 @@ class PlayerControl(player : Player) extends Actor
|
||||||
DestructionAwareness(player, None)
|
DestructionAwareness(player, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
case CommonMessages.Use(user, Some(item : Tool)) if item.Definition == GlobalDefinitions.medicalapplicator && player.isAlive =>
|
case CommonMessages.Use(user, Some(item: Tool))
|
||||||
|
if item.Definition == GlobalDefinitions.medicalapplicator && player.isAlive =>
|
||||||
//heal
|
//heal
|
||||||
val originalHealth = player.Health
|
val originalHealth = player.Health
|
||||||
val definition = player.Definition
|
val definition = player.Definition
|
||||||
if(player.MaxHealth > 0 && originalHealth < player.MaxHealth &&
|
if (
|
||||||
|
player.MaxHealth > 0 && originalHealth < player.MaxHealth &&
|
||||||
user.Faction == player.Faction &&
|
user.Faction == player.Faction &&
|
||||||
item.Magazine > 0 &&
|
item.Magazine > 0 &&
|
||||||
Vector3.Distance(user.Position, player.Position) < definition.RepairDistance) {
|
Vector3.Distance(user.Position, player.Position) < definition.RepairDistance
|
||||||
|
) {
|
||||||
val zone = player.Zone
|
val zone = player.Zone
|
||||||
val events = zone.AvatarEvents
|
val events = zone.AvatarEvents
|
||||||
val uname = user.Name
|
val uname = user.Name
|
||||||
|
|
@ -121,25 +131,46 @@ class PlayerControl(player : Player) extends Actor
|
||||||
if (!(player.isMoving || user.isMoving)) { //only allow stationary heals
|
if (!(player.isMoving || user.isMoving)) { //only allow stationary heals
|
||||||
val newHealth = player.Health = originalHealth + 10
|
val newHealth = player.Health = originalHealth + 10
|
||||||
val magazine = item.Discharge()
|
val magazine = item.Discharge()
|
||||||
events ! AvatarServiceMessage(uname, AvatarAction.SendResponse(Service.defaultPlayerGUID, InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong)))
|
events ! AvatarServiceMessage(
|
||||||
|
uname,
|
||||||
|
AvatarAction.SendResponse(
|
||||||
|
Service.defaultPlayerGUID,
|
||||||
|
InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong)
|
||||||
|
)
|
||||||
|
)
|
||||||
events ! AvatarServiceMessage(zone.Id, AvatarAction.PlanetsideAttributeToAll(guid, 0, newHealth))
|
events ! AvatarServiceMessage(zone.Id, AvatarAction.PlanetsideAttributeToAll(guid, 0, newHealth))
|
||||||
player.History(HealFromEquipment(PlayerSource(player), PlayerSource(user), newHealth - originalHealth, GlobalDefinitions.medicalapplicator))
|
player.History(
|
||||||
|
HealFromEquipment(
|
||||||
|
PlayerSource(player),
|
||||||
|
PlayerSource(user),
|
||||||
|
newHealth - originalHealth,
|
||||||
|
GlobalDefinitions.medicalapplicator
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (player != user) {
|
if (player != user) {
|
||||||
//"Someone is trying to heal you"
|
//"Someone is trying to heal you"
|
||||||
events ! AvatarServiceMessage(player.Name, AvatarAction.PlanetsideAttributeToAll(guid, 55, 1))
|
events ! AvatarServiceMessage(player.Name, AvatarAction.PlanetsideAttributeToAll(guid, 55, 1))
|
||||||
//progress bar remains visible for all heal attempts
|
//progress bar remains visible for all heal attempts
|
||||||
events ! AvatarServiceMessage(uname, AvatarAction.SendResponse(Service.defaultPlayerGUID, RepairMessage(guid, player.Health * 100 / definition.MaxHealth)))
|
events ! AvatarServiceMessage(
|
||||||
|
uname,
|
||||||
|
AvatarAction.SendResponse(
|
||||||
|
Service.defaultPlayerGUID,
|
||||||
|
RepairMessage(guid, player.Health * 100 / definition.MaxHealth)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case CommonMessages.Use(user, Some(item: Tool)) if item.Definition == GlobalDefinitions.medicalapplicator =>
|
case CommonMessages.Use(user, Some(item: Tool)) if item.Definition == GlobalDefinitions.medicalapplicator =>
|
||||||
//revive
|
//revive
|
||||||
if(user != player &&
|
if (
|
||||||
|
user != player &&
|
||||||
user.Faction == player.Faction &&
|
user.Faction == player.Faction &&
|
||||||
user.isAlive && !user.isMoving &&
|
user.isAlive && !user.isMoving &&
|
||||||
!player.isAlive && !player.isBackpack &&
|
!player.isAlive && !player.isBackpack &&
|
||||||
item.Magazine >= 25) {
|
item.Magazine >= 25
|
||||||
|
) {
|
||||||
sender ! CommonMessages.Progress(
|
sender ! CommonMessages.Progress(
|
||||||
4,
|
4,
|
||||||
Players.FinishRevivingPlayer(player, user.Name, item),
|
Players.FinishRevivingPlayer(player, user.Name, item),
|
||||||
|
|
@ -150,20 +181,36 @@ class PlayerControl(player : Player) extends Actor
|
||||||
case CommonMessages.Use(user, Some(item: Tool)) if item.Definition == GlobalDefinitions.bank =>
|
case CommonMessages.Use(user, Some(item: Tool)) if item.Definition == GlobalDefinitions.bank =>
|
||||||
val originalArmor = player.Armor
|
val originalArmor = player.Armor
|
||||||
val definition = player.Definition
|
val definition = player.Definition
|
||||||
if(player.MaxArmor > 0 && originalArmor < player.MaxArmor &&
|
if (
|
||||||
|
player.MaxArmor > 0 && originalArmor < player.MaxArmor &&
|
||||||
user.Faction == player.Faction &&
|
user.Faction == player.Faction &&
|
||||||
item.AmmoType == Ammo.armor_canister && item.Magazine > 0 &&
|
item.AmmoType == Ammo.armor_canister && item.Magazine > 0 &&
|
||||||
Vector3.Distance(user.Position, player.Position) < definition.RepairDistance) {
|
Vector3.Distance(user.Position, player.Position) < definition.RepairDistance
|
||||||
|
) {
|
||||||
val zone = player.Zone
|
val zone = player.Zone
|
||||||
val events = zone.AvatarEvents
|
val events = zone.AvatarEvents
|
||||||
val uname = user.Name
|
val uname = user.Name
|
||||||
val guid = player.GUID
|
val guid = player.GUID
|
||||||
if (!(player.isMoving || user.isMoving)) { //only allow stationary repairs
|
if (!(player.isMoving || user.isMoving)) { //only allow stationary repairs
|
||||||
val newArmor = player.Armor = originalArmor + Repairable.Quality + RepairValue(item) + definition.RepairMod
|
val newArmor = player.Armor =
|
||||||
|
originalArmor + Repairable.Quality + RepairValue(item) + definition.RepairMod
|
||||||
val magazine = item.Discharge()
|
val magazine = item.Discharge()
|
||||||
events ! AvatarServiceMessage(uname, AvatarAction.SendResponse(Service.defaultPlayerGUID, InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong)))
|
events ! AvatarServiceMessage(
|
||||||
|
uname,
|
||||||
|
AvatarAction.SendResponse(
|
||||||
|
Service.defaultPlayerGUID,
|
||||||
|
InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong)
|
||||||
|
)
|
||||||
|
)
|
||||||
events ! AvatarServiceMessage(zone.Id, AvatarAction.PlanetsideAttributeToAll(guid, 4, player.Armor))
|
events ! AvatarServiceMessage(zone.Id, AvatarAction.PlanetsideAttributeToAll(guid, 4, player.Armor))
|
||||||
player.History(RepairFromEquipment(PlayerSource(player), PlayerSource(user), newArmor - originalArmor, GlobalDefinitions.bank))
|
player.History(
|
||||||
|
RepairFromEquipment(
|
||||||
|
PlayerSource(player),
|
||||||
|
PlayerSource(user),
|
||||||
|
newArmor - originalArmor,
|
||||||
|
GlobalDefinitions.bank
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (player != user) {
|
if (player != user) {
|
||||||
if (player.isAlive) {
|
if (player.isAlive) {
|
||||||
|
|
@ -174,7 +221,11 @@ class PlayerControl(player : Player) extends Actor
|
||||||
context.system.scheduler.scheduleOnce(250 milliseconds, events, msg)
|
context.system.scheduler.scheduleOnce(250 milliseconds, events, msg)
|
||||||
}
|
}
|
||||||
//progress bar remains visible for all repair attempts
|
//progress bar remains visible for all repair attempts
|
||||||
events ! AvatarServiceMessage(uname, AvatarAction.SendResponse(Service.defaultPlayerGUID, RepairMessage(guid, player.Armor * 100 / player.MaxArmor)))
|
events ! AvatarServiceMessage(
|
||||||
|
uname,
|
||||||
|
AvatarAction
|
||||||
|
.SendResponse(Service.defaultPlayerGUID, RepairMessage(guid, player.Armor * 100 / player.MaxArmor))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -190,13 +241,11 @@ class PlayerControl(player : Player) extends Actor
|
||||||
(if (exosuit == ExoSuitType.MAX) {
|
(if (exosuit == ExoSuitType.MAX) {
|
||||||
if (time - player.GetLastUsedTime(exosuit, subtype) < 300000L) {
|
if (time - player.GetLastUsedTime(exosuit, subtype) < 300000L) {
|
||||||
false
|
false
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
player.SetLastUsedTime(exosuit, subtype, time)
|
player.SetLastUsedTime(exosuit, subtype, time)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
player.SetLastUsedTime(exosuit, subtype, time)
|
player.SetLastUsedTime(exosuit, subtype, time)
|
||||||
true
|
true
|
||||||
})
|
})
|
||||||
|
|
@ -212,8 +261,7 @@ class PlayerControl(player : Player) extends Actor
|
||||||
if (originalSuit != exosuit || originalSubtype != subtype || originalArmor > toMaxArmor) {
|
if (originalSuit != exosuit || originalSubtype != subtype || originalArmor > toMaxArmor) {
|
||||||
player.History(HealFromExoSuitChange(PlayerSource(player), exosuit))
|
player.History(HealFromExoSuitChange(PlayerSource(player), exosuit))
|
||||||
player.Armor = toMaxArmor
|
player.Armor = toMaxArmor
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
player.Armor = originalArmor
|
player.Armor = originalArmor
|
||||||
}
|
}
|
||||||
//ensure arm is down, even if it needs to go back up
|
//ensure arm is down, even if it needs to go back up
|
||||||
|
|
@ -224,23 +272,25 @@ class PlayerControl(player : Player) extends Actor
|
||||||
val (maxWeapons, normalWeapons) = beforeHolsters.partition(elem => elem.obj.Size == EquipmentSize.Max)
|
val (maxWeapons, normalWeapons) = beforeHolsters.partition(elem => elem.obj.Size == EquipmentSize.Max)
|
||||||
toDelete ++= maxWeapons
|
toDelete ++= maxWeapons
|
||||||
normalWeapons
|
normalWeapons
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
beforeHolsters
|
beforeHolsters
|
||||||
}
|
}
|
||||||
//populate holsters
|
//populate holsters
|
||||||
val (afterHolsters, finalInventory) = if (exosuit == ExoSuitType.MAX) {
|
val (afterHolsters, finalInventory) = if (exosuit == ExoSuitType.MAX) {
|
||||||
(normalHolsters, Players.fillEmptyHolsters(List(player.Slot(4)).iterator, normalHolsters) ++ beforeInventory)
|
(
|
||||||
}
|
normalHolsters,
|
||||||
else if (originalSuit == exosuit) { //note - this will rarely be the situation
|
Players.fillEmptyHolsters(List(player.Slot(4)).iterator, normalHolsters) ++ beforeInventory
|
||||||
|
)
|
||||||
|
} else if (originalSuit == exosuit) { //note - this will rarely be the situation
|
||||||
(normalHolsters, Players.fillEmptyHolsters(player.Holsters().iterator, normalHolsters))
|
(normalHolsters, Players.fillEmptyHolsters(player.Holsters().iterator, normalHolsters))
|
||||||
}
|
} else {
|
||||||
else {
|
val (afterHolsters, toInventory) =
|
||||||
val (afterHolsters, toInventory) = normalHolsters.partition(elem => elem.obj.Size == player.Slot(elem.start).Size)
|
normalHolsters.partition(elem => elem.obj.Size == player.Slot(elem.start).Size)
|
||||||
afterHolsters.foreach({ elem => player.Slot(elem.start).Equipment = elem.obj })
|
afterHolsters.foreach({ elem => player.Slot(elem.start).Equipment = elem.obj })
|
||||||
val remainder = Players.fillEmptyHolsters(player.Holsters().iterator, toInventory ++ beforeInventory)
|
val remainder = Players.fillEmptyHolsters(player.Holsters().iterator, toInventory ++ beforeInventory)
|
||||||
(
|
(
|
||||||
player.Holsters()
|
player
|
||||||
|
.Holsters()
|
||||||
.zipWithIndex
|
.zipWithIndex
|
||||||
.map { case (slot, i) => (slot.Equipment, i) }
|
.map { case (slot, i) => (slot.Equipment, i) }
|
||||||
.collect { case (Some(obj), index) => InventoryItem(obj, index) }
|
.collect { case (Some(obj), index) => InventoryItem(obj, index) }
|
||||||
|
|
@ -251,12 +301,14 @@ class PlayerControl(player : Player) extends Actor
|
||||||
//put items back into inventory
|
//put items back into inventory
|
||||||
val (stow, drop) = if (originalSuit == exosuit) {
|
val (stow, drop) = if (originalSuit == exosuit) {
|
||||||
(finalInventory, Nil)
|
(finalInventory, Nil)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val (a, b) = GridInventory.recoverInventory(finalInventory, player.Inventory)
|
val (a, b) = GridInventory.recoverInventory(finalInventory, player.Inventory)
|
||||||
(a, b.map {
|
(
|
||||||
|
a,
|
||||||
|
b.map {
|
||||||
InventoryItem(_, -1)
|
InventoryItem(_, -1)
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
stow.foreach { elem =>
|
stow.foreach { elem =>
|
||||||
player.Inventory.InsertQuickly(elem.start, elem.obj)
|
player.Inventory.InsertQuickly(elem.start, elem.obj)
|
||||||
|
|
@ -264,23 +316,38 @@ class PlayerControl(player : Player) extends Actor
|
||||||
//deactivate non-passive implants
|
//deactivate non-passive implants
|
||||||
implantSlotTimers.keys.foreach { index =>
|
implantSlotTimers.keys.foreach { index =>
|
||||||
val implantSlot = player.ImplantSlot(index)
|
val implantSlot = player.ImplantSlot(index)
|
||||||
if(implantSlot.Installed.nonEmpty && implantSlot.Active && (implantSlot.Charge(originalSuit) > 0 || implantSlot.Charge(exosuit) > 0)) {
|
if (
|
||||||
|
implantSlot.Installed.nonEmpty && implantSlot.Active && (implantSlot.Charge(
|
||||||
|
originalSuit
|
||||||
|
) > 0 || implantSlot.Charge(exosuit) > 0)
|
||||||
|
) {
|
||||||
ImplantActivation(index, status = 0)
|
ImplantActivation(index, status = 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
player.Zone.AvatarEvents ! AvatarServiceMessage(player.Zone.Id,
|
player.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
AvatarAction.ChangeExosuit(player.GUID, exosuit, subtype, player.LastDrawnSlot, exosuit == ExoSuitType.MAX && requestToChangeArmor,
|
player.Zone.Id,
|
||||||
beforeHolsters.map { case InventoryItem(obj, _) => (obj, obj.GUID) }, afterHolsters,
|
AvatarAction.ChangeExosuit(
|
||||||
beforeInventory.map { case InventoryItem(obj, _) => (obj, obj.GUID) }, stow, drop,
|
player.GUID,
|
||||||
|
exosuit,
|
||||||
|
subtype,
|
||||||
|
player.LastDrawnSlot,
|
||||||
|
exosuit == ExoSuitType.MAX && requestToChangeArmor,
|
||||||
|
beforeHolsters.map { case InventoryItem(obj, _) => (obj, obj.GUID) },
|
||||||
|
afterHolsters,
|
||||||
|
beforeInventory.map { case InventoryItem(obj, _) => (obj, obj.GUID) },
|
||||||
|
stow,
|
||||||
|
drop,
|
||||||
toDelete.map { case InventoryItem(obj, _) => (obj, obj.GUID) }
|
toDelete.map { case InventoryItem(obj, _) => (obj, obj.GUID) }
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
true
|
true
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
player.Zone.AvatarEvents ! AvatarServiceMessage(player.Name, AvatarAction.TerminalOrderResult(msg.terminal_guid, msg.transaction_type, result))
|
player.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
player.Name,
|
||||||
|
AvatarAction.TerminalOrderResult(msg.terminal_guid, msg.transaction_type, result)
|
||||||
|
)
|
||||||
|
|
||||||
case Terminal.InfantryLoadout(exosuit, subtype, holsters, inventory) =>
|
case Terminal.InfantryLoadout(exosuit, subtype, holsters, inventory) =>
|
||||||
log.info(s"wants to change equipment loadout to their option #${msg.unk1 + 1}")
|
log.info(s"wants to change equipment loadout to their option #${msg.unk1 + 1}")
|
||||||
|
|
@ -300,8 +367,7 @@ class PlayerControl(player : Player) extends Actor
|
||||||
player.FreeHand.Equipment = None
|
player.FreeHand.Equipment = None
|
||||||
if (dropPred(out)) {
|
if (dropPred(out)) {
|
||||||
List(out)
|
List(out)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Nil
|
Nil
|
||||||
}
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
@ -310,24 +376,26 @@ class PlayerControl(player : Player) extends Actor
|
||||||
//a loadout with a prohibited exo-suit type will result in the fallback exo-suit type
|
//a loadout with a prohibited exo-suit type will result in the fallback exo-suit type
|
||||||
//imposed 5min delay on mechanized exo-suit switches
|
//imposed 5min delay on mechanized exo-suit switches
|
||||||
val time = System.currentTimeMillis()
|
val time = System.currentTimeMillis()
|
||||||
val (nextSuit, nextSubtype) = if (Players.CertificationToUseExoSuit(player, exosuit, subtype) &&
|
val (nextSuit, nextSubtype) =
|
||||||
|
if (
|
||||||
|
Players.CertificationToUseExoSuit(player, exosuit, subtype) &&
|
||||||
(if (exosuit == ExoSuitType.MAX) {
|
(if (exosuit == ExoSuitType.MAX) {
|
||||||
if (time - player.GetLastUsedTime(exosuit, subtype) < 300000L) {
|
if (time - player.GetLastUsedTime(exosuit, subtype) < 300000L) {
|
||||||
false
|
false
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
player.SetLastUsedTime(exosuit, subtype, time)
|
player.SetLastUsedTime(exosuit, subtype, time)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
player.SetLastUsedTime(exosuit, subtype, time)
|
player.SetLastUsedTime(exosuit, subtype, time)
|
||||||
true
|
true
|
||||||
})) {
|
})
|
||||||
|
) {
|
||||||
(exosuit, subtype)
|
(exosuit, subtype)
|
||||||
}
|
} else {
|
||||||
else {
|
log.warn(
|
||||||
log.warn(s"no longer has permission to wear the exo-suit type $exosuit; will wear $fallbackSuit instead")
|
s"no longer has permission to wear the exo-suit type $exosuit; will wear $fallbackSuit instead"
|
||||||
|
)
|
||||||
player.SetLastUsedTime(fallbackSuit, fallbackSubtype, time)
|
player.SetLastUsedTime(fallbackSuit, fallbackSubtype, time)
|
||||||
(fallbackSuit, fallbackSubtype)
|
(fallbackSuit, fallbackSubtype)
|
||||||
}
|
}
|
||||||
|
|
@ -352,8 +420,7 @@ class PlayerControl(player : Player) extends Actor
|
||||||
if (originalSuit != nextSuit || originalSubtype != nextSubtype || originalArmor > toMaxArmor) {
|
if (originalSuit != nextSuit || originalSubtype != nextSubtype || originalArmor > toMaxArmor) {
|
||||||
player.History(HealFromExoSuitChange(PlayerSource(player), nextSuit))
|
player.History(HealFromExoSuitChange(PlayerSource(player), nextSuit))
|
||||||
player.Armor = toMaxArmor
|
player.Armor = toMaxArmor
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
player.Armor = originalArmor
|
player.Armor = originalArmor
|
||||||
}
|
}
|
||||||
//ensure arm is down, even if it needs to go back up
|
//ensure arm is down, even if it needs to go back up
|
||||||
|
|
@ -367,21 +434,20 @@ class PlayerControl(player : Player) extends Actor
|
||||||
//melee slot preservation for MAX
|
//melee slot preservation for MAX
|
||||||
if (nextSuit == ExoSuitType.MAX) {
|
if (nextSuit == ExoSuitType.MAX) {
|
||||||
holsters.filter(_.start == 4)
|
holsters.filter(_.start == 4)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
curatedHolsters.filterNot(dropPred)
|
curatedHolsters.filterNot(dropPred)
|
||||||
},
|
},
|
||||||
curatedInventory.filterNot(dropPred)
|
curatedInventory.filterNot(dropPred)
|
||||||
)
|
)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
//our exo-suit type was hijacked by changing permissions; we shouldn't even be able to use that loadout(!)
|
//our exo-suit type was hijacked by changing permissions; we shouldn't even be able to use that loadout(!)
|
||||||
//holsters
|
//holsters
|
||||||
val leftoversForInventory = Players.fillEmptyHolsters(
|
val leftoversForInventory = Players.fillEmptyHolsters(
|
||||||
player.Holsters().iterator,
|
player.Holsters().iterator,
|
||||||
(curatedHolsters ++ curatedInventory).filterNot(dropPred)
|
(curatedHolsters ++ curatedInventory).filterNot(dropPred)
|
||||||
)
|
)
|
||||||
val finalHolsters = player.Holsters()
|
val finalHolsters = player
|
||||||
|
.Holsters()
|
||||||
.zipWithIndex
|
.zipWithIndex
|
||||||
.collect { case (slot, index) if slot.Equipment.nonEmpty => InventoryItem(slot.Equipment.get, index) }
|
.collect { case (slot, index) if slot.Equipment.nonEmpty => InventoryItem(slot.Equipment.get, index) }
|
||||||
.toList
|
.toList
|
||||||
|
|
@ -394,16 +460,33 @@ class PlayerControl(player : Player) extends Actor
|
||||||
//deactivate non-passive implants
|
//deactivate non-passive implants
|
||||||
implantSlotTimers.keys.foreach { index =>
|
implantSlotTimers.keys.foreach { index =>
|
||||||
val implantSlot = player.ImplantSlot(index)
|
val implantSlot = player.ImplantSlot(index)
|
||||||
if(implantSlot.Installed.nonEmpty && implantSlot.Active && (implantSlot.Charge(originalSuit) > 0 || implantSlot.Charge(nextSuit) > 0)) {
|
if (
|
||||||
|
implantSlot.Installed.nonEmpty && implantSlot.Active && (implantSlot.Charge(
|
||||||
|
originalSuit
|
||||||
|
) > 0 || implantSlot.Charge(nextSuit) > 0)
|
||||||
|
) {
|
||||||
ImplantActivation(index, status = 0)
|
ImplantActivation(index, status = 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
player.Zone.AvatarEvents ! AvatarServiceMessage(player.Zone.Id,
|
player.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
AvatarAction.ChangeLoadout(player.GUID, nextSuit, nextSubtype, player.LastDrawnSlot, exosuit == ExoSuitType.MAX,
|
player.Zone.Id,
|
||||||
oldHolsters.map { case InventoryItem(obj, _) => (obj, obj.GUID) }, afterHolsters,
|
AvatarAction.ChangeLoadout(
|
||||||
oldInventory.map { case InventoryItem(obj, _) => (obj, obj.GUID) }, afterInventory, toDeleteOrDrop)
|
player.GUID,
|
||||||
|
nextSuit,
|
||||||
|
nextSubtype,
|
||||||
|
player.LastDrawnSlot,
|
||||||
|
exosuit == ExoSuitType.MAX,
|
||||||
|
oldHolsters.map { case InventoryItem(obj, _) => (obj, obj.GUID) },
|
||||||
|
afterHolsters,
|
||||||
|
oldInventory.map { case InventoryItem(obj, _) => (obj, obj.GUID) },
|
||||||
|
afterInventory,
|
||||||
|
toDeleteOrDrop
|
||||||
|
)
|
||||||
|
)
|
||||||
|
player.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
player.Name,
|
||||||
|
AvatarAction.TerminalOrderResult(msg.terminal_guid, msg.transaction_type, true)
|
||||||
)
|
)
|
||||||
player.Zone.AvatarEvents ! AvatarServiceMessage(player.Name, AvatarAction.TerminalOrderResult(msg.terminal_guid, msg.transaction_type, true))
|
|
||||||
|
|
||||||
case Terminal.LearnImplant(implant) =>
|
case Terminal.LearnImplant(implant) =>
|
||||||
val zone = player.Zone
|
val zone = player.Zone
|
||||||
|
|
@ -419,8 +502,7 @@ class PlayerControl(player : Player) extends Actor
|
||||||
if (!player.Implants.exists({ case (implantType, _, _) => implantType == implant_type })) {
|
if (!player.Implants.exists({ case (implantType, _, _) => implantType == implant_type })) {
|
||||||
//no duplicates
|
//no duplicates
|
||||||
player.InstallImplant(implant)
|
player.InstallImplant(implant)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -430,26 +512,31 @@ class PlayerControl(player : Player) extends Actor
|
||||||
val result = if (interface.contains(terminal_guid.guid) && slotNumber.isDefined) {
|
val result = if (interface.contains(terminal_guid.guid) && slotNumber.isDefined) {
|
||||||
val slot = slotNumber.get
|
val slot = slotNumber.get
|
||||||
log.info(s"$message - put in slot $slot")
|
log.info(s"$message - put in slot $slot")
|
||||||
events ! AvatarServiceMessage(playerChannel, AvatarAction.SendResponse(Service.defaultPlayerGUID, AvatarImplantMessage(player.GUID, ImplantAction.Add, slot, implant_type.id)))
|
events ! AvatarServiceMessage(
|
||||||
|
playerChannel,
|
||||||
|
AvatarAction.SendResponse(
|
||||||
|
Service.defaultPlayerGUID,
|
||||||
|
AvatarImplantMessage(player.GUID, ImplantAction.Add, slot, implant_type.id)
|
||||||
|
)
|
||||||
|
)
|
||||||
ImplantInitializationStart(slot)
|
ImplantInitializationStart(slot)
|
||||||
true
|
true
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (interface.isEmpty) {
|
if (interface.isEmpty) {
|
||||||
log.warn(s"$message - not interacting with a terminal")
|
log.warn(s"$message - not interacting with a terminal")
|
||||||
}
|
} else if (!interface.contains(terminal_guid.guid)) {
|
||||||
else if(!interface.contains(terminal_guid.guid)) {
|
|
||||||
log.warn(s"$message - interacting with the wrong terminal, ${interface.get}")
|
log.warn(s"$message - interacting with the wrong terminal, ${interface.get}")
|
||||||
}
|
} else if (slotNumber.isEmpty) {
|
||||||
else if(slotNumber.isEmpty) {
|
|
||||||
log.warn(s"$message - already knows that implant")
|
log.warn(s"$message - already knows that implant")
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
log.warn(s"$message - forgot to sit at a terminal")
|
log.warn(s"$message - forgot to sit at a terminal")
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
events ! AvatarServiceMessage(playerChannel, AvatarAction.TerminalOrderResult(terminal_guid, msg.transaction_type, result))
|
events ! AvatarServiceMessage(
|
||||||
|
playerChannel,
|
||||||
|
AvatarAction.TerminalOrderResult(terminal_guid, msg.transaction_type, result)
|
||||||
|
)
|
||||||
|
|
||||||
case Terminal.SellImplant(implant) =>
|
case Terminal.SellImplant(implant) =>
|
||||||
val zone = player.Zone
|
val zone = player.Zone
|
||||||
|
|
@ -470,31 +557,37 @@ class PlayerControl(player : Player) extends Actor
|
||||||
val slot = slotNumber.get
|
val slot = slotNumber.get
|
||||||
log.info(s"is uninstalling $implant_type - take from slot $slot")
|
log.info(s"is uninstalling $implant_type - take from slot $slot")
|
||||||
UninitializeImplant(slot)
|
UninitializeImplant(slot)
|
||||||
events ! AvatarServiceMessage(playerChannel, AvatarAction.SendResponse(Service.defaultPlayerGUID, AvatarImplantMessage(player.GUID, ImplantAction.Remove, slot, 0)))
|
events ! AvatarServiceMessage(
|
||||||
|
playerChannel,
|
||||||
|
AvatarAction.SendResponse(
|
||||||
|
Service.defaultPlayerGUID,
|
||||||
|
AvatarImplantMessage(player.GUID, ImplantAction.Remove, slot, 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
true
|
true
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val message = s"${player.Name} can not sell $implant_type"
|
val message = s"${player.Name} can not sell $implant_type"
|
||||||
if (interface.isEmpty) {
|
if (interface.isEmpty) {
|
||||||
log.warn(s"$message - not interacting with a terminal")
|
log.warn(s"$message - not interacting with a terminal")
|
||||||
}
|
} else if (!interface.contains(terminal_guid.guid)) {
|
||||||
else if(!interface.contains(terminal_guid.guid)) {
|
|
||||||
log.warn(s"$message - interacting with the wrong terminal, ${interface.get}")
|
log.warn(s"$message - interacting with the wrong terminal, ${interface.get}")
|
||||||
}
|
} else if (slotNumber.isEmpty) {
|
||||||
else if(slotNumber.isEmpty) {
|
|
||||||
log.warn(s"$message - does not know that implant")
|
log.warn(s"$message - does not know that implant")
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
log.warn(s"$message - forgot to sit at a terminal")
|
log.warn(s"$message - forgot to sit at a terminal")
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
events ! AvatarServiceMessage(playerChannel, AvatarAction.TerminalOrderResult(terminal_guid, msg.transaction_type, result))
|
events ! AvatarServiceMessage(
|
||||||
|
playerChannel,
|
||||||
|
AvatarAction.TerminalOrderResult(terminal_guid, msg.transaction_type, result)
|
||||||
|
)
|
||||||
|
|
||||||
case _ => ; //terminal messages not handled here
|
case _ => ; //terminal messages not handled here
|
||||||
}
|
}
|
||||||
|
|
||||||
case Zone.Ground.ItemOnGround(item, _, _) => ;
|
case Zone.Ground.ItemOnGround(item, _, _) =>
|
||||||
|
;
|
||||||
val name = player.Name
|
val name = player.Name
|
||||||
val zone = player.Zone
|
val zone = player.Zone
|
||||||
val avatarEvents = zone.AvatarEvents
|
val avatarEvents = zone.AvatarEvents
|
||||||
|
|
@ -509,24 +602,36 @@ class PlayerControl(player : Player) extends Actor
|
||||||
if (avatar.Deployables.Remove(boomer)) {
|
if (avatar.Deployables.Remove(boomer)) {
|
||||||
boomer.Faction = PlanetSideEmpire.NEUTRAL
|
boomer.Faction = PlanetSideEmpire.NEUTRAL
|
||||||
boomer.AssignOwnership(None)
|
boomer.AssignOwnership(None)
|
||||||
avatar.Deployables.UpdateUIElement(boomer.Definition.Item).foreach { case (currElem, curr, maxElem, max) =>
|
avatar.Deployables.UpdateUIElement(boomer.Definition.Item).foreach {
|
||||||
avatarEvents ! AvatarServiceMessage(name, AvatarAction.PlanetsideAttributeToAll(Service.defaultPlayerGUID, maxElem, max))
|
case (currElem, curr, maxElem, max) =>
|
||||||
avatarEvents ! AvatarServiceMessage(name, AvatarAction.PlanetsideAttributeToAll(Service.defaultPlayerGUID, currElem, curr))
|
avatarEvents ! AvatarServiceMessage(
|
||||||
|
name,
|
||||||
|
AvatarAction.PlanetsideAttributeToAll(Service.defaultPlayerGUID, maxElem, max)
|
||||||
|
)
|
||||||
|
avatarEvents ! AvatarServiceMessage(
|
||||||
|
name,
|
||||||
|
AvatarAction.PlanetsideAttributeToAll(Service.defaultPlayerGUID, currElem, curr)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
localEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(boomer, zone))
|
localEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(boomer, zone))
|
||||||
localEvents ! LocalServiceMessage(factionChannel,
|
localEvents ! LocalServiceMessage(
|
||||||
LocalAction.DeployableMapIcon(Service.defaultPlayerGUID, DeploymentAction.Dismiss,
|
factionChannel,
|
||||||
|
LocalAction.DeployableMapIcon(
|
||||||
|
Service.defaultPlayerGUID,
|
||||||
|
DeploymentAction.Dismiss,
|
||||||
DeployableInfo(guid, DeployableIcon.Boomer, boomer.Position, PlanetSideGUID(0))
|
DeployableInfo(guid, DeployableIcon.Boomer, boomer.Position, PlanetSideGUID(0))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
avatarEvents ! AvatarServiceMessage(factionChannel, AvatarAction.SetEmpire(Service.defaultPlayerGUID, guid, PlanetSideEmpire.NEUTRAL))
|
avatarEvents ! AvatarServiceMessage(
|
||||||
|
factionChannel,
|
||||||
|
AvatarAction.SetEmpire(Service.defaultPlayerGUID, guid, PlanetSideEmpire.NEUTRAL)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
case _ => ; //pointless trigger? or a trigger being deleted?
|
case _ => ; //pointless trigger? or a trigger being deleted?
|
||||||
}
|
}
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
case Zone.Ground.CanNotDropItem(_, item, reason) =>
|
case Zone.Ground.CanNotDropItem(_, item, reason) =>
|
||||||
log.warn(s"${player.Name} tried to drop a ${item.Definition.Name} on the ground, but it $reason")
|
log.warn(s"${player.Name} tried to drop a ${item.Definition.Name} on the ground, but it $reason")
|
||||||
|
|
||||||
|
|
@ -556,7 +661,9 @@ class PlayerControl(player : Player) extends Actor
|
||||||
val damageToCapacitor = originalCapacitor - capacitor
|
val damageToCapacitor = originalCapacitor - capacitor
|
||||||
HandleDamage(player, cause, damageToHealth, damageToArmor, damageToStamina, damageToCapacitor)
|
HandleDamage(player, cause, damageToHealth, damageToArmor, damageToStamina, damageToCapacitor)
|
||||||
if (damageToHealth > 0 || damageToArmor > 0 || damageToStamina > 0 || damageToCapacitor > 0) {
|
if (damageToHealth > 0 || damageToArmor > 0 || damageToStamina > 0 || damageToCapacitor > 0) {
|
||||||
damageLog.info(s"${player.Name}-infantry: BEFORE=$originalHealth/$originalArmor/$originalStamina/$originalCapacitor, AFTER=$health/$armor/$stamina/$capacitor, CHANGE=$damageToHealth/$damageToArmor/$damageToStamina/$damageToCapacitor")
|
damageLog.info(
|
||||||
|
s"${player.Name}-infantry: BEFORE=$originalHealth/$originalArmor/$originalStamina/$originalCapacitor, AFTER=$health/$armor/$stamina/$capacitor, CHANGE=$damageToHealth/$damageToArmor/$damageToStamina/$damageToCapacitor"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -565,7 +672,14 @@ class PlayerControl(player : Player) extends Actor
|
||||||
* na
|
* na
|
||||||
* @param target na
|
* @param target na
|
||||||
*/
|
*/
|
||||||
def HandleDamage(target : Player, cause : ResolvedProjectile, damageToHealth : Int, damageToArmor : Int, damageToStamina : Int, damageToCapacitor : Int) : Unit = {
|
def HandleDamage(
|
||||||
|
target: Player,
|
||||||
|
cause: ResolvedProjectile,
|
||||||
|
damageToHealth: Int,
|
||||||
|
damageToArmor: Int,
|
||||||
|
damageToStamina: Int,
|
||||||
|
damageToCapacitor: Int
|
||||||
|
): Unit = {
|
||||||
val targetGUID = target.GUID
|
val targetGUID = target.GUID
|
||||||
val zone = target.Zone
|
val zone = target.Zone
|
||||||
val zoneId = zone.Id
|
val zoneId = zone.Id
|
||||||
|
|
@ -576,7 +690,10 @@ class PlayerControl(player : Player) extends Actor
|
||||||
}
|
}
|
||||||
if (health > 0) {
|
if (health > 0) {
|
||||||
if (damageToCapacitor > 0) {
|
if (damageToCapacitor > 0) {
|
||||||
events ! AvatarServiceMessage(target.Name, AvatarAction.PlanetsideAttributeSelf(targetGUID, 7, target.Capacitor.toLong))
|
events ! AvatarServiceMessage(
|
||||||
|
target.Name,
|
||||||
|
AvatarAction.PlanetsideAttributeSelf(targetGUID, 7, target.Capacitor.toLong)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (damageToHealth > 0 || damageToStamina > 0) {
|
if (damageToHealth > 0 || damageToStamina > 0) {
|
||||||
target.History(cause)
|
target.History(cause)
|
||||||
|
|
@ -594,8 +711,7 @@ class PlayerControl(player : Player) extends Actor
|
||||||
if (Damageable.CanJammer(target, cause)) {
|
if (Damageable.CanJammer(target, cause)) {
|
||||||
target.Actor ! JammableUnit.Jammered(cause)
|
target.Actor ! JammableUnit.Jammered(cause)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
DestructionAwareness(target, Some(cause))
|
DestructionAwareness(target, Some(cause))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -614,9 +730,11 @@ class PlayerControl(player : Player) extends Actor
|
||||||
val name = pSource.Name
|
val name = pSource.Name
|
||||||
zone.LivePlayers.find(_.Name == name).orElse(zone.Corpses.find(_.Name == name)) match {
|
zone.LivePlayers.find(_.Name == name).orElse(zone.Corpses.find(_.Name == name)) match {
|
||||||
case Some(tplayer) => AvatarAction.HitHint(tplayer.GUID, target.GUID)
|
case Some(tplayer) => AvatarAction.HitHint(tplayer.GUID, target.GUID)
|
||||||
case None => AvatarAction.SendResponse(Service.defaultPlayerGUID, DamageWithPositionMessage(10, pSource.Position))
|
case None =>
|
||||||
|
AvatarAction.SendResponse(Service.defaultPlayerGUID, DamageWithPositionMessage(10, pSource.Position))
|
||||||
}
|
}
|
||||||
case source => AvatarAction.SendResponse(Service.defaultPlayerGUID, DamageWithPositionMessage(10, source.Position))
|
case source =>
|
||||||
|
AvatarAction.SendResponse(Service.defaultPlayerGUID, DamageWithPositionMessage(10, source.Position))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -652,11 +770,15 @@ class PlayerControl(player : Player) extends Actor
|
||||||
target.Stamina = 0
|
target.Stamina = 0
|
||||||
UpdateStamina() //turn off implants / OutOfStamina
|
UpdateStamina() //turn off implants / OutOfStamina
|
||||||
//uninitialize implants
|
//uninitialize implants
|
||||||
target.Implants.indices.foreach { case slot if target.Implant(slot) != ImplantType.None =>
|
target.Implants.indices.foreach {
|
||||||
|
case slot if target.Implant(slot) != ImplantType.None =>
|
||||||
UninitializeImplant(slot)
|
UninitializeImplant(slot)
|
||||||
}
|
}
|
||||||
target.ResetAllImplants() //anything else specific to the backend
|
target.ResetAllImplants() //anything else specific to the backend
|
||||||
events ! AvatarServiceMessage(nameChannel, AvatarAction.Killed(player_guid, target.VehicleSeated)) //align client interface fields with state
|
events ! AvatarServiceMessage(
|
||||||
|
nameChannel,
|
||||||
|
AvatarAction.Killed(player_guid, target.VehicleSeated)
|
||||||
|
) //align client interface fields with state
|
||||||
zone.GUID(target.VehicleSeated) match {
|
zone.GUID(target.VehicleSeated) match {
|
||||||
case Some(obj: Mountable) =>
|
case Some(obj: Mountable) =>
|
||||||
//boot cadaver from seat internally (vehicle perspective)
|
//boot cadaver from seat internally (vehicle perspective)
|
||||||
|
|
@ -666,8 +788,12 @@ class PlayerControl(player : Player) extends Actor
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
//boot cadaver from seat on client
|
//boot cadaver from seat on client
|
||||||
events ! AvatarServiceMessage(nameChannel, AvatarAction.SendResponse(Service.defaultPlayerGUID,
|
events ! AvatarServiceMessage(
|
||||||
ObjectDetachMessage(obj.GUID, player_guid, target.Position, Vector3.Zero))
|
nameChannel,
|
||||||
|
AvatarAction.SendResponse(
|
||||||
|
Service.defaultPlayerGUID,
|
||||||
|
ObjectDetachMessage(obj.GUID, player_guid, target.Position, Vector3.Zero)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
//make player invisible on client
|
//make player invisible on client
|
||||||
events ! AvatarServiceMessage(nameChannel, AvatarAction.PlanetsideAttributeToAll(player_guid, 29, 1))
|
events ! AvatarServiceMessage(nameChannel, AvatarAction.PlanetsideAttributeToAll(player_guid, 29, 1))
|
||||||
|
|
@ -695,11 +821,17 @@ class PlayerControl(player : Player) extends Actor
|
||||||
}
|
}
|
||||||
events ! AvatarServiceMessage(
|
events ! AvatarServiceMessage(
|
||||||
nameChannel,
|
nameChannel,
|
||||||
AvatarAction.SendResponse(Service.defaultPlayerGUID, DestroyMessage(player_guid, attribute, Service.defaultPlayerGUID, pos)) //how many players get this message?
|
AvatarAction.SendResponse(
|
||||||
|
Service.defaultPlayerGUID,
|
||||||
|
DestroyMessage(player_guid, attribute, Service.defaultPlayerGUID, pos)
|
||||||
|
) //how many players get this message?
|
||||||
)
|
)
|
||||||
events ! AvatarServiceMessage(
|
events ! AvatarServiceMessage(
|
||||||
nameChannel,
|
nameChannel,
|
||||||
AvatarAction.SendResponse(Service.defaultPlayerGUID, AvatarDeadStateMessage(DeadState.Dead, respawnTimer, respawnTimer, pos, target.Faction, true))
|
AvatarAction.SendResponse(
|
||||||
|
Service.defaultPlayerGUID,
|
||||||
|
AvatarDeadStateMessage(DeadState.Dead, respawnTimer, respawnTimer, pos, target.Faction, true)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
//TODO other methods of death?
|
//TODO other methods of death?
|
||||||
val pentry = PlayerSource(target)
|
val pentry = PlayerSource(target)
|
||||||
|
|
@ -711,8 +843,7 @@ class PlayerControl(player : Player) extends Actor
|
||||||
case out @ Some(shot) =>
|
case out @ Some(shot) =>
|
||||||
if (System.nanoTime - shot.hit_time < (10 seconds).toNanos) {
|
if (System.nanoTime - shot.hit_time < (10 seconds).toNanos) {
|
||||||
out
|
out
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
None //suicide
|
None //suicide
|
||||||
}
|
}
|
||||||
case None =>
|
case None =>
|
||||||
|
|
@ -720,7 +851,10 @@ class PlayerControl(player : Player) extends Actor
|
||||||
}
|
}
|
||||||
}) match {
|
}) match {
|
||||||
case Some(shot) =>
|
case Some(shot) =>
|
||||||
events ! AvatarServiceMessage(zoneChannel, AvatarAction.DestroyDisplay(shot.projectile.owner, pentry, shot.projectile.attribute_to))
|
events ! AvatarServiceMessage(
|
||||||
|
zoneChannel,
|
||||||
|
AvatarAction.DestroyDisplay(shot.projectile.owner, pentry, shot.projectile.attribute_to)
|
||||||
|
)
|
||||||
case None =>
|
case None =>
|
||||||
events ! AvatarServiceMessage(zoneChannel, AvatarAction.DestroyDisplay(pentry, pentry, 0))
|
events ! AvatarServiceMessage(zoneChannel, AvatarAction.DestroyDisplay(pentry, pentry, 0))
|
||||||
}
|
}
|
||||||
|
|
@ -735,9 +869,13 @@ class PlayerControl(player : Player) extends Actor
|
||||||
* @param dur the duration of the timer, in milliseconds;
|
* @param dur the duration of the timer, in milliseconds;
|
||||||
* by default, 30000
|
* by default, 30000
|
||||||
*/
|
*/
|
||||||
override def StartJammeredSound(target : Any, dur : Int) : Unit = target match {
|
override def StartJammeredSound(target: Any, dur: Int): Unit =
|
||||||
|
target match {
|
||||||
case obj: Player if !jammedSound =>
|
case obj: Player if !jammedSound =>
|
||||||
obj.Zone.AvatarEvents ! AvatarServiceMessage(obj.Zone.Id, AvatarAction.PlanetsideAttributeToAll(obj.GUID, 27, 1))
|
obj.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
obj.Zone.Id,
|
||||||
|
AvatarAction.PlanetsideAttributeToAll(obj.GUID, 27, 1)
|
||||||
|
)
|
||||||
super.StartJammeredSound(obj, 3000)
|
super.StartJammeredSound(obj, 3000)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
@ -755,7 +893,10 @@ class PlayerControl(player : Player) extends Actor
|
||||||
//TODO these features
|
//TODO these features
|
||||||
val zone = player.Zone
|
val zone = player.Zone
|
||||||
player.Implants.indices.foreach { slot => // Deactivate & uninitialize all implants
|
player.Implants.indices.foreach { slot => // Deactivate & uninitialize all implants
|
||||||
zone.AvatarEvents ! AvatarServiceMessage(zone.Id, AvatarAction.PlanetsideAttribute(player.GUID, 28, player.Implant(slot).id * 2)) // Deactivation sound / effect
|
zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
zone.Id,
|
||||||
|
AvatarAction.PlanetsideAttribute(player.GUID, 28, player.Implant(slot).id * 2)
|
||||||
|
) // Deactivation sound / effect
|
||||||
ImplantActivation(slot, status = 0)
|
ImplantActivation(slot, status = 0)
|
||||||
UninitializeImplant(slot)
|
UninitializeImplant(slot)
|
||||||
}
|
}
|
||||||
|
|
@ -776,17 +917,21 @@ class PlayerControl(player : Player) extends Actor
|
||||||
* @see `JammableBehavior.CancelJammeredSound`
|
* @see `JammableBehavior.CancelJammeredSound`
|
||||||
* @param target an object that can be affected by the jammered status
|
* @param target an object that can be affected by the jammered status
|
||||||
*/
|
*/
|
||||||
override def CancelJammeredSound(target : Any) : Unit = target match {
|
override def CancelJammeredSound(target: Any): Unit =
|
||||||
|
target match {
|
||||||
case obj: Player if jammedSound =>
|
case obj: Player if jammedSound =>
|
||||||
obj.Zone.AvatarEvents ! AvatarServiceMessage(obj.Zone.Id, AvatarAction.PlanetsideAttributeToAll(obj.GUID, 27, 0))
|
obj.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
obj.Zone.Id,
|
||||||
|
AvatarAction.PlanetsideAttributeToAll(obj.GUID, 27, 0)
|
||||||
|
)
|
||||||
super.CancelJammeredSound(obj)
|
super.CancelJammeredSound(obj)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
def RepairValue(item : Tool) : Int = if(player.ExoSuit != ExoSuitType.MAX) {
|
def RepairValue(item: Tool): Int =
|
||||||
|
if (player.ExoSuit != ExoSuitType.MAX) {
|
||||||
item.FireMode.Modifiers.Damage0
|
item.FireMode.Modifiers.Damage0
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
item.FireMode.Modifiers.Damage3
|
item.FireMode.Modifiers.Damage3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -856,15 +1001,33 @@ class PlayerControl(player : Player) extends Actor
|
||||||
if (avatar.Deployables.Add(boomer)) {
|
if (avatar.Deployables.Add(boomer)) {
|
||||||
boomer.Faction = faction
|
boomer.Faction = faction
|
||||||
boomer.AssignOwnership(player)
|
boomer.AssignOwnership(player)
|
||||||
avatar.Deployables.UpdateUIElement(boomer.Definition.Item).foreach { case (currElem, curr, maxElem, max) =>
|
avatar.Deployables.UpdateUIElement(boomer.Definition.Item).foreach {
|
||||||
events ! AvatarServiceMessage(name, AvatarAction.PlanetsideAttributeToAll(Service.defaultPlayerGUID, maxElem, max))
|
case (currElem, curr, maxElem, max) =>
|
||||||
events ! AvatarServiceMessage(name, AvatarAction.PlanetsideAttributeToAll(Service.defaultPlayerGUID, currElem, curr))
|
events ! AvatarServiceMessage(
|
||||||
|
name,
|
||||||
|
AvatarAction.PlanetsideAttributeToAll(Service.defaultPlayerGUID, maxElem, max)
|
||||||
|
)
|
||||||
|
events ! AvatarServiceMessage(
|
||||||
|
name,
|
||||||
|
AvatarAction.PlanetsideAttributeToAll(Service.defaultPlayerGUID, currElem, curr)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(boomer), zone))
|
zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(boomer), zone))
|
||||||
events ! AvatarServiceMessage(factionChannel, AvatarAction.SetEmpire(Service.defaultPlayerGUID, bguid, faction))
|
events ! AvatarServiceMessage(
|
||||||
zone.LocalEvents ! LocalServiceMessage(factionChannel,
|
factionChannel,
|
||||||
LocalAction.DeployableMapIcon(Service.defaultPlayerGUID, DeploymentAction.Build,
|
AvatarAction.SetEmpire(Service.defaultPlayerGUID, bguid, faction)
|
||||||
DeployableInfo(bguid, DeployableIcon.Boomer, boomer.Position, boomer.Owner.getOrElse(PlanetSideGUID(0)))
|
)
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
factionChannel,
|
||||||
|
LocalAction.DeployableMapIcon(
|
||||||
|
Service.defaultPlayerGUID,
|
||||||
|
DeploymentAction.Build,
|
||||||
|
DeployableInfo(
|
||||||
|
bguid,
|
||||||
|
DeployableIcon.Boomer,
|
||||||
|
boomer.Position,
|
||||||
|
boomer.Owner.getOrElse(PlanetSideGUID(0))
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -877,7 +1040,10 @@ class PlayerControl(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(player.Name, AvatarAction.SendResponse(Service.defaultPlayerGUID, ObjectDetachMessage(obj.GUID, item.GUID, Vector3.Zero, 0f)))
|
zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
player.Name,
|
||||||
|
AvatarAction.SendResponse(Service.defaultPlayerGUID, ObjectDetachMessage(obj.GUID, item.GUID, Vector3.Zero, 0f))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -906,22 +1072,36 @@ class PlayerControl(player : Player) extends Actor
|
||||||
player.skipStaminaRegenForTurns = math.max(player.skipStaminaRegenForTurns, 6)
|
player.skipStaminaRegenForTurns = math.max(player.skipStaminaRegenForTurns, 6)
|
||||||
player.Implants.indices.foreach { slot => // Disable all implants
|
player.Implants.indices.foreach { slot => // Disable all implants
|
||||||
ImplantActivation(slot, status = 0)
|
ImplantActivation(slot, status = 0)
|
||||||
player.Zone.AvatarEvents ! AvatarServiceMessage(player.Name, AvatarAction.SendResponse(Service.defaultPlayerGUID, AvatarImplantMessage(player.GUID, ImplantAction.OutOfStamina, slot, 1)))
|
player.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
player.Name,
|
||||||
|
AvatarAction.SendResponse(
|
||||||
|
Service.defaultPlayerGUID,
|
||||||
|
AvatarImplantMessage(player.GUID, ImplantAction.OutOfStamina, slot, 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
} else if (currentStamina >= 20) {
|
||||||
else if(currentStamina >= 20) {
|
|
||||||
val wasFatigued = player.Fatigued
|
val wasFatigued = player.Fatigued
|
||||||
player.Fatigued = false
|
player.Fatigued = false
|
||||||
if (wasFatigued) { //reactivate only if we were fatigued
|
if (wasFatigued) { //reactivate only if we were fatigued
|
||||||
player.Implants.indices.foreach { slot => // Re-enable all implants
|
player.Implants.indices.foreach { slot => // Re-enable all implants
|
||||||
player.Zone.AvatarEvents ! AvatarServiceMessage(player.Name, AvatarAction.SendResponse(Service.defaultPlayerGUID, AvatarImplantMessage(player.GUID, ImplantAction.OutOfStamina, slot, 0)))
|
player.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
player.Name,
|
||||||
|
AvatarAction.SendResponse(
|
||||||
|
Service.defaultPlayerGUID,
|
||||||
|
AvatarImplantMessage(player.GUID, ImplantAction.OutOfStamina, slot, 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
if (!player.ImplantSlot(slot).Initialized) {
|
if (!player.ImplantSlot(slot).Initialized) {
|
||||||
ImplantInitializationStart(slot)
|
ImplantInitializationStart(slot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
player.Zone.AvatarEvents ! AvatarServiceMessage(player.Name, AvatarAction.PlanetsideAttributeToAll(player.GUID, 2, currentStamina))
|
player.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
player.Name,
|
||||||
|
AvatarAction.PlanetsideAttributeToAll(player.GUID, 2, currentStamina)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -938,28 +1118,32 @@ class PlayerControl(player : Player) extends Actor
|
||||||
val initializationTime = if (implantSlot.InitializeTime == 0L) {
|
val initializationTime = if (implantSlot.InitializeTime == 0L) {
|
||||||
implantSlot.InitializeTime = time
|
implantSlot.InitializeTime = time
|
||||||
time
|
time
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
implantSlot.InitializeTime
|
implantSlot.InitializeTime
|
||||||
}
|
}
|
||||||
val maxInitializationTime = implantSlot.MaxTimer * 1000
|
val maxInitializationTime = implantSlot.MaxTimer * 1000
|
||||||
if (time - initializationTime > maxInitializationTime) {
|
if (time - initializationTime > maxInitializationTime) {
|
||||||
//this implant should have already been initialized
|
//this implant should have already been initialized
|
||||||
ImplantInitializationComplete(slot)
|
ImplantInitializationComplete(slot)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Start client side initialization timer
|
// Start client side initialization timer
|
||||||
// Check this along the bottom of the character information window
|
// Check this along the bottom of the character information window
|
||||||
//progress accumulates according to the client's knowledge of the implant initialization time
|
//progress accumulates according to the client's knowledge of the implant initialization time
|
||||||
//what is normally a 60s timer that is set to 120s on the server will still visually update as if 60s
|
//what is normally a 60s timer that is set to 120s on the server will still visually update as if 60s
|
||||||
val percent = (100 * (time - initializationTime) / maxInitializationTime.toFloat).toInt
|
val percent = (100 * (time - initializationTime) / maxInitializationTime.toFloat).toInt
|
||||||
player.Zone.AvatarEvents ! AvatarServiceMessage(player.Name, AvatarAction.SendResponse(Service.defaultPlayerGUID, ActionProgressMessage(slot + 6, percent)))
|
player.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
player.Name,
|
||||||
|
AvatarAction.SendResponse(Service.defaultPlayerGUID, ActionProgressMessage(slot + 6, percent))
|
||||||
|
)
|
||||||
// Callback after initialization timer to complete initialization
|
// Callback after initialization timer to complete initialization
|
||||||
implantSlotTimers(slot).cancel
|
implantSlotTimers(slot).cancel
|
||||||
implantSlotTimers(slot) = context.system.scheduler.scheduleOnce((maxInitializationTime - (time - initializationTime)) milliseconds, self, Player.ImplantInitializationComplete(slot))
|
implantSlotTimers(slot) = context.system.scheduler.scheduleOnce(
|
||||||
|
(maxInitializationTime - (time - initializationTime)) milliseconds,
|
||||||
|
self,
|
||||||
|
Player.ImplantInitializationComplete(slot)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
ImplantInitializationComplete(slot)
|
ImplantInitializationComplete(slot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -974,7 +1158,13 @@ class PlayerControl(player : Player) extends Actor
|
||||||
val implantSlot = player.ImplantSlot(slot)
|
val implantSlot = player.ImplantSlot(slot)
|
||||||
if (implantSlot.Installed.isDefined) {
|
if (implantSlot.Installed.isDefined) {
|
||||||
implantSlot.Initialized = true
|
implantSlot.Initialized = true
|
||||||
player.Zone.AvatarEvents ! AvatarServiceMessage(player.Name, AvatarAction.SendResponse(Service.defaultPlayerGUID, AvatarImplantMessage(player.GUID, ImplantAction.Initialization, slot, 1)))
|
player.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
player.Name,
|
||||||
|
AvatarAction.SendResponse(
|
||||||
|
Service.defaultPlayerGUID,
|
||||||
|
AvatarImplantMessage(player.GUID, ImplantAction.Initialization, slot, 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
implantSlotTimers(slot).cancel
|
implantSlotTimers(slot).cancel
|
||||||
implantSlotTimers(slot) = Default.Cancellable
|
implantSlotTimers(slot) = Default.Cancellable
|
||||||
}
|
}
|
||||||
|
|
@ -996,19 +1186,26 @@ class PlayerControl(player : Player) extends Actor
|
||||||
implantSlotTimers(slot) = Default.Cancellable
|
implantSlotTimers(slot) = Default.Cancellable
|
||||||
implantSlot.Active = false
|
implantSlot.Active = false
|
||||||
//normal deactivation
|
//normal deactivation
|
||||||
player.Zone.AvatarEvents ! AvatarServiceMessage(player.Name, AvatarAction.DeactivateImplantSlot(player.GUID, slot))
|
player.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
player.Name,
|
||||||
|
AvatarAction.DeactivateImplantSlot(player.GUID, slot)
|
||||||
|
)
|
||||||
//initialization process (from scratch)
|
//initialization process (from scratch)
|
||||||
implantSlot.InitializeTime = 0
|
implantSlot.InitializeTime = 0
|
||||||
ImplantInitializationStart(slot)
|
ImplantInitializationStart(slot)
|
||||||
}
|
} else if (status == 0 && implantSlot.Active) {
|
||||||
else if(status == 0 && implantSlot.Active) {
|
|
||||||
implantSlotTimers(slot).cancel
|
implantSlotTimers(slot).cancel
|
||||||
implantSlotTimers(slot) = Default.Cancellable
|
implantSlotTimers(slot) = Default.Cancellable
|
||||||
implantSlot.Active = false
|
implantSlot.Active = false
|
||||||
player.Zone.AvatarEvents ! AvatarServiceMessage(player.Zone.Id, AvatarAction.PlanetsideAttribute(player.GUID, 28, player.Implant(slot).id * 2)) // Deactivation sound / effect
|
player.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
player.Zone.AvatarEvents ! AvatarServiceMessage(player.Name, AvatarAction.DeactivateImplantSlot(player.GUID, slot))
|
player.Zone.Id,
|
||||||
}
|
AvatarAction.PlanetsideAttribute(player.GUID, 28, player.Implant(slot).id * 2)
|
||||||
else if(status == 1 && implantSlot.Initialized && !player.Fatigued) {
|
) // Deactivation sound / effect
|
||||||
|
player.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
player.Name,
|
||||||
|
AvatarAction.DeactivateImplantSlot(player.GUID, slot)
|
||||||
|
)
|
||||||
|
} else if (status == 1 && implantSlot.Initialized && !player.Fatigued) {
|
||||||
implantSlot.Installed match {
|
implantSlot.Installed match {
|
||||||
case Some(implant)
|
case Some(implant)
|
||||||
if (implant.Type == ImplantType.PersonalShield && player.ExoSuit == ExoSuitType.Infiltration) ||
|
if (implant.Type == ImplantType.PersonalShield && player.ExoSuit == ExoSuitType.Infiltration) ||
|
||||||
|
|
@ -1033,9 +1230,17 @@ class PlayerControl(player : Player) extends Actor
|
||||||
val drainInterval = implant.GetCostIntervalByExoSuit(player.ExoSuit)
|
val drainInterval = implant.GetCostIntervalByExoSuit(player.ExoSuit)
|
||||||
if (drainInterval > 0) { // Ongoing stamina drain, if applicable
|
if (drainInterval > 0) { // Ongoing stamina drain, if applicable
|
||||||
implantSlotTimers(slot).cancel
|
implantSlotTimers(slot).cancel
|
||||||
implantSlotTimers(slot) = context.system.scheduler.scheduleWithFixedDelay(initialDelay = 0 seconds, drainInterval milliseconds, self, Player.StaminaChanged(-implant.StaminaCost))
|
implantSlotTimers(slot) = context.system.scheduler.scheduleWithFixedDelay(
|
||||||
|
initialDelay = 0 seconds,
|
||||||
|
drainInterval milliseconds,
|
||||||
|
self,
|
||||||
|
Player.StaminaChanged(-implant.StaminaCost)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
zone.AvatarEvents ! AvatarServiceMessage(zone.Id, AvatarAction.PlanetsideAttribute(player.GUID, 28, player.Implant(slot).id * 2 + 1)) // Activation sound / effect
|
zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
zone.Id,
|
||||||
|
AvatarAction.PlanetsideAttribute(player.GUID, 28, player.Implant(slot).id * 2 + 1)
|
||||||
|
) // Activation sound / effect
|
||||||
zone.AvatarEvents ! AvatarServiceMessage(player.Name, AvatarAction.ActivateImplantSlot(player.GUID, slot))
|
zone.AvatarEvents ! AvatarServiceMessage(player.Name, AvatarAction.ActivateImplantSlot(player.GUID, slot))
|
||||||
}
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
@ -1067,12 +1272,23 @@ class PlayerControl(player : Player) extends Actor
|
||||||
implantSlot.Active = false
|
implantSlot.Active = false
|
||||||
implantSlot.Initialized = false
|
implantSlot.Initialized = false
|
||||||
implantSlot.InitializeTime = 0L
|
implantSlot.InitializeTime = 0L
|
||||||
zone.AvatarEvents ! AvatarServiceMessage(playerChannel, AvatarAction.SendResponse(Service.defaultPlayerGUID, ActionProgressMessage(slot + 6, 100)))
|
zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
zone.AvatarEvents ! AvatarServiceMessage(zoneChannel, AvatarAction.SendResponse(Service.defaultPlayerGUID, AvatarImplantMessage(guid, ImplantAction.Initialization, slot, 0)))
|
playerChannel,
|
||||||
|
AvatarAction.SendResponse(Service.defaultPlayerGUID, ActionProgressMessage(slot + 6, 100))
|
||||||
|
)
|
||||||
|
zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
zoneChannel,
|
||||||
|
AvatarAction.SendResponse(
|
||||||
|
Service.defaultPlayerGUID,
|
||||||
|
AvatarImplantMessage(guid, ImplantAction.Initialization, slot, 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object PlayerControl {
|
object PlayerControl {
|
||||||
/** */
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
private case class StaminaRegen()
|
private case class StaminaRegen()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,15 @@ 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(
|
||||||
|
obj_def: ObjectDefinition with BaseDeployableDefinition,
|
||||||
faction: PlanetSideEmpire.Value,
|
faction: PlanetSideEmpire.Value,
|
||||||
health: Int,
|
health: Int,
|
||||||
shields: Int,
|
shields: Int,
|
||||||
ownerName: String,
|
ownerName: String,
|
||||||
position: Vector3,
|
position: Vector3,
|
||||||
orientation : Vector3) extends SourceEntry {
|
orientation: Vector3
|
||||||
|
) extends SourceEntry {
|
||||||
override def Name = SourceEntry.NameFormat(obj_def.Name)
|
override def Name = SourceEntry.NameFormat(obj_def.Name)
|
||||||
override def Faction = faction
|
override def Faction = faction
|
||||||
def Definition: ObjectDefinition with BaseDeployableDefinition = obj_def
|
def Definition: ObjectDefinition with BaseDeployableDefinition = obj_def
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,14 @@ 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(
|
||||||
|
obj_def: ObjectDefinition with BaseDeployableDefinition,
|
||||||
faction: PlanetSideEmpire.Value,
|
faction: PlanetSideEmpire.Value,
|
||||||
health: Int,
|
health: Int,
|
||||||
ownerName: String,
|
ownerName: String,
|
||||||
position: Vector3,
|
position: Vector3,
|
||||||
orientation : Vector3) extends SourceEntry {
|
orientation: Vector3
|
||||||
|
) extends SourceEntry {
|
||||||
override def Name = SourceEntry.NameFormat(obj_def.Name)
|
override def Name = SourceEntry.NameFormat(obj_def.Name)
|
||||||
override def Faction = faction
|
override def Faction = faction
|
||||||
def Definition: ObjectDefinition with BaseDeployableDefinition = obj_def
|
def Definition: ObjectDefinition with BaseDeployableDefinition = obj_def
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,13 @@ 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(
|
||||||
|
obj: PlanetSideGameObject with FactionAffinity,
|
||||||
faction: PlanetSideEmpire.Value,
|
faction: PlanetSideEmpire.Value,
|
||||||
position: Vector3,
|
position: Vector3,
|
||||||
orientation: Vector3,
|
orientation: Vector3,
|
||||||
velocity : Option[Vector3]) extends SourceEntry {
|
velocity: Option[Vector3]
|
||||||
|
) extends SourceEntry {
|
||||||
override def Name = SourceEntry.NameFormat(obj.Definition.Name)
|
override def Name = SourceEntry.NameFormat(obj.Definition.Name)
|
||||||
override def Faction = faction
|
override def Faction = faction
|
||||||
def Definition = obj.Definition
|
def Definition = obj.Definition
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@ 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(
|
||||||
|
name: String,
|
||||||
char_id: Long,
|
char_id: Long,
|
||||||
obj_def: ObjectDefinition,
|
obj_def: ObjectDefinition,
|
||||||
faction: PlanetSideEmpire.Value,
|
faction: PlanetSideEmpire.Value,
|
||||||
|
|
@ -17,7 +18,8 @@ final case class PlayerSource(name : String,
|
||||||
position: Vector3,
|
position: Vector3,
|
||||||
orientation: Vector3,
|
orientation: Vector3,
|
||||||
velocity: Option[Vector3],
|
velocity: Option[Vector3],
|
||||||
modifiers : ResistanceProfile) extends SourceEntry {
|
modifiers: ResistanceProfile
|
||||||
|
) extends SourceEntry {
|
||||||
override def Name = name
|
override def Name = name
|
||||||
override def Faction = faction
|
override def Faction = faction
|
||||||
override def CharId = char_id
|
override def CharId = char_id
|
||||||
|
|
@ -34,8 +36,19 @@ final case class PlayerSource(name : String,
|
||||||
|
|
||||||
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)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,14 +28,16 @@ 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(
|
||||||
|
profile: ProjectileDefinition,
|
||||||
tool_def: ToolDefinition,
|
tool_def: ToolDefinition,
|
||||||
fire_mode: FireModeDefinition,
|
fire_mode: FireModeDefinition,
|
||||||
owner: SourceEntry,
|
owner: SourceEntry,
|
||||||
attribute_to: Int,
|
attribute_to: Int,
|
||||||
shot_origin: Vector3,
|
shot_origin: Vector3,
|
||||||
shot_angle: Vector3,
|
shot_angle: Vector3,
|
||||||
fire_time: Long = System.nanoTime) extends PlanetSideGameObject {
|
fire_time: Long = System.nanoTime
|
||||||
|
) extends PlanetSideGameObject {
|
||||||
Position = shot_origin
|
Position = shot_origin
|
||||||
Orientation = shot_angle
|
Orientation = shot_angle
|
||||||
Velocity = {
|
Velocity = {
|
||||||
|
|
@ -45,6 +47,7 @@ final case class Projectile(profile : ProjectileDefinition,
|
||||||
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
|
||||||
|
|
@ -68,10 +71,13 @@ final case class Projectile(profile : ProjectileDefinition,
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,7 @@ 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
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
resolution: ProjectileResolution.Value,
|
||||||
projectile: Projectile,
|
projectile: Projectile,
|
||||||
target: SourceEntry,
|
target: SourceEntry,
|
||||||
damage_model: DamageResistanceModel,
|
damage_model: DamageResistanceModel,
|
||||||
hit_pos : Vector3) {
|
hit_pos: Vector3
|
||||||
|
) {
|
||||||
val hit_time: Long = System.nanoTime
|
val hit_time: Long = System.nanoTime
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,8 @@ object SourceEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
def NameFormat(name: String): String = {
|
def NameFormat(name: String): String = {
|
||||||
name.replace("_", " ")
|
name
|
||||||
|
.replace("_", " ")
|
||||||
.split(" ")
|
.split(" ")
|
||||||
.map(_.capitalize)
|
.map(_.capitalize)
|
||||||
.mkString(" ")
|
.mkString(" ")
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,16 @@ 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(
|
||||||
|
obj_def: VehicleDefinition,
|
||||||
faction: PlanetSideEmpire.Value,
|
faction: PlanetSideEmpire.Value,
|
||||||
health: Int,
|
health: Int,
|
||||||
shields: Int,
|
shields: Int,
|
||||||
position: Vector3,
|
position: Vector3,
|
||||||
orientation: Vector3,
|
orientation: Vector3,
|
||||||
velocity: Option[Vector3],
|
velocity: Option[Vector3],
|
||||||
modifiers : ResistanceProfile) extends SourceEntry {
|
modifiers: ResistanceProfile
|
||||||
|
) extends SourceEntry {
|
||||||
override def Name = SourceEntry.NameFormat(obj_def.Name)
|
override def Name = SourceEntry.NameFormat(obj_def.Name)
|
||||||
override def Faction = faction
|
override def Faction = faction
|
||||||
def Definition: VehicleDefinition = obj_def
|
def Definition: VehicleDefinition = obj_def
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,7 @@ 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
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,7 @@ 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
|
|
||||||
with OwnableByPlayer
|
|
||||||
with ZoneAware {
|
|
||||||
this: PlanetSideGameObject =>
|
this: PlanetSideGameObject =>
|
||||||
private var faction: PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
|
private var faction: PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -76,8 +76,7 @@ object TelepadLike {
|
||||||
//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 _ =>
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,10 @@ 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"
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,13 @@ import net.psforever.objects.inventory.InventoryTile
|
||||||
* @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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ 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)
|
||||||
|
extends BasicDefinition
|
||||||
with ResistanceProfileMutators
|
with ResistanceProfileMutators
|
||||||
with DamageResistanceModel {
|
with DamageResistanceModel {
|
||||||
protected var permissions: List[CertificationType.Value] = List.empty
|
protected var permissions: List[CertificationType.Value] = List.empty
|
||||||
|
|
@ -86,8 +87,7 @@ class ExoSuitDefinition(private val suitType : ExoSuitType.Value) extends BasicD
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -96,8 +96,7 @@ class ExoSuitDefinition(private val suitType : ExoSuitType.Value) extends BasicD
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -113,7 +112,8 @@ class ExoSuitDefinition(private val suitType : ExoSuitType.Value) extends BasicD
|
||||||
|
|
||||||
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 =
|
||||||
|
other match {
|
||||||
case that: ExoSuitDefinition =>
|
case that: ExoSuitDefinition =>
|
||||||
(that canEqual this) &&
|
(that canEqual this) &&
|
||||||
suitType == that.suitType
|
suitType == that.suitType
|
||||||
|
|
@ -172,12 +172,7 @@ object SpecialExoSuitDefinition {
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -197,7 +192,8 @@ object ExoSuitDefinition {
|
||||||
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 =>
|
||||||
|
faction match {
|
||||||
case PlanetSideEmpire.TR => GlobalDefinitions.TRMAX.Use
|
case PlanetSideEmpire.TR => GlobalDefinitions.TRMAX.Use
|
||||||
case PlanetSideEmpire.NC => GlobalDefinitions.NCMAX.Use
|
case PlanetSideEmpire.NC => GlobalDefinitions.NCMAX.Use
|
||||||
case PlanetSideEmpire.VS => GlobalDefinitions.VSMAX.Use
|
case PlanetSideEmpire.VS => GlobalDefinitions.VSMAX.Use
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,16 @@ import scala.collection.mutable
|
||||||
*/
|
*/
|
||||||
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
|
||||||
|
|
||||||
|
|
@ -69,7 +73,6 @@ class ImplantDefinition(private val implantType : Int) extends BasicDefinition {
|
||||||
StaminaCost
|
StaminaCost
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def CostIntervalDefault: Int = {
|
def CostIntervalDefault: Int = {
|
||||||
costIntervalDefault
|
costIntervalDefault
|
||||||
}
|
}
|
||||||
|
|
@ -78,7 +81,8 @@ class ImplantDefinition(private val implantType : Int) extends BasicDefinition {
|
||||||
CostIntervalDefault
|
CostIntervalDefault
|
||||||
}
|
}
|
||||||
|
|
||||||
def GetCostIntervalByExoSuit(exosuit : ExoSuitType.Value) : Int = costIntervalByExoSuit.getOrElse(exosuit, CostIntervalDefault)
|
def GetCostIntervalByExoSuit(exosuit: ExoSuitType.Value): Int =
|
||||||
|
costIntervalByExoSuit.getOrElse(exosuit, CostIntervalDefault)
|
||||||
def CostIntervalByExoSuitHashMap: mutable.Map[ExoSuitType.Value, Int] = costIntervalByExoSuit
|
def CostIntervalByExoSuitHashMap: mutable.Map[ExoSuitType.Value, Int] = costIntervalByExoSuit
|
||||||
|
|
||||||
def Type: ImplantType.Value = ImplantType(implantType)
|
def Type: ImplantType.Value = ImplantType(implantType)
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import net.psforever.objects.definition.converter.{ObjectCreateConverter, Packet
|
||||||
* @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"
|
||||||
|
|
@ -26,7 +27,8 @@ abstract class ObjectDefinition(private val objectId : Int) extends BasicDefinit
|
||||||
* 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.
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ 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)
|
||||||
|
extends ObjectDefinition(objectId)
|
||||||
with JammingUnit
|
with JammingUnit
|
||||||
with StandardDamageProfile {
|
with StandardDamageProfile {
|
||||||
private val projectileType: Projectiles.Value = Projectiles(objectId) //let throw NoSuchElementException
|
private val projectileType: Projectiles.Value = Projectiles(objectId) //let throw NoSuchElementException
|
||||||
|
|
@ -26,7 +27,8 @@ class ProjectileDefinition(objectId : Int) extends ObjectDefinition(objectId)
|
||||||
private var damageRadius: Float = 1f
|
private var damageRadius: Float = 1f
|
||||||
private var useDamage1Subtract: Boolean = false
|
private var useDamage1Subtract: Boolean = false
|
||||||
private var existsOnRemoteClients: Boolean = false //`true` spawns a server-managed object
|
private var existsOnRemoteClients: Boolean = false //`true` spawns a server-managed object
|
||||||
private var remoteClientData : (Int, Int) = (0, 0) //artificial values; for ObjectCreateMessage packet (oicw_little_buddy is undefined)
|
private var remoteClientData: (Int, Int) =
|
||||||
|
(0, 0) //artificial values; for ObjectCreateMessage packet (oicw_little_buddy is undefined)
|
||||||
private var autoLock: Boolean = false
|
private var autoLock: Boolean = false
|
||||||
private var additionalEffect: Boolean = false
|
private var additionalEffect: Boolean = false
|
||||||
private var jammerProjectile: Boolean = false
|
private var jammerProjectile: Boolean = false
|
||||||
|
|
@ -168,9 +170,9 @@ object ProjectileDefinition {
|
||||||
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)
|
||||||
|
|
@ -181,11 +183,9 @@ object ProjectileDefinition {
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,13 @@ 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"
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,12 @@ 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._
|
||||||
|
|
||||||
|
|
@ -42,7 +47,8 @@ trait BaseDeployableDefinition {
|
||||||
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)
|
||||||
|
extends ObjectDefinition(objectId)
|
||||||
with DamageResistanceModel
|
with DamageResistanceModel
|
||||||
with ResistanceProfileMutators
|
with ResistanceProfileMutators
|
||||||
with VitalityDefinition
|
with VitalityDefinition
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,12 @@ 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)
|
||||||
|
extends ObjectDefinition(objectId)
|
||||||
with VitalityDefinition
|
with VitalityDefinition
|
||||||
with ResistanceProfileMutators
|
with ResistanceProfileMutators
|
||||||
with DamageResistanceModel {
|
with DamageResistanceModel {
|
||||||
|
|
||||||
/** vehicle shields offered through amp station facility benefits (generally: 20% of health + 1) */
|
/** vehicle shields offered through amp station facility benefits (generally: 20% of health + 1) */
|
||||||
private var maxShields: Int = 0
|
private var maxShields: Int = 0
|
||||||
/* key - seat index, value - seat object */
|
/* key - seat index, value - seat object */
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
@ -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,6 +56,7 @@ 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
|
||||||
|
|
@ -115,8 +114,7 @@ object AvatarConverter {
|
||||||
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),
|
||||||
|
|
@ -129,30 +127,44 @@ 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) }
|
||||||
|
else { None }
|
||||||
val ba: DetailedCharacterA = DetailedCharacterA(
|
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)
|
||||||
|
|
@ -163,7 +175,9 @@ object AvatarConverter {
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -176,14 +190,11 @@ object AvatarConverter {
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -198,20 +209,15 @@ object AvatarConverter {
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -225,14 +231,16 @@ object AvatarConverter {
|
||||||
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
|
||||||
|
.map({
|
||||||
|
case (implant, initialization, _) =>
|
||||||
if (initialization == 0) {
|
if (initialization == 0) {
|
||||||
ImplantEntry(implant, None)
|
ImplantEntry(implant, None)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
ImplantEntry(implant, Some(math.max(0, initialization).toInt))
|
ImplantEntry(implant, Some(math.max(0, initialization).toInt))
|
||||||
}
|
}
|
||||||
}).toList
|
})
|
||||||
|
.toList
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -260,8 +268,7 @@ object AvatarConverter {
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -276,7 +283,12 @@ object AvatarConverter {
|
||||||
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
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -326,7 +338,12 @@ object AvatarConverter {
|
||||||
* @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,11 +354,15 @@ 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(
|
||||||
|
iter: Iterator[EquipmentSlot],
|
||||||
|
builder: (Int, Equipment) => InternalSlot,
|
||||||
|
list: List[InternalSlot] = Nil,
|
||||||
|
index: Int = 0
|
||||||
|
): List[InternalSlot] = {
|
||||||
if (!iter.hasNext) {
|
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
|
||||||
|
|
@ -351,8 +372,7 @@ object AvatarConverter {
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,10 @@ class BoomerTriggerConverter extends ObjectCreateConverter[SimpleItem]() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override def DetailedConstructorData(obj: SimpleItem): Try[DetailedConstructionToolData] = {
|
override def DetailedConstructorData(obj: SimpleItem): Try[DetailedConstructionToolData] = {
|
||||||
Success(DetailedConstructionToolData(
|
Success(
|
||||||
|
DetailedConstructionToolData(
|
||||||
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0))
|
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0))
|
||||||
))
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,7 +15,8 @@ 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(
|
||||||
|
|
@ -82,30 +83,44 @@ class CharacterSelectConverter extends AvatarConverter {
|
||||||
|
|
||||||
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) }
|
||||||
|
else { None }
|
||||||
val ba: DetailedCharacterA = DetailedCharacterA(
|
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)
|
||||||
|
|
@ -129,11 +144,14 @@ 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(
|
||||||
|
iter: Iterator[EquipmentSlot],
|
||||||
|
list: List[InternalSlot] = Nil,
|
||||||
|
index: Int = 0
|
||||||
|
): List[InternalSlot] = {
|
||||||
if (!iter.hasNext) {
|
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) =>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ 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}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,30 +76,44 @@ class CorpseConverter extends AvatarConverter {
|
||||||
}
|
}
|
||||||
|
|
||||||
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) }
|
||||||
|
else { None }
|
||||||
val ba: DetailedCharacterA = DetailedCharacterA(
|
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)
|
||||||
|
|
@ -139,11 +153,14 @@ 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(
|
||||||
|
iter: Iterator[EquipmentSlot],
|
||||||
|
list: List[InternalSlot] = Nil,
|
||||||
|
index: Int = 0
|
||||||
|
): List[InternalSlot] = {
|
||||||
if (!iter.hasNext) {
|
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
|
||||||
|
|
@ -152,8 +169,7 @@ class CorpseConverter extends AvatarConverter {
|
||||||
list :+ BuildEquipment(index, equip),
|
list :+ BuildEquipment(index, equip),
|
||||||
index + 1
|
index + 1
|
||||||
)
|
)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
recursiveMakeHolsters(iter, list, index + 1)
|
recursiveMakeHolsters(iter, list, index + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -166,7 +182,12 @@ class CorpseConverter extends AvatarConverter {
|
||||||
* @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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,16 @@ 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)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,7 @@ class DroppodConverter extends ObjectCreateConverter[Vehicle]() {
|
||||||
unk = false
|
unk = false
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
} else { //destroyed
|
||||||
else { //destroyed
|
|
||||||
Success(
|
Success(
|
||||||
DroppodData(
|
DroppodData(
|
||||||
CommonFieldDataWithPlacement(
|
CommonFieldDataWithPlacement(
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
@ -66,11 +65,13 @@ class FieldTurretConverter extends ObjectCreateConverter[TurretDeployable]() {
|
||||||
|
|
||||||
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
|
||||||
|
.map({
|
||||||
case (index, slot) =>
|
case (index, slot) =>
|
||||||
val equip: Equipment = slot.Equipment.get
|
val equip: Equipment = slot.Equipment.get
|
||||||
val equipDef = equip.Definition
|
val equipDef = equip.Definition
|
||||||
InventoryItemData(equipDef.ObjectId, equip.GUID, index, equipDef.Packet.ConstructorData(equip).get)
|
InventoryItemData(equipDef.ObjectId, equip.GUID, index, equipDef.Packet.ConstructorData(equip).get)
|
||||||
}).toList
|
})
|
||||||
|
.toList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,16 +21,19 @@ 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(
|
||||||
|
DetailedLockerContainerData(
|
||||||
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)),
|
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)),
|
||||||
Some(InventoryData(MakeDetailedInventory(obj.Inventory)))
|
Some(InventoryData(MakeDetailedInventory(obj.Inventory)))
|
||||||
))
|
)
|
||||||
}
|
)
|
||||||
else {
|
} else {
|
||||||
Success(DetailedLockerContainerData(
|
Success(
|
||||||
|
DetailedLockerContainerData(
|
||||||
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)),
|
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)),
|
||||||
None
|
None
|
||||||
))
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -44,7 +47,12 @@ class LockerContainerConverter extends ObjectCreateConverter[LockerEquipment]()
|
||||||
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
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,7 +66,12 @@ class LockerContainerConverter extends ObjectCreateConverter[LockerEquipment]()
|
||||||
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
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,17 +17,22 @@ sealed trait PacketConverter
|
||||||
* @tparam A the type of game object
|
* @tparam A the type of game object
|
||||||
*/
|
*/
|
||||||
abstract class ObjectCreateConverter[A <: PlanetSideGameObject] extends PacketConverter {
|
abstract class ObjectCreateConverter[A <: PlanetSideGameObject] extends PacketConverter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take a game object and transform it into its equivalent data for an `0x17` packet.
|
* Take a game object and transform it into its equivalent data for an `0x17` packet.
|
||||||
* @param obj the game object
|
* @param obj the game object
|
||||||
* @return the specific `ConstructorData` that is equivalent to this object
|
* @return the specific `ConstructorData` that is equivalent to this object
|
||||||
*/
|
*/
|
||||||
def ConstructorData(obj : A) : Try[ConstructorData] = { Failure(new NoSuchMethodException(s"method not defined for object $obj")) }
|
def ConstructorData(obj: A): Try[ConstructorData] = {
|
||||||
|
Failure(new NoSuchMethodException(s"method not defined for object $obj"))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take a game object and transform it into its equivalent data for an `0x18` packet.
|
* Take a game object and transform it into its equivalent data for an `0x18` packet.
|
||||||
* @param obj the game object
|
* @param obj the game object
|
||||||
* @return the specific `ConstructorData` that is equivalent to this object
|
* @return the specific `ConstructorData` that is equivalent to this object
|
||||||
*/
|
*/
|
||||||
def DetailedConstructorData(obj : A) : Try[ConstructorData] = { Failure(new NoSuchMethodException(s"method not defined for object $obj")) }
|
def DetailedConstructorData(obj: A): Try[ConstructorData] = {
|
||||||
|
Failure(new NoSuchMethodException(s"method not defined for object $obj"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,13 @@
|
||||||
package net.psforever.objects.definition.converter
|
package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
import net.psforever.objects.ballistics.Projectile
|
import net.psforever.objects.ballistics.Projectile
|
||||||
import net.psforever.packet.game.objectcreate.{CommonFieldData, CommonFieldDataWithPlacement, FlightPhysics, PlacementData, RemoteProjectileData}
|
import net.psforever.packet.game.objectcreate.{
|
||||||
|
CommonFieldData,
|
||||||
|
CommonFieldDataWithPlacement,
|
||||||
|
FlightPhysics,
|
||||||
|
PlacementData,
|
||||||
|
RemoteProjectileData
|
||||||
|
}
|
||||||
import net.psforever.types.PlanetSideGUID
|
import net.psforever.types.PlanetSideGUID
|
||||||
|
|
||||||
import scala.util.{Failure, Success, Try}
|
import scala.util.{Failure, Success, Try}
|
||||||
|
|
@ -39,5 +45,7 @@ class ProjectileConverter extends ObjectCreateConverter[Projectile]() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override def DetailedConstructorData(obj: Projectile): Try[RemoteProjectileData] =
|
override def DetailedConstructorData(obj: Projectile): Try[RemoteProjectileData] =
|
||||||
Failure(new Exception("ProjectileConverter should not be used to generate detailed projectile data (nothing should)"))
|
Failure(
|
||||||
|
new Exception("ProjectileConverter should not be used to generate detailed projectile data (nothing should)")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ class REKConverter extends ObjectCreateConverter[SimpleItem]() {
|
||||||
false,
|
false,
|
||||||
Some(false),
|
Some(false),
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0))
|
PlanetSideGUID(0)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,13 @@ object SeatConverter {
|
||||||
var offset = initialOffset
|
var offset = initialOffset
|
||||||
seats
|
seats
|
||||||
.filter({ case (_, seat) => seat.isOccupied })
|
.filter({ case (_, seat) => seat.isOccupied })
|
||||||
.map({case (index, seat) =>
|
.map({
|
||||||
|
case (index, seat) =>
|
||||||
val player = seat.Occupant.get
|
val player = seat.Occupant.get
|
||||||
val entry = InventoryItemData(ObjectClass.avatar, player.GUID, index, SeatConverter.MakeSeat(player, offset))
|
val entry = InventoryItemData(ObjectClass.avatar, player.GUID, index, SeatConverter.MakeSeat(player, offset))
|
||||||
offset += entry.bitsize
|
offset += entry.bitsize
|
||||||
entry
|
entry
|
||||||
}).toList
|
})
|
||||||
|
.toList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,7 @@ class ShieldGeneratorConverter extends ObjectCreateConverter[ShieldGeneratorDepl
|
||||||
health
|
health
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Success(
|
Success(
|
||||||
AegisShieldGeneratorData(
|
AegisShieldGeneratorData(
|
||||||
CommonFieldDataWithPlacement(
|
CommonFieldDataWithPlacement(
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,7 @@ class SmallTurretConverter extends ObjectCreateConverter[TurretDeployable]() {
|
||||||
Some(InventoryData(SmallTurretConverter.MakeMountings(obj)))
|
Some(InventoryData(SmallTurretConverter.MakeMountings(obj)))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Success(
|
Success(
|
||||||
SmallTurretData(
|
SmallTurretData(
|
||||||
CommonFieldDataWithPlacement(
|
CommonFieldDataWithPlacement(
|
||||||
|
|
@ -66,11 +65,13 @@ class SmallTurretConverter extends ObjectCreateConverter[TurretDeployable]() {
|
||||||
|
|
||||||
object SmallTurretConverter {
|
object SmallTurretConverter {
|
||||||
private def MakeMountings(obj: WeaponTurret): List[InventoryItemData.InventoryItem] = {
|
private def MakeMountings(obj: WeaponTurret): List[InventoryItemData.InventoryItem] = {
|
||||||
obj.Weapons.map({
|
obj.Weapons
|
||||||
|
.map({
|
||||||
case ((index, slot)) =>
|
case ((index, slot)) =>
|
||||||
val equip: Equipment = slot.Equipment.get
|
val equip: Equipment = slot.Equipment.get
|
||||||
val equipDef = equip.Definition
|
val equipDef = equip.Definition
|
||||||
InventoryItemData(equipDef.ObjectId, equip.GUID, index, equipDef.Packet.ConstructorData(equip).get)
|
InventoryItemData(equipDef.ObjectId, equip.GUID, index, equipDef.Packet.ConstructorData(equip).get)
|
||||||
}).toList
|
})
|
||||||
|
.toList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package net.psforever.objects.definition.converter
|
package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
object StatConverter {
|
object StatConverter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a measure of a value against the maximum possible value and
|
* Takes a measure of a value against the maximum possible value and
|
||||||
* transforms it to a scaled number that can be written within a specific domain.<br>
|
* transforms it to a scaled number that can be written within a specific domain.<br>
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,7 @@ class TRAPConverter extends ObjectCreateConverter[TrapDeployable]() {
|
||||||
health
|
health
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Success(
|
Success(
|
||||||
TRAPData(
|
TRAPData(
|
||||||
CommonFieldDataWithPlacement(
|
CommonFieldDataWithPlacement(
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,7 @@ class TelepadDeployableConverter extends ObjectCreateConverter[TelepadDeployable
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Success(
|
Success(
|
||||||
DroppedItemData(
|
DroppedItemData(
|
||||||
PlacementData(obj.Position, obj.Orientation),
|
PlacementData(obj.Position, obj.Orientation),
|
||||||
|
|
@ -60,7 +59,9 @@ class TelepadDeployableConverter extends ObjectCreateConverter[TelepadDeployable
|
||||||
}
|
}
|
||||||
|
|
||||||
case None =>
|
case None =>
|
||||||
Failure(new IllegalStateException("TelepadDeployableConverter: telepad needs to know id of its associated Router"))
|
Failure(
|
||||||
|
new IllegalStateException("TelepadDeployableConverter: telepad needs to know id of its associated Router")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,12 @@ import scala.util.{Success, Try}
|
||||||
|
|
||||||
class ToolConverter extends ObjectCreateConverter[Tool]() {
|
class ToolConverter extends ObjectCreateConverter[Tool]() {
|
||||||
override def ConstructorData(obj: Tool): Try[WeaponData] = {
|
override def ConstructorData(obj: Tool): Try[WeaponData] = {
|
||||||
val slots : List[InternalSlot] = (0 until obj.MaxAmmoSlot).map(index => {
|
val slots: List[InternalSlot] = (0 until obj.MaxAmmoSlot)
|
||||||
|
.map(index => {
|
||||||
val box = obj.AmmoSlots(index).Box
|
val box = obj.AmmoSlots(index).Box
|
||||||
InternalSlot(box.Definition.ObjectId, box.GUID, index, box.Definition.Packet.ConstructorData(box).get)
|
InternalSlot(box.Definition.ObjectId, box.GUID, index, box.Definition.Packet.ConstructorData(box).get)
|
||||||
}).toList
|
})
|
||||||
|
.toList
|
||||||
Success(
|
Success(
|
||||||
WeaponData(
|
WeaponData(
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
|
|
@ -33,10 +35,12 @@ class ToolConverter extends ObjectCreateConverter[Tool]() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override def DetailedConstructorData(obj: Tool): Try[DetailedWeaponData] = {
|
override def DetailedConstructorData(obj: Tool): Try[DetailedWeaponData] = {
|
||||||
val slots : List[InternalSlot] = (0 until obj.MaxAmmoSlot).map(index => {
|
val slots: List[InternalSlot] = (0 until obj.MaxAmmoSlot)
|
||||||
|
.map(index => {
|
||||||
val box = obj.AmmoSlots(index).Box
|
val box = obj.AmmoSlots(index).Box
|
||||||
InternalSlot(box.Definition.ObjectId, box.GUID, index, box.Definition.Packet.DetailedConstructorData(box).get)
|
InternalSlot(box.Definition.ObjectId, box.GUID, index, box.Definition.Packet.DetailedConstructorData(box).get)
|
||||||
}).toList
|
})
|
||||||
|
.toList
|
||||||
Success(
|
Success(
|
||||||
DetailedWeaponData(
|
DetailedWeaponData(
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,10 @@ class VariantVehicleConverter extends VehicleConverter {
|
||||||
landed is 0
|
landed is 0
|
||||||
flying is 7
|
flying is 7
|
||||||
*/
|
*/
|
||||||
Some(VariantVehicleData(
|
Some(
|
||||||
|
VariantVehicleData(
|
||||||
if (obj.Definition.CanFly && obj.Flying) 7 else 0
|
if (obj.Definition.CanFly && obj.Flying) 7 else 0
|
||||||
))
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,7 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
|
||||||
Some(InventoryData(MakeDriverSeat(obj) ++ MakeUtilities(obj) ++ MakeMountings(obj)))
|
Some(InventoryData(MakeDriverSeat(obj) ++ MakeUtilities(obj) ++ MakeMountings(obj)))
|
||||||
)(SpecificFormatModifier)
|
)(SpecificFormatModifier)
|
||||||
)
|
)
|
||||||
}
|
} else { //destroyed
|
||||||
else { //destroyed
|
|
||||||
Success(
|
Success(
|
||||||
VehicleData(
|
VehicleData(
|
||||||
PlacementData(obj.Position, obj.Orientation),
|
PlacementData(obj.Position, obj.Orientation),
|
||||||
|
|
@ -86,7 +85,8 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private def MakeMountings(obj: Vehicle): List[InventoryItemData.InventoryItem] = {
|
private def MakeMountings(obj: Vehicle): List[InventoryItemData.InventoryItem] = {
|
||||||
obj.Weapons.collect { case (index, slot) if slot.Equipment.nonEmpty =>
|
obj.Weapons.collect {
|
||||||
|
case (index, slot) if slot.Equipment.nonEmpty =>
|
||||||
val equip: Equipment = slot.Equipment.get
|
val equip: Equipment = slot.Equipment.get
|
||||||
val equipDef = equip.Definition
|
val equipDef = equip.Definition
|
||||||
InventoryItemData(equipDef.ObjectId, equip.GUID, index, equipDef.Packet.ConstructorData(equip).get)
|
InventoryItemData(equipDef.ObjectId, equip.GUID, index, equipDef.Packet.ConstructorData(equip).get)
|
||||||
|
|
@ -94,12 +94,15 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected def MakeUtilities(obj: Vehicle): List[InventoryItemData.InventoryItem] = {
|
protected def MakeUtilities(obj: Vehicle): List[InventoryItemData.InventoryItem] = {
|
||||||
Vehicle.EquipmentUtilities(obj.Utilities).map({
|
Vehicle
|
||||||
|
.EquipmentUtilities(obj.Utilities)
|
||||||
|
.map({
|
||||||
case (index, utilContainer) =>
|
case (index, utilContainer) =>
|
||||||
val util = utilContainer()
|
val util = utilContainer()
|
||||||
val utilDef = util.Definition
|
val utilDef = util.Definition
|
||||||
InventoryItemData(utilDef.ObjectId, util.GUID, index, utilDef.Packet.ConstructorData(util).get)
|
InventoryItemData(utilDef.ObjectId, util.GUID, index, utilDef.Packet.ConstructorData(util).get)
|
||||||
}).toList
|
})
|
||||||
|
.toList
|
||||||
}
|
}
|
||||||
|
|
||||||
protected def SpecificFormatModifier: VehicleFormat.Value = VehicleFormat.Normal
|
protected def SpecificFormatModifier: VehicleFormat.Value = VehicleFormat.Normal
|
||||||
|
|
|
||||||
|
|
@ -28,13 +28,12 @@ abstract class GUIDException(message : String, cause : Throwable, obj : Identifi
|
||||||
* @param obj the entity being manipulated when the complaint arose
|
* @param obj the entity being manipulated when the complaint arose
|
||||||
* @param cause the cause of this error
|
* @param cause the cause of this error
|
||||||
*/
|
*/
|
||||||
class NoGUIDException(message : String,
|
class NoGUIDException(message: String, obj: IdentifiableEntity = None.orNull, cause: Throwable = None.orNull)
|
||||||
obj : IdentifiableEntity = None.orNull,
|
extends GUIDException(message, cause, obj, null)
|
||||||
cause : Throwable = None.orNull
|
|
||||||
) extends GUIDException(message, cause, obj, null)
|
|
||||||
|
|
||||||
object NoGUIDException {
|
object NoGUIDException {
|
||||||
def unapply(e : NoGUIDException): Option[(String, IdentifiableEntity, Throwable)] = Some((e.getMessage, e.getEntity, e.getCause))
|
def unapply(e: NoGUIDException): Option[(String, IdentifiableEntity, Throwable)] =
|
||||||
|
Some((e.getMessage, e.getEntity, e.getCause))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -44,12 +43,14 @@ object NoGUIDException {
|
||||||
* @param guid the identifier number being manipulated when the ciomplaint arose
|
* @param guid the identifier number being manipulated when the ciomplaint arose
|
||||||
* @param cause the cause of this error
|
* @param cause the cause of this error
|
||||||
*/
|
*/
|
||||||
class AssigningGUIDException(message : String,
|
class AssigningGUIDException(
|
||||||
|
message: String,
|
||||||
obj: IdentifiableEntity,
|
obj: IdentifiableEntity,
|
||||||
guid: PlanetSideGUID,
|
guid: PlanetSideGUID,
|
||||||
cause: Throwable = None.orNull
|
cause: Throwable = None.orNull
|
||||||
) extends GUIDException(message, cause, obj, guid)
|
) extends GUIDException(message, cause, obj, guid)
|
||||||
|
|
||||||
object AssigningGUIDException {
|
object AssigningGUIDException {
|
||||||
def unapply(e : AssigningGUIDException): Option[(String, Throwable, IdentifiableEntity, PlanetSideGUID)] = Some((e.getMessage, e.getCause, e.getEntity, e.getGUID))
|
def unapply(e: AssigningGUIDException): Option[(String, Throwable, IdentifiableEntity, PlanetSideGUID)] =
|
||||||
|
Some((e.getMessage, e.getCause, e.getEntity, e.getGUID))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,16 @@ import net.psforever.types.{PlanetSideGUID, StalePlanetSideGUID}
|
||||||
* @throws `NoGUIDException` if a GUID has not yet been assigned
|
* @throws `NoGUIDException` if a GUID has not yet been assigned
|
||||||
*/
|
*/
|
||||||
abstract class IdentifiableEntity extends Identifiable {
|
abstract class IdentifiableEntity extends Identifiable {
|
||||||
|
|
||||||
/** storage for the GUID information; starts as a `StalePlanetSideGUID` */
|
/** storage for the GUID information; starts as a `StalePlanetSideGUID` */
|
||||||
private var current: PlanetSideGUID = StalePlanetSideGUID(0)
|
private var current: PlanetSideGUID = StalePlanetSideGUID(0)
|
||||||
|
|
||||||
/** indicate the validity of the current GUID */
|
/** indicate the validity of the current GUID */
|
||||||
private var guidValid: Boolean = false
|
private var guidValid: Boolean = false
|
||||||
|
|
||||||
/** the current accessor; can be re-assigned */
|
/** the current accessor; can be re-assigned */
|
||||||
private var guidAccessor: IdentifiableEntity => PlanetSideGUID = IdentifiableEntity.getWhenNoGUID
|
private var guidAccessor: IdentifiableEntity => PlanetSideGUID = IdentifiableEntity.getWhenNoGUID
|
||||||
|
|
||||||
/** the current mutator; can be re-assigned */
|
/** the current mutator; can be re-assigned */
|
||||||
private var guidMutator: (IdentifiableEntity, PlanetSideGUID) => PlanetSideGUID = IdentifiableEntity.setWhenNoGUID
|
private var guidMutator: (IdentifiableEntity, PlanetSideGUID) => PlanetSideGUID = IdentifiableEntity.setWhenNoGUID
|
||||||
|
|
||||||
|
|
@ -71,6 +75,7 @@ abstract class IdentifiableEntity extends Identifiable {
|
||||||
}
|
}
|
||||||
|
|
||||||
object IdentifiableEntity {
|
object IdentifiableEntity {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raise an `Exception` because the entity is never considered having a GUID to give.
|
* Raise an `Exception` because the entity is never considered having a GUID to give.
|
||||||
* @param o the any entity with a GUID
|
* @param o the any entity with a GUID
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ trait WorldEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
object WorldEntity {
|
object WorldEntity {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A velocity of non-zero is the same as moving.
|
* A velocity of non-zero is the same as moving.
|
||||||
* @return `true`, if we are moving; `false`, otherwise
|
* @return `true`, if we are moving; `false`, otherwise
|
||||||
|
|
@ -58,7 +59,8 @@ object WorldEntity {
|
||||||
* @param test the (squared) velocity to test against
|
* @param test the (squared) velocity to test against
|
||||||
* @return `true`, if we are moving; `false`, otherwise
|
* @return `true`, if we are moving; `false`, otherwise
|
||||||
*/
|
*/
|
||||||
def isMoving(velocity : Option[Vector3], test : Vector3) : Boolean = WorldEntity.isMoving(velocity, Vector3.MagnitudeSquared(test))
|
def isMoving(velocity: Option[Vector3], test: Vector3): Boolean =
|
||||||
|
WorldEntity.isMoving(velocity, Vector3.MagnitudeSquared(test))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This object is not considered moving unless it is moving at least as fast as a certain velocity.
|
* This object is not considered moving unless it is moving at least as fast as a certain velocity.
|
||||||
|
|
|
||||||
|
|
@ -8,19 +8,13 @@ import net.psforever.objects.serverobject.turret.FacilityTurret
|
||||||
final case class TargetValidation(category: EffectTarget.Category.Value, test: EffectTarget.Validation.Value)
|
final case class TargetValidation(category: EffectTarget.Category.Value, test: EffectTarget.Validation.Value)
|
||||||
|
|
||||||
object EffectTarget {
|
object EffectTarget {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A classification of the target of interactions.
|
* A classification of the target of interactions.
|
||||||
* Arbitrary, but useful.
|
* Arbitrary, but useful.
|
||||||
*/
|
*/
|
||||||
object Category extends Enumeration {
|
object Category extends Enumeration {
|
||||||
val
|
val Aircraft, Deployable, Equipment, Player, Turret, Vehicle = Value
|
||||||
Aircraft,
|
|
||||||
Deployable,
|
|
||||||
Equipment,
|
|
||||||
Player,
|
|
||||||
Turret,
|
|
||||||
Vehicle
|
|
||||||
= Value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object Validation {
|
object Validation {
|
||||||
|
|
@ -28,56 +22,64 @@ object EffectTarget {
|
||||||
|
|
||||||
def Invalid(target: PlanetSideGameObject): Boolean = false
|
def Invalid(target: PlanetSideGameObject): Boolean = false
|
||||||
|
|
||||||
def Medical(target : PlanetSideGameObject) : Boolean = target match {
|
def Medical(target: PlanetSideGameObject): Boolean =
|
||||||
|
target match {
|
||||||
case p: Player =>
|
case p: Player =>
|
||||||
p.Health > 0 && (p.Health < p.MaxHealth || p.Armor < p.MaxArmor)
|
p.Health > 0 && (p.Health < p.MaxHealth || p.Armor < p.MaxArmor)
|
||||||
case _ =>
|
case _ =>
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
def HealthCrystal(target : PlanetSideGameObject) : Boolean = target match {
|
def HealthCrystal(target: PlanetSideGameObject): Boolean =
|
||||||
|
target match {
|
||||||
case p: Player =>
|
case p: Player =>
|
||||||
p.Health > 0 && p.Health < p.MaxHealth
|
p.Health > 0 && p.Health < p.MaxHealth
|
||||||
case _ =>
|
case _ =>
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
def RepairSilo(target : PlanetSideGameObject) : Boolean = target match {
|
def RepairSilo(target: PlanetSideGameObject): Boolean =
|
||||||
|
target match {
|
||||||
case v: Vehicle =>
|
case v: Vehicle =>
|
||||||
!GlobalDefinitions.isFlightVehicle(v.Definition) && v.Health > 0 && v.Health < v.MaxHealth
|
!GlobalDefinitions.isFlightVehicle(v.Definition) && v.Health > 0 && v.Health < v.MaxHealth
|
||||||
case _ =>
|
case _ =>
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
def PadLanding(target : PlanetSideGameObject) : Boolean = target match {
|
def PadLanding(target: PlanetSideGameObject): Boolean =
|
||||||
|
target match {
|
||||||
case v: Vehicle =>
|
case v: Vehicle =>
|
||||||
GlobalDefinitions.isFlightVehicle(v.Definition) && v.Health > 0 && v.Health < v.MaxHealth
|
GlobalDefinitions.isFlightVehicle(v.Definition) && v.Health > 0 && v.Health < v.MaxHealth
|
||||||
case _ =>
|
case _ =>
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
def Player(target : PlanetSideGameObject) : Boolean = target match {
|
def Player(target: PlanetSideGameObject): Boolean =
|
||||||
|
target match {
|
||||||
case p: Player =>
|
case p: Player =>
|
||||||
p.isAlive
|
p.isAlive
|
||||||
case _ =>
|
case _ =>
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
def MotionSensor(target : PlanetSideGameObject) : Boolean = target match {
|
def MotionSensor(target: PlanetSideGameObject): Boolean =
|
||||||
|
target match {
|
||||||
case s: SensorDeployable =>
|
case s: SensorDeployable =>
|
||||||
s.Health > 0
|
s.Health > 0
|
||||||
case _ =>
|
case _ =>
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
def Spitfire(target : PlanetSideGameObject) : Boolean = target match {
|
def Spitfire(target: PlanetSideGameObject): Boolean =
|
||||||
|
target match {
|
||||||
case t: TurretDeployable =>
|
case t: TurretDeployable =>
|
||||||
t.Definition.DeployCategory == DeployableCategory.SmallTurrets && t.Health > 0
|
t.Definition.DeployCategory == DeployableCategory.SmallTurrets && t.Health > 0
|
||||||
case _ =>
|
case _ =>
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
def Turret(target : PlanetSideGameObject) : Boolean = target match {
|
def Turret(target: PlanetSideGameObject): Boolean =
|
||||||
|
target match {
|
||||||
case t: TurretDeployable =>
|
case t: TurretDeployable =>
|
||||||
t.Definition.DeployCategory == DeployableCategory.FieldTurrets && t.Health > 0
|
t.Definition.DeployCategory == DeployableCategory.FieldTurrets && t.Health > 0
|
||||||
case t: FacilityTurret =>
|
case t: FacilityTurret =>
|
||||||
|
|
@ -86,14 +88,16 @@ object EffectTarget {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
def AMS(target : PlanetSideGameObject) : Boolean = target match {
|
def AMS(target: PlanetSideGameObject): Boolean =
|
||||||
|
target match {
|
||||||
case v: Vehicle =>
|
case v: Vehicle =>
|
||||||
v.Health > 0 && v.Definition == GlobalDefinitions.ams
|
v.Health > 0 && v.Definition == GlobalDefinitions.ams
|
||||||
case _ =>
|
case _ =>
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
def VehicleNotAMS(target : PlanetSideGameObject) : Boolean = target match {
|
def VehicleNotAMS(target: PlanetSideGameObject): Boolean =
|
||||||
|
target match {
|
||||||
case v: Vehicle =>
|
case v: Vehicle =>
|
||||||
v.Health > 0 && v.Definition != GlobalDefinitions.ams
|
v.Health > 0 && v.Definition != GlobalDefinitions.ams
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@ import net.psforever.types.PlanetSideEmpire
|
||||||
* and, special carried (like a lattice logic unit);
|
* and, special carried (like a lattice logic unit);
|
||||||
* and, dropped on the ground in the game world and render where it was deposited.
|
* and, dropped on the ground in the game world and render where it was deposited.
|
||||||
*/
|
*/
|
||||||
abstract class Equipment extends PlanetSideGameObject
|
abstract class Equipment extends PlanetSideGameObject with FactionAffinity {
|
||||||
with FactionAffinity {
|
|
||||||
private var faction: PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
|
private var faction: PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
|
||||||
|
|
||||||
def Faction: PlanetSideEmpire.Value = faction
|
def Faction: PlanetSideEmpire.Value = faction
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,7 @@ package net.psforever.objects.equipment
|
||||||
* Check the comments for originating use.
|
* Check the comments for originating use.
|
||||||
*/
|
*/
|
||||||
object EquipmentSize extends Enumeration {
|
object EquipmentSize extends Enumeration {
|
||||||
val
|
val Blocked, Melee, //special
|
||||||
Blocked,
|
|
||||||
Melee, //special
|
|
||||||
Pistol, //2x2 and 3x3
|
Pistol, //2x2 and 3x3
|
||||||
Rifle, //6x3 and 9x3
|
Rifle, //6x3 and 9x3
|
||||||
Max, //max weapon only
|
Max, //max weapon only
|
||||||
|
|
@ -33,11 +31,9 @@ object EquipmentSize extends Enumeration {
|
||||||
def isEqual(type1: EquipmentSize.Value, type2: EquipmentSize.Value): Boolean = {
|
def isEqual(type1: EquipmentSize.Value, type2: EquipmentSize.Value): Boolean = {
|
||||||
if (type1 == Blocked || type2 == Blocked) {
|
if (type1 == Blocked || type2 == Blocked) {
|
||||||
false
|
false
|
||||||
}
|
} else if (type1 == Inventory || type2 == Inventory) {
|
||||||
else if(type1 == Inventory || type2 == Inventory) {
|
|
||||||
true
|
true
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
type1 == type2
|
type1 == type2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,7 @@ class EquipmentSlot {
|
||||||
if (tool.isEmpty && EquipmentSize.isEqual(size, assignEquipment.get.Size)) {
|
if (tool.isEmpty && EquipmentSize.isEqual(size, assignEquipment.get.Size)) {
|
||||||
tool = assignEquipment
|
tool = assignEquipment
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
tool = None
|
tool = None
|
||||||
}
|
}
|
||||||
Equipment
|
Equipment
|
||||||
|
|
|
||||||
|
|
@ -7,26 +7,39 @@ import net.psforever.objects.vital.damage.DamageProfile
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
||||||
class FireModeDefinition {
|
class FireModeDefinition {
|
||||||
|
|
||||||
/** indices pointing to all ammo types used, in (an) order
|
/** indices pointing to all ammo types used, in (an) order
|
||||||
* the ammo types list will be available from the `ToolDefinition` */
|
* the ammo types list will be available from the `ToolDefinition`
|
||||||
|
*/
|
||||||
private val ammoTypeIndices: mutable.ListBuffer[Int] = mutable.ListBuffer[Int]()
|
private val ammoTypeIndices: mutable.ListBuffer[Int] = mutable.ListBuffer[Int]()
|
||||||
|
|
||||||
/** custom indices pointing to the projectile type used for this mode's ammo types
|
/** custom indices pointing to the projectile type used for this mode's ammo types
|
||||||
* for most weapon fire modes, this list will be empty and the projectile will align with the `ammoTypeIndex`
|
* for most weapon fire modes, this list will be empty and the projectile will align with the `ammoTypeIndex`
|
||||||
* if at least one ammo type has a redirected projectile type, all projectiles must be defined for this mode */
|
* if at least one ammo type has a redirected projectile type, all projectiles must be defined for this mode
|
||||||
|
*/
|
||||||
private val projectileTypeIndices: mutable.ListBuffer[Int] = mutable.ListBuffer[Int]()
|
private val projectileTypeIndices: mutable.ListBuffer[Int] = mutable.ListBuffer[Int]()
|
||||||
|
|
||||||
/** ammunition slot number this fire mode utilizes */
|
/** ammunition slot number this fire mode utilizes */
|
||||||
private var ammoSlotIndex: Int = 0
|
private var ammoSlotIndex: Int = 0
|
||||||
|
|
||||||
/** how many rounds are replenished each reload cycle */
|
/** how many rounds are replenished each reload cycle */
|
||||||
private var magazine: Int = 1
|
private var magazine: Int = 1
|
||||||
|
|
||||||
/** how many rounds are replenished each reload cycle, per type of ammunition loaded
|
/** how many rounds are replenished each reload cycle, per type of ammunition loaded
|
||||||
* key - ammo type index, value - magazine capacity*/
|
* key - ammo type index, value - magazine capacity
|
||||||
|
*/
|
||||||
private val customAmmoMagazine: mutable.HashMap[Ammo.Value, Int] = mutable.HashMap[Ammo.Value, Int]()
|
private val customAmmoMagazine: mutable.HashMap[Ammo.Value, Int] = mutable.HashMap[Ammo.Value, Int]()
|
||||||
|
|
||||||
/** how much is subtracted from the magazine each fire cycle;
|
/** how much is subtracted from the magazine each fire cycle;
|
||||||
* most weapons will only fire 1 round per fire cycle; the flamethrower in fire mode 1 fires 50 */
|
* most weapons will only fire 1 round per fire cycle; the flamethrower in fire mode 1 fires 50
|
||||||
|
*/
|
||||||
private var rounds: Int = 1
|
private var rounds: Int = 1
|
||||||
|
|
||||||
/** how many sub-rounds are queued per round fired;
|
/** how many sub-rounds are queued per round fired;
|
||||||
* the flechette fires 8 pellets per shell and generates 8 fire reports before the ammo count goes down */
|
* the flechette fires 8 pellets per shell and generates 8 fire reports before the ammo count goes down
|
||||||
|
*/
|
||||||
private var chamber: Int = 1
|
private var chamber: Int = 1
|
||||||
|
|
||||||
/** modifiers for each damage type */
|
/** modifiers for each damage type */
|
||||||
private val modifiers: DamageModifiers = new DamageModifiers
|
private val modifiers: DamageModifiers = new DamageModifiers
|
||||||
|
|
||||||
|
|
@ -96,6 +109,7 @@ class FireModeDefinition {
|
||||||
}
|
}
|
||||||
|
|
||||||
class PelletFireModeDefinition extends FireModeDefinition {
|
class PelletFireModeDefinition extends FireModeDefinition {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shoot a weapon, remove an anticipated amount of ammunition.<br>
|
* Shoot a weapon, remove an anticipated amount of ammunition.<br>
|
||||||
* <br>
|
* <br>
|
||||||
|
|
@ -112,14 +126,14 @@ class PelletFireModeDefinition extends FireModeDefinition {
|
||||||
if (chamber <= 0) {
|
if (chamber <= 0) {
|
||||||
ammoSlot.Chamber = Chamber
|
ammoSlot.Chamber = Chamber
|
||||||
magazine - Rounds
|
magazine - Rounds
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
magazine
|
magazine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class InfiniteFireModeDefinition extends FireModeDefinition {
|
class InfiniteFireModeDefinition extends FireModeDefinition {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shoot a weapon, remove an anticipated amount of ammunition.<br>
|
* Shoot a weapon, remove an anticipated amount of ammunition.<br>
|
||||||
* <br>
|
* <br>
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue