Commits (15)
image: "rustlang/rust:nightly"
image: "rust:latest"
stages:
- build
......
......@@ -4,235 +4,235 @@
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "chrono"
version = "0.4.15"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
"libc",
"num-integer",
"num-traits",
"time",
"winapi",
]
[[package]]
name = "derivative"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f"
dependencies = [
"proc-macro2 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "itoa"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
[[package]]
name = "libc"
version = "0.2.76"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
[[package]]
name = "md5"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
[[package]]
name = "num-integer"
version = "0.1.43"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.12"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"autocfg",
]
[[package]]
name = "num_enum"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "226b45a5c2ac4dd696ed30fa6b94b057ad909c7b7fc2e0d0808192bced894066"
dependencies = [
"derivative 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num_enum_derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"derivative",
"num_enum_derive",
]
[[package]]
name = "num_enum_derive"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c0fd9eba1d5db0994a239e09c1be402d35622277e35468ba891aa5e3188ce7e"
dependencies = [
"proc-macro-crate 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "powers"
version = "2.2.1"
version = "2.3.0"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)",
"md5 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num_enum 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags",
"chrono",
"md5",
"num_enum",
"serde",
"serde_json",
"toml",
]
[[package]]
name = "proc-macro-crate"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
dependencies = [
"toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"toml",
]
[[package]]
name = "proc-macro2"
version = "1.0.20"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
dependencies = [
"unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
dependencies = [
"proc-macro2 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
]
[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "serde"
version = "1.0.115"
version = "1.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a"
dependencies = [
"serde_derive 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.115"
version = "1.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e"
dependencies = [
"proc-macro2 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.57"
version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95"
dependencies = [
"itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "1.0.39"
version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b4f34193997d92804d359ed09953e25d5138df6bcc055a71bf68ee89fdf9223"
dependencies = [
"proc-macro2 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "time"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)",
"wasi 0.10.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc",
"wasi",
"winapi",
]
[[package]]
name = "toml"
version = "0.5.6"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645"
dependencies = [
"serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)",
"serde",
]
[[package]]
name = "unicode-xid"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum chrono 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)" = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b"
"checksum derivative 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f"
"checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
"checksum libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)" = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3"
"checksum md5 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
"checksum num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
"checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
"checksum num_enum 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "226b45a5c2ac4dd696ed30fa6b94b057ad909c7b7fc2e0d0808192bced894066"
"checksum num_enum_derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1c0fd9eba1d5db0994a239e09c1be402d35622277e35468ba891aa5e3188ce7e"
"checksum proc-macro-crate 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
"checksum proc-macro2 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "175c513d55719db99da20232b06cda8bab6b83ec2d04e3283edf0213c37c1a29"
"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
"checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
"checksum serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)" = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5"
"checksum serde_derive 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)" = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48"
"checksum serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)" = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c"
"checksum syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "891d8d6567fe7c7f8835a3a98af4208f3846fba258c1bc3c31d6e506239f11f9"
"checksum time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"
"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
"checksum wasi 0.10.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[package]
name = "powers"
version = "2.2.1"
version = "2.3.0"
authors = ["Ruby <ruby@rubidium.dev>"]
edition = "2018"
[dependencies]
bitflags = "1.2.1"
chrono = "0.4.15"
chrono = "0.4.19"
md5 = "0.7.0"
num_enum = "0.5.1"
serde = { version = "1.0.115", features = ["rc", "serde_derive"] }
serde_json = "1.0.57"
toml = "0.5.6"
serde = { version = "1.0.117", features = ["rc", "serde_derive"] }
serde_json = "1.0.59"
toml = "0.5.7"
# Example config file
# Issue that the data were extracted from.
issue = "i26p5"
issue = "i27"
# Identifies the source of the data.
source = "homecoming"
......
......@@ -37,8 +37,6 @@ Once you have everything set, simply run:
And this will do the magic. I recommend release mode while you're not debugging as it parses much faster.
**Note:** Version 2.0.0 forward require a nightly version of Rust for the time being.
## Output
The description of the JSON output files can be found in the [data dictionary](docs/index.md).
......
......@@ -9,7 +9,7 @@ Each [power](https://paragonwiki.com/wiki/Power) has a set of effect groups that
| Field | Type | Description |
| --- | --- | --- |
| `pve_or_pvp` | enum | Some effect groups only apply when used in either PVE or PVP. If this is present, this will indicate which one. If not present, the effect group is active in both PVE and PVP. <br> `PVE` <br> `PVP` |
| `tags` | array | This is an array of enums that describe different aspects of the effect group. See below for descriptions: <br> `FieryEmbrace` - This effect group only applies if [Fiery Embrace](https://paragonwiki.com/wiki/Fiery_Aura#Fiery_Embrace) is active. <br> `Critical` - This effect group represents extra damage from a critical hit. <br> `Domination` - This effect group only applies if a Dominator's Domination inherent is active. <br> `Scourge` - This effect group represents extra damage from a Corrupter's Scourge inherent. <br> `Containment` - This effect group represents extra damage from a Controller's Containment inherent. <br> `DualPistolsLethalMode`, `DualPistolsFireMode`, `DualPistolsColdMode`, `DualPistolsToxicMode` - This effect group only applies if the corresponding [Swap Ammo toggle](https://paragonwiki.com/wiki/Dual_Pistols#Swap_Ammo) is active. |
| `tags` | array | This is an array of enums that describe different aspects of the effect group. See below for descriptions: <br> `FieryEmbrace` - This effect group only applies if [Fiery Embrace](https://paragonwiki.com/wiki/Fiery_Aura#Fiery_Embrace) is active. <br> `Critical` - This effect group represents extra damage from a critical hit. <br> `Domination` - This effect group only applies if a Dominator's Domination inherent is active. <br> `Scourge` - This effect group represents extra damage from a Corrupter's Scourge inherent. <br> `Containment` - This effect group represents extra damage from a Controller's Containment inherent. <br> `DualPistolsLethalMode`, `DualPistolsFireMode`, `DualPistolsColdMode`, `DualPistolsToxicMode` - This effect group only applies if the corresponding [Swap Ammo toggle](https://paragonwiki.com/wiki/Dual_Pistols#Swap_Ammo) is active. <br> `SoundBoost` - Sonic manipulation sound boost is active. |
| `visible_in_info_window` | bool | If `true`, this effect is visible in the power info window in the game UI. |
| `chance_percent` | percent | This represents the chance that the effect group actually activates when the power is activated. |
| `procs_per_minute` | float | Not used by powers. |
......@@ -45,6 +45,7 @@ Effects are individual effects applied to a target of a power when the containin
| `suppress_events` | array | If the effect is suppressed by certain events, they are described here. See [suppress events](#suppress-events) below. |
| `cancel_events` | array | If the effect is cancelled by certain events, they are listed here. See [events](#events) below. |
| `scaled` | array | An effect generated by different archetypes will have different specific values for damage, resistance, etc. This array will have one [scaled effect](#scaled-effects) object per archetype that can use the power. <br> **Note:** Where possible, I've tried to narrow this group down to ATs that can actually use the power. In some cases, however, that wasn't possible to determine programmatically, and you'll see data for every AT even if it's not available to some of them. |
| `mode` | enum | For effects that `Set Mode` or `Unset Mode`, this will contain the mdoe. See [modes](#modes) below. |
### Attributes
......@@ -104,6 +105,7 @@ These are the possible attributes that can be modified by an effect.
| `DoNotDisplayShift` | Causes a level shift to not be reported by the game client. |
| `NoTokenTime` | Don't update the token timer when a token is added or removed from the target. |
| `RevokeAll` | Revokes all copies of the power from the target, regardless of how many they have. |
| `AlwaysUseHeight` | Forces the use of the height parameters even for flying targets. |
| `DoNotTintCostume` | Do not apply power tinting to a pet's costume. |
| `CopyBoosts` | Copy enhancements to a created power or pet if they apply. |
| `CopyCreatorMods` | Copy the owner's strength buff values to a pet. |
......@@ -111,6 +113,153 @@ These are the possible attributes that can be modified by an effect.
| `PseudoPet` | Creates a generic entity the same class as its creator (i.e. doesn't use a specific villain definition). |
| `PetVisible` | Forces a created entity to show up in the owner's pet window. |
| `PetCommandable` | Forces a created entity to be commandable like a mastermind pet. |
| `CheckLineOfSight` | Performs an additional line-of-sight check between caster and target (with executed powers). |
| `SetTimer` | Instead of recharging the power to ready, sets the recharge timer to a specific value. |
| `AdjustTimer` | If the aspect is Absolute, add the magnitude (in seconds) to the recharge timer. If the aspect is Current, the magnitude is used as a multiplier for the remaining time, if any. |
| `Cooldown` | Places the power on cooldown, using the recharge time. |
| `CopyCreatorCostume` | Copies the costume of the creator, as if it were a doppelganger. |
### Modes
Characters can have certain modes that are checked by the game. Powers can set and unset these modes.
| Value | Description |
| --- | --- |
| `ServerTrayOverride` | The server is forcing display of a power tray. |
| `Peacebringer_Blaster_Mode` | Bright Nova |
| `Peacebringer_Tanker_Mode` | White Dwarf |
| `Peacebringer_Light_Mode` | Light Form |
| `Warshade_Blaster_Mode` | Dark Nova |
| `Warshade_Tanker_Mode` | Black Hole |
| `Shivan_Mode` | Shivan Form |
| `Disable_Travel` | No Travel Powers |
| `Disable_Pool` | No Pool Powers |
| `Disable_Temp` | No Temporary Powers |
| `Disable_Teleport` | No Travel Teleport |
| `Disable_Portals` | Disable Portals |
| `Disable_All` | Disable all Powers |
| `Disable_Inspiration` | Disable Inspirations |
| `Disable_Inspiration_Small` | Disable Small Inspirations |
| `Disable_Inspiration_Medium` | Disable Medium Inspirations |
| `Disable_Inspiration_Large` | Disable Large Inspirations |
| `Disable_Inspiration_Special` | Disable Special Inspirations |
| `Disable_SetBonus` | Disable Set Bonuses |
| `Disable_Recall` | Disable Recall Teleportation |
| `Disable_Walk` | Disable Walk |
| `Disable_Suicide` | Disable Self Destruct |
| `Disable_RocketBoard` | Disable Rocket Board |
| `Disable_FlyingCarpet` | Disable Flying Carpet |
| `Disable_VoidSkiff` | Disable Void Skiff |
| `Disable_SteamJump` | Disable Steam Jump |
| `Disable_JumpPack` | Disable Jump Pack |
| `Arena` | Arena |
| `Disable_Awaken` | Disable Awaken |
| `Disable_Toggle` | Disable Toggle |
| `Mastermind_Upgrade_1` | Upgraded |
| `Mastermind_Upgrade_2` | Empowered |
| `Domination` | Domination |
| `Domination_Active` | Domination |
| `Vengeance_Mode` | Vengeance does not Stack |
| `Proc_Mode` | Bonus Effects are time limited. |
| `No_Shopping` | Auction House TP Powers only works so often. |
| `Disable_Epic` | Disable Ancillary and Patron Powers. |
| `Raid_Defender_Mode` | Raid Defender |
| `Raid_Attacker_Mode` | Raid Attacker |
| `Range_Finder_Mode` | Target Locked |
| `Temporal_Disruption` | Temporal Disruption |
| `DD_StatusMode_1` | Dual Blade Status Mode 1 |
| `DD_StatusMode_2` | Dual Blade Status Mode 2 |
| `DD_DebuffMode_1` | Dual Blade Debuff Mode 1 |
| `DD_DebuffMode_2` | Dual Blade Debuff Mode 2 |
| `DD_BonusAoEMode_1` | Dual Blade AoE Mode 1 |
| `DD_BonusAoEMode_2` | Dual Blade AoE Mode 2 |
| `DD_BonusDoTMode_1` | Dual Blade DoT Mode 1 |
| `DD_BonusDoTMode_2` | Dual Blade DoT Mode 2 |
| `KillTK` | Telekinetic Failure |
| `Engaged` | Engaged |
| `OutOfCombat` | OutOfCombat |
| `Defiant` | Defiance |
| `LostCure` | Lost Cure |
| `Midnight_Disguise` | Midnight Disguise |
| `Chain_Induction` | Chain Induction |
| `Chain_Stun_Mode` | Stun Mode |
| `Chain_Jolt_Mode` | Jolt Mode |
| `Chain_Confuse_Mode` | Confuse Mode |
| `Sequestor_1` | Sequestor step one |
| `Sequestor_2` | Sequestor step two |
| `Sequestor_3` | Sequestor step three |
| `NoNukes` | No Nukes |
| `HAC_Offense` | Hyper-Advanced Clockwork Offfensive Mode |
| `HAC_Defense` | Hyper-Advanced Clockwork Defensive Mode |
| `Disable_Juggernaut` | Forcably End Juggernaut Mode |
| `Tower_Protection` | Tower Protection |
| `Panacea` | Have Panacea_F Slotted |
| `Grounded` | Target Dimensionally Grounded |
| `LethalAmmo` | Piercing Ammo Loaded |
| `IceAmmo` | Cryo Ammo Loaded |
| `FireAmmo` | Incendiary Ammo Loaded |
| `ToxicAmmo` | Chemical Ammo Loaded |
| `ArchitectMissionMode` | On an Architect Mission |
| `CoOpTeam` | Co-Op Team Mode |
| `Broken` | Broken |
| `DisableFortuneBuffs` | Disable Mystic Fortune Buffs |
| `InCostume` | In Costume |
| `Wintery_Aegis` | Wintery Aegis |
| `RoidedIDF` | Roided IDF |
| `Harmonic_Destabilizer` | Harmonic Destabilizer |
| `Hidden_Attack` | Hidden Attack |
| `SiphonMode` | Siphon Mode |
| `TurretStage1` | Turret Stage 1 Damage |
| `TurretStage2` | Turret Stage 2 Damage |
| `TurretStage3` | Turret Stage 3 Damage |
| `TurretStage4` | Turret Stage 4 Damage |
| `TurretStage5` | Turret Maximum Damage |
| `Defeated_OilSlick` | Defeated Oil Slick |
| `MarkedForDeath` | Marked for Death |
| `Enraged` | Enraged |
| `TargetingReticule` | Targeting Reticule |
| `NotInCombat` | Entity is not currently engaged in combat |
| `UltimateInspire` | You have been Ultimately Inspired |
| `AmbrosiaInspire` | You have been Inspired by Ambrosia |
| `EoEInspire` | You have been Inspired by Essence of the Earth |
| `FastMode` | Your next RBW swing will not have the long Wind Up. |
| `Opportunity` | You next attack may have a bonus effect. |
| `OpportunityLock` | You recently found an Opportunity. |
| `OpportunitySustain` | You exploited an Opportunity, all your attacks heal you for a limited time. |
| `OpportunitySmashing` | You exploited an Opportunity, all your attacks do extra damage. |
| `OpportunityLethal` | You exploited an Opportunity, all your attacks do extra damage. |
| `OpportunityFire` | You exploited an Opportunity, all your attacks do extra damage. |
| `OpportunityCold` | You exploited an Opportunity, all your attacks do extra damage. |
| `OpportunityEnergy` | You exploited an Opportunity, all your attacks do extra damage. |
| `OpportunityNegative` | You exploited an Opportunity, all your attacks do extra damage. |
| `OpportunityToxic` | You exploited an Opportunity, all your attacks do extra damage. |
| `OpportunityPsionic` | You exploited an Opportunity, all your attacks do extra damage. |
| `Infected_01` | You've been infected by the Hamidon Plague |
| `Infected_02` | You've been infected by the Hamidon Plague |
| `Infected_03` | You've been infected by the Hamidon Plague |
| `Incarnate_Equipped` | Incarnate Mode |
| `OnePowerCell` | One Power Cell |
| `TwoPowerCell` | Two Power Cells |
| `ThreePowerCell` | Three Power Cells |
| `EntangledA` | Alpha Entanglement |
| `EntangledB` | Beta Entanglement |
| `HunterMode` | In Hunter Form |
| `ProwlerMode` | In Prowler Form |
| `ProwlerCloakMode` | In Prowler Form with Primal Cloak Active |
| `HybridLockout` | Your Hybrid power has been used recently and is recharging. |
| `RestedAdaptation` | You have no active Adaptation and are in a rested state. |
| `DefensiveAdaptation` | You have Defensive Adaptation active. |
| `OffensiveAdaptation` | You have Offensive Adaptation active. |
| `ClearSkies` | Clear Skies |
| `CloudedSkies` | Clouded Skies |
| `SpeedofSoundOn` | Speed of Sound Active |
| `MightyLeapOn` | Mighty Leap Active |
| `JetpackOn` | Jetpack Active |
| `MysticFlightOn` | Mystic Flight Active |
| `FreeRunningOn` | Freerunning Active |
| `BoostRange` | Range increased |
| `BoostPower` | Power increased |
| `EnergyFocus` | Energy Focus |
| `FullyCharged` | Fully Charged |
## Parameters
......@@ -220,7 +369,7 @@ Describes how the effect stacks, if at all.
| Field | Type | Description |
| --- | --- | --- |
| `behavior` | enum | The specific stacking behavior. <br> `Stack` - Allow multiple. <br> `Extend` - Update the parameters and extend the existing effect. <br> `Replace` - Update the parameters and replace the existing effect. <br> `Overlap` - Update the parameters, but don't extend the existing effect. <br> `StackToLimit` - Allow multiple up to `limit` times (see below). <br> `Refresh` - Update the duration of all similar effects, then add a new copy. <br> `RefreshToLimit` - As `Refresh`, but if below `limit` (see below), also add a new copy. <br> `Maximize` - If the new effect has a greater magnitude, replace the current effect. <br> `Suppress` - Keep all copies, but only apply the highest magnitude. |
| `behavior` | enum | The specific stacking behavior. <br> `Stack` - Allow multiple. <br> `Extend` - Update the parameters and extend the existing effect. <br> `Replace` - Update the parameters and replace the existing effect. <br> `Overlap` - Update the parameters, but don't extend the existing effect. <br> `StackToLimit` - Allow multiple up to `limit` times (see below). <br> `Refresh` - Update the duration of all similar effects, then add a new copy. <br> `RefreshToLimit` - As `Refresh`, but if below `limit` (see below), also add a new copy. <br> `Maximize` - If the new effect has a greater magnitude, replace the current effect. <br> `Suppress` - Keep all copies, but only apply the highest magnitude. <br> `Continuous` - If the effect is about to expire, replace it. Otherwise don't stack. |
| `by_caster` | bool | If `true`, then each caster can apply their own stacks to a target. Otherwise, effects placed by any caster are treated as the same for stacking. |
| `limit` | int | If `behavior` is `StackToLimit` or `RefreshToLimit`, this is the maximum number of times the effect will stack. |
| `key` | string | If this value is present, then stacking happens based on effects with this same `key` value, rather than the specific effect. |
......
......@@ -30,12 +30,16 @@ Each [power](https://paragonwiki.com/wiki/Power) represents an ability that can
| `target_auto_hit_tags` | array | What types of targets does this power auto-hit? (i.e. bypasses accuracy checks) <br> See [target type tags](#target-type-tags) below.|
| `display_target_auto_hit` | string | A human-readable string that describes `target_auto_hit_tags`. |
| `requires_line_of_sight` | bool | If `true`, the character must have line of sight to the target when activating the power. |
| `modes_required` | array | If present, these are the "modes" the character must be in to activate this power. Mostly used by the Kheldian's different forms. |
| `modes_disallowed` | array | If present, these are the "modes" the character cannot be in to activate this power. Most often you will see `Disable_All` in this field, which unsurprisingly means when all of the player's powers have been disabled globally. |
| `chain` | object | A [chain](#chain) object that gives detailed info on chain powers. |
| `modes_required` | array | If present, these are the "modes" the character must be in to activate this power. Mostly used by the Kheldian's different forms. See [modes](effectgroups.md#modes) for values. |
| `modes_disallowed` | array | If present, these are the "modes" the character cannot be in to activate this power. Most often you will see `Disable_All` in this field, which unsurprisingly means when all of the player's powers have been disabled globally. See [modes](effectgroups.md#modes) for values. |
| `status_interaction` | object | A [status interaction](#status-interaction) object that describes how this power interacts with different status effects. |
| `activate` | object | An [activation](#activation) object that describes the activation characteristics of this power. |
| `usage` | object | A [usage](#usage) object that describes how much the power can be used before it is removed from the character. Most often used by limited-use temp powers. |
| `strengths_disallowed` | array | An array of attributes that cannot be enhanced by boosts on this power. See [attributes](effectgroups.md#attributes) for values. |
| `global_strengths_disallowed` | array | An array of attributes that cannot be enhanced on this power from global sources. See [attributes](effectgroups.md#attributes) for values. |
| `effect_groups` | array | An array of [effect groups](effectgroups.md) that describe the specific effects created by this power when it is activated, such as dealing damage, summoning pets, etc. |
| `activate_effect_groups` | array | An array of [effect groups](effectgroups.md) that will always be activated, even if none of the normal `effect_groups` hit the target. |
| `redirects` | array | An array of [redirects](#redirects) that point to other powers. If present, evaluate these to take the place of this power when activated. |
## Display Info
......@@ -167,3 +171,13 @@ Some powers don't have their own effects, instead utilizing a redirected power t
| `fallback` | bool | If `true`, this is the fallback power to use if no other suitable power is found in the set (i.e. all `requires` expressions evaluate to `false`). |
| `requires` | expression | This expression must evaluate to `true` for the power named by this redirect to take the place of the parent power. |
| `url` | url | A URL pointing to the [power set](powersets.md) where the power referenced by `name` can be found. |
## Chain
For powers with an effect area of `Chain`, this will have additional information regarding the chain's attributes.
| Field | Type | Description |
| --- | --- | --- |
| `chain_effectivess` | expression | This is evaluated and stored as `@ChainEff`, which can be used to adjust the magnitude of the power based on each target it hits. |
| `chain_target_expression` | expression | This is evaluated on each chain target past the first to determine whether or not the power should affect that target. |
| `chain_fork` | array | An array of integers. After this jump, the chain should fork. This can have multiple jumps listed to create more than one fork. |
\ No newline at end of file
......@@ -2,7 +2,6 @@ use super::*;
use crate::structs::{
Archetype, CharacterAttributes, CharacterAttributesTable, Keyed, NameKey, NamedTable,
};
use std::rc::Rc;
/// Reads all of the archetypes in the current .bin file.
///
......@@ -34,8 +33,8 @@ where
for _ in 0..at_size {
let mut archetype = read_archetype(reader, strings, messages)?;
archetype.is_villain = is_villain;
if let Some(class_key) = &archetype.class_key {
archetypes.insert(class_key.clone(), Rc::new(archetype));
if let Some(class_key) = archetype.class_key.clone() {
archetypes.insert(class_key, archetype);
}
}
......
use super::*;
use crate::structs::{BoostList, BoostSet, BoostSetBonus, Keyed, NameKey};
use std::rc::Rc;
/// Reads all of the boost sets in the current .bin file.
///
......@@ -29,8 +28,8 @@ where
let bs_size: usize = bin_read(reader)?;
for _ in 0..bs_size {
let boost_set = read_boost_set(reader, strings, messages)?;
if let Some(name) = &boost_set.pch_name {
boost_sets.insert(name.clone(), Rc::new(boost_set));
if let Some(name) = boost_set.pch_name.clone() {
boost_sets.insert(name, boost_set);
}
}
......
......@@ -283,9 +283,11 @@ where
T: Default + TryFrom<u32>,
R: Read,
{
if let Ok(val) = T::try_from(bin_read::<u32, _>(reader)?) {
let ival = bin_read::<u32, _>(reader)?;
if let Ok(val) = T::try_from(ival) {
Ok(val)
} else {
eprintln!("Unknown enum {} value {}", std::any::type_name::<T>(), ival);
Ok(T::default())
}
}
......
use super::*;
use crate::structs::{Keyed, PowerCategory};
use std::rc::Rc;
/// Reads all of the power categories in the current .bin file.
///
......@@ -31,8 +30,8 @@ where
let pcat_size: usize = bin_read(reader)?;
for _ in 0..pcat_size {
let powercat = read_power_category(reader, strings, messages)?;
if let Some(powercat_name) = &powercat.pch_name {
powercats.insert(powercat_name.clone(), Rc::new(powercat));
if let Some(powercat_name) = powercat.pch_name.clone() {
powercats.insert(powercat_name, powercat);
}
}
......
use super::*;
use crate::structs::*;
use std::cell::RefCell;
use std::rc::Rc;
const MAX_ATTRIBMOD_FX: usize = 4;
......@@ -33,8 +34,8 @@ where
let mut powers = Keyed::<_>::new();
for _ in 0..pbp_size {
let power = read_base_power(reader, strings, messages)?;
if let Some(power_name) = &power.pch_full_name {
powers.insert(power_name.clone(), Rc::new(power));
if let Some(power_name) = power.pch_full_name.clone() {
powers.insert(power_name, power);
}
}
verify_struct_length(powers, expected_bytes, begin_pos, reader)
......@@ -90,6 +91,16 @@ where
};
}
macro_rules! pwr_char_attrib_arr {
($field:ident) => {
bin_read_arr_fn(
&mut power.$field,
|re| Ok(CharacterAttrib(bin_read(re)?)),
reader,
)?;
};
}
// TOK_STRUCT data length
let (expected_bytes, begin_pos) = read_struct_length(reader)?;
......@@ -146,6 +157,7 @@ where
b_toggle_ignore_stun,
b_ignore_level_bought,
b_shoot_through_untouchable,
b_target_untargetable,
b_interrupt_like_sleep
);
......@@ -158,10 +170,11 @@ where
pwr!(f_radius, f_arc, f_chain_delay);
pwr_string_arr!(ppch_chain_eff);
bin_read_arr(&mut power.pi_chain_fork, reader)?;
// added i26p5
bin_read_arr(&mut power.pi_unknown, reader)?;
pwr_string_arr!(ppch_chain_target_expr);
bin_read_arr(&mut power.pi_chain_fork, reader)?;
pwr!(vec_box_offset, vec_box_size);
pwr!(
......@@ -220,7 +233,12 @@ where
)?;
bin_read_arr_fn(
&mut power.pp_effects,
|re| Ok(Rc::new(read_effect_group(re, strings, messages)?)),
|re| Ok(Rc::new(RefCell::new(read_effect_group(re, strings, messages)?))),
reader,
)?;
bin_read_arr_fn(
&mut power.pp_activation_effects,
|re| Ok(Rc::new(RefCell::new(read_effect_group(re, strings, messages)?))),
reader,
)?;
......@@ -255,11 +273,6 @@ where
i_max_boost_level
);
// next 3 added i26p5
let _: f32 = bin_read(reader)?; // default 1.0?
let _: f32 = bin_read(reader)?; // default 999999.0?
let _: f32 = bin_read(reader)?; // default 1.0?
// changed i26p5: pp_vars appears to be an array of character attributes now
pwr_attrib_arr!(pp_vars);
......@@ -267,9 +280,18 @@ where
// toggles droppable TOK_REDUNDANTNAME
pwr_enum!(e_proc_allowed);
// changed i26p5: removed these?
//pwr_attrib_arr!(p_strengths_disallowed);
//pwr!(b_use_non_boost_templates_on_main_target, b_main_target_only);
// A list of character attributes whose strength cannot be modified.
// This can be used to make a Range buff not affect a power, for
// example.
pwr_char_attrib_arr!(p_strengths_disallowed);
// A list of character attributes whose strength cannot be modified
// by buffs, but still can be modified by enhancements.
// This can be used to make a Range buff not affect a power while
// allowing range enhancements to work, for example.
pwr_char_attrib_arr!(p_global_strengths_disallowed);
pwr!(b_use_non_boost_templates_on_main_target, b_main_target_only);
pwr_string_arr!(ppch_highlight_eval);
pwr_string!(pch_highlight_icon);
......@@ -442,14 +464,17 @@ where
)?;
template.boost_mod_allowed = SpecialAttrib::from_i32(bin_read(reader)?);
// i_flags are stored in two separate 32-bit ints, I combine them into a single 64-bit flag
let mut i_flags = [0u32; ATTRIBMOD_FLAGS_SIZE];
for idx in 0..ATTRIBMOD_FLAGS_SIZE {
i_flags[idx] = bin_read(reader)?;
}
let u_flags = i_flags[0] as u64 | ((i_flags[1] as u64) << 32);
template.i_flags = AttribModFlag::from_bits(u_flags)
.unwrap_or_else(|| panic!("Unknown AttribModFlags: {:#b}", u_flags));
template.i_flags = AttribModFlag::from_bits(i_flags[0])
.unwrap_or_else(|| panic!("Unknown AttribModFlags: {:#b}", i_flags[0]));
if let Some(attr) = template.p_attrib.get(0) {
if let Some(attr) = attr.as_special_attrib() {
template.i_flags_special = EffectSpecificAttribModFlag::from_bits(i_flags[1], &attr);
}
}
// TOK_OPTIONALSTRUCT
if bin_read::<u32, _>(reader)? > 0 {
......@@ -639,19 +664,29 @@ where
Some(AttribModParam::EffectFilter(filter))
}
11 => {
// Added i26p5. Unknown.
let mut param11 = AttribModParam_Param11::new();
param11.i_unknown_1 = bin_read(reader)?;
param11.i_unknown_2 = bin_read(reader)?;
param11.i_unknown_3 = bin_read(reader)?;
param11.f_unknown_4 = bin_read(reader)?;
param11.i_unknown_5 = bin_read(reader)?;
param11.i_unknown_6 = bin_read(reader)?;
param11.f_unknown_7 = bin_read(reader)?;
param11.f_unknown_8 = bin_read(reader)?;
param11.f_unknown_9 = bin_read(reader)?;
param11.f_unknown_10 = bin_read(reader)?;
Some(AttribModParam::Param11(param11))
// Added i26p5
let mut knock = AttribModParam_Knock::new();
knock.e_vec_start = {
if let Ok(val) = KnockAnchor::try_from(bin_read::<u32, _>(reader)?) {
val
} else {
KnockAnchor::default()
}
};
knock.e_vec_end = {
if let Ok(val) = KnockAnchor::try_from(bin_read::<u32, _>(reader)?) {
val
} else {
KnockAnchor::default()
}
};
knock.vec_adjust_pyr = bin_read(reader)?;
knock.i_priority = bin_read(reader)?;
knock.f_vel = bin_read(reader)?;
knock.f_vel_mag = bin_read(reader)?;
knock.f_height = bin_read(reader)?;
knock.f_height_mag = bin_read(reader)?;
Some(AttribModParam::Knock(knock))
}
_ => {
panic!("AttribModParam unknown struct_id: {}", struct_id);
......
use super::*;
use crate::structs::{BasePowerSet, Keyed};
use std::rc::Rc;
/// Reads all of the power sets in the current .bin file.
///
......@@ -30,8 +29,8 @@ where
let mut powersets = Keyed::<_>::new();
for _ in 0..pbps_size {
let powerset = read_base_powerset(reader, strings, messages)?;
if let Some(powerset_name) = &powerset.pch_full_name {
powersets.insert(powerset_name.clone(), Rc::new(powerset));
if let Some(powerset_name) = powerset.pch_full_name.clone() {
powersets.insert(powerset_name, powerset);
}
}
......
......@@ -3,7 +3,6 @@ use crate::structs::{
Keyed, PetCommandStrings, PowerNameRef, VillainDef, VillainDefFlags, VillainExclusion,
VillainLevelDef,
};
use std::rc::Rc;
/// Reads all of the villain definitions in the current .bin file.
///
......@@ -33,8 +32,8 @@ where
let mut villains = Keyed::<_>::new();
for _ in 0..v_size {
let villain = read_villain_def(reader, strings, messages)?;
if let Some(villain_name) = &villain.name {
villains.insert(villain_name.clone(), Rc::new(villain));
if let Some(villain_name) = villain.name.clone() {
villains.insert(villain_name, villain);
}
}
......
This diff is collapsed.
#![feature(get_mut_unchecked)]
#[macro_use]
extern crate bitflags;
extern crate chrono;
......
......@@ -2,14 +2,13 @@ mod structs;
use crate::structs::config::{OutputStyleConfig, PowersConfig};
use crate::structs::{
Archetype, AttribNames, BasePowerSet, Keyed, PowerCategory, PowersDictionary,
Archetype, AttribNames, BasePowerSet, Keyed, ObjRef, PowerCategory, PowersDictionary,
};
use std::fs;
use std::io;
use std::io::prelude::*;
use std::io::{Error, ErrorKind};
use std::path::Path;
use std::rc::Rc;
use structs::*;
/// Default name for the .json files.
......@@ -64,19 +63,19 @@ pub fn write_powers_dictionary(
write_archetypes(&powers_dict.archetypes, config)?;
// write all of the categories
for category in &powers_dict.power_categories {
for category in powers_dict.power_categories.iter().map(|c| c.borrow()) {
if !category.include_in_output {
continue;
}
write_power_category(category, config)?;
write_power_category(&*category, config)?;
if let Some(pcat_name) = category.pch_name.as_ref() {
// write the category's power sets
for set in &category.pp_power_sets {
for set in category.pp_power_sets.iter().map(|p| p.borrow()) {
if set.include_in_output {
write_power_set(
Some(pcat_name.get_string()),
set,
&*set,
&powers_dict.attrib_names,
config,
)?;
......@@ -89,7 +88,10 @@ pub fn write_powers_dictionary(
}
/// Writes the root .json file.
fn write_root(power_categories: &Vec<Rc<PowerCategory>>, config: &PowersConfig) -> io::Result<()> {
fn write_root(
power_categories: &Vec<ObjRef<PowerCategory>>,
config: &PowersConfig,
) -> io::Result<()> {
let output_file = config.join_to_output_path(JSON_FILE);
println!("Writing: {} ...", output_file.display());
let mut f = fs::File::create(output_file)?;
......@@ -149,11 +151,7 @@ fn write_power_set(
println!("\tWriting: {} ...", output_file.display());
let mut f = fs::File::create(output_file)?;
let pset = PowerSetOutput::from_base_power_set(
power_set,
attrib_names,
config,
);
let pset = PowerSetOutput::from_base_power_set(power_set, attrib_names, config);
match config.output_style {
OutputStyleConfig::Pretty => serde_json::to_writer_pretty(&mut f, &pset)?,
OutputStyleConfig::Compact => serde_json::to_writer(&mut f, &pset)?,
......
......@@ -116,7 +116,7 @@ impl AttribModParamOutput {
if let Some(villain) = &e.villain_def {
let mut display_name = None;
let mut powers = Vec::new();
if let Some(level_def) = villain.levels.get(config.at_level as usize) {
if let Some(level_def) = villain.borrow().levels.get(config.at_level as usize) {
display_name = level_def.display_names.get(0).cloned();
}
for power in &e.power_refs {
......@@ -198,9 +198,8 @@ impl AttribModParamOutput {
}
Some(AttribModParamOutput::ScriptValue { values })
}
AttribModParam::Param11(_) => {
// TODO: not sure what this is yet, something related to chains?
// Currently it doesn't seem to be used by any player power
AttribModParam::Knock(_) => {
// TODO: not sure this is super informative to output
None
}
}
......@@ -309,6 +308,8 @@ pub struct AttribModOutput {
pub cancel_events: Vec<&'static str>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub scaled: Vec<AttribModScaled>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mode: Option<String>,
// unserialized fields
#[serde(skip)]
pub attr_type: Option<AttribType>,
......@@ -318,7 +319,7 @@ impl AttribModOutput {
fn from_attrib_mod_template(
attrib_mod: &AttribModTemplate,
attrib_names: &AttribNames,
archetypes: &Vec<Rc<Archetype>>,
archetypes: &Vec<ObjRef<Archetype>>,
config: &PowersConfig,
) -> Self {
let mut output = AttribModOutput {
......@@ -330,6 +331,11 @@ impl AttribModOutput {
flags: attrib_mod.i_flags.get_strings(),
..Default::default()
};
// Additional flags
for special_flag in &attrib_mod.i_flags_special
{
output.flags.push(special_flag.get_string());
}
// Stacking rules
if !matches!(attrib_mod.e_stack, StackType::kStackType_Ignore) {
output.stacking = Some(StackingOutput::from_attrib_mod_template(
......@@ -414,19 +420,30 @@ impl AttribModOutput {
_ => (),
}
}
// modes
for attr in &attrib_mod.p_attrib {
if let Some(attr) = attr.as_special_attrib() {
if matches!(
attr,
SpecialAttrib::kSpecialAttrib_SetMode | SpecialAttrib::kSpecialAttrib_UnsetMode
) {
let mode = ModeAttrib(attrib_mod.f_magnitude as i32);
output.mode = mode.get_string(attrib_names);
break;
}
}
}
// params
if let Some(param) = &attrib_mod.p_params {
output.parameter = AttribModParamOutput::from_attrib_mod_param(param, config);
}
// scaling per archetype
if !matches!(output.attr_type, Some(AttribType::kAttribType_Special)) {
output.add_effect_scales(attrib_mod, archetypes, config.at_level);
if let Some(scaled) = output.scaled.get(0) {
match scaled.scaled_effect {
// Reduce confusion by blanking the base magnitude (would always be 1.0 in this case anyways)
ScaledUnit::Magnitude(_) => output.magnitude = None,
_ => (),
}
output.add_effect_scales(attrib_mod, archetypes, config.at_level);
if let Some(scaled) = output.scaled.get(0) {
match scaled.scaled_effect {
// Reduce confusion by blanking the base magnitude (would always be 1.0 in this case anyways)
ScaledUnit::Magnitude(_) => output.magnitude = None,
_ => (),
}
}
output
......@@ -436,11 +453,11 @@ impl AttribModOutput {
fn add_effect_scales(
&mut self,
attrib_mod: &AttribModTemplate,
archetypes: &Vec<Rc<Archetype>>,
archetypes: &Vec<ObjRef<Archetype>>,
at_level: i32,
) {
if let Some(table_name) = &attrib_mod.pch_table {
for at in archetypes {
for at in archetypes.iter().map(|at| at.borrow()) {
// calculate scaled effect for each archetype attached to this power
if let Some(named_table) = at.pp_named_tables.get(&table_name.to_lowercase()) {
let base_value = named_table.pf_values[(at_level - 1) as usize];
......@@ -497,7 +514,7 @@ impl EffectGroupOutput {
effect: &EffectGroup,
attrib_names: &AttribNames,
base_power: &BasePower,
archetypes: &Vec<Rc<Archetype>>,
archetypes: &Vec<ObjRef<Archetype>>,
config: &PowersConfig,
) -> Self {
let mut group = EffectGroupOutput {
......@@ -627,18 +644,19 @@ fn calculate_damage(
/// If `effect` has no requirements, all archetypes passed in will be returned.
fn filter_archetypes_eg(
effect: &EffectGroup,
archetypes: &Vec<Rc<Archetype>>,
) -> Vec<Rc<Archetype>> {
archetypes: &Vec<ObjRef<Archetype>>,
) -> Vec<ObjRef<Archetype>> {
// filter out the MLCrit and BossCrit effects, they use arch to test for NPC archetypes
if !is_critical_by_tags(&effect.ppch_tags)
// pets sometimes check for the "owner" which can confuse this rule
&& !archetypes.iter().any(|at| at.is_villain)
&& !archetypes.iter().any(|at| at.borrow().is_villain)
&& effect.ppch_requires.iter().any(|rule| rule == "arch")
{
// second form of this rule compares to the latter half of the class key
archetypes
.iter()
.filter(|at| {
let at = at.borrow();
if let Some(class_key) = &at.class_key {
if let Some(class_name) = &at.pch_name {
effect.ppch_requires.iter().any(|rule| {
......@@ -775,6 +793,9 @@ fn check_tags_group(effect_group: &mut EffectGroupOutput, tags: &Vec<String>) {
"ToxicDamage" | "HailofBulletsToxic" => {
effect_group.tags.insert("DualPistolsToxicMode");
}
"SoundBoost" => {
effect_group.tags.insert("SoundBoost");
}
_ => (),
}
}
......@@ -844,6 +865,20 @@ fn get_scaled_effect(
attrib_type: &AttribType,
scaled_value: f32,
) -> Option<ScaledUnit> {
// special attributes require special handling
if let Some(attrib) = attrib_mod.p_attrib.get(0) {
if let Some(special) = attrib.as_special_attrib() {
match special {
// global/power chance mods need cumulative chance value
SpecialAttrib::kSpecialAttrib_GlobalChanceMod
| SpecialAttrib::kSpecialAttrib_PowerChanceMod => {
return Some(ScaledUnit::Percent(normalize(scaled_value * 100.0)));
}
// discard all other special attribs
_ => return None,
}
}
}
// duration in seconds
if matches!(attrib_mod.e_type, ModType::kModType_Duration) {
return Some(ScaledUnit::DurationSeconds(normalize(scaled_value)));
......
......@@ -9,7 +9,6 @@ use powers::PowerOutput;
use serde::Serialize;
use std::borrow::Cow;
use std::collections::HashMap;
use std::rc::Rc;
/// Used when joining parts of an URL together.
const URL_SEP: char = '/';
......@@ -127,7 +126,7 @@ impl ArchetypesOutput {
};
for at in ats.values() {
ats_out.archetypes.push(ArchetypeOutput::from_archetype(
at,
&*at.borrow(),
&PrimarySecondary::None,
true,
config,
......@@ -161,14 +160,14 @@ impl RootOutput {
///
/// Arguments:
///
/// * `power_categories` - A `Vec<Rc<PowerCategory>>`.
/// * `power_categories` - A `Vec<ObjRef<PowerCategory>>`.
/// * `config` - Configuration information.
///
/// Returns:
///
/// A `RootOutput`.
pub fn from_power_categories(
power_categories: &Vec<Rc<PowerCategory>>,
power_categories: &Vec<ObjRef<PowerCategory>>,
config: &PowersConfig,
) -> Self {
let mut at_url = String::new();
......@@ -185,7 +184,7 @@ impl RootOutput {
archetypes: at_url,
power_categories: Vec::new(),
};
for pcat in power_categories {
for pcat in power_categories.iter().map(|p| p.borrow()) {
if !pcat.top_level || !pcat.include_in_output {
continue;
}
......@@ -208,7 +207,7 @@ impl RootOutput {
if pcat.archetypes.len() == 1 {
// if there's only 1 archetype attached, then this is a group of sets intended for that archetype
rpc.archetype = Some(ArchetypeOutput::from_archetype(
&pcat.archetypes[0],
&*pcat.archetypes[0].borrow(),
&pcat.pri_sec,
false,
config,
......@@ -261,15 +260,14 @@ impl PowerCategoryOutput {
if power_category.archetypes.len() == 1 {
// if there's only 1 archetype attached, then this is a group of sets intended for that archetype
pcat.archetype = Some(ArchetypeOutput::from_archetype(
&power_category.archetypes[0],
&*power_category.archetypes[0].borrow(),
&power_category.pri_sec,
false,
config,
));
}
for pset in &power_category.pp_power_sets {
if !pset.include_in_output
{
for pset in power_category.pp_power_sets.iter().map(|p| p.borrow()) {
if !pset.include_in_output {
continue;
}
let mut url = String::new();
......@@ -374,14 +372,11 @@ impl PowerSetOutput {
power_set.pch_set_buy_requires_failed_text.clone();
}
// map individual powers
for power in &power_set.pp_powers {
for power in power_set.pp_powers.iter().map(|p| p.borrow()) {
// skip disabled powers
if power.include_in_output {
pset.powers.push(PowerOutput::from_base_power(
power,
attrib_names,
config,
));
pset.powers
.push(PowerOutput::from_base_power(&*power, attrib_names, config));
}
}
// copy minimum levels
......@@ -623,8 +618,8 @@ where
expression.push(')');
return Some(expression);
}
"source.MapTeamArea>" => {
// weird exception to below
"source.MapTeamArea>" | "source.VillainName>" => {
// weird exceptions to below
return Some(token[0..token.len() - 1].to_owned());
}
_ => {
......@@ -658,4 +653,3 @@ where
}
None
}
......@@ -218,6 +218,38 @@ impl PowerRedirectOutput {
}
}
// Serializable representation of chain effects.
#[derive(Serialize)]
pub struct ChainEffectOutput {
/// I might deprecate the value in effect area in v3.
#[serde(skip)]
pub chain_delay_time: f32,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub chain_effectiveness: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub chain_target_expression: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub chain_fork: Vec<i32>,
}
impl ChainEffectOutput {
fn from_base_power(power: &BasePower) -> Self {
let mut output = ChainEffectOutput {
chain_delay_time: normalize(power.f_chain_delay),
chain_effectiveness: Vec::new(),
chain_target_expression: Vec::new(),
chain_fork: power.pi_chain_fork.clone(),
};
if let Some(rule) = requires_to_string(&power.ppch_chain_eff) {
output.chain_effectiveness.push(rule);
}
if let Some(rule) = requires_to_string(&power.ppch_chain_target_expr) {
output.chain_target_expression.push(rule);
}
output
}
}
/// Serializable representation of a power.
#[derive(Serialize)]
pub struct PowerOutput {
......@@ -257,6 +289,8 @@ pub struct PowerOutput {
#[serde(skip_serializing_if = "Vec::is_empty")]
pub display_target_auto_hit: Vec<&'static str>,
pub requires_line_of_sight: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub chain: Option<ChainEffectOutput>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub modes_required: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
......@@ -266,8 +300,14 @@ pub struct PowerOutput {
pub activate: ActivationOutput,
#[serde(skip_serializing_if = "UsageOutput::is_empty")]
pub usage: UsageOutput,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub strengths_disallowed: Vec<Cow<'static, str>>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub global_strengths_disallowed: Vec<Cow<'static, str>>,
pub effect_groups: Vec<EffectGroupOutput>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub activate_effect_groups: Vec<EffectGroupOutput>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub redirects: Vec<PowerRedirectOutput>,
}
......@@ -310,12 +350,16 @@ impl PowerOutput {
TargetVisibility::kTargetVisibility_LineOfSight => true,
TargetVisibility::kTargetVisibility_None => false,
},
chain: None,
modes_required: Vec::new(),
modes_disallowed: Vec::new(),
status_interaction: StatusOptionsOutput::from_base_power(power),
activate: ActivationOutput::from_base_power(power),
usage: UsageOutput::from_base_power(power),
strengths_disallowed: Vec::new(),
global_strengths_disallowed: Vec::new(),
effect_groups: Vec::new(),
activate_effect_groups: Vec::new(),
redirects: Vec::new(),
};
// power icon
......@@ -328,8 +372,7 @@ impl PowerOutput {
}
// attack types
for atk in &power.pe_attack_types {
pwr.attack_types
.push(atk.get_string(attrib_names));
pwr.attack_types.push(atk.get_string(attrib_names));
}
// enhancements
for enh in &power.pe_boosts_allowed {
......@@ -348,6 +391,17 @@ impl PowerOutput {
pwr.modes_disallowed.push(m);
}
}
// disallowed strengths
for attrib in &power.p_strengths_disallowed {
if let Some(attrib_name) = attrib.get_string(attrib_names) {
pwr.strengths_disallowed.push(attrib_name);
}
}
for attrib in &power.p_global_strengths_disallowed {
if let Some(attrib_name) = attrib.get_string(attrib_names) {
pwr.global_strengths_disallowed.push(attrib_name);
}
}
// auto hit tags
for target in &power.p_auto_hit {
if !matches!(target, TargetType::kTargetType_None) {
......@@ -357,18 +411,32 @@ impl PowerOutput {
}
}
}
// chain parameters
if matches!(power.e_effect_area, EffectArea::kEffectArea_Chain) {
pwr.chain = Some(ChainEffectOutput::from_base_power(power));
}
// filter archetypes to only those that can purchase this power, if necessary
let archetypes = filter_archetypes_pwr(power, &power.archetypes);
// effect groups
for effect_group in &power.pp_effects {
pwr.effect_groups.push(EffectGroupOutput::from_effect_group(
effect_group,
&*effect_group.borrow(),
attrib_names,
power,
&archetypes,
config,
));
}
for effect_group in &power.pp_activation_effects {
pwr.activate_effect_groups
.push(EffectGroupOutput::from_effect_group(
&*effect_group.borrow(),
attrib_names,
power,
&archetypes,
config,
));
}
// redirected powers
for redirect in &power.pp_redirect {
pwr.redirects
......@@ -382,7 +450,7 @@ impl PowerOutput {
/// Filters the archetypes vector based on any purchase requirements specified in `power`.
/// If `power` has no requirements, all archetypes passed in will be returned.
fn filter_archetypes_pwr(power: &BasePower, archetypes: &Vec<Rc<Archetype>>) -> Vec<Rc<Archetype>> {
fn filter_archetypes_pwr(power: &BasePower, archetypes: &Vec<ObjRef<Archetype>>) -> Vec<ObjRef<Archetype>> {
if power
.ppch_buy_requires
.iter()
......@@ -392,7 +460,7 @@ fn filter_archetypes_pwr(power: &BasePower, archetypes: &Vec<Rc<Archetype>>) ->
archetypes
.iter()
.filter(|at| {
if let Some(class_key) = &at.class_key {
if let Some(class_key) = &at.borrow().class_key {
power
.ppch_buy_requires
.iter()
......