diff --git a/.gitlab/CI/publish.gitlab-ci.yml b/.gitlab/CI/publish.gitlab-ci.yml index bda73f5c1a..37c4d265f5 100644 --- a/.gitlab/CI/publish.gitlab-ci.yml +++ b/.gitlab/CI/publish.gitlab-ci.yml @@ -33,9 +33,12 @@ gittag: extends: .publish rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "schedule" - image: registry.gitlab.com/veloren/veloren-docker-ci/base/common:${CACHE_IMAGE_TAG} + image: bitnami/git:latest dependencies: [] tags: ["veloren/veloren", "publish", "trusted"] + before_script: + - git --version + - git lfs --version script: - git config --global user.email "gitlab-veloren-bot@veloren.net" - git config --global user.name "veloren-bot" diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ff35a4a69..85ebbed6da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,7 +38,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - A way to target non-player entities with commands. With rtsim_id: `rtsim@`, with uid: `uid@`. - Shorthand in voxygen for specific entities in commands, some examples `@target`, `@mount`, `@viewpoint`. - Added hit_timing to BasicMelee abilities -- Potion of Agility +- A tavern building where npcs go to relax. +- Toggle for walking instead of running (Default: `I`). +- Added day duration slider configuration on map creation UI. ### Changed @@ -90,6 +92,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed "low fps" of different shaders caused by low floating point precision when using time. - Fixed bug where airship captains would mass generate after using /reload_chunks - Fixed french translation "Énergie Consommée" -> "Regain d'Énergie" +- Fixed Perforate icon not displaying ## [0.15.0] - 2023-07-01 diff --git a/Cargo.lock b/Cargo.lock index d89a3ddff2..5861bca5eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1880,9 +1880,9 @@ dependencies = [ [[package]] name = "enumset" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e875f1719c16de097dee81ed675e2d9bb63096823ed3f0ca827b7dea3028bbbb" +checksum = "226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d" dependencies = [ "enumset_derive", ] @@ -7430,6 +7430,7 @@ dependencies = [ "csv", "deflate", "enum-map", + "enumset", "fallible-iterator", "flate2", "fxhash", diff --git a/assets/common/abilities/ability_set_manifest.ron b/assets/common/abilities/ability_set_manifest.ron index 062240bbc0..f75c928036 100644 --- a/assets/common/abilities/ability_set_manifest.ron +++ b/assets/common/abilities/ability_set_manifest.ron @@ -565,6 +565,12 @@ Simple(None, "common.abilities.custom.arthropods.dagonite.leapshockwave"), ], ), + // Crustaceans + Custom("Crab"): ( + primary: Simple(None, "common.abilities.custom.crab.triplestrike"), + secondary: Simple(None, "common.abilities.custom.crab.triplestrike"), + abilities: [], + ), /// TODO: Organize the rest into further catagories and give purple tier droppers+ custom skillsets Custom("Turret"): ( primary: Simple(None, "common.abilities.custom.turret.arrows"), diff --git a/assets/common/abilities/axesimple/doublestrike.ron b/assets/common/abilities/axesimple/doublestrike.ron index cdcebef941..d80d9e3a38 100644 --- a/assets/common/abilities/axesimple/doublestrike.ron +++ b/assets/common/abilities/axesimple/doublestrike.ron @@ -1,55 +1,57 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 8.0, - damage_increase: 1.0, - base_poise_damage: 15, - poise_damage_increase: 0, - knockback: 8.0, - range: 3.5, - angle: 50.0, - base_buildup_duration: 0.4, - base_swing_duration: 0.08, + melee_constructor: ( + kind: Slash( + damage: 8, + poise: 15, + knockback: 8, + energy_regen: 0, + ), + range: 3.5, + angle: 50.0, + damage_effect: Some(Buff(( + kind: Bleeding, + dur_secs: 10.0, + strength: DamageFraction(0.1), + chance: 0.1, + ))), + ), + buildup_duration: 0.4, + swing_duration: 0.08, hit_timing: 0.5, - base_recover_duration: 0.5, - forward_movement: 2.5, - damage_kind: Slashing, - damage_effect: Some(Buff(( - kind: Bleeding, - dur_secs: 10.0, - strength: DamageFraction(0.1), - chance: 0.1, - ))), + recover_duration: 0.5, + movement: ( + swing: Some(Forward(2.5)), + ), + ori_modifier: 0.7, ), ( - stage: 2, - base_damage: 10.0, - damage_increase: 1.5, - base_poise_damage: 20, - poise_damage_increase: 0, - knockback: 12.0, - range: 3.5, - angle: 30.0, - base_buildup_duration: 0.7, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Slash( + damage: 10, + poise: 20, + knockback: 12, + energy_regen: 0, + ), + range: 3.5, + angle: 30.0, + damage_effect: Some(Buff(( + kind: Bleeding, + dur_secs: 10.0, + strength: DamageFraction(0.1), + chance: 0.1, + ))), + ), + buildup_duration: 0.7, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.7, - forward_movement: 2.0, - damage_kind: Slashing, - damage_effect: Some(Buff(( - kind: Bleeding, - dur_secs: 10.0, - strength: DamageFraction(0.1), - chance: 0.1, - ))), + recover_duration: 0.7, + movement: ( + swing: Some(Forward(2.0)), + ), + ori_modifier: 0.7, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.7, -) \ No newline at end of file + energy_cost_per_strike: 0, +) diff --git a/assets/common/abilities/custom/arthropods/antlion/singlestrike.ron b/assets/common/abilities/custom/arthropods/antlion/singlestrike.ron index b8be2929c9..9a7d5d8d98 100644 --- a/assets/common/abilities/custom/arthropods/antlion/singlestrike.ron +++ b/assets/common/abilities/custom/arthropods/antlion/singlestrike.ron @@ -1,33 +1,31 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 74, - damage_increase: 0, - base_poise_damage: 27.5, - poise_damage_increase: 0, - knockback: 9.0, - range: 3.0, - angle: 60.0, - base_buildup_duration: 1.4, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Bash( + damage: 74, + poise: 27.5, + knockback: 9, + energy_regen: 0, + ), + range: 3.0, + angle: 60.0, + damage_effect: Some(Buff(( + kind: Ensnared, + dur_secs: 6.0, + strength: Value(0.5), + chance: 0.6, + ))), + ), + buildup_duration: 1.4, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.8, - forward_movement: 1.0, - damage_kind: Crushing, - damage_effect: Some(Buff(( - kind: Ensnared, - dur_secs: 6.0, - strength: DamageFraction(0.1), - chance: 0.6, - ))), + recover_duration: 0.8, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.8, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.8, -) \ No newline at end of file + energy_cost_per_strike: 0, +) diff --git a/assets/common/abilities/custom/arthropods/blackwidow/singlestrike.ron b/assets/common/abilities/custom/arthropods/blackwidow/singlestrike.ron index 4b996d24e8..d13f5f7b05 100644 --- a/assets/common/abilities/custom/arthropods/blackwidow/singlestrike.ron +++ b/assets/common/abilities/custom/arthropods/blackwidow/singlestrike.ron @@ -1,33 +1,31 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 50, - damage_increase: 0, - base_poise_damage: 16, - poise_damage_increase: 0, - knockback: 2.0, - range: 3.0, - angle: 60.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Stab( + damage: 50, + poise: 16, + knockback: 2, + energy_regen: 0, + ), + range: 3.0, + angle: 60.0, + damage_effect: Some(Buff(( + kind: Poisoned, + dur_secs: 7.0, + strength: DamageFraction(0.6), + chance: 0.4, + ))), + ), + buildup_duration: 0.8, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.8, - forward_movement: 1.0, - damage_kind: Piercing, - damage_effect: Some(Buff(( - kind: Poisoned, - dur_secs: 7.0, - strength: DamageFraction(0.6), - chance: 0.4, - ))), + recover_duration: 0.8, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.8, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.8, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/arthropods/hornbeetle/singlestrike.ron b/assets/common/abilities/custom/arthropods/hornbeetle/singlestrike.ron index 171813d5b0..d50bdaa969 100644 --- a/assets/common/abilities/custom/arthropods/hornbeetle/singlestrike.ron +++ b/assets/common/abilities/custom/arthropods/hornbeetle/singlestrike.ron @@ -1,27 +1,25 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 54, - damage_increase: 0, - base_poise_damage: 20, - poise_damage_increase: 0, - knockback: 5.0, - range: 3.0, - angle: 60.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Bash( + damage: 54, + poise: 20, + knockback: 5, + energy_regen: 0, + ), + range: 3.0, + angle: 60.0, + ), + buildup_duration: 0.8, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.8, - forward_movement: 1.0, - damage_kind: Crushing, + recover_duration: 0.8, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.5, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.5, -) \ No newline at end of file + energy_cost_per_strike: 0, +) diff --git a/assets/common/abilities/custom/arthropods/tarantula/singlestrike.ron b/assets/common/abilities/custom/arthropods/tarantula/singlestrike.ron index 491e047f85..9038d0709e 100644 --- a/assets/common/abilities/custom/arthropods/tarantula/singlestrike.ron +++ b/assets/common/abilities/custom/arthropods/tarantula/singlestrike.ron @@ -1,33 +1,31 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 60, - damage_increase: 0, - base_poise_damage: 21, - poise_damage_increase: 0, - knockback: 3.0, - range: 3.0, - angle: 60.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Stab( + damage: 60, + poise: 21, + knockback: 3, + energy_regen: 0, + ), + range: 3.0, + angle: 60.0, + damage_effect: Some(Buff(( + kind: Poisoned, + dur_secs: 9.0, + strength: DamageFraction(0.7), + chance: 0.8, + ))), + ), + buildup_duration: 0.8, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.8, - forward_movement: 1.0, - damage_kind: Piercing, - damage_effect: Some(Buff(( - kind: Poisoned, - dur_secs: 9.0, - strength: DamageFraction(0.7), - chance: 0.8, - ))), + recover_duration: 0.8, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.8, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.8, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/arthropods/weevil/singlestrike.ron b/assets/common/abilities/custom/arthropods/weevil/singlestrike.ron index 29692ed1b2..a53e224097 100644 --- a/assets/common/abilities/custom/arthropods/weevil/singlestrike.ron +++ b/assets/common/abilities/custom/arthropods/weevil/singlestrike.ron @@ -1,27 +1,25 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 44, - damage_increase: 0, - base_poise_damage: 14, - poise_damage_increase: 0, - knockback: 3.0, - range: 3.0, - angle: 60.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Bash( + damage: 44, + poise: 14, + knockback: 3, + energy_regen: 0, + ), + range: 3.0, + angle: 60.0, + ), + buildup_duration: 0.8, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.8, - forward_movement: 1.0, - damage_kind: Crushing, + recover_duration: 0.8, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.6, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.6, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/asp/singlestrike.ron b/assets/common/abilities/custom/asp/singlestrike.ron index 4b20b6615d..99b8bd3a64 100644 --- a/assets/common/abilities/custom/asp/singlestrike.ron +++ b/assets/common/abilities/custom/asp/singlestrike.ron @@ -1,27 +1,25 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 28.0, - damage_increase: 0, - base_poise_damage: 28, - poise_damage_increase: 0, - knockback: 3.0, - range: 3.5, - angle: 60.0, - base_buildup_duration: 1.2, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Bash( + damage: 28, + poise: 28, + knockback: 3, + energy_regen: 0, + ), + range: 3.5, + angle: 60.0, + ), + buildup_duration: 1.2, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.4, - forward_movement: 2.0, - damage_kind: Crushing, + recover_duration: 0.4, + movement: ( + swing: Some(Forward(2.0)), + ), + ori_modifier: 0.65, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.65, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/basilisk/triplestrike.ron b/assets/common/abilities/custom/basilisk/triplestrike.ron index 0339a5a8fe..4e5e5c1d90 100644 --- a/assets/common/abilities/custom/basilisk/triplestrike.ron +++ b/assets/common/abilities/custom/basilisk/triplestrike.ron @@ -1,59 +1,65 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 36.0, - damage_increase: 0, - base_poise_damage: 15, - poise_damage_increase: 0, - knockback: 3.0, - range: 2.8, - angle: 30.0, - base_buildup_duration: 1.4, - base_swing_duration: 0.07, + melee_constructor: ( + kind: Bash( + damage: 36, + poise: 15, + knockback: 3, + energy_regen: 0, + ), + range: 2.8, + angle: 30.0, + ), + buildup_duration: 1.4, + swing_duration: 0.07, hit_timing: 0.5, - base_recover_duration: 0.3, - forward_movement: 2.0, - damage_kind: Crushing, + recover_duration: 0.3, + movement: ( + swing: Some(Forward(2.0)), + ), + ori_modifier: 0.65, ), ( - stage: 2, - base_damage: 36.0, - damage_increase: 0, - base_poise_damage: 18, - poise_damage_increase: 0, - knockback: 3.0, - range: 2.8, - angle: 30.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.07, + melee_constructor: ( + kind: Bash( + damage: 36, + poise: 18, + knockback: 3, + energy_regen: 0, + ), + range: 2.8, + angle: 30.0, + ), + buildup_duration: 0.8, + swing_duration: 0.07, hit_timing: 0.5, - base_recover_duration: 0.3, - forward_movement: 1.5, - damage_kind: Crushing, + recover_duration: 0.3, + movement: ( + swing: Some(Forward(1.5)), + ), + ori_modifier: 0.65, ), ( - stage: 3, - base_damage: 36.0, - damage_increase: 0, - base_poise_damage: 20, - poise_damage_increase: 0, - knockback: 3.0, - range: 2.8, - angle: 30.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.07, + melee_constructor: ( + kind: Bash( + damage: 36, + poise: 20, + knockback: 3, + energy_regen: 0, + ), + range: 2.8, + angle: 30.0, + ), + buildup_duration: 0.8, + swing_duration: 0.07, hit_timing: 0.5, - base_recover_duration: 0.3, - forward_movement: 1.5, - damage_kind: Crushing, + recover_duration: 0.3, + movement: ( + swing: Some(Forward(1.5)), + ), + ori_modifier: 0.65, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.65, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/birdmediumbasic/singlestrike.ron b/assets/common/abilities/custom/birdmediumbasic/singlestrike.ron index 774dda8307..b4ed42e026 100644 --- a/assets/common/abilities/custom/birdmediumbasic/singlestrike.ron +++ b/assets/common/abilities/custom/birdmediumbasic/singlestrike.ron @@ -1,27 +1,18 @@ -ComboMelee( - stage_data: [ - ( - stage: 1, - base_damage: 1.0, - damage_increase: 0, - base_poise_damage: 0, - poise_damage_increase: 0, - knockback: 0.0, - range: 2.5, - angle: 150.0, - base_buildup_duration: 0.1, - base_swing_duration: 0.07, - hit_timing: 0.5, - base_recover_duration: 0.2, - forward_movement: 0.0, - damage_kind: Piercing, +BasicMelee( + energy_cost: 0, + buildup_duration: 0.1, + swing_duration: 0.07, + hit_timing: 0.5, + recover_duration: 0.2, + melee_constructor: ( + kind: Stab( + damage: 1, + poise: 0, + knockback: 0, + energy_regen: 0, ), - ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, + range: 2.5, + angle: 150.0, + ), ori_modifier: 0.6, ) diff --git a/assets/common/abilities/custom/boreal_warrior/hammer/singlestrike.ron b/assets/common/abilities/custom/boreal_warrior/hammer/singlestrike.ron index cf12b4631a..6aa0832916 100644 --- a/assets/common/abilities/custom/boreal_warrior/hammer/singlestrike.ron +++ b/assets/common/abilities/custom/boreal_warrior/hammer/singlestrike.ron @@ -1,31 +1,28 @@ -ComboMelee( - stage_data: [( - stage: 1, - base_damage: 15.0, - damage_increase: 0.75, - base_poise_damage: 0, - poise_damage_increase: 0, - knockback: 3.5, - range: 4.5, - angle: 50.0, - base_buildup_duration: 0.7, - base_swing_duration: 0.1, - hit_timing: 0.5, - base_recover_duration: 0.45, - forward_movement: 0.0, - damage_kind: Crushing, - damage_effect: Some(Buff(( - kind: Frozen, - dur_secs: 2.0, - strength: Value(0.3), - chance: 0.4, - ))), - )], - initial_energy_gain: 5.0, - max_energy_gain: 12.5, - energy_increase: 2.5, - speed_increase: 0.1, - max_speed_increase: 0.4, - scales_from_combo: 2, - ori_modifier: 1.0, -) \ No newline at end of file +ComboMelee2( + strikes: [ + ( + melee_constructor: ( + kind: Bash( + damage: 15, + poise: 0, + knockback: 3.5, + energy_regen: 5, + ), + range: 4.5, + angle: 50.0, + damage_effect: Some(Buff(( + kind: Frozen, + dur_secs: 2.0, + strength: Value(0.3), + chance: 0.4, + ))), + ), + buildup_duration: 0.7, + swing_duration: 0.1, + hit_timing: 0.5, + recover_duration: 0.45, + ori_modifier: 1.0, + ), + ], + energy_cost_per_strike: 0, +) diff --git a/assets/common/abilities/custom/crab/triplestrike.ron b/assets/common/abilities/custom/crab/triplestrike.ron new file mode 100644 index 0000000000..4a026a239b --- /dev/null +++ b/assets/common/abilities/custom/crab/triplestrike.ron @@ -0,0 +1,65 @@ +ComboMelee2( + strikes: [ + ( + melee_constructor: ( + kind: Slash( + damage: 5, + poise: 5, + knockback: 0, + energy_regen: 0, + ), + range: 1.1, + angle: 30.0, + ), + buildup_duration: 1.3, + swing_duration: 0.07, + hit_timing: 0.5, + recover_duration: 0.6, + movement: ( + swing: Some(Forward(0.5)), + ), + ori_modifier: 0.65, + ), + ( + melee_constructor: ( + kind: Slash( + damage: 8, + poise: 8, + knockback: 1, + energy_regen: 0, + ), + range: 1.1, + angle: 30.0, + ), + buildup_duration: 0.8, + swing_duration: 0.07, + hit_timing: 0.5, + recover_duration: 0.6, + movement: ( + swing: Some(Forward(0.5)), + ), + ori_modifier: 0.65, + ), + ( + melee_constructor: ( + kind: Slash( + damage: 12, + poise: 9, + knockback: 1, + energy_regen: 0, + ), + range: 1.1, + angle: 30.0, + ), + buildup_duration: 0.8, + swing_duration: 0.07, + hit_timing: 0.5, + recover_duration: 0.6, + movement: ( + swing: Some(Forward(0.5)), + ), + ori_modifier: 0.65, + ), + ], + energy_cost_per_strike: 0, +) diff --git a/assets/common/abilities/custom/cyclops/doublestrike.ron b/assets/common/abilities/custom/cyclops/doublestrike.ron index 0fa7b32a60..fd1121ab4d 100644 --- a/assets/common/abilities/custom/cyclops/doublestrike.ron +++ b/assets/common/abilities/custom/cyclops/doublestrike.ron @@ -1,49 +1,51 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 32.0, - damage_increase: 0.0, - base_poise_damage: 20, - poise_damage_increase: 0.0, - knockback: 5.0, - range: 6, - angle: 90.0, - base_buildup_duration: 0.5, - base_swing_duration: 0.4, + melee_constructor: ( + kind: Bash( + damage: 32, + poise: 20, + knockback: 5, + energy_regen: 0, + ), + range: 6.0, + angle: 90.0, + ), + buildup_duration: 0.5, + swing_duration: 0.4, hit_timing: 0.4, - base_recover_duration: 0.4, - forward_movement: 0.3, - damage_kind: Crushing, + recover_duration: 0.4, + movement: ( + swing: Some(Forward(0.3)), + ), + ori_modifier: 0.65, ), ( - stage: 2, - base_damage: 36.0, - damage_increase: 0.0, - base_poise_damage: 40.0, - poise_damage_increase: 0.0, - knockback: 10.0, - range: 8, - angle: 45.0, - base_buildup_duration: 0.6, - base_swing_duration: 0.6, + melee_constructor: ( + kind: Bash( + damage: 36, + poise: 40, + knockback: 10, + energy_regen: 0, + ), + range: 8.0, + angle: 45.0, + damage_effect: Some(Buff(( + kind: Crippled, + dur_secs: 3.0, + strength: DamageFraction(0.1), + chance: 1.0, + ))), + ), + buildup_duration: 0.6, + swing_duration: 0.6, hit_timing: 0.3, - base_recover_duration: 1.2, - forward_movement: 0.2, - damage_kind: Crushing, - damage_effect: Some(Buff(( - kind: Crippled, - dur_secs: 3.0, - strength: DamageFraction(0.1), - chance: 1.0, - ))), + recover_duration: 1.2, + movement: ( + swing: Some(Forward(0.2)), + ), + ori_modifier: 0.65, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.65, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/dullahan/melee.ron b/assets/common/abilities/custom/dullahan/melee.ron index c5e30bfc0e..3aee8dddf7 100644 --- a/assets/common/abilities/custom/dullahan/melee.ron +++ b/assets/common/abilities/custom/dullahan/melee.ron @@ -1,55 +1,57 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 35.5, - damage_increase: 0.0, - base_poise_damage: 15.0, - poise_damage_increase: 0.0, - knockback: 2.0, - range: 6.0, - angle: 60.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Slash( + damage: 35, + poise: 15, + knockback: 2, + energy_regen: 0, + ), + range: 6.0, + angle: 60.0, + damage_effect: Some(Buff(( + kind: Bleeding, + dur_secs: 3.0, + strength: DamageFraction(0.05), + chance: 0.3, + ))), + ), + buildup_duration: 0.8, + swing_duration: 0.1, hit_timing: 0.4, - base_recover_duration: 0.3, - forward_movement: 0.8, - damage_kind: Slashing, - damage_effect: Some(Buff(( - kind: Bleeding, - dur_secs: 3.0, - strength: DamageFraction(0.05), - chance: 0.3, - ))), + recover_duration: 0.3, + movement: ( + swing: Some(Forward(0.8)), + ), + ori_modifier: 0.6, ), ( - stage: 2, - base_damage: 38.5, - damage_increase: 0.0, - base_poise_damage: 20.0, - poise_damage_increase: 0.0, - knockback: 8.0, - range: 6.0, - angle: 60.0, - base_buildup_duration: 0.7, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Slash( + damage: 38.5, + poise: 20, + knockback: 8, + energy_regen: 0, + ), + range: 6.0, + angle: 60.0, + damage_effect: Some(Buff(( + kind: Bleeding, + dur_secs: 3.0, + strength: DamageFraction(0.1), + chance: 0.15, + ))), + ), + buildup_duration: 0.7, + swing_duration: 0.1, hit_timing: 0.4, - base_recover_duration: 1.3, - forward_movement: 0.2, - damage_kind: Slashing, - damage_effect: Some(Buff(( - kind: Bleeding, - dur_secs: 3.0, - strength: DamageFraction(0.1), - chance: 0.15, - ))), + recover_duration: 1.3, + movement: ( + swing: Some(Forward(0.2)), + ), + ori_modifier: 0.6, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.6, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/husk_brute/singlestrike.ron b/assets/common/abilities/custom/husk_brute/singlestrike.ron index d0f6834487..0f1ada65f6 100644 --- a/assets/common/abilities/custom/husk_brute/singlestrike.ron +++ b/assets/common/abilities/custom/husk_brute/singlestrike.ron @@ -1,27 +1,18 @@ -ComboMelee( - stage_data: [ - ( - stage: 1, - base_damage: 40.0, - damage_increase: 0, - base_poise_damage: 12, - poise_damage_increase: 0, - knockback: 5.0, - range: 3.5, - angle: 60.0, - base_buildup_duration: 1.0, - base_swing_duration: 0.2, - hit_timing: 0.5, - base_recover_duration: 1.0, - forward_movement: 0.5, - damage_kind: Crushing, +BasicMelee( + energy_cost: 0, + buildup_duration: 1.0, + swing_duration: 0.2, + hit_timing: 0.5, + recover_duration: 1.0, + melee_constructor: ( + kind: Bash( + damage: 40, + poise: 12, + knockback: 5, + energy_regen: 0, ), - ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, + range: 3.5, + angle: 60.0, + ), ori_modifier: 0.6, ) diff --git a/assets/common/abilities/custom/maneater/singlestrike.ron b/assets/common/abilities/custom/maneater/singlestrike.ron index 47624c8d27..756337b4a2 100644 --- a/assets/common/abilities/custom/maneater/singlestrike.ron +++ b/assets/common/abilities/custom/maneater/singlestrike.ron @@ -1,27 +1,25 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 40.0, - damage_increase: 0, - base_poise_damage: 28, - poise_damage_increase: 0, - knockback: 3.0, - range: 3.5, - angle: 60.0, - base_buildup_duration: 1.0, - base_swing_duration: 0.075, + melee_constructor: ( + kind: Bash( + damage: 40, + poise: 28, + knockback: 3, + energy_regen: 0, + ), + range: 3.5, + angle: 60.0, + ), + buildup_duration: 1.0, + swing_duration: 0.075, hit_timing: 0.5, - base_recover_duration: 0.4, - forward_movement: 2.0, - damage_kind: Crushing, + recover_duration: 0.4, + movement: ( + swing: Some(Forward(2.0)), + ), + ori_modifier: 0.65, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.65, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/oni/doublestrike.ron b/assets/common/abilities/custom/oni/doublestrike.ron index 91ad4917b5..f347805769 100644 --- a/assets/common/abilities/custom/oni/doublestrike.ron +++ b/assets/common/abilities/custom/oni/doublestrike.ron @@ -1,55 +1,57 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 18.0, - damage_increase: 1.0, - base_poise_damage: 0, - poise_damage_increase: 0, - knockback: 4.0, - range: 3.5, - angle: 50.0, - base_buildup_duration: 1.2, - base_swing_duration: 0.12, + melee_constructor: ( + kind: Slash( + damage: 18, + poise: 0, + knockback: 4, + energy_regen: 0, + ), + range: 3.5, + angle: 50.0, + damage_effect: Some(Buff(( + kind: Bleeding, + dur_secs: 10.0, + strength: DamageFraction(0.1), + chance: 0.1, + ))), + ), + buildup_duration: 1.2, + swing_duration: 0.12, hit_timing: 0.5, - base_recover_duration: 1.2, - forward_movement: 3.5, - damage_kind: Slashing, - damage_effect: Some(Buff(( - kind: Bleeding, - dur_secs: 10.0, - strength: DamageFraction(0.1), - chance: 0.1, - ))), + recover_duration: 1.2, + movement: ( + swing: Some(Forward(3.5)), + ), + ori_modifier: 0.6, ), ( - stage: 2, - base_damage: 26.0, - damage_increase: 1.5, - base_poise_damage: 0, - poise_damage_increase: 0, - knockback: 16.0, - range: 5.5, - angle: 15.0, - base_buildup_duration: 1.0, - base_swing_duration: 0.15, + melee_constructor: ( + kind: Slash( + damage: 26, + poise: 0, + knockback: 16, + energy_regen: 0, + ), + range: 5.5, + angle: 15.0, + damage_effect: Some(Buff(( + kind: Bleeding, + dur_secs: 10.0, + strength: DamageFraction(0.1), + chance: 0.1, + ))), + ), + buildup_duration: 1.0, + swing_duration: 0.15, hit_timing: 0.5, - base_recover_duration: 2.4, - forward_movement: 4.5, - damage_kind: Slashing, - damage_effect: Some(Buff(( - kind: Bleeding, - dur_secs: 10.0, - strength: DamageFraction(0.1), - chance: 0.1, - ))), + recover_duration: 2.4, + movement: ( + swing: Some(Forward(4.5)), + ), + ori_modifier: 0.6, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.6, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/quadlowbasic/singlestrike.ron b/assets/common/abilities/custom/quadlowbasic/singlestrike.ron index 3938023f8a..a929d60112 100644 --- a/assets/common/abilities/custom/quadlowbasic/singlestrike.ron +++ b/assets/common/abilities/custom/quadlowbasic/singlestrike.ron @@ -1,27 +1,25 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 40.0, - damage_increase: 0, - base_poise_damage: 28, - poise_damage_increase: 0, - knockback: 3.0, - range: 2.0, - angle: 60.0, - base_buildup_duration: 1.2, - base_swing_duration: 0.07, + melee_constructor: ( + kind: Bash( + damage: 40, + poise: 28, + knockback: 3, + energy_regen: 0, + ), + range: 2.0, + angle: 60.0, + ), + buildup_duration: 1.2, + swing_duration: 0.07, hit_timing: 0.5, - base_recover_duration: 0.8, - forward_movement: 3.0, - damage_kind: Crushing, + recover_duration: 0.8, + movement: ( + swing: Some(Forward(3.0)), + ), + ori_modifier: 0.6, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.6, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/quadlowbasic/triplestrike.ron b/assets/common/abilities/custom/quadlowbasic/triplestrike.ron index b90c3aca84..33276cdc93 100644 --- a/assets/common/abilities/custom/quadlowbasic/triplestrike.ron +++ b/assets/common/abilities/custom/quadlowbasic/triplestrike.ron @@ -1,59 +1,65 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 28.0, - damage_increase: 0, - base_poise_damage: 15, - poise_damage_increase: 0, - knockback: 3.0, - range: 2.2, - angle: 30.0, - base_buildup_duration: 1.3, - base_swing_duration: 0.07, + melee_constructor: ( + kind: Bash( + damage: 28, + poise: 15, + knockback: 3, + energy_regen: 0, + ), + range: 2.2, + angle: 30.0, + ), + buildup_duration: 1.3, + swing_duration: 0.07, hit_timing: 0.5, - base_recover_duration: 0.6, - forward_movement: 2.0, - damage_kind: Crushing, + recover_duration: 0.6, + movement: ( + swing: Some(Forward(2.0)), + ), + ori_modifier: 0.65, ), ( - stage: 2, - base_damage: 28.0, - damage_increase: 0, - base_poise_damage: 18, - poise_damage_increase: 0, - knockback: 3.0, - range: 2.2, - angle: 30.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.07, + melee_constructor: ( + kind: Bash( + damage: 28, + poise: 18, + knockback: 3, + energy_regen: 0, + ), + range: 2.2, + angle: 30.0, + ), + buildup_duration: 0.8, + swing_duration: 0.07, hit_timing: 0.5, - base_recover_duration: 0.6, - forward_movement: 1.5, - damage_kind: Crushing, + recover_duration: 0.6, + movement: ( + swing: Some(Forward(1.5)), + ), + ori_modifier: 0.65, ), ( - stage: 3, - base_damage: 28.0, - damage_increase: 0, - base_poise_damage: 20, - poise_damage_increase: 0, - knockback: 3.0, - range: 2.2, - angle: 30.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.07, + melee_constructor: ( + kind: Bash( + damage: 28, + poise: 20, + knockback: 3, + energy_regen: 0, + ), + range: 2.2, + angle: 30.0, + ), + buildup_duration: 0.8, + swing_duration: 0.07, hit_timing: 0.5, - base_recover_duration: 0.6, - forward_movement: 1.5, - damage_kind: Crushing, + recover_duration: 0.6, + movement: ( + swing: Some(Forward(1.5)), + ), + ori_modifier: 0.65, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.65, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/quadlowbreathe/triplestrike.ron b/assets/common/abilities/custom/quadlowbreathe/triplestrike.ron index 6884a54b17..aa109a29d0 100644 --- a/assets/common/abilities/custom/quadlowbreathe/triplestrike.ron +++ b/assets/common/abilities/custom/quadlowbreathe/triplestrike.ron @@ -1,59 +1,65 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 44.0, - damage_increase: 0, - base_poise_damage: 20, - poise_damage_increase: 0, - knockback: 3.0, - range: 2.5, - angle: 30.0, - base_buildup_duration: 1.3, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Bash( + damage: 44, + poise: 20, + knockback: 3, + energy_regen: 0, + ), + range: 2.5, + angle: 30.0, + ), + buildup_duration: 1.3, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.6, - forward_movement: 2.0, - damage_kind: Crushing, + recover_duration: 0.6, + movement: ( + swing: Some(Forward(2.0)), + ), + ori_modifier: 0.7, ), ( - stage: 2, - base_damage: 44.0, - damage_increase: 0, - base_poise_damage: 20, - poise_damage_increase: 0, - knockback: 3.0, - range: 2.5, - angle: 30.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Bash( + damage: 44, + poise: 20, + knockback: 3, + energy_regen: 0, + ), + range: 2.5, + angle: 30.0, + ), + buildup_duration: 0.8, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.6, - forward_movement: 1.5, - damage_kind: Crushing, + recover_duration: 0.6, + movement: ( + swing: Some(Forward(1.5)), + ), + ori_modifier: 0.7, ), ( - stage: 3, - base_damage: 44.0, - damage_increase: 0, - base_poise_damage: 20, - poise_damage_increase: 0, - knockback: 3.0, - range: 2.5, - angle: 30.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Bash( + damage: 44, + poise: 20, + knockback: 3, + energy_regen: 0, + ), + range: 2.5, + angle: 30.0, + ), + buildup_duration: 0.8, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.6, - forward_movement: 1.5, - damage_kind: Crushing, + recover_duration: 0.6, + movement: ( + swing: Some(Forward(1.5)), + ), + ori_modifier: 0.7, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.7, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/quadlowquick/quadstrike.ron b/assets/common/abilities/custom/quadlowquick/quadstrike.ron index fe86f0e1fb..a0ec0c8b8a 100644 --- a/assets/common/abilities/custom/quadlowquick/quadstrike.ron +++ b/assets/common/abilities/custom/quadlowquick/quadstrike.ron @@ -1,75 +1,85 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 12.0, - damage_increase: 0, - base_poise_damage: 15, - poise_damage_increase: 0, - knockback: 1.0, - range: 2.5, - angle: 30.0, - base_buildup_duration: 1.2, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Bash( + damage: 12, + poise: 15, + knockback: 1, + energy_regen: 0, + ), + range: 2.5, + angle: 30.0, + ), + buildup_duration: 1.2, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.2, - forward_movement: 1.5, - damage_kind: Crushing, + recover_duration: 0.2, + movement: ( + swing: Some(Forward(1.5)), + ), + ori_modifier: 0.8, ), ( - stage: 2, - base_damage: 12.0, - damage_increase: 0, - base_poise_damage: 15, - poise_damage_increase: 0, - knockback: 1.0, - range: 2.5, - angle: 30.0, - base_buildup_duration: 0.3, - base_swing_duration: 0.07, + melee_constructor: ( + kind: Bash( + damage: 12, + poise: 15, + knockback: 1, + energy_regen: 0, + ), + range: 2.5, + angle: 30.0, + ), + buildup_duration: 0.3, + swing_duration: 0.07, hit_timing: 0.5, - base_recover_duration: 0.2, - forward_movement: 0.8, - damage_kind: Crushing, + recover_duration: 0.2, + movement: ( + swing: Some(Forward(0.8)), + ), + ori_modifier: 0.8, ), ( - stage: 3, - base_damage: 12.0, - damage_increase: 0, - base_poise_damage: 15, - poise_damage_increase: 0, - knockback: 1.0, - range: 2.5, - angle: 30.0, - base_buildup_duration: 0.4, - base_swing_duration: 0.07, + melee_constructor: ( + kind: Bash( + damage: 12, + poise: 15, + knockback: 1, + energy_regen: 0, + ), + range: 2.5, + angle: 30.0, + ), + buildup_duration: 0.4, + swing_duration: 0.07, hit_timing: 0.5, - base_recover_duration: 0.2, - forward_movement: 0.8, - damage_kind: Crushing, + recover_duration: 0.2, + movement: ( + swing: Some(Forward(0.8)), + ), + ori_modifier: 0.8, ), ( - stage: 4, - base_damage: 12.0, - damage_increase: 0, - base_poise_damage: 15, - poise_damage_increase: 0, - knockback: 8.0, - range: 2.5, - angle: 30.0, - base_buildup_duration: 0.4, - base_swing_duration: 0.07, + melee_constructor: ( + kind: Bash( + damage: 12, + poise: 15, + knockback: 8, + energy_regen: 0, + ), + range: 2.5, + angle: 30.0, + ), + buildup_duration: 0.4, + swing_duration: 0.07, hit_timing: 0.5, - base_recover_duration: 0.2, - forward_movement: 0.8, - damage_kind: Crushing, + recover_duration: 0.2, + movement: ( + swing: Some(Forward(0.8)), + ), + ori_modifier: 0.8, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.8, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/quadlowtail/triplestrike.ron b/assets/common/abilities/custom/quadlowtail/triplestrike.ron index 2c532bd30a..2b2e056d84 100644 --- a/assets/common/abilities/custom/quadlowtail/triplestrike.ron +++ b/assets/common/abilities/custom/quadlowtail/triplestrike.ron @@ -1,59 +1,65 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 16.0, - damage_increase: 0, - base_poise_damage: 0, - poise_damage_increase: 22, - knockback: 10.0, - range: 2.2, - angle: 30.0, - base_buildup_duration: 1.3, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Bash( + damage: 16, + poise: 22, + knockback: 10, + energy_regen: 0, + ), + range: 2.2, + angle: 30.0, + ), + buildup_duration: 1.3, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.4, - forward_movement: 2.0, - damage_kind: Crushing, + recover_duration: 0.4, + movement: ( + swing: Some(Forward(2.0)), + ), + ori_modifier: 0.7, ), ( - stage: 2, - base_damage: 16.0, - damage_increase: 0, - base_poise_damage: 22, - poise_damage_increase: 0, - knockback: 10.0, - range: 2.2, - angle: 30.0, - base_buildup_duration: 0.4, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Bash( + damage: 16, + poise: 22, + knockback: 10, + energy_regen: 0, + ), + range: 2.2, + angle: 30.0, + ), + buildup_duration: 0.4, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.4, - forward_movement: 1.0, - damage_kind: Crushing, + recover_duration: 0.4, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.7, ), ( - stage: 3, - base_damage: 16.0, - damage_increase: 0, - base_poise_damage: 22, - poise_damage_increase: 0, - knockback: 10.0, - range: 2.2, - angle: 30.0, - base_buildup_duration: 0.2, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Bash( + damage: 16, + poise: 22, + knockback: 10, + energy_regen: 0, + ), + range: 2.2, + angle: 30.0, + ), + buildup_duration: 0.2, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.4, - forward_movement: 1.0, - damage_kind: Crushing, + recover_duration: 0.4, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.7, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.7, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/quadmedbasic/singlestrike.ron b/assets/common/abilities/custom/quadmedbasic/singlestrike.ron index 312c4dd9ad..fc8b819beb 100644 --- a/assets/common/abilities/custom/quadmedbasic/singlestrike.ron +++ b/assets/common/abilities/custom/quadmedbasic/singlestrike.ron @@ -1,27 +1,25 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 20.0, - damage_increase: 0, - base_poise_damage: 28, - poise_damage_increase: 0, - knockback: 3.0, - range: 2.7, - angle: 60.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Bash( + damage: 20, + poise: 28, + knockback: 3, + energy_regen: 0, + ), + range: 2.7, + angle: 60.0, + ), + buildup_duration: 0.8, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.8, - forward_movement: 1.0, - damage_kind: Crushing, + recover_duration: 0.8, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.7, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.7, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/quadmedbasic/triplestrike.ron b/assets/common/abilities/custom/quadmedbasic/triplestrike.ron index 62e3b574ce..757a3d9a8a 100644 --- a/assets/common/abilities/custom/quadmedbasic/triplestrike.ron +++ b/assets/common/abilities/custom/quadmedbasic/triplestrike.ron @@ -1,59 +1,62 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 10.0, - damage_increase: 0, - base_poise_damage: 15, - poise_damage_increase: 0, - knockback: 5.0, - range: 2.5, - angle: 30.0, - base_buildup_duration: 0.9, - base_swing_duration: 0.07, + melee_constructor: ( + kind: Bash( + damage: 10, + poise: 15, + knockback: 5, + energy_regen: 0, + ), + range: 2.5, + angle: 30.0, + ), + buildup_duration: 0.9, + swing_duration: 0.07, hit_timing: 0.5, - base_recover_duration: 0.4, - forward_movement: 1.0, - damage_kind: Crushing, + recover_duration: 0.4, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.7, ), ( - stage: 2, - base_damage: 10.0, - damage_increase: 0, - base_poise_damage: 18, - poise_damage_increase: 0, - knockback: 5.0, - range: 2.5, - angle: 30.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.07, + melee_constructor: ( + kind: Bash( + damage: 10, + poise: 18, + knockback: 5, + energy_regen: 0, + ), + range: 2.5, + angle: 30.0, + ), + buildup_duration: 0.8, + swing_duration: 0.07, hit_timing: 0.5, - base_recover_duration: 0.4, - forward_movement: 0.0, - damage_kind: Crushing, + recover_duration: 0.4, + ori_modifier: 0.7, ), ( - stage: 3, - base_damage: 10.0, - damage_increase: 0, - base_poise_damage: 20, - poise_damage_increase: 0, - knockback: 5.0, - range: 2.5, - angle: 30.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.07, + melee_constructor: ( + kind: Bash( + damage: 10, + poise: 20, + knockback: 5, + energy_regen: 0, + ), + range: 2.5, + angle: 30.0, + ), + buildup_duration: 0.8, + swing_duration: 0.07, hit_timing: 0.5, - base_recover_duration: 0.4, - forward_movement: 1.0, - damage_kind: Crushing, + recover_duration: 0.4, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.7, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.7, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/quadmedcharge/doublestrike.ron b/assets/common/abilities/custom/quadmedcharge/doublestrike.ron index 59eeddd680..076cc6c178 100644 --- a/assets/common/abilities/custom/quadmedcharge/doublestrike.ron +++ b/assets/common/abilities/custom/quadmedcharge/doublestrike.ron @@ -1,43 +1,45 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 50.0, - damage_increase: 0, - base_poise_damage: 22, - poise_damage_increase: 0, - knockback: 4.0, - range: 2.5, - angle: 30.0, - base_buildup_duration: 1.3, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Bash( + damage: 50, + poise: 22, + knockback: 4, + energy_regen: 0, + ), + range: 2.5, + angle: 30.0, + ), + buildup_duration: 1.3, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.6, - forward_movement: 1.0, - damage_kind: Crushing, + recover_duration: 0.6, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.7, ), ( - stage: 2, - base_damage: 74.0, - damage_increase: 0, - base_poise_damage: 0, - poise_damage_increase: 22, - knockback: 4.0, - range: 2.5, - angle: 30.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Bash( + damage: 74, + poise: 22, + knockback: 4, + energy_regen: 0, + ), + range: 2.5, + angle: 30.0, + ), + buildup_duration: 0.8, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.6, - forward_movement: 0.5, - damage_kind: Crushing, + recover_duration: 0.6, + movement: ( + swing: Some(Forward(0.5)), + ), + ori_modifier: 0.7, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.7, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/quadmedjump/doublestrike.ron b/assets/common/abilities/custom/quadmedjump/doublestrike.ron index ca4fa9c29f..07d0b4d635 100644 --- a/assets/common/abilities/custom/quadmedjump/doublestrike.ron +++ b/assets/common/abilities/custom/quadmedjump/doublestrike.ron @@ -1,43 +1,45 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 16.0, - damage_increase: 0, - base_poise_damage: 30, - poise_damage_increase: 0, - knockback: 4.0, - range: 2.2, - angle: 30.0, - base_buildup_duration: 1.3, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Bash( + damage: 16, + poise: 30, + knockback: 4, + energy_regen: 0, + ), + range: 2.2, + angle: 30.0, + ), + buildup_duration: 1.3, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.6, - forward_movement: 1.0, - damage_kind: Crushing, + recover_duration: 0.6, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.8, ), ( - stage: 2, - base_damage: 16.0, - damage_increase: 0, - base_poise_damage: 30, - poise_damage_increase: 0, - knockback: 4.0, - range: 2.2, - angle: 30.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Bash( + damage: 16, + poise: 30, + knockback: 4, + energy_regen: 0, + ), + range: 2.2, + angle: 30.0, + ), + buildup_duration: 0.8, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.6, - forward_movement: 1.5, - damage_kind: Crushing, + recover_duration: 0.6, + movement: ( + swing: Some(Forward(1.5)), + ), + ori_modifier: 0.8, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.8, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/quadmedquick/triplestrike.ron b/assets/common/abilities/custom/quadmedquick/triplestrike.ron index 015e7dbc2b..2b0ee263c9 100644 --- a/assets/common/abilities/custom/quadmedquick/triplestrike.ron +++ b/assets/common/abilities/custom/quadmedquick/triplestrike.ron @@ -1,59 +1,65 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 20.0, - damage_increase: 0, - base_poise_damage: 15, - poise_damage_increase: 0, - knockback: 5.0, - range: 2.2, - angle: 40.0, - base_buildup_duration: 1.2, - base_swing_duration: 0.15, + melee_constructor: ( + kind: Bash( + damage: 20, + poise: 15, + knockback: 5, + energy_regen: 0, + ), + range: 2.2, + angle: 40.0, + ), + buildup_duration: 1.2, + swing_duration: 0.15, hit_timing: 0.5, - base_recover_duration: 0.8, - forward_movement: 0.3, - damage_kind: Crushing, + recover_duration: 0.8, + movement: ( + swing: Some(Forward(0.3)), + ), + ori_modifier: 0.8, ), ( - stage: 2, - base_damage: 20.0, - damage_increase: 0, - base_poise_damage: 17, - poise_damage_increase: 0, - knockback: 5.0, - range: 2.2, - angle: 40.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.15, + melee_constructor: ( + kind: Bash( + damage: 20, + poise: 17, + knockback: 5, + energy_regen: 0, + ), + range: 2.2, + angle: 40.0, + ), + buildup_duration: 0.8, + swing_duration: 0.15, hit_timing: 0.5, - base_recover_duration: 0.6, - forward_movement: 0.5, - damage_kind: Crushing, + recover_duration: 0.6, + movement: ( + swing: Some(Forward(0.5)), + ), + ori_modifier: 0.8, ), ( - stage: 3, - base_damage: 20.0, - damage_increase: 0, - base_poise_damage: 20, - poise_damage_increase: 0, - knockback: 5.0, - range: 2.2, - angle: 40.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.15, + melee_constructor: ( + kind: Bash( + damage: 20, + poise: 20, + knockback: 5, + energy_regen: 0, + ), + range: 2.2, + angle: 40.0, + ), + buildup_duration: 0.8, + swing_duration: 0.15, hit_timing: 0.5, - base_recover_duration: 0.6, - forward_movement: 0.5, - damage_kind: Crushing, + recover_duration: 0.6, + movement: ( + swing: Some(Forward(0.5)), + ), + ori_modifier: 0.8, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.8, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/quadsmallbasic/singlestrike.ron b/assets/common/abilities/custom/quadsmallbasic/singlestrike.ron index 8b10305b23..a83773e74b 100644 --- a/assets/common/abilities/custom/quadsmallbasic/singlestrike.ron +++ b/assets/common/abilities/custom/quadsmallbasic/singlestrike.ron @@ -1,27 +1,18 @@ -ComboMelee( - stage_data: [ - ( - stage: 1, - base_damage: 6.0, - damage_increase: 0, - base_poise_damage: 10, - poise_damage_increase: 0, - knockback: 1.0, - range: 1.5, - angle: 50.0, - base_buildup_duration: 0.6, - base_swing_duration: 0.15, - hit_timing: 0.5, - base_recover_duration: 0.6, - forward_movement: 1.0, - damage_kind: Crushing, +BasicMelee( + energy_cost: 0, + buildup_duration: 0.6, + swing_duration: 0.15, + hit_timing: 0.5, + recover_duration: 0.6, + melee_constructor: ( + kind: Bash( + damage: 6, + poise: 10, + knockback: 1, + energy_regen: 0, ), - ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, + range: 1.5, + angle: 50.0, + ), ori_modifier: 0.7, ) diff --git a/assets/common/abilities/custom/roshwalr/doublehusk.ron b/assets/common/abilities/custom/roshwalr/doublehusk.ron index 95b11639ad..002139e71c 100644 --- a/assets/common/abilities/custom/roshwalr/doublehusk.ron +++ b/assets/common/abilities/custom/roshwalr/doublehusk.ron @@ -1,43 +1,45 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 28.0, - damage_increase: 0, - base_poise_damage: 7.5, - poise_damage_increase: 0, - knockback: 3.0, - range: 3, - angle: 75.0, - base_buildup_duration: 1.2, - base_swing_duration: 0.07, + melee_constructor: ( + kind: Stab( + damage: 28, + poise: 7.5, + knockback: 3, + energy_regen: 5, + ), + range: 3.0, + angle: 75.0, + ), + buildup_duration: 1.2, + swing_duration: 0.07, hit_timing: 0.5, - base_recover_duration: 0.3, - forward_movement: 0.25, - damage_kind: Piercing, + recover_duration: 0.3, + movement: ( + swing: Some(Forward(0.25)), + ), + ori_modifier: 0.5, ), ( - stage: 2, - base_damage: 28.0, - damage_increase: 0, - base_poise_damage: 7.5, - poise_damage_increase: 0, - knockback: 3.0, - range: 3, - angle: 75.0, - base_buildup_duration: 0.2, - base_swing_duration: 0.07, + melee_constructor: ( + kind: Stab( + damage: 28, + poise: 7.5, + knockback: 3, + energy_regen: 5, + ), + range: 3.0, + angle: 75.0, + ), + buildup_duration: 0.2, + swing_duration: 0.07, hit_timing: 0.5, - base_recover_duration: 0.6, - forward_movement: 0.25, - damage_kind: Piercing, + recover_duration: 0.6, + movement: ( + swing: Some(Forward(0.25)), + ), + ori_modifier: 0.5, ), ], - initial_energy_gain: 5, - max_energy_gain: 5, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.65, -) \ No newline at end of file + energy_cost_per_strike: 0, +) diff --git a/assets/common/abilities/custom/simpleflyingmelee/singlestrike.ron b/assets/common/abilities/custom/simpleflyingmelee/singlestrike.ron index 774dda8307..b4ed42e026 100644 --- a/assets/common/abilities/custom/simpleflyingmelee/singlestrike.ron +++ b/assets/common/abilities/custom/simpleflyingmelee/singlestrike.ron @@ -1,27 +1,18 @@ -ComboMelee( - stage_data: [ - ( - stage: 1, - base_damage: 1.0, - damage_increase: 0, - base_poise_damage: 0, - poise_damage_increase: 0, - knockback: 0.0, - range: 2.5, - angle: 150.0, - base_buildup_duration: 0.1, - base_swing_duration: 0.07, - hit_timing: 0.5, - base_recover_duration: 0.2, - forward_movement: 0.0, - damage_kind: Piercing, +BasicMelee( + energy_cost: 0, + buildup_duration: 0.1, + swing_duration: 0.07, + hit_timing: 0.5, + recover_duration: 0.2, + melee_constructor: ( + kind: Stab( + damage: 1, + poise: 0, + knockback: 0, + energy_regen: 0, ), - ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, + range: 2.5, + angle: 150.0, + ), ori_modifier: 0.6, ) diff --git a/assets/common/abilities/custom/stonegolemfist/singlestrike.ron b/assets/common/abilities/custom/stonegolemfist/singlestrike.ron index 1ecf3c0de5..239124743b 100644 --- a/assets/common/abilities/custom/stonegolemfist/singlestrike.ron +++ b/assets/common/abilities/custom/stonegolemfist/singlestrike.ron @@ -1,27 +1,18 @@ -ComboMelee( - stage_data: [ - ( - stage: 1, - base_damage: 60.0, - damage_increase: 0, - base_poise_damage: 40, - poise_damage_increase: 0, - knockback: 3.0, - range: 3.5, - angle: 60.0, - base_buildup_duration: 1.8, - base_swing_duration: 0.1, - hit_timing: 0.5, - base_recover_duration: 1.8, - forward_movement: 3.0, - damage_kind: Crushing, +BasicMelee( + energy_cost: 0, + buildup_duration: 1.8, + swing_duration: 0.1, + hit_timing: 0.5, + recover_duration: 1.8, + melee_constructor: ( + kind: Bash( + damage: 60, + poise: 40, + knockback: 3, + energy_regen: 0, ), - ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, + range: 3.5, + angle: 60.0, + ), ori_modifier: 0.7, ) diff --git a/assets/common/abilities/custom/theropodbasic/singlestrike.ron b/assets/common/abilities/custom/theropodbasic/singlestrike.ron index dc8fc4fb43..f73beb51c1 100644 --- a/assets/common/abilities/custom/theropodbasic/singlestrike.ron +++ b/assets/common/abilities/custom/theropodbasic/singlestrike.ron @@ -1,27 +1,25 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 54.0, - damage_increase: 0, - base_poise_damage: 40, - poise_damage_increase: 0, - knockback: 4.0, - range: 7.5, - angle: 60.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.15, + melee_constructor: ( + kind: Bash( + damage: 54, + poise: 40, + knockback: 4, + energy_regen: 0, + ), + range: 7.5, + angle: 60.0, + ), + buildup_duration: 0.8, + swing_duration: 0.15, hit_timing: 0.5, - base_recover_duration: 0.8, - forward_movement: 3.0, - damage_kind: Crushing, + recover_duration: 0.8, + movement: ( + swing: Some(Forward(3.0)), + ), + ori_modifier: 0.7, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.7, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/theropodbasic/triplestrike.ron b/assets/common/abilities/custom/theropodbasic/triplestrike.ron index c989cdef26..0d7f779ffb 100644 --- a/assets/common/abilities/custom/theropodbasic/triplestrike.ron +++ b/assets/common/abilities/custom/theropodbasic/triplestrike.ron @@ -1,59 +1,65 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 40.0, - damage_increase: 0, - base_poise_damage: 32.5, - poise_damage_increase: 0, - knockback: 3.0, - range: 7.5, - angle: 30.0, - base_buildup_duration: 1.3, - base_swing_duration: 0.15, + melee_constructor: ( + kind: Bash( + damage: 40, + poise: 32.5, + knockback: 3, + energy_regen: 0, + ), + range: 7.5, + angle: 30.0, + ), + buildup_duration: 1.3, + swing_duration: 0.15, hit_timing: 0.5, - base_recover_duration: 0.5, - forward_movement: 1.0, - damage_kind: Crushing, + recover_duration: 0.5, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.7, ), ( - stage: 2, - base_damage: 50.0, - damage_increase: 0, - base_poise_damage: 32.5, - poise_damage_increase: 0, - knockback: 3.0, - range: 5.5, - angle: 30.0, - base_buildup_duration: 0.2, - base_swing_duration: 0.15, + melee_constructor: ( + kind: Bash( + damage: 50, + poise: 32.5, + knockback: 3, + energy_regen: 0, + ), + range: 5.5, + angle: 30.0, + ), + buildup_duration: 0.2, + swing_duration: 0.15, hit_timing: 0.5, - base_recover_duration: 0.3, - forward_movement: 1.0, - damage_kind: Crushing, + recover_duration: 0.3, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.7, ), ( - stage: 3, - base_damage: 60.0, - damage_increase: 0, - base_poise_damage: 32.5, - poise_damage_increase: 0, - knockback: 25.0, - range: 5.5, - angle: 30.0, - base_buildup_duration: 0.4, - base_swing_duration: 0.125, + melee_constructor: ( + kind: Bash( + damage: 60, + poise: 32.5, + knockback: 25, + energy_regen: 0, + ), + range: 5.5, + angle: 30.0, + ), + buildup_duration: 0.4, + swing_duration: 0.125, hit_timing: 0.5, - base_recover_duration: 1.6, - forward_movement: 1.0, - damage_kind: Crushing, + recover_duration: 1.6, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.7, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.7, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/theropodbird/singlestrike.ron b/assets/common/abilities/custom/theropodbird/singlestrike.ron index 217070715f..61c04e29ce 100644 --- a/assets/common/abilities/custom/theropodbird/singlestrike.ron +++ b/assets/common/abilities/custom/theropodbird/singlestrike.ron @@ -1,27 +1,25 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 22.0, - damage_increase: 0, - base_poise_damage: 28, - poise_damage_increase: 0, - knockback: 2.0, - range: 3.0, - angle: 15.0, - base_buildup_duration: 0.8, - base_swing_duration: 0.15, + melee_constructor: ( + kind: Bash( + damage: 22, + poise: 28, + knockback: 2, + energy_regen: 0, + ), + range: 3.0, + angle: 15.0, + ), + buildup_duration: 0.8, + swing_duration: 0.15, hit_timing: 0.5, - base_recover_duration: 0.8, - forward_movement: 3.0, - damage_kind: Crushing, + recover_duration: 0.8, + movement: ( + swing: Some(Forward(3.0)), + ), + ori_modifier: 0.7, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.7, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/theropodbird/triplestrike.ron b/assets/common/abilities/custom/theropodbird/triplestrike.ron index 6124283d1b..d4d1965298 100644 --- a/assets/common/abilities/custom/theropodbird/triplestrike.ron +++ b/assets/common/abilities/custom/theropodbird/triplestrike.ron @@ -1,59 +1,65 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 16.5, - damage_increase: 0, - base_poise_damage: 20, - poise_damage_increase: 0, - knockback: 3.0, - range: 3.0, - angle: 15.0, - base_buildup_duration: 0.95, - base_swing_duration: 0.15, + melee_constructor: ( + kind: Bash( + damage: 16.5, + poise: 20, + knockback: 3, + energy_regen: 0, + ), + range: 3.0, + angle: 15.0, + ), + buildup_duration: 0.95, + swing_duration: 0.15, hit_timing: 0.5, - base_recover_duration: 0.50, - forward_movement: 1.0, - damage_kind: Crushing, + recover_duration: 0.5, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.6, ), ( - stage: 2, - base_damage: 30.0, - damage_increase: 0, - base_poise_damage: 20, - poise_damage_increase: 0, - knockback: 3.0, - range: 3.0, - angle: 15.0, - base_buildup_duration: 0.65, - base_swing_duration: 0.15, + melee_constructor: ( + kind: Bash( + damage: 30, + poise: 20, + knockback: 3, + energy_regen: 0, + ), + range: 3.0, + angle: 15.0, + ), + buildup_duration: 0.65, + swing_duration: 0.15, hit_timing: 0.5, - base_recover_duration: 0.50, - forward_movement: 1.0, - damage_kind: Crushing, + recover_duration: 0.5, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.6, ), ( - stage: 3, - base_damage: 36.0, - damage_increase: 0, - base_poise_damage: 20, - poise_damage_increase: 0, - knockback: 3.0, - range: 3.0, - angle: 15.0, - base_buildup_duration: 0.525, - base_swing_duration: 0.125, + melee_constructor: ( + kind: Bash( + damage: 36, + poise: 20, + knockback: 3, + energy_regen: 0, + ), + range: 3.0, + angle: 15.0, + ), + buildup_duration: 0.525, + swing_duration: 0.125, hit_timing: 0.5, - base_recover_duration: 1.25, - forward_movement: 1.0, - damage_kind: Crushing, + recover_duration: 1.25, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.6, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.6, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/custom/theropodsmall/triplestrike.ron b/assets/common/abilities/custom/theropodsmall/triplestrike.ron index 95b93b7584..33cf6f3ca7 100644 --- a/assets/common/abilities/custom/theropodsmall/triplestrike.ron +++ b/assets/common/abilities/custom/theropodsmall/triplestrike.ron @@ -1,59 +1,65 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 30.0, - damage_increase: 0, - base_poise_damage: 17.5, - poise_damage_increase: 0, - knockback: 3.0, - range: 4.5, - angle: 30.0, - base_buildup_duration: 1.3, - base_swing_duration: 0.15, + melee_constructor: ( + kind: Bash( + damage: 30, + poise: 17.5, + knockback: 3, + energy_regen: 0, + ), + range: 4.5, + angle: 30.0, + ), + buildup_duration: 1.3, + swing_duration: 0.15, hit_timing: 0.5, - base_recover_duration: 0.5, - forward_movement: 1.0, - damage_kind: Crushing, + recover_duration: 0.5, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.7, ), ( - stage: 2, - base_damage: 30.0, - damage_increase: 0, - base_poise_damage: 20.5, - poise_damage_increase: 0, - knockback: 3.0, - range: 4.5, - angle: 30.0, - base_buildup_duration: 0.2, - base_swing_duration: 0.15, + melee_constructor: ( + kind: Bash( + damage: 30, + poise: 20.5, + knockback: 3, + energy_regen: 0, + ), + range: 4.5, + angle: 30.0, + ), + buildup_duration: 0.2, + swing_duration: 0.15, hit_timing: 0.5, - base_recover_duration: 0.3, - forward_movement: 1.0, - damage_kind: Crushing, + recover_duration: 0.3, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.7, ), ( - stage: 3, - base_damage: 30.0, - damage_increase: 0, - base_poise_damage: 22.5, - poise_damage_increase: 0, - knockback: 25.0, - range: 5.5, - angle: 30.0, - base_buildup_duration: 0.4, - base_swing_duration: 0.125, + melee_constructor: ( + kind: Bash( + damage: 30, + poise: 22.5, + knockback: 25, + energy_regen: 0, + ), + range: 5.5, + angle: 30.0, + ), + buildup_duration: 0.4, + swing_duration: 0.125, hit_timing: 0.5, - base_recover_duration: 1.6, - forward_movement: 1.0, - damage_kind: Crushing, + recover_duration: 1.6, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.7, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.7, -) \ No newline at end of file + energy_cost_per_strike: 0, +) diff --git a/assets/common/abilities/custom/wendigomagic/singlestrike.ron b/assets/common/abilities/custom/wendigomagic/singlestrike.ron index 6e4cd6edcf..3990f13158 100644 --- a/assets/common/abilities/custom/wendigomagic/singlestrike.ron +++ b/assets/common/abilities/custom/wendigomagic/singlestrike.ron @@ -1,27 +1,18 @@ -ComboMelee( - stage_data: [ - ( - stage: 1, - base_damage: 36.0, - damage_increase: 0, - base_poise_damage: 40, - poise_damage_increase: 0, - knockback: 3.0, - range: 2.5, - angle: 30.0, - base_buildup_duration: 1.2, - base_swing_duration: 0.4, - hit_timing: 0.5, - base_recover_duration: 0.8, - forward_movement: 5.0, - damage_kind: Crushing, +BasicMelee( + energy_cost: 0, + buildup_duration: 1.2, + swing_duration: 0.4, + hit_timing: 0.5, + recover_duration: 0.8, + melee_constructor: ( + kind: Bash( + damage: 36, + poise: 40, + knockback: 3, + energy_regen: 0, ), - ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, + range: 2.5, + angle: 30.0, + ), ori_modifier: 0.7, ) diff --git a/assets/common/abilities/daggersimple/singlestrike.ron b/assets/common/abilities/daggersimple/singlestrike.ron index 4cf543c1b7..428a8bd297 100644 --- a/assets/common/abilities/daggersimple/singlestrike.ron +++ b/assets/common/abilities/daggersimple/singlestrike.ron @@ -1,33 +1,25 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 2.0, - damage_increase: 1.0, - base_poise_damage: 8, - poise_damage_increase: 0, - knockback: 8.0, - range: 3.5, - angle: 50.0, - base_buildup_duration: 0.1, - base_swing_duration: 0.05, + melee_constructor: ( + kind: Slash( + damage: 2, + poise: 8, + knockback: 8, + energy_regen: 0, + ), + range: 3.5, + angle: 50.0, + ), + buildup_duration: 0.1, + swing_duration: 0.05, hit_timing: 0.5, - base_recover_duration: 0.05, - forward_movement: 1.0, - damage_kind: Slashing, - damage_effect: Some(Buff(( - kind: Bleeding, - dur_secs: 10.0, - strength: DamageFraction(0.1), - chance: 0.1, - ))), + recover_duration: 0.05, + movement: ( + swing: Some(Forward(1.0)), + ), + ori_modifier: 0.7, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.7, -) \ No newline at end of file + energy_cost_per_strike: 0, +) diff --git a/assets/common/abilities/hammer/singlestrike.ron b/assets/common/abilities/hammer/singlestrike.ron index 40e8f9ae57..3f93b52230 100644 --- a/assets/common/abilities/hammer/singlestrike.ron +++ b/assets/common/abilities/hammer/singlestrike.ron @@ -1,4 +1,4 @@ -ComboMelee( +ComboMeleeDeprecated( stage_data: [( stage: 1, base_damage: 15.0, diff --git a/assets/common/abilities/hammersimple/doublestrike.ron b/assets/common/abilities/hammersimple/doublestrike.ron index bd98b61286..cfde38dd41 100644 --- a/assets/common/abilities/hammersimple/doublestrike.ron +++ b/assets/common/abilities/hammersimple/doublestrike.ron @@ -1,43 +1,45 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 24.0, - damage_increase: 1.0, - base_poise_damage: 40, - poise_damage_increase: 0, - knockback: 4.0, - range: 4.5, - angle: 50.0, - base_buildup_duration: 0.6, - base_swing_duration: 0.08, + melee_constructor: ( + kind: Bash( + damage: 24, + poise: 40, + knockback: 4, + energy_regen: 0, + ), + range: 4.5, + angle: 50.0, + ), + buildup_duration: 0.6, + swing_duration: 0.08, hit_timing: 0.5, - base_recover_duration: 0.6, - forward_movement: 3.5, - damage_kind: Crushing, + recover_duration: 0.6, + movement: ( + swing: Some(Forward(3.5)), + ), + ori_modifier: 0.65, ), ( - stage: 2, - base_damage: 32.0, - damage_increase: 1.5, - base_poise_damage: 40, - poise_damage_increase: 0, - knockback: 16.0, - range: 2.5, - angle: 30.0, - base_buildup_duration: 0.6, - base_swing_duration: 0.25, + melee_constructor: ( + kind: Bash( + damage: 32, + poise: 40, + knockback: 16, + energy_regen: 0, + ), + range: 2.5, + angle: 30.0, + ), + buildup_duration: 0.6, + swing_duration: 0.25, hit_timing: 0.5, - base_recover_duration: 1.2, - forward_movement: 2.0, - damage_kind: Crushing, + recover_duration: 1.2, + movement: ( + swing: Some(Forward(2.0)), + ), + ori_modifier: 0.65, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.65, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/spear/doublestrike.ron b/assets/common/abilities/spear/doublestrike.ron index 3c7f904ae2..76e629d136 100644 --- a/assets/common/abilities/spear/doublestrike.ron +++ b/assets/common/abilities/spear/doublestrike.ron @@ -1,55 +1,57 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 6.5, - damage_increase: 0, - base_poise_damage: 18, - poise_damage_increase: 0, - knockback: 4.0, - range: 2.5, - angle: 15.0, - base_buildup_duration: 0.35, - base_swing_duration: 0.075, + melee_constructor: ( + kind: Stab( + damage: 6.5, + poise: 18, + knockback: 4, + energy_regen: 0, + ), + range: 2.5, + angle: 15.0, + damage_effect: Some(Buff(( + kind: Bleeding, + dur_secs: 10.0, + strength: DamageFraction(0.1), + chance: 0.1, + ))), + ), + buildup_duration: 0.35, + swing_duration: 0.075, hit_timing: 0.5, - base_recover_duration: 0.4, - forward_movement: 0.7, - damage_kind: Piercing, - damage_effect: Some(Buff(( - kind: Bleeding, - dur_secs: 10.0, - strength: DamageFraction(0.1), - chance: 0.1, - ))), + recover_duration: 0.4, + movement: ( + swing: Some(Forward(0.7)), + ), + ori_modifier: 0.75, ), ( - stage: 2, - base_damage: 8.0, - damage_increase: 0, - base_poise_damage: 18, - poise_damage_increase: 0, - knockback: 7.0, - range: 2.5, - angle: 15.0, - base_buildup_duration: 0.5, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Stab( + damage: 8, + poise: 18, + knockback: 7, + energy_regen: 0, + ), + range: 2.5, + angle: 15.0, + damage_effect: Some(Buff(( + kind: Bleeding, + dur_secs: 10.0, + strength: DamageFraction(0.1), + chance: 0.1, + ))), + ), + buildup_duration: 0.5, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.5, - forward_movement: 0.7, - damage_kind: Piercing, - damage_effect: Some(Buff(( - kind: Bleeding, - dur_secs: 10.0, - strength: DamageFraction(0.1), - chance: 0.1, - ))), + recover_duration: 0.5, + movement: ( + swing: Some(Forward(0.7)), + ), + ori_modifier: 0.75, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 3.0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 2, - ori_modifier: 0.75, + energy_cost_per_strike: 0, ) diff --git a/assets/common/abilities/swordsimple/doublestrike.ron b/assets/common/abilities/swordsimple/doublestrike.ron index 34ca8c1f76..d80d9e3a38 100644 --- a/assets/common/abilities/swordsimple/doublestrike.ron +++ b/assets/common/abilities/swordsimple/doublestrike.ron @@ -1,55 +1,57 @@ -ComboMelee( - stage_data: [ +ComboMelee2( + strikes: [ ( - stage: 1, - base_damage: 8.0, - damage_increase: 1.0, - base_poise_damage: 15, - poise_damage_increase: 0, - knockback: 8.0, - range: 3.5, - angle: 50.0, - base_buildup_duration: 0.4, - base_swing_duration: 0.08, + melee_constructor: ( + kind: Slash( + damage: 8, + poise: 15, + knockback: 8, + energy_regen: 0, + ), + range: 3.5, + angle: 50.0, + damage_effect: Some(Buff(( + kind: Bleeding, + dur_secs: 10.0, + strength: DamageFraction(0.1), + chance: 0.1, + ))), + ), + buildup_duration: 0.4, + swing_duration: 0.08, hit_timing: 0.5, - base_recover_duration: 0.5, - forward_movement: 2.5, - damage_kind: Slashing, - damage_effect: Some(Buff(( - kind: Bleeding, - dur_secs: 10.0, - strength: DamageFraction(0.1), - chance: 0.1, - ))), + recover_duration: 0.5, + movement: ( + swing: Some(Forward(2.5)), + ), + ori_modifier: 0.7, ), ( - stage: 2, - base_damage: 10.0, - damage_increase: 1.5, - base_poise_damage: 20, - poise_damage_increase: 0, - knockback: 12.0, - range: 3.5, - angle: 30.0, - base_buildup_duration: 0.7, - base_swing_duration: 0.1, + melee_constructor: ( + kind: Slash( + damage: 10, + poise: 20, + knockback: 12, + energy_regen: 0, + ), + range: 3.5, + angle: 30.0, + damage_effect: Some(Buff(( + kind: Bleeding, + dur_secs: 10.0, + strength: DamageFraction(0.1), + chance: 0.1, + ))), + ), + buildup_duration: 0.7, + swing_duration: 0.1, hit_timing: 0.5, - base_recover_duration: 0.7, - forward_movement: 2.0, - damage_kind: Slashing, - damage_effect: Some(Buff(( - kind: Bleeding, - dur_secs: 10.0, - strength: DamageFraction(0.1), - chance: 0.1, - ))), + recover_duration: 0.7, + movement: ( + swing: Some(Forward(2.0)), + ), + ori_modifier: 0.7, ), ], - initial_energy_gain: 0, - max_energy_gain: 0, - energy_increase: 0, - speed_increase: 0.0, - max_speed_increase: 0.0, - scales_from_combo: 0, - ori_modifier: 0.7, + energy_cost_per_strike: 0, ) diff --git a/assets/common/entity/wild/peaceful/crab.ron b/assets/common/entity/wild/peaceful/crab.ron new file mode 100644 index 0000000000..c3e4d1196f --- /dev/null +++ b/assets/common/entity/wild/peaceful/crab.ron @@ -0,0 +1,11 @@ +#![enable(implicit_some)] +( + name: Automatic, + body: RandomWith("crab"), + alignment: Alignment(Wild), + loot: LootTable("common.loot_tables.creature.crustacean.crab"), + inventory: ( + loadout: FromBody, + ), + meta: [], +) \ No newline at end of file diff --git a/assets/common/items/armor/misc/bag/tiny_leather_pouch.ron b/assets/common/items/armor/misc/bag/tiny_leather_pouch.ron index 9346ae033b..6149d719a0 100644 --- a/assets/common/items/armor/misc/bag/tiny_leather_pouch.ron +++ b/assets/common/items/armor/misc/bag/tiny_leather_pouch.ron @@ -8,7 +8,7 @@ ItemDef( quality: Common, tags: [ Bag, - SalvageInto(Leather, 1), + SalvageInto(Rawhide, 1), ], slots: 6, ) diff --git a/assets/common/items/npc_armor/bird_large/wyvern.ron b/assets/common/items/npc_armor/bird_large/wyvern.ron index fb74ca77b2..5f92d41967 100644 --- a/assets/common/items/npc_armor/bird_large/wyvern.ron +++ b/assets/common/items/npc_armor/bird_large/wyvern.ron @@ -5,7 +5,7 @@ ItemDef( kind: Chest, stats: Direct(( protection: Some(Normal(150.0)), - poise_resilience: Some(Normal(5.0)), + poise_resilience: Some(Normal(25.0)), )), )), quality: Epic, diff --git a/assets/common/items/npc_armor/quadruped_low/dagon.ron b/assets/common/items/npc_armor/quadruped_low/dagon.ron index 52bf5baf17..1c1ebc521d 100644 --- a/assets/common/items/npc_armor/quadruped_low/dagon.ron +++ b/assets/common/items/npc_armor/quadruped_low/dagon.ron @@ -5,7 +5,7 @@ ItemDef( kind: Chest, stats: Direct(( protection: Some(Normal(100.0)), - poise_resilience: Some(Normal(5.0)), + poise_resilience: Some(Normal(25.0)), )), )), quality: Epic, diff --git a/assets/common/items/npc_armor/theropod/rugged.ron b/assets/common/items/npc_armor/theropod/rugged.ron index b6b850b182..003741fe7f 100644 --- a/assets/common/items/npc_armor/theropod/rugged.ron +++ b/assets/common/items/npc_armor/theropod/rugged.ron @@ -5,7 +5,7 @@ ItemDef( kind: Chest, stats: Direct(( protection: Some(Normal(80.0)), - poise_resilience: Some(Normal(0.0)), + poise_resilience: Some(Normal(25.0)), )), )), quality: Moderate, diff --git a/assets/common/items/npc_weapons/unique/crab_pincer.ron b/assets/common/items/npc_weapons/unique/crab_pincer.ron new file mode 100644 index 0000000000..83b24cc10f --- /dev/null +++ b/assets/common/items/npc_weapons/unique/crab_pincer.ron @@ -0,0 +1,20 @@ +ItemDef( + name: "Crab Pincer", + description: "testing123", + kind: Tool(( + kind: Natural, + hands: Two, + stats: ( + equip_time_secs: 0.5, + power: 1.0, + effect_power: 1.0, + speed: 1.0, + range: 1.0, + energy_efficiency: 1.0, + buff_strength: 1.0, + ), + )), + quality: Low, + tags: [], + ability_spec: Some(Custom("Crab")), +) \ No newline at end of file diff --git a/assets/common/loadout/village/captain.ron b/assets/common/loadout/village/captain.ron index aef4a702b9..1851117a51 100644 --- a/assets/common/loadout/village/captain.ron +++ b/assets/common/loadout/village/captain.ron @@ -1,8 +1,12 @@ -// Christmas event -//(1.0, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))), #![enable(implicit_some)] ( - head: Item("common.items.armor.pirate.hat"), + head: Seasonal([ + (Some(Christmas), Choice([ + (1, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))), + (1, Some(Item("common.items.armor.pirate.hat"))) + ])), + (None, Item("common.items.armor.pirate.hat")), + ]), shoulders: Item("common.items.armor.mail.orichalcum.shoulder"), chest: Item("common.items.armor.mail.orichalcum.chest"), gloves: Item("common.items.armor.mail.orichalcum.hand"), diff --git a/assets/common/loadout/village/farmer.ron b/assets/common/loadout/village/farmer.ron index 14f646383a..b466a5a91c 100644 --- a/assets/common/loadout/village/farmer.ron +++ b/assets/common/loadout/village/farmer.ron @@ -1,11 +1,17 @@ -// Christmas event -//(1.0, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))), #![enable(implicit_some)] ( - head: Choice([ - (3, Item("common.items.armor.misc.head.straw")), - (3, Item("common.items.armor.misc.head.bamboo_twig")), - (2, None), + head: Seasonal([ + (Some(Christmas), Choice([ + (9, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))), + (3, Item("common.items.armor.misc.head.straw")), + (3, Item("common.items.armor.misc.head.bamboo_twig")), + (2, None), + ])), + (None, Choice([ + (3, Item("common.items.armor.misc.head.straw")), + (3, Item("common.items.armor.misc.head.bamboo_twig")), + (2, None), + ])), ]), chest: Choice([ (1, Item("common.items.armor.misc.chest.worker_green_0")), diff --git a/assets/common/loadout/village/guard.ron b/assets/common/loadout/village/guard.ron index 172899a959..48ec26276b 100644 --- a/assets/common/loadout/village/guard.ron +++ b/assets/common/loadout/village/guard.ron @@ -1,14 +1,11 @@ -// Christmas event -//(1.0, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))), -// Christmas event -//(1.0, Some(Item("common.items.lantern.blue_0"))), -//(1.0, Some(Item("common.items.lantern.polaris"))), -//(2.0, Some(Item("common.items.lantern.red_0"))), -//(2.0, Some(Item("common.items.lantern.green_0"))), #![enable(implicit_some)] ( - head: Choice([ - (1, Item("common.items.armor.misc.head.helmet")), + head: Seasonal([ + (Some(Christmas), Choice([ + (1, Some(Item("common.items.armor.misc.head.helmet"))), + (1, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))), + ])), + (None, Item("common.items.armor.misc.head.helmet")), ]), shoulders: Item("common.items.armor.leather_plate.shoulder"), chest: Item("common.items.armor.leather_plate.chest"), @@ -16,8 +13,18 @@ belt: Item("common.items.armor.leather_plate.belt"), legs: Item("common.items.armor.leather_plate.pants"), feet: Item("common.items.armor.leather_plate.foot"), - lantern: Choice([ - (1, Item("common.items.lantern.black_0")), - (2, None), - ]), + lantern: Seasonal([ + (Some(Christmas), Choice([ + (1, Some(Item("common.items.lantern.blue_0"))), + (1, Some(Item("common.items.lantern.polaris"))), + (2, Some(Item("common.items.lantern.red_0"))), + (2, Some(Item("common.items.lantern.green_0"))), + (1, Item("common.items.lantern.black_0")), + (2, None), + ])), + (None, Choice([ + (1, Item("common.items.lantern.black_0")), + (2, None), + ])), + ]) ) \ No newline at end of file diff --git a/assets/common/loadout/village/herbalist.ron b/assets/common/loadout/village/herbalist.ron index e41a4f4fdb..bc44de9142 100644 --- a/assets/common/loadout/village/herbalist.ron +++ b/assets/common/loadout/village/herbalist.ron @@ -1,11 +1,17 @@ -// Christmas event -//(1.0, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))), #![enable(implicit_some)] ( - head: Choice([ - (3, Item("common.items.armor.misc.head.straw")), - (3, Item("common.items.armor.misc.head.hood")), - (2, None), + head: Seasonal([ + (Some(Christmas), Choice([ + (9, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))), + (3, Item("common.items.armor.misc.head.straw")), + (3, Item("common.items.armor.misc.head.hood")), + (2, None), + ])), + (None, Choice([ + (3, Item("common.items.armor.misc.head.straw")), + (3, Item("common.items.armor.misc.head.hood")), + (2, None), + ])), ]), chest: Choice([ (1, Item("common.items.armor.twigs.chest")), diff --git a/assets/common/loadout/village/hunter.ron b/assets/common/loadout/village/hunter.ron index 8a4933751d..28031e4f71 100644 --- a/assets/common/loadout/village/hunter.ron +++ b/assets/common/loadout/village/hunter.ron @@ -1,12 +1,19 @@ -// Christmas event -//(1.0, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))), #![enable(implicit_some)] ( - head: Choice([ - (6, None), - (2, Item("common.items.armor.misc.head.straw")), - (3, Item("common.items.armor.misc.head.hood")), - (3, Item("common.items.armor.misc.head.hood_dark")), + head: Seasonal([ + (Some(Christmas), Choice([ + (15, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))), + (6, None), + (2, Item("common.items.armor.misc.head.straw")), + (3, Item("common.items.armor.misc.head.hood")), + (3, Item("common.items.armor.misc.head.hood_dark")), + ])), + (None, Choice([ + (6, None), + (2, Item("common.items.armor.misc.head.straw")), + (3, Item("common.items.armor.misc.head.hood")), + (3, Item("common.items.armor.misc.head.hood_dark")), + ])), ]), chest: Choice([ (1, Item("common.items.armor.hide.leather.chest")), diff --git a/assets/common/loadout/village/mountaineer.ron b/assets/common/loadout/village/mountaineer.ron index 9b4d4fea7c..2fa4aea575 100644 --- a/assets/common/loadout/village/mountaineer.ron +++ b/assets/common/loadout/village/mountaineer.ron @@ -1,10 +1,15 @@ -// Christmas event -//(1.0, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))), #![enable(implicit_some)] ( - head: Choice([ - (1, Item("common.items.armor.misc.head.headband")), - (2, None), + head: Seasonal([ + (Some(Christmas), Choice([ + (3, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))), + (2, None), + (1, Item("common.items.armor.misc.head.headband")), + ])), + (None, Choice([ + (2, None), + (1, Item("common.items.armor.misc.head.headband")), + ])), ]), shoulders: Choice([ (1, Item("common.items.armor.cloth_blue.shoulder_0")), diff --git a/assets/common/loadout/village/villager.ron b/assets/common/loadout/village/villager.ron index a5b4ebb30c..ada4c24d8c 100644 --- a/assets/common/loadout/village/villager.ron +++ b/assets/common/loadout/village/villager.ron @@ -1,10 +1,15 @@ -// Christmas event -//(1.0, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))), #![enable(implicit_some)] ( - head: Choice([ - (1, Item("common.items.armor.misc.head.straw")), - (2, None), + head: Seasonal([ + (Some(Christmas), Choice([ + (3, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))), + (1, Item("common.items.armor.misc.head.straw")), + (2, None), + ])), + (None, Choice([ + (1, Item("common.items.armor.misc.head.straw")), + (2, None), + ])), ]), chest: Choice([ (1, Item("common.items.armor.misc.chest.worker_green_0")), diff --git a/assets/common/loot_tables/creature/crustacean/crab.ron b/assets/common/loot_tables/creature/crustacean/crab.ron new file mode 100644 index 0000000000..85c669f0e4 --- /dev/null +++ b/assets/common/loot_tables/creature/crustacean/crab.ron @@ -0,0 +1,5 @@ +[ + (2.0, Nothing), + (1.0, Item("common.items.crafting_ing.animal_misc.viscous_ooze")), + (1.0, Item("common.items.crafting_ing.animal_misc.strong_pincer")), +] \ No newline at end of file diff --git a/assets/common/loot_tables/creature/quad_medium/mammoth.ron b/assets/common/loot_tables/creature/quad_medium/mammoth.ron index 124b10b7aa..3ee6b12510 100644 --- a/assets/common/loot_tables/creature/quad_medium/mammoth.ron +++ b/assets/common/loot_tables/creature/quad_medium/mammoth.ron @@ -1,6 +1,6 @@ [ (1, All([ - MultiDrop(Item("common.items.crafting_ing.hide.rugged_hide"), 0, 3), + MultiDrop(Item("common.items.crafting_ing.hide.rugged_hide"), 0, 1), MultiDrop(Item("common.items.crafting_ing.animal_misc.long_tusk"), 0, 2), ], )), diff --git a/assets/common/loot_tables/creature/quad_medium/ngoubou.ron b/assets/common/loot_tables/creature/quad_medium/ngoubou.ron index 5b71ebe8b7..14a37401fe 100644 --- a/assets/common/loot_tables/creature/quad_medium/ngoubou.ron +++ b/assets/common/loot_tables/creature/quad_medium/ngoubou.ron @@ -1,6 +1,6 @@ [ (1, All([ - MultiDrop(Item("common.items.crafting_ing.hide.rugged_hide"), 0, 3), + MultiDrop(Item("common.items.crafting_ing.hide.rugged_hide"), 0, 1), MultiDrop(Item("common.items.crafting_ing.animal_misc.large_horn"), 0, 2), MultiDrop(Item("common.items.crafting_ing.animal_misc.long_tusk"), 0, 2), ], diff --git a/assets/common/material_stats_manifest.ron b/assets/common/material_stats_manifest.ron index c95995aae6..42eb5d6a69 100644 --- a/assets/common/material_stats_manifest.ron +++ b/assets/common/material_stats_manifest.ron @@ -127,11 +127,11 @@ poise_resilience: Some(Normal(30.0)), ), "Cobalt": ( - protection: Some(Normal(122.0)), + protection: Some(Normal(132.0)), poise_resilience: Some(Normal(40.0)), ), "Bloodsteel": ( - protection: Some(Normal(146.0)), + protection: Some(Normal(156.0)), poise_resilience: Some(Normal(50.0)), ), "Orichalcum": ( diff --git a/assets/common/npc_names.ron b/assets/common/npc_names.ron index 6516ea1b79..c35b0dd555 100644 --- a/assets/common/npc_names.ron +++ b/assets/common/npc_names.ron @@ -1417,4 +1417,16 @@ ), ) ), + crustacean: ( + body: ( + keyword: "crustacean", + names_0: ["Ferris"], + ), + species: ( + crab: ( + keyword: "crab", + generic: "Crab", + ), + ) + ), ) diff --git a/assets/common/trading/item_price_calculation.ron b/assets/common/trading/item_price_calculation.ron index c94f067c0a..eac06b1278 100644 --- a/assets/common/trading/item_price_calculation.ron +++ b/assets/common/trading/item_price_calculation.ron @@ -16,7 +16,7 @@ loot_tables: [ // Ingredients (72.5, true, "common.trading.sellable_materials"), - (1.7205, false, "common.trading.unsellable_materials"), + (2.774, false, "common.trading.unsellable_materials"), // Food Ingredients (20.375, true, "common.trading.food"), diff --git a/assets/common/trading/unsellable_materials.ron b/assets/common/trading/unsellable_materials.ron index c6ba439a81..0e975388c2 100644 --- a/assets/common/trading/unsellable_materials.ron +++ b/assets/common/trading/unsellable_materials.ron @@ -37,6 +37,11 @@ (0.15, Item("common.items.crafting_ing.animal_misc.lively_vine")), (0.225, Item("common.items.crafting_ing.sticky_thread")), + // Miscellaneous Materials + (0.75, Item("common.items.crafting_ing.resin")), + (1.0, Item("common.items.crafting_ing.sentient_seed")), + (2.0, Item("common.items.crafting_ing.living_embers")), + // Ultra Rare drops (0.0005, Item("common.items.crafting_ing.mindflayer_bag_damaged")), ] diff --git a/assets/voxygen/audio/calendar/christmas/soundtrack.ron b/assets/voxygen/audio/calendar/christmas/soundtrack.ron index ead126e9a8..88aef1d681 100644 --- a/assets/voxygen/audio/calendar/christmas/soundtrack.ron +++ b/assets/voxygen/audio/calendar/christmas/soundtrack.ron @@ -307,6 +307,19 @@ // Dungeon music + Individual(( + title: "A Heart's Ice-Cold Protection", + path: "voxygen.audio.soundtrack.dungeon.a_hearts_ice-cold_protection", + length: 205.0, + timing: None, + weather: None, + biomes:[], + sites: [ + Dungeon(Adlet), + ], + music_state: Activity(Explore), + artist: ("GeekyGami", "https://geekygami.newgrounds.com/audio/"), + )), Individual(( title: "Mysty Temple", path: "voxygen.audio.soundtrack.dungeon.mysty_temple", @@ -316,6 +329,7 @@ biomes:[], sites: [ Dungeon(Old), + Dungeon(Adlet), ], music_state: Activity(Explore), artist: ("Tiny", None), @@ -342,6 +356,7 @@ biomes: [], sites: [ Dungeon(Old), + Dungeon(Adlet), ], music_state: Activity(Explore), artist: ("Aeronic", "https://soundcloud.com/aeronic"), @@ -355,6 +370,7 @@ biomes: [], sites: [ Dungeon(Old), + Dungeon(Adlet), ], music_state: Activity(Explore), artist: ("Aeronic", "https://soundcloud.com/aeronic"), @@ -436,8 +452,8 @@ Dungeon(Old), ], segments: [ - ("voxygen.audio.soundtrack.combat.barred_paths.barred_paths-start", 56.0, Transition(Explore, Combat(High)), Some(Combat(High))), - ("voxygen.audio.soundtrack.combat.barred_paths.barred_paths-loop", 54.0, Activity(Combat(High)), None), + ("voxygen.audio.soundtrack.combat.barred_paths.barred_paths-start", 61.818, Transition(Explore, Combat(High)), Some(Combat(High))), + ("voxygen.audio.soundtrack.combat.barred_paths.barred_paths-loop", 54.545, Activity(Combat(High)), None), ("voxygen.audio.soundtrack.combat.barred_paths.barred_paths-end", 6.0, Transition(Combat(High), Explore), None), ], artist: ("DaforLynx", "https://daforlynx.neocities.org/"), @@ -451,14 +467,14 @@ Dungeon(Old), ], segments: [ - ("voxygen.audio.soundtrack.combat.reversal.reversal-start", 60.0, Transition(Explore, Combat(High)), Some(Combat(High))), + ("voxygen.audio.soundtrack.combat.reversal.reversal-start", 61.666, Transition(Explore, Combat(High)), Some(Combat(High))), ("voxygen.audio.soundtrack.combat.reversal.reversal-loop", 60.0, Activity(Combat(High)), None), - ("voxygen.audio.soundtrack.combat.reversal.reversal-end", 4.0, Transition(Combat(High), Explore), None), + ("voxygen.audio.soundtrack.combat.reversal.reversal-end", 3.666, Transition(Combat(High), Explore), None), ], artist: ("DaforLynx", "https://daforlynx.neocities.org/"), ), Segmented( - title: "Valiant Voxels", + title: "Clash", timing: None, weather: None, biomes: [], @@ -466,11 +482,11 @@ Dungeon(Old), ], segments: [ - ("voxygen.audio.soundtrack.combat.valiant_voxels.valiant_voxels-start", 7.846, Transition(Explore, Combat(High)), Some(Combat(High))), - ("voxygen.audio.soundtrack.combat.valiant_voxels.valiant_voxels-loop", 59.126, Activity(Combat(High)), None), - ("voxygen.audio.soundtrack.combat.valiant_voxels.valiant_voxels-end", 5.49, Transition(Combat(High), Explore), None), + ("voxygen.audio.soundtrack.combat.clash.clash-start", 121.5, Transition(Explore, Combat(High)), Some(Combat(High))), + ("voxygen.audio.soundtrack.combat.clash.clash-loop", 81.0, Activity(Combat(High)), None), + ("voxygen.audio.soundtrack.combat.clash.clash-end", 1.5, Transition(Combat(High), Explore), None), ], - artist: ("Seventh Sam", "https://seventhsam.com/"), + artist: ("Alfredo Pompa D & Rodriogo Plata", None), ), ] ) \ No newline at end of file diff --git a/assets/voxygen/audio/calendar/halloween/soundtrack.ron b/assets/voxygen/audio/calendar/halloween/soundtrack.ron index 5b33dcfec8..526b83e19b 100644 --- a/assets/voxygen/audio/calendar/halloween/soundtrack.ron +++ b/assets/voxygen/audio/calendar/halloween/soundtrack.ron @@ -165,6 +165,19 @@ // Dungeon music + Individual(( + title: "A Heart's Ice-Cold Protection", + path: "voxygen.audio.soundtrack.dungeon.a_hearts_ice-cold_protection", + length: 205.0, + timing: None, + weather: None, + biomes:[], + sites: [ + Dungeon(Adlet), + ], + music_state: Activity(Explore), + artist: ("GeekyGami", "https://geekygami.newgrounds.com/audio/"), + )), Individual(( title: "Mysty Temple", path: "voxygen.audio.soundtrack.dungeon.mysty_temple", @@ -174,6 +187,7 @@ biomes:[], sites: [ Dungeon(Old), + Dungeon(Adlet), ], music_state: Activity(Explore), artist: ("Tiny", None), @@ -200,6 +214,7 @@ biomes: [], sites: [ Dungeon(Old), + Dungeon(Adlet), ], music_state: Activity(Explore), artist: ("Aeronic", "https://soundcloud.com/aeronic"), @@ -213,6 +228,7 @@ biomes: [], sites: [ Dungeon(Old), + Dungeon(Adlet), ], music_state: Activity(Explore), artist: ("Aeronic", "https://soundcloud.com/aeronic"), @@ -294,8 +310,8 @@ Dungeon(Old), ], segments: [ - ("voxygen.audio.soundtrack.combat.barred_paths.barred_paths-start", 56.0, Transition(Explore, Combat(High)), Some(Combat(High))), - ("voxygen.audio.soundtrack.combat.barred_paths.barred_paths-loop", 54.0, Activity(Combat(High)), None), + ("voxygen.audio.soundtrack.combat.barred_paths.barred_paths-start", 61.818, Transition(Explore, Combat(High)), Some(Combat(High))), + ("voxygen.audio.soundtrack.combat.barred_paths.barred_paths-loop", 54.545, Activity(Combat(High)), None), ("voxygen.audio.soundtrack.combat.barred_paths.barred_paths-end", 6.0, Transition(Combat(High), Explore), None), ], artist: ("DaforLynx", "https://daforlynx.neocities.org/"), @@ -309,11 +325,26 @@ Dungeon(Old), ], segments: [ - ("voxygen.audio.soundtrack.combat.reversal.reversal-start", 60.0, Transition(Explore, Combat(High)), Some(Combat(High))), + ("voxygen.audio.soundtrack.combat.reversal.reversal-start", 61.666, Transition(Explore, Combat(High)), Some(Combat(High))), ("voxygen.audio.soundtrack.combat.reversal.reversal-loop", 60.0, Activity(Combat(High)), None), - ("voxygen.audio.soundtrack.combat.reversal.reversal-end", 4.0, Transition(Combat(High), Explore), None), + ("voxygen.audio.soundtrack.combat.reversal.reversal-end", 3.666, Transition(Combat(High), Explore), None), ], artist: ("DaforLynx", "https://daforlynx.neocities.org/"), ), + Segmented( + title: "Clash", + timing: None, + weather: None, + biomes: [], + sites: [ + Dungeon(Old), + ], + segments: [ + ("voxygen.audio.soundtrack.combat.clash.clash-start", 121.5, Transition(Explore, Combat(High)), Some(Combat(High))), + ("voxygen.audio.soundtrack.combat.clash.clash-loop", 81.0, Activity(Combat(High)), None), + ("voxygen.audio.soundtrack.combat.clash.clash-end", 1.5, Transition(Combat(High), Explore), None), + ], + artist: ("Alfredo Pompa D & Rodriogo Plata", None), + ), ] ) \ No newline at end of file diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index 86289a130b..893fee2c16 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -397,27 +397,6 @@ threshold: 0.7, subtitle: "subtitle-hammer-attack", ), - Attack(ComboMelee(Action, 1), Sword): ( - files: [ - "voxygen.audio.sfx.abilities.swing_sword", - ], - threshold: 0.7, - subtitle: "subtitle-sword_attack", - ), - Attack(ComboMelee(Action, 2), Sword): ( - files: [ - "voxygen.audio.sfx.abilities.separated_second_swing", - ], - threshold: 0.7, - subtitle: "subtitle-sword_attack", - ), - Attack(ComboMelee(Action, 3), Sword): ( - files: [ - "voxygen.audio.sfx.abilities.separated_third_swing", - ], - threshold: 0.7, - subtitle: "subtitle-sword_attack", - ), Inventory(CollectedTool(Sword)): ( files: [ "voxygen.audio.sfx.inventory.pickup_sword", @@ -443,7 +422,7 @@ threshold: 0.5, subtitle: "subtitle-unwield_hammer", ), - Attack(ComboMelee(Action, 1), Hammer): ( + Attack(ComboMeleeDeprecated(Action, 1), Hammer): ( files: [ "voxygen.audio.sfx.abilities.swing", ], @@ -489,20 +468,6 @@ threshold: 0.5, subtitle: "subtitle-unwield_axe", ), - Attack(ComboMelee(Action, 1), Axe): ( - files: [ - "voxygen.audio.sfx.abilities.swing", - ], - threshold: 0.7, - subtitle: "subtitle-axe_attack", - ), - Attack(ComboMelee(Action, 2), Axe): ( - files: [ - "voxygen.audio.sfx.abilities.swing", - ], - threshold: 0.7, - subtitle: "subtitle-axe_attack", - ), Attack(RapidMelee(Action), Axe): ( files: [ "voxygen.audio.sfx.abilities.swing", @@ -549,13 +514,6 @@ threshold: 0.5, subtitle: "subtitle-unwield_staff", ), - Attack(BasicBeam, Staff): ( - files: [ - "voxygen.audio.sfx.abilities.flame_thrower", - ], - threshold: 0.2, - subtitle: "subtitle-staff_attack", - ), //Attack(BasicRanged, Staff): ( // files: [ // "voxygen.audio.sfx.abilities.staff_channeling", diff --git a/assets/voxygen/audio/soundtrack.ron b/assets/voxygen/audio/soundtrack.ron index 023f2eab02..8ebbca0ce1 100644 --- a/assets/voxygen/audio/soundtrack.ron +++ b/assets/voxygen/audio/soundtrack.ron @@ -16,6 +16,20 @@ // Overworld exploration tracks + Individual(( + title: "Graceful Journey", + path: "voxygen.audio.soundtrack.overworld.graceful_journey", + length: 240.0, + timing: Day, + weather: None, + biomes: [ + (Lake, 1), + (Grassland, 1), + ], + sites: [Void], + music_state: Activity(Explore), + artist: ("Tobias Thy - (Thy SFX)", "https://soundcloud.com/thyofficial"), + )), Individual(( title: "A Cold Breeze Blows", path: "voxygen.audio.soundtrack.overworld.a_cold_breeze_blows", @@ -744,6 +758,19 @@ // Dungeon music + Individual(( + title: "A Heart's Ice-Cold Protection", + path: "voxygen.audio.soundtrack.dungeon.a_hearts_ice-cold_protection", + length: 205.0, + timing: None, + weather: None, + biomes:[], + sites: [ + Dungeon(Adlet), + ], + music_state: Activity(Explore), + artist: ("GeekyGami", "https://geekygami.newgrounds.com/audio/"), + )), Individual(( title: "Mysty Temple", path: "voxygen.audio.soundtrack.dungeon.mysty_temple", @@ -753,6 +780,7 @@ biomes:[], sites: [ Dungeon(Old), + Dungeon(Adlet), ], music_state: Activity(Explore), artist: ("Tiny", None), @@ -779,6 +807,7 @@ biomes: [], sites: [ Dungeon(Old), + Dungeon(Adlet), ], music_state: Activity(Explore), artist: ("Aeronic", "https://soundcloud.com/aeronic"), @@ -792,6 +821,7 @@ biomes: [], sites: [ Dungeon(Old), + Dungeon(Adlet), ], music_state: Activity(Explore), artist: ("Aeronic", "https://soundcloud.com/aeronic"), @@ -873,8 +903,8 @@ Dungeon(Old), ], segments: [ - ("voxygen.audio.soundtrack.combat.barred_paths.barred_paths-start", 56.0, Transition(Explore, Combat(High)), Some(Combat(High))), - ("voxygen.audio.soundtrack.combat.barred_paths.barred_paths-loop", 54.0, Activity(Combat(High)), None), + ("voxygen.audio.soundtrack.combat.barred_paths.barred_paths-start", 61.818, Transition(Explore, Combat(High)), Some(Combat(High))), + ("voxygen.audio.soundtrack.combat.barred_paths.barred_paths-loop", 54.545, Activity(Combat(High)), None), ("voxygen.audio.soundtrack.combat.barred_paths.barred_paths-end", 6.0, Transition(Combat(High), Explore), None), ], artist: ("DaforLynx", "https://daforlynx.neocities.org/"), @@ -888,11 +918,26 @@ Dungeon(Old), ], segments: [ - ("voxygen.audio.soundtrack.combat.reversal.reversal-start", 60.0, Transition(Explore, Combat(High)), Some(Combat(High))), + ("voxygen.audio.soundtrack.combat.reversal.reversal-start", 61.666, Transition(Explore, Combat(High)), Some(Combat(High))), ("voxygen.audio.soundtrack.combat.reversal.reversal-loop", 60.0, Activity(Combat(High)), None), - ("voxygen.audio.soundtrack.combat.reversal.reversal-end", 4.0, Transition(Combat(High), Explore), None), + ("voxygen.audio.soundtrack.combat.reversal.reversal-end", 3.666, Transition(Combat(High), Explore), None), ], artist: ("DaforLynx", "https://daforlynx.neocities.org/"), ), + Segmented( + title: "Clash", + timing: None, + weather: None, + biomes: [], + sites: [ + Dungeon(Old), + ], + segments: [ + ("voxygen.audio.soundtrack.combat.clash.clash-start", 121.5, Transition(Explore, Combat(High)), Some(Combat(High))), + ("voxygen.audio.soundtrack.combat.clash.clash-loop", 81.0, Activity(Combat(High)), None), + ("voxygen.audio.soundtrack.combat.clash.clash-end", 1.5, Transition(Combat(High), Explore), None), + ], + artist: ("Alfredo Pompa D & Rodriogo Plata", None), + ), ] ) diff --git a/assets/voxygen/audio/soundtrack/combat/barred_paths/barred_paths-end.ogg b/assets/voxygen/audio/soundtrack/combat/barred_paths/barred_paths-end.ogg index e37ec3d725..c56b2b3388 100644 --- a/assets/voxygen/audio/soundtrack/combat/barred_paths/barred_paths-end.ogg +++ b/assets/voxygen/audio/soundtrack/combat/barred_paths/barred_paths-end.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f5c8599fc233c297c38007171b7dd6f69aca672fa35e4b19b5302321f2322589 -size 120714 +oid sha256:06cc579f22b2a4c936d6c1f18568baa38be7c4bbef2dba68198ec369bb5236e3 +size 108695 diff --git a/assets/voxygen/audio/soundtrack/combat/barred_paths/barred_paths-loop.ogg b/assets/voxygen/audio/soundtrack/combat/barred_paths/barred_paths-loop.ogg index 9633b51d0d..b1b069676f 100644 --- a/assets/voxygen/audio/soundtrack/combat/barred_paths/barred_paths-loop.ogg +++ b/assets/voxygen/audio/soundtrack/combat/barred_paths/barred_paths-loop.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1cce1fa94fa5c0ccb00e5395ece57efd4a790e5ae9fe62e5bbfca83ab50a19bf -size 943627 +oid sha256:0e2e93bb20dc3e8385ff28e9f52d2b846716ed696bf96ff4a582932bb7281432 +size 1135031 diff --git a/assets/voxygen/audio/soundtrack/combat/barred_paths/barred_paths-start.ogg b/assets/voxygen/audio/soundtrack/combat/barred_paths/barred_paths-start.ogg index 0660e81960..0892ea73a0 100644 --- a/assets/voxygen/audio/soundtrack/combat/barred_paths/barred_paths-start.ogg +++ b/assets/voxygen/audio/soundtrack/combat/barred_paths/barred_paths-start.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fbc1d7abca1f39d8bdf5357c3b200ab690707dab922ee1cfd664e516ba26a420 -size 964398 +oid sha256:1cb04992aba1daf08d06737fcaee628dff8c933b0371dac85161fedfae8e625a +size 1269890 diff --git a/assets/voxygen/audio/soundtrack/combat/clash/clash-end.ogg b/assets/voxygen/audio/soundtrack/combat/clash/clash-end.ogg new file mode 100644 index 0000000000..49b8e51068 --- /dev/null +++ b/assets/voxygen/audio/soundtrack/combat/clash/clash-end.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c81b21c7fb02f0abbf59a1ec726518b8fe71fa7a5e17041e07486ae2f7e36717 +size 84147 diff --git a/assets/voxygen/audio/soundtrack/combat/clash/clash-loop.ogg b/assets/voxygen/audio/soundtrack/combat/clash/clash-loop.ogg new file mode 100644 index 0000000000..ff6ed2ad4e --- /dev/null +++ b/assets/voxygen/audio/soundtrack/combat/clash/clash-loop.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9c15dfa6c62d15306d5c7d8b579099676d9f6f0d577bdbbd8e67b71805f034c2 +size 4625703 diff --git a/assets/voxygen/audio/soundtrack/combat/clash/clash-start.ogg b/assets/voxygen/audio/soundtrack/combat/clash/clash-start.ogg new file mode 100644 index 0000000000..3a1526e9cb --- /dev/null +++ b/assets/voxygen/audio/soundtrack/combat/clash/clash-start.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6b563dec0b4ab2ffd0b19d638e07270c9a3841db72f90ebccf17fc6a853fa924 +size 6881122 diff --git a/assets/voxygen/audio/soundtrack/combat/reversal/reversal-end.ogg b/assets/voxygen/audio/soundtrack/combat/reversal/reversal-end.ogg index 24d16db2da..e667c9db8e 100644 --- a/assets/voxygen/audio/soundtrack/combat/reversal/reversal-end.ogg +++ b/assets/voxygen/audio/soundtrack/combat/reversal/reversal-end.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:87e520774165f100cdb518d02d30813d32cb0972ffdc64721864527dfbf8cf8f -size 74003 +oid sha256:65320e821bf0885073fa6d85de32e75f0cc3959cf01f92b31183061dc807c464 +size 76296 diff --git a/assets/voxygen/audio/soundtrack/combat/reversal/reversal-loop.ogg b/assets/voxygen/audio/soundtrack/combat/reversal/reversal-loop.ogg index cc21c059bc..01802a29f0 100644 --- a/assets/voxygen/audio/soundtrack/combat/reversal/reversal-loop.ogg +++ b/assets/voxygen/audio/soundtrack/combat/reversal/reversal-loop.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7c3d57aef0e7d2d3d09cad432d2842a31b50ebe4c66a6bc00cb851463f240029 -size 1207268 +oid sha256:a9288aeb3c2e22f949654e76df2d8b8199cb1a6065e290095b0c5c8ed6d4ef9e +size 1237788 diff --git a/assets/voxygen/audio/soundtrack/combat/reversal/reversal-start.ogg b/assets/voxygen/audio/soundtrack/combat/reversal/reversal-start.ogg index c29dcb2a01..016522f90c 100644 --- a/assets/voxygen/audio/soundtrack/combat/reversal/reversal-start.ogg +++ b/assets/voxygen/audio/soundtrack/combat/reversal/reversal-start.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8895e472f2d1f6379afef7e2a220278b31c06beacdcd3d8c7bba588c4b6a6ff6 -size 1196913 +oid sha256:0092e0a19117895ff1b2f89901349890f46d035c98d2bb70e10fe90a25b369d0 +size 1274056 diff --git a/assets/voxygen/audio/soundtrack/dungeon/a_hearts_ice-cold_protection.ogg b/assets/voxygen/audio/soundtrack/dungeon/a_hearts_ice-cold_protection.ogg new file mode 100644 index 0000000000..e7d9512630 --- /dev/null +++ b/assets/voxygen/audio/soundtrack/dungeon/a_hearts_ice-cold_protection.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:28543be4d93d52510911e69dc00b66496bb6e136c1abce34f918ab47dfb33bb8 +size 4163325 diff --git a/assets/voxygen/audio/soundtrack/overworld/graceful_journey.ogg b/assets/voxygen/audio/soundtrack/overworld/graceful_journey.ogg new file mode 100644 index 0000000000..f76d865b77 --- /dev/null +++ b/assets/voxygen/audio/soundtrack/overworld/graceful_journey.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:68eb2b8efacb2f7413d7ee23f57c37940eec52290da5885a4b34d5daca8757c2 +size 3798458 diff --git a/assets/voxygen/i18n/en/gameinput.ftl b/assets/voxygen/i18n/en/gameinput.ftl index 8c6527660b..e3de56ea0e 100644 --- a/assets/voxygen/i18n/en/gameinput.ftl +++ b/assets/voxygen/i18n/en/gameinput.ftl @@ -75,3 +75,4 @@ gameinput-muteinactivemaster = Mute master volume (inactive window) gameinput-mutemusic = Mute music volume gameinput-mutesfx = Mute SFX volume gameinput-muteambience = Mute ambience volume +gameinput-togglewalk = Toggle Walking diff --git a/assets/voxygen/i18n/en/hud/misc.ftl b/assets/voxygen/i18n/en/hud/misc.ftl index 7f5b51943e..e1307e867e 100644 --- a/assets/voxygen/i18n/en/hud/misc.ftl +++ b/assets/voxygen/i18n/en/hud/misc.ftl @@ -59,6 +59,7 @@ hud-follow = Follow hud-stay= Stay hud-sit = Sit hud-steer = Steer +hud-lay = Lay hud-portal = Portal -server = Server diff --git a/assets/voxygen/i18n/en/hud/settings.ftl b/assets/voxygen/i18n/en/hud/settings.ftl index 92befd432e..fc2ec20847 100644 --- a/assets/voxygen/i18n/en/hud/settings.ftl +++ b/assets/voxygen/i18n/en/hud/settings.ftl @@ -53,6 +53,8 @@ hud-settings-invert_controller_y_axis = Invert Controller Y Axis hud-settings-enable_mouse_smoothing = Camera Smoothing hud-settings-free_look_behavior = Free look behavior hud-settings-auto_walk_behavior = Auto walk behavior +hud-settings-walking_speed_behavior = Walking speed behavior +hud-settings-walking_speed = Walking speed hud-settings-camera_clamp_behavior = Camera clamp behavior hud-settings-zoom_lock_behavior = Camera zoom lock behavior hud-settings-player_physics_behavior = Player physics (experimental) diff --git a/assets/voxygen/i18n/en/main.ftl b/assets/voxygen/i18n/en/main.ftl index 7c7ef8a1c8..bb137293ff 100644 --- a/assets/voxygen/i18n/en/main.ftl +++ b/assets/voxygen/i18n/en/main.ftl @@ -7,30 +7,30 @@ main-tip = Tip: main-unbound_key_tip = unbound main-notice = Welcome to the alpha version of Veloren! - + Before you dive into the fun, please keep a few things in mind: - + - This is a very early alpha. Expect bugs, extremely unfinished gameplay, unpolished mechanics, and missing features. - + - If you have constructive feedback or bug reports, you can contact us via Reddit, GitLab, or our community Discord server. - + - Veloren is licensed under the GPL 3 open-source licence. That means you're free to play, modify, and redistribute the game however you wish (provided derived work is also under GPL 3). - + - Veloren is a non-profit community project, and everybody working on it is a volunteer. If you like what you see, you're welcome to join the development or art teams! - + Thanks for taking the time to read this notice, we hope you enjoy the game! - + ~ The Veloren Devs main-login_process = Information on the Login Process: - + Please note that you need an account to play on auth-enabled servers. - + You can create an account over at - + https://veloren.net/account/. main-singleplayer-new = New main-singleplayer-delete = Delete @@ -38,6 +38,7 @@ main-singleplayer-regenerate = Regenerate main-singleplayer-create_custom = Create Custom main-singleplayer-invalid_name = Error: Invalid name main-singleplayer-seed = Seed +main-singleplayer-day_length = Day duration main-singleplayer-random_seed = Random main-singleplayer-size_lg = Logarithmic size main-singleplayer-map_large_warning = Warning: Large worlds will take a long time to start for the first time diff --git a/assets/voxygen/shaders/premultiply-alpha-vert.glsl b/assets/voxygen/shaders/premultiply-alpha-vert.glsl index 646582ee3f..e8737f9e9b 100644 --- a/assets/voxygen/shaders/premultiply-alpha-vert.glsl +++ b/assets/voxygen/shaders/premultiply-alpha-vert.glsl @@ -13,17 +13,14 @@ layout(push_constant) uniform Params { layout(location = 0) out vec2 source_coords; -uvec2 unpack(uint xy) { - return uvec2( - bitfieldExtract(xy, 0, 16), - bitfieldExtract(xy, 16, 16) - ); +vec2 unpack(uint xy) { + return vec2(xy & 0xFFFF, (xy >> 16) & 0xFFFF); } void main() { - vec2 source_size = vec2(unpack(source_size_xy)); - vec2 target_offset = vec2(unpack(target_offset_xy)); - vec2 target_size = vec2(unpack(target_size_xy)); + vec2 source_size = unpack(source_size_xy); + vec2 target_offset = unpack(target_offset_xy); + vec2 target_size = unpack(target_size_xy); // Generate rectangle (counter clockwise triangles) // diff --git a/assets/voxygen/voxel/armor/brinestone/crown.vox b/assets/voxygen/voxel/armor/brinestone/crown.vox index 8facc874bc..d9708b69ba 100644 --- a/assets/voxygen/voxel/armor/brinestone/crown.vox +++ b/assets/voxygen/voxel/armor/brinestone/crown.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d61e8ad288a06476fe5192ddd68168e8c42b531545441281f166863cc0f5715f +oid sha256:e94494383f9ca214910e6b5ca28475f57b5afd35831d5c9332670bebfcc454a9 size 2104 diff --git a/assets/voxygen/voxel/armor/cardinal/mitre.vox b/assets/voxygen/voxel/armor/cardinal/mitre.vox index 072021fb08..7dc2e02277 100644 --- a/assets/voxygen/voxel/armor/cardinal/mitre.vox +++ b/assets/voxygen/voxel/armor/cardinal/mitre.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e9f0d30ec87211eacc1ba59fe69c87c73a1bbb52e38cdb43c38ef5c4971f2f8a -size 35676 +oid sha256:d3f10f13fd283cb7c1d79ed9e8107dead9e2a45c56bb09ff8ea70aba47a843eb +size 12932 diff --git a/assets/voxygen/voxel/armor/misc/head/crown.vox b/assets/voxygen/voxel/armor/misc/head/crown.vox index ef7ad72e02..a21c49b7dd 100644 --- a/assets/voxygen/voxel/armor/misc/head/crown.vox +++ b/assets/voxygen/voxel/armor/misc/head/crown.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4642ed18f4e43058dd4d0d0c9aadb40a6376eb332a9a453f2d20c00a6e193f7b -size 8600 +oid sha256:41a45fccca5625f8484fa103ff79a0b432648fe1edbe019eb15a5ed492b15467 +size 8928 diff --git a/assets/voxygen/voxel/armor/misc/head/hood.vox b/assets/voxygen/voxel/armor/misc/head/hood.vox index 2b1155b982..b62c759db8 100644 --- a/assets/voxygen/voxel/armor/misc/head/hood.vox +++ b/assets/voxygen/voxel/armor/misc/head/hood.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ee6d90525115d07044671e6aa28b48a56316db1354b95d66ad0874b888864bbc -size 14512 +oid sha256:bb4069c0b4857d894e7d96784bbd5e425da6a8ef13338d0cb37fc3b4c912adfa +size 16912 diff --git a/assets/voxygen/voxel/crustacean_central_manifest.ron b/assets/voxygen/voxel/crustacean_central_manifest.ron new file mode 100644 index 0000000000..a9630ff6f3 --- /dev/null +++ b/assets/voxygen/voxel/crustacean_central_manifest.ron @@ -0,0 +1,30 @@ +({ + (Crab, Male): ( + chest: ( + offset: (-5.0, -4.5, 2.0), + central: ("npc.crab.crab"), + ), + tail_f: ( + offset: (0.0, 0.0, 0.0), + central: ("armor.empty"), + ), + tail_b: ( + offset: (0.0, 0.0, 0.0), + central: ("armor.empty"), + ), + ), + (Crab, Female): ( + chest: ( + offset: (-5.0, -4.5, 2.0), + central: ("npc.crab.crab"), + ), + tail_f: ( + offset: (0.0, 0.0, 0.0), + central: ("armor.empty"), + ), + tail_b: ( + offset: (0.0, 0.0, 0.0), + central: ("armor.empty"), + ), + ), +}) \ No newline at end of file diff --git a/assets/voxygen/voxel/crustacean_lateral_manifest.ron b/assets/voxygen/voxel/crustacean_lateral_manifest.ron new file mode 100644 index 0000000000..91cd03c18f --- /dev/null +++ b/assets/voxygen/voxel/crustacean_lateral_manifest.ron @@ -0,0 +1,127 @@ + +({ + (Crab, Male): ( + arm_l: ( + offset: (-6.0, 0.5, 2.0), + lateral: ("npc.crab.crab"), + model_index: 1, + ), + pincer_l0: ( + offset: (-9.0, 2.5, 1.0), + lateral: ("npc.crab.crab"), + model_index: 5, + ), + pincer_l1: ( + offset: (-5.0, 4.5, 2.0), + lateral: ("npc.crab.crab"), + model_index: 6, + ), + arm_r: ( + offset: (3.0, 0.5, 2.0), + lateral: ("npc.crab.crab"), + model_index: 1, + ), + pincer_r0: ( + offset: (2.0, 2.5, 1.0), + lateral: ("npc.crab.crab"), + model_index: 5, + ), + pincer_r1: ( + offset: (2.0, 4.5, 2.0), + lateral: ("npc.crab.crab"), + model_index: 6, + ), + leg_fl: ( + offset: (-8.5, -2.5, 0.0), + lateral: ("npc.crab.crab"), + model_index: 4, + ), + leg_cl: ( + offset: (-8.5, -2.5, 0.0), + lateral: ("npc.crab.crab"), + model_index: 3, + ), + leg_bl: ( + offset: (-7.5, -3.0, 0.0), + lateral: ("npc.crab.crab"), + model_index: 2, + ), + leg_fr: ( + offset: (3.5, -2.5, 0.0), + lateral: ("npc.crab.crab"), + model_index: 4, + ), + leg_cr: ( + offset: (3.5, -2.5, 0.0), + lateral: ("npc.crab.crab"), + model_index: 3, + ), + leg_br: ( + offset: (2.5, -3.0, 0.0), + lateral: ("npc.crab.crab"), + model_index: 2, + ), + ), + (Crab, Female): ( + arm_l: ( + offset: (-6.0, 0.5, 2.0), + lateral: ("npc.crab.crab"), + model_index: 1, + ), + pincer_l0: ( + offset: (-9.0, 2.5, 1.0), + lateral: ("npc.crab.crab"), + model_index: 5, + ), + pincer_l1: ( + offset: (-5.0, 4.5, 2.0), + lateral: ("npc.crab.crab"), + model_index: 6, + ), + arm_r: ( + offset: (3.0, 0.5, 2.0), + lateral: ("npc.crab.crab"), + model_index: 1, + ), + pincer_r0: ( + offset: (2.0, 2.5, 1.0), + lateral: ("npc.crab.crab"), + model_index: 5, + ), + pincer_r1: ( + offset: (2.0, 4.5, 2.0), + lateral: ("npc.crab.crab"), + model_index: 6, + ), + leg_fl: ( + offset: (-8.5, -2.5, 0.0), + lateral: ("npc.crab.crab"), + model_index: 4, + ), + leg_cl: ( + offset: (-8.5, -2.5, 0.0), + lateral: ("npc.crab.crab"), + model_index: 3, + ), + leg_bl: ( + offset: (-7.5, -3.0, 0.0), + lateral: ("npc.crab.crab"), + model_index: 2, + ), + leg_fr: ( + offset: (3.5, -2.5, 0.0), + lateral: ("npc.crab.crab"), + model_index: 4, + ), + leg_cr: ( + offset: (3.5, -2.5, 0.0), + lateral: ("npc.crab.crab"), + model_index: 3, + ), + leg_br: ( + offset: (2.5, -3.0, 0.0), + lateral: ("npc.crab.crab"), + model_index: 2, + ), + ), +}) \ No newline at end of file diff --git a/assets/voxygen/voxel/humanoid_armor_back_manifest.ron b/assets/voxygen/voxel/humanoid_armor_back_manifest.ron index 0db340b87a..8b3c86c360 100644 --- a/assets/voxygen/voxel/humanoid_armor_back_manifest.ron +++ b/assets/voxygen/voxel/humanoid_armor_back_manifest.ron @@ -5,23 +5,23 @@ ), map: { "common.items.armor.misc.back.short_0": ( - vox_spec: ("armor.misc.back.short-0", (-5.0, -1.0, -11.0)), + vox_spec: ("armor.misc.back.short-0", (-5.0, -1.5, -11.0)), color: None ), "common.items.armor.misc.back.admin": ( - vox_spec: ("armor.misc.back.admin", (-5.0, -1.0, -11.0)), + vox_spec: ("armor.misc.back.admin", (-5.0, -1.5, -11.0)), color: None ), "common.items.debug.admin_back": ( - vox_spec: ("armor.misc.back.admin", (-5.0, -1.0, -11.0)), + vox_spec: ("armor.misc.back.admin", (-5.0, -1.5, -11.0)), color: None ), "common.items.armor.misc.back.dungeon_purple": ( - vox_spec: ("armor.misc.back.dungeon_purple", (-5.0, -1.0, -14.0)), + vox_spec: ("armor.misc.back.dungeon_purple", (-5.0, -1.5, -14.0)), color: None ), "common.items.armor.misc.back.short_1": ( - vox_spec: ("armor.misc.back.short-1", (-5.0, -1.0, -11.0)), + vox_spec: ("armor.misc.back.short-1", (-5.0, -1.5, -11.0)), color: None ), "common.items.armor.ferocious.back": ( @@ -29,55 +29,55 @@ color: None ), "common.items.armor.boreal.back": ( - vox_spec: ("armor.boreal.back", (-5.0, -2.0, -14.0)), + vox_spec: ("armor.boreal.back", (-5.0, -2.5, -13.0)), color: None ), "common.items.armor.brinestone.back": ( - vox_spec: ("armor.brinestone.back", (-5.0, -2.0, -14.0)), + vox_spec: ("armor.brinestone.back", (-5.0, -2.5, -12.0)), color: None ), "common.items.armor.misc.back.backpack": ( - vox_spec: ("armor.misc.back.backpack", (-7.0, -5.0, -10.0)), + vox_spec: ("armor.misc.back.backpack", (-7.0, -5.5, -10.0)), color: None ), "common.items.npc_armor.back.backpack_blue": ( - vox_spec: ("armor.misc.back.backpack-grey", (-7.0, -5.0, -10.0)), + vox_spec: ("armor.misc.back.backpack-grey", (-7.0, -5.5, -10.0)), color: Some((76, 72, 178)) ), "common.items.armor.velorite_mage.back": ( - vox_spec: ("armor.velorite_battlemage.back", (-5.0, -1.0, -14.0)), + vox_spec: ("armor.velorite_battlemage.back", (-5.0, -1.5, -14.0)), color: None ), "common.items.debug.admin_back": ( - vox_spec: ("armor.velorite_battlemage.back", (-5.0, -1.0, -14.0)), + vox_spec: ("armor.velorite_battlemage.back", (-5.0, -1.5, -14.0)), color: None ), "common.items.debug.admin_back": ( - vox_spec: ("armor.velorite_battlemage.back", (-5.0, -1.0, -14.0)), + vox_spec: ("armor.velorite_battlemage.back", (-5.0, -1.5, -14.0)), color: None ), "common.items.debug.dungeon_purple": ( - vox_spec: ("armor.velorite_battlemage.back", (-5.0, -1.0, -14.0)), + vox_spec: ("armor.velorite_battlemage.back", (-5.0, -1.5, -14.0)), color: None ), "common.items.npc_armor.back.leather_blue": ( - vox_spec: ("armor.leather_blue.back", (-5.0, -1.0, -11.0)), + vox_spec: ("armor.leather_blue.back", (-5.0, -1.5, -10.0)), color: None ), "common.items.armor.hide.rawhide.back": ( - vox_spec: ("armor.hide.rawhide.back", (-4.0, -1.0, -6.0)), + vox_spec: ("armor.hide.rawhide.back", (-4.0, -1.5, -7.0)), color: None ), "common.items.armor.hide.leather.back": ( - vox_spec: ("armor.hide.leather.back", (-5.0, -1.0, -11.0)), + vox_spec: ("armor.hide.leather.back", (-5.0, -1.5, -11.0)), color: None ), "common.items.armor.miner.back": ( - vox_spec: ("armor.hide.leather.back", (-5.0, -1.0, -11.0)), + vox_spec: ("armor.hide.leather.back", (-5.0, -1.5, -11.0)), color: None ), "common.items.armor.hide.scale.back": ( - vox_spec: ("armor.hide.scale.back", (-5.0, -2.0, -10.5)), + vox_spec: ("armor.hide.scale.back", (-5.0, -1.5, -10.0)), color: None ), "common.items.armor.hide.carapace.back": ( @@ -85,7 +85,7 @@ color: None ), "common.items.armor.hide.primal.back": ( - vox_spec: ("armor.hide.primal.back", (-5.0, -4.5, -10.5)), + vox_spec: ("armor.hide.primal.back", (-5.0, -3.5, -10.0)), color: None ), "common.items.armor.hide.dragonscale.back": ( @@ -97,19 +97,19 @@ color: None ), "common.items.armor.cloth.linen.back": ( - vox_spec: ("armor.cloth.linen.back", (-4.0, -2.5, -8.5)), + vox_spec: ("armor.cloth.linen.back", (-4.0, -1.5, -8.0)), color: None ), "common.items.armor.cloth.woolen.back": ( - vox_spec: ("armor.cloth.woolen.back", (-5.0, -2.5, -8.5)), + vox_spec: ("armor.cloth.woolen.back", (-5.0, -1.5, -8.0)), color: None ), "common.items.armor.cloth.silken.back": ( - vox_spec: ("armor.cloth.silken.back", (-4.0, -2.5, -11.5)), + vox_spec: ("armor.cloth.silken.back", (-4.0, -1.5, -11.0)), color: None ), "common.items.armor.witch.back": ( - vox_spec: ("armor.witch.back", (-4.0, -2.5, -11.5)), + vox_spec: ("armor.witch.back", (-4.0, -1.5, -11.0)), color: None ), "common.items.armor.cloth.druid.back": ( @@ -117,7 +117,7 @@ color: None ), "common.items.armor.cloth.moonweave.back": ( - vox_spec: ("armor.cloth.moonweave.back", (-4.0, -2.0, -12.5)), + vox_spec: ("armor.cloth.moonweave.back", (-4.0, -1.5, -12.5)), color: None ), "common.items.armor.cloth.sunsilk.back": ( @@ -125,19 +125,19 @@ color: None ), "common.items.armor.mail.bronze.back": ( - vox_spec: ("armor.mail.bronze.back", (-4.0, -2.5, -7.0)), + vox_spec: ("armor.mail.bronze.back", (-4.0, -1.5, -7.0)), color: None ), "common.items.armor.mail.iron.back": ( - vox_spec: ("armor.mail.iron.back", (-4.0, -2.5, -10.0)), + vox_spec: ("armor.mail.iron.back", (-4.0, -1.5, -10.0)), color: None ), "common.items.armor.mail.steel.back": ( - vox_spec: ("armor.mail.steel.back", (-4.0, -2.5, -12.0)), + vox_spec: ("armor.mail.steel.back", (-4.0, -1.5, -10.0)), color: None ), "common.items.armor.mail.cobalt.back": ( - vox_spec: ("armor.mail.cobalt.back", (-4.0, -2.5, -12.0)), + vox_spec: ("armor.mail.cobalt.back", (-4.0, -1.5, -11.0)), color: None ), "common.items.armor.mail.bloodsteel.back": ( @@ -145,11 +145,11 @@ color: None ), "common.items.armor.mail.orichalcum.back": ( - vox_spec: ("armor.mail.orichalcum", (-5.0, -4.5, -12.0), 6), + vox_spec: ("armor.mail.orichalcum", (-5.0, -4.5, -12.5), 6), color: None ), "common.items.armor.merchant.back": ( - vox_spec: ("armor.merchant.back", (-8.0, -7.0, -11.0)), + vox_spec: ("armor.merchant.back", (-8.0, -8.5, -11.0)), color: None ), }, diff --git a/assets/voxygen/voxel/humanoid_armor_belt_manifest.ron b/assets/voxygen/voxel/humanoid_armor_belt_manifest.ron index 6ed93956d3..cb03437591 100644 --- a/assets/voxygen/voxel/humanoid_armor_belt_manifest.ron +++ b/assets/voxygen/voxel/humanoid_armor_belt_manifest.ron @@ -29,11 +29,11 @@ color: None ), "common.items.armor.boreal.belt": ( - vox_spec: ("armor.boreal.belt", (-4.0, -3.0, 2.0)), + vox_spec: ("armor.boreal.belt", (-4.0, -3.5, 2.0)), color: None ), "common.items.armor.brinestone.belt": ( - vox_spec: ("armor.brinestone.belt", (-4.0, -3.0, 2.0)), + vox_spec: ("armor.brinestone.belt", (-4.0, -3.5, 1.0)), color: None ), "common.items.armor.cloth_purple.belt": ( @@ -53,7 +53,7 @@ color: None ), "common.items.armor.leather_plate.belt": ( - vox_spec: ("armor.leather_plate.belt", (-4.0, -4.5, 2.0)), + vox_spec: ("armor.leather_plate.belt", (-4.0, -3.5, 2.0)), color: None ), "common.items.armor.twigs.belt": ( @@ -101,19 +101,19 @@ color: None ), "common.items.armor.hide.carapace.belt":( - vox_spec: ("armor.hide.carapace.belt", (-4.0, -4.0, 1.5)), + vox_spec: ("armor.hide.carapace.belt", (-4.0, -3.5, 2.0)), color: None ), "common.items.armor.hide.primal.belt":( - vox_spec: ("armor.hide.primal.belt", (-4.0, -4.0, 1.0)), + vox_spec: ("armor.hide.primal.belt", (-4.0, -3.5, 2.0)), color: None ), "common.items.armor.hide.dragonscale.belt":( - vox_spec: ("armor.hide.dragonscale.belt", (-4.0, -3.5, 1.5)), + vox_spec: ("armor.hide.dragonscale.belt", (-4.0, -3.5, 2.0)), color: None ), "common.items.armor.savage.belt":( - vox_spec: ("armor.savage.belt", (-4.0, -4.0, 1.0)), + vox_spec: ("armor.savage.belt", (-4.0, -4.5, 2.0)), color: None ), "common.items.armor.witch.belt":( @@ -121,59 +121,59 @@ color: None ), "common.items.armor.pirate.belt":( - vox_spec: ("armor.pirate.belt", (-4.0, -4.0, 2.5)), + vox_spec: ("armor.pirate.belt", (-4.0, -3.5, 2.0)), color: None ), "common.items.armor.alchemist.belt":( - vox_spec: ("armor.alchemist", (-4.0, -4.0, 2.5), 2), + vox_spec: ("armor.alchemist", (-4.0, -3.5, 2.0), 2), color: None ), "common.items.armor.blacksmith.belt":( - vox_spec: ("armor.blacksmith.belt", (-4.0, -4.0, 2.0)), + vox_spec: ("armor.blacksmith.belt", (-4.0, -3.5, 2.0)), color: None ), "common.items.armor.chef.belt":( - vox_spec: ("armor.chef.belt", (-4.0, -4.0, 2.0)), + vox_spec: ("armor.chef.belt", (-4.0, -4.5, 2.0)), color: None ), "common.items.armor.cloth.linen.belt":( - vox_spec: ("armor.cloth.linen.belt", (-4.0, -4.0, 0.0)), + vox_spec: ("armor.cloth.linen.belt", (-4.0, -3.5, 0.0)), color: None ), "common.items.armor.cloth.woolen.belt":( - vox_spec: ("armor.cloth.woolen.belt", (-4.0, -4.0, 1.0)), + vox_spec: ("armor.cloth.woolen.belt", (-4.0, -3.5, 2.0)), color: None ), "common.items.armor.cloth.silken.belt":( - vox_spec: ("armor.cloth.silken.belt", (-4.0, -3.5, -3.0)), + vox_spec: ("armor.cloth.silken.belt", (-4.0, -3.5, -2.0)), color: None ), "common.items.armor.cloth.druid.belt":( - vox_spec: ("armor.cloth.druid.belt", (-4.0, -4.0, -0.5)), + vox_spec: ("armor.cloth.druid.belt", (-4.0, -3.5, -1.0)), color: None ), "common.items.armor.cloth.moonweave.belt":( - vox_spec: ("armor.cloth.moonweave.belt", (-4.0, -3.5, 1.0)), + vox_spec: ("armor.cloth.moonweave.belt", (-4.0, -3.5, 2.0)), color: None ), "common.items.armor.cloth.sunsilk.belt":( - vox_spec: ("armor.cloth.sunsilk.belt", (-4.0, -3.5, -2.5)), + vox_spec: ("armor.cloth.sunsilk.belt", (-4.0, -3.5, -2.0)), color: None ), "common.items.armor.mail.bronze.belt":( - vox_spec: ("armor.mail.bronze.belt", (-4.0, -4.0, 2.0)), + vox_spec: ("armor.mail.bronze.belt", (-4.0, -3.5, 2.0)), color: None ), "common.items.armor.mail.iron.belt":( - vox_spec: ("armor.mail.iron.belt", (-4.0, -4.0, 2.0)), + vox_spec: ("armor.mail.iron.belt", (-4.0, -3.5, 2.0)), color: None ), "common.items.armor.mail.steel.belt":( - vox_spec: ("armor.mail.steel.belt", (-5.0, -4.0, 1.0)), + vox_spec: ("armor.mail.steel.belt", (-5.0, -4.5, 2.0)), color: None ), "common.items.armor.mail.cobalt.belt":( - vox_spec: ("armor.mail.cobalt.belt", (-5.0, -4.0, 1.0)), + vox_spec: ("armor.mail.cobalt.belt", (-5.0, -3.5, 2.0)), color: None ), "common.items.armor.mail.bloodsteel.belt":( @@ -185,11 +185,11 @@ color: None ), "common.items.armor.cardinal.belt": ( - vox_spec: ("armor.cardinal.belt", (-4.0, -3.8, 1.3)), + vox_spec: ("armor.cardinal.belt", (-4.0, -3.5, 2.0)), color: None ), "common.items.armor.merchant.belt": ( - vox_spec: ("armor.merchant.belt", (-5.0, -4.0, 2.0)), + vox_spec: ("armor.merchant.belt", (-5.0, -3.5, 2.0)), color: None ), }, diff --git a/assets/voxygen/voxel/humanoid_armor_chest_manifest.ron b/assets/voxygen/voxel/humanoid_armor_chest_manifest.ron index f18f0b9621..0e618cbeec 100644 --- a/assets/voxygen/voxel/humanoid_armor_chest_manifest.ron +++ b/assets/voxygen/voxel/humanoid_armor_chest_manifest.ron @@ -37,7 +37,7 @@ color: None ), "common.items.armor.brinestone.chest": ( - vox_spec: ("armor.brinestone.chest", (-7.0, -3.5, 0.0)), + vox_spec: ("armor.brinestone.chest", (-7.0, -3.5, 2.0)), color: None ), "common.items.armor.assassin.chest": ( @@ -135,7 +135,7 @@ color: Some((30, 0, 64)) ), "common.items.armor.leather_plate.chest": ( - vox_spec: ("armor.leather_plate.chest", (-8.0, -5.5, 2.0)), + vox_spec: ("armor.leather_plate.chest", (-8.0, -4.5, 2.0)), color: None ), "common.items.armor.tarasque.chest":( @@ -147,11 +147,11 @@ color: None ), "common.items.armor.velorite_mage.chest": ( - vox_spec: ("armor.velorite_battlemage.chest", (-7.0, -3.5, 0.5)), + vox_spec: ("armor.velorite_battlemage.chest", (-7.0, -3.5, 1.0)), color: None ), "common.items.debug.cultist_chest_blue": ( - vox_spec: ("armor.velorite_battlemage.chest", (-7.0, -3.5, 0.5)), + vox_spec: ("armor.velorite_battlemage.chest", (-7.0, -3.5, 1.0)), color: None ), "common.items.armor.hide.rawhide.chest": ( @@ -171,15 +171,15 @@ color: None ), "common.items.armor.hide.carapace.chest": ( - vox_spec: ("armor.hide.carapace.chest", (-7.0, -3.5, 1.5)), + vox_spec: ("armor.hide.carapace.chest", (-7.0, -3.5, 2.0)), color: None ), "common.items.armor.hide.primal.chest": ( - vox_spec: ("armor.hide.primal.chest", (-7.0, -3.5, 0.5)), + vox_spec: ("armor.hide.primal.chest", (-7.0, -3.5, 2.0)), color: None ), "common.items.armor.hide.dragonscale.chest": ( - vox_spec: ("armor.hide.dragonscale.chest", (-7.0, -3.5, 1.5)), + vox_spec: ("armor.hide.dragonscale.chest", (-7.0, -3.5, 2.0)), color: None ), "common.items.armor.savage.chest": ( @@ -187,79 +187,79 @@ color: None ), "common.items.armor.witch.chest": ( - vox_spec: ("armor.witch.chest", (-7.0, -4.0, 2.0)), + vox_spec: ("armor.witch.chest", (-7.0, -3.5, 2.0)), color: None ), "common.items.armor.pirate.chest": ( - vox_spec: ("armor.pirate.chest", (-7.0, -4.0, 2.0)), + vox_spec: ("armor.pirate.chest", (-7.0, -3.5, 2.0)), color: None ), "common.items.armor.alchemist.chest": ( - vox_spec: ("armor.alchemist", (-7.0, -4.0, 2.0), 1), + vox_spec: ("armor.alchemist", (-7.0, -3.5, 2.0), 1), color: None ), "common.items.armor.blacksmith.chest": ( - vox_spec: ("armor.blacksmith.chest", (-7.0, -4.0, 2.0)), + vox_spec: ("armor.blacksmith.chest", (-7.0, -3.5, 2.0)), color: None ), "common.items.armor.chef.chest": ( - vox_spec: ("armor.chef.chest", (-7.0, -4.0, 2.0)), + vox_spec: ("armor.chef.chest", (-7.0, -3.5, 2.0)), color: None ), "common.items.armor.cloth.linen.chest": ( - vox_spec: ("armor.cloth.linen.chest", (-7.0, -4.0, 2.0)), + vox_spec: ("armor.cloth.linen.chest", (-7.0, -3.5, 2.0)), color: None ), "common.items.armor.cloth.woolen.chest": ( - vox_spec: ("armor.cloth.woolen.chest", (-7.0, -4.0, 1.0)), + vox_spec: ("armor.cloth.woolen.chest", (-7.0, -3.5, 2.0)), color: None ), "common.items.armor.cloth.silken.chest": ( - vox_spec: ("armor.cloth.silken.chest", (-7.0, -4.0, 1.0)), + vox_spec: ("armor.cloth.silken.chest", (-7.0, -3.5, 2.0)), color: None ), "common.items.armor.cloth.druid.chest": ( - vox_spec: ("armor.cloth.druid.chest", (-7.0, -4.0, 2.0)), + vox_spec: ("armor.cloth.druid.chest", (-7.0, -3.5, 2.0)), color: None ), "common.items.armor.cloth.moonweave.chest": ( - vox_spec: ("armor.cloth.moonweave.chest", (-7.0, -4.0, 1.0)), + vox_spec: ("armor.cloth.moonweave.chest", (-7.0, -3.5, 2.0)), color: None ), "common.items.armor.cloth.sunsilk.chest": ( - vox_spec: ("armor.cloth.sunsilk.chest", (-7.0, -4.0, 1.0)), + vox_spec: ("armor.cloth.sunsilk.chest", (-7.0, -3.5, 2.0)), color: None ), "common.items.armor.mail.bronze.chest": ( - vox_spec: ("armor.mail.bronze.chest", (-7.0, -4.0, 2.0)), + vox_spec: ("armor.mail.bronze.chest", (-7.0, -3.5, 2.0)), color: None ), "common.items.armor.mail.iron.chest": ( - vox_spec: ("armor.mail.iron.chest", (-7.0, -4.0, 2.0)), + vox_spec: ("armor.mail.iron.chest", (-7.0, -3.5, 2.0)), color: None ), "common.items.armor.mail.steel.chest": ( - vox_spec: ("armor.mail.steel.chest", (-8.0, -4.0, 1.0)), + vox_spec: ("armor.mail.steel.chest", (-8.0, -4.5, 2.0)), color: None ), "common.items.armor.mail.cobalt.chest": ( - vox_spec: ("armor.mail.cobalt.chest", (-8.0, -4.0, 1.0)), + vox_spec: ("armor.mail.cobalt.chest", (-8.0, -4.5, 2.0)), color: None ), "common.items.armor.mail.bloodsteel.chest": ( - vox_spec: ("armor.mail.bloodsteel.chest", (-8.0, -4.0, 1.0)), + vox_spec: ("armor.mail.bloodsteel.chest", (-8.0, -4.5, 2.0)), color: None ), "common.items.armor.mail.orichalcum.chest": ( - vox_spec: ("armor.mail.orichalcum", (-7.0, -4.0, 1.0), 0), + vox_spec: ("armor.mail.orichalcum", (-7.0, -3.5, 2.0), 0), color: None ), "common.items.armor.cardinal.chest": ( - vox_spec: ("armor.cardinal.chest", (-7.0, -4.0, 1.0)), + vox_spec: ("armor.cardinal.chest", (-7.0, -3.5, 2.0)), color: None ), "common.items.armor.merchant.chest": ( - vox_spec: ("armor.merchant.chest", (-7.0, -4.0, 1.0)), + vox_spec: ("armor.merchant.chest", (-7.0, -3.5, 1.0)), color: None ), }, diff --git a/assets/voxygen/voxel/humanoid_armor_foot_manifest.ron b/assets/voxygen/voxel/humanoid_armor_foot_manifest.ron index 1fc99b006f..1635f8fa5e 100644 --- a/assets/voxygen/voxel/humanoid_armor_foot_manifest.ron +++ b/assets/voxygen/voxel/humanoid_armor_foot_manifest.ron @@ -29,7 +29,7 @@ color: None ), "common.items.armor.brinestone.foot": ( - vox_spec: ("armor.brinestone.foot", (-2.5, -3.5, -2.0)), + vox_spec: ("armor.brinestone.foot", (-2.5, -4.5, -2.0)), color: None ), "common.items.armor.cloth_blue.foot": ( @@ -53,7 +53,7 @@ color: None ), "common.items.armor.misc.foot.jackalope_slippers": ( - vox_spec: ("armor.misc.foot.jackalope", (-2.5, -3.5, -2.0)), + vox_spec: ("armor.misc.foot.jackalope", (-2.5, -4.5, -2.0)), color: None ), "common.items.armor.twigs.foot": ( @@ -97,7 +97,7 @@ color: None ), "common.items.armor.hide.scale.foot": ( - vox_spec: ("armor.hide.scale.foot", (-2.5, -3.5, -2.0)), + vox_spec: ("armor.hide.scale.foot", (-2.5, -4.5, -2.0)), color: None ), "common.items.armor.hide.carapace.foot": ( @@ -105,7 +105,7 @@ color: None ), "common.items.armor.hide.primal.foot": ( - vox_spec: ("armor.hide.primal.foot", (-2.5, -3.5, -2.0)), + vox_spec: ("armor.hide.primal.foot", (-2.5, -4.5, -2.0)), color: None ), "common.items.armor.hide.dragonscale.foot": ( @@ -161,15 +161,15 @@ color: None ), "common.items.armor.mail.cobalt.foot": ( - vox_spec: ("armor.mail.cobalt.foot", (-2.5, -3.5, -2.0)), + vox_spec: ("armor.mail.cobalt.foot", (-2.5, -4.5, -2.0)), color: None ), "common.items.armor.mail.bloodsteel.foot": ( - vox_spec: ("armor.mail.bloodsteel.foot", (-2.5, -3.5, -2.0)), + vox_spec: ("armor.mail.bloodsteel.foot", (-2.5, -4.5, -2.0)), color: None ), "common.items.armor.mail.orichalcum.foot": ( - vox_spec: ("armor.mail.orichalcum", (-2.5, -3.5, -2.0), 3), + vox_spec: ("armor.mail.orichalcum", (-2.5, -4.5, -2.0), 3), color: None ), "common.items.armor.cardinal.foot": ( @@ -185,7 +185,7 @@ color: None ), "common.items.armor.misc.foot.iceskate": ( - vox_spec: ("armor.misc.foot.iceskate", (-2.5, -3.5, -2.0)), + vox_spec: ("armor.misc.foot.iceskate", (-2.5, -4.5, -2.0)), color: None ), }, diff --git a/assets/voxygen/voxel/humanoid_armor_hand_manifest.ron b/assets/voxygen/voxel/humanoid_armor_hand_manifest.ron index 924b00eb7f..73bdcc198e 100644 --- a/assets/voxygen/voxel/humanoid_armor_hand_manifest.ron +++ b/assets/voxygen/voxel/humanoid_armor_hand_manifest.ron @@ -32,31 +32,31 @@ ), "common.items.armor.ferocious.hand": ( left: ( - vox_spec: ("armor.ferocious.hand", (-1.5, -1.5, -3.0)), + vox_spec: ("armor.ferocious.hand", (-1.5, -1.5, -2.5)), color: None ), right: ( - vox_spec: ("armor.ferocious.hand", (-1.5, -1.5, -3.0)), + vox_spec: ("armor.ferocious.hand", (-1.5, -1.5, -2.5)), color: None ) ), "common.items.armor.boreal.hand": ( left: ( - vox_spec: ("armor.boreal.hand", (-2.0, -1.5, -3.0)), + vox_spec: ("armor.boreal.hand", (-2.5, -1.5, -2.5)), color: None ), right: ( - vox_spec: ("armor.boreal.hand", (-2.0, -1.5, -3.0)), + vox_spec: ("armor.boreal.hand", (-1.5, -1.5, -2.5)), color: None ) ), "common.items.armor.brinestone.hand": ( left: ( - vox_spec: ("armor.brinestone.hand", (-3.5, -1.5, -4.0)), + vox_spec: ("armor.brinestone.hand", (-3.5, -1.5, -3.5)), color: None ), right: ( - vox_spec: ("armor.brinestone.hand", (-1.5, -1.5, -4.0)), + vox_spec: ("armor.brinestone.hand", (-1.5, -1.5, -3.5)), color: None ) ), @@ -92,11 +92,11 @@ ), "common.items.armor.cultist.hand": ( left: ( - vox_spec: ("armor.cultist.hand", (-3.0, -1.5, -2.5)), + vox_spec: ("armor.cultist.hand", (-2.5, -2.5, -2.5)), color: Some((30, 0, 64)) ), right: ( - vox_spec: ("armor.cultist.hand", (-2.0, -1.5, -2.5)), + vox_spec: ("armor.cultist.hand", (-2.2, -2.5, -2.5)), color: Some((30, 0, 64)) ) ), @@ -122,7 +122,7 @@ ), "common.items.armor.twigsleaves.hand": ( left: ( - vox_spec: ("armor.twigsleaves.hand", (-1.5, -1.5, -2.5)), + vox_spec: ("armor.twigsleaves.hand", (-2.5, -1.5, -2.5)), color: None ), right: ( @@ -132,7 +132,7 @@ ), "common.items.armor.twigsflowers.hand": ( left: ( - vox_spec: ("armor.twigsflowers.hand", (-1.5, -1.5, -2.5)), + vox_spec: ("armor.twigsflowers.hand", (-2.5, -1.5, -2.5)), color: None ), right: ( @@ -162,21 +162,21 @@ ), "common.items.armor.velorite_mage.hand": ( left: ( - vox_spec: ("armor.velorite_battlemage.hand", (-2.5, -1.5, -2.5)), + vox_spec: ("armor.velorite_battlemage.hand", (-2.5, -2.5, -2.5)), color: None ), right: ( - vox_spec: ("armor.velorite_battlemage.hand", (-2.5, -1.5, -2.5)), + vox_spec: ("armor.velorite_battlemage.hand", (-2.5, -2.5, -2.5)), color: None ) ), "common.items.debug.cultist_hands_blue": ( left: ( - vox_spec: ("armor.velorite_battlemage.hand", (-2.5, -1.5, -2.5)), + vox_spec: ("armor.velorite_battlemage.hand", (-2.5, -2.5, -2.5)), color: None ), right: ( - vox_spec: ("armor.velorite_battlemage.hand", (-2.5, -1.5, -2.5)), + vox_spec: ("armor.velorite_battlemage.hand", (-2.5, -2.5, -2.5)), color: None ) ), @@ -202,11 +202,11 @@ ), "common.items.armor.miner.hand": ( left: ( - vox_spec: ("armor.mail.bronze.hand", (-1.5, -1.0, -3.0)), + vox_spec: ("armor.mail.bronze.hand", (-1.5, -1.5, -2.5)), color: None ), right: ( - vox_spec: ("armor.mail.bronze.hand", (-1.5, -1.0, -3.0)), + vox_spec: ("armor.mail.bronze.hand", (-1.5, -1.5, -2.5)), color: None ) ), @@ -222,211 +222,211 @@ ), "common.items.armor.hide.carapace.hand": ( left: ( - vox_spec: ("armor.hide.carapace.hand", (-3.5, -2.5, -3.0)), + vox_spec: ("armor.hide.carapace.hand", (-3.5, -2.5, -3.5)), color: None ), right: ( - vox_spec: ("armor.hide.carapace.hand", (-1.5, -2.5, -3.0)), + vox_spec: ("armor.hide.carapace.hand", (-1.5, -2.5, -3.5)), color: None ) ), "common.items.armor.hide.primal.hand": ( left: ( - vox_spec: ("armor.hide.primal.hand", (-3.5, -3.5, -4.0)), + vox_spec: ("armor.hide.primal.hand", (-3.5, -2.5, -3.5)), color: None ), right: ( - vox_spec: ("armor.hide.primal.hand", (-1.5, -3.5, -4.0)), + vox_spec: ("armor.hide.primal.hand", (-1.5, -2.5, -3.5)), color: None ) ), "common.items.armor.hide.dragonscale.hand": ( left: ( - vox_spec: ("armor.hide.dragonscale.hand", (-5.0, -1.5, -3.5)), + vox_spec: ("armor.hide.dragonscale.hand", (-5.5, -1.5, -3.5)), color: None ), right: ( - vox_spec: ("armor.hide.dragonscale.hand", (-2.0, -1.5, -3.5)), + vox_spec: ("armor.hide.dragonscale.hand", (-1.5, -1.5, -3.5)), color: None ) ), "common.items.armor.savage.hand": ( left: ( - vox_spec: ("armor.savage.hand", (-2.5, -3.0, -4.0)), + vox_spec: ("armor.savage.hand", (-2.5, -2.5, -3.5)), color: None ), right: ( - vox_spec: ("armor.savage.hand", (-1.5, -3.0, -4.0)), + vox_spec: ("armor.savage.hand", (-1.5, -2.5, -3.5)), color: None ) ), "common.items.armor.witch.hand": ( left: ( - vox_spec: ("armor.witch.hand", (-2.5, -2.5, -4.0)), + vox_spec: ("armor.witch.hand", (-2.5, -2.5, -3.5)), color: None ), right: ( - vox_spec: ("armor.witch.hand", (-1.5, -2.5, -4.0)), + vox_spec: ("armor.witch.hand", (-1.5, -2.5, -3.5)), color: None ) ), "common.items.armor.pirate.hand": ( left: ( - vox_spec: ("armor.pirate.hand", (-2.5, -2.5, -4.0)), + vox_spec: ("armor.pirate.hand", (-2.5, -2.5, -3.5)), color: None ), right: ( - vox_spec: ("armor.pirate.hand", (-1.5, -2.5, -4.0)), + vox_spec: ("armor.pirate.hand", (-1.5, -2.5, -3.5)), color: None ) ), "common.items.armor.blacksmith.hand": ( left: ( - vox_spec: ("armor.blacksmith.hand", (-1.5, -2.5, -4.0)), + vox_spec: ("armor.blacksmith.hand", (-1.5, -1.5, -2.5)), color: None ), right: ( - vox_spec: ("armor.blacksmith.hand", (-1.5, -2.5, -4.0)), + vox_spec: ("armor.blacksmith.hand", (-1.5, -1.5, -2.5)), color: None ) ), "common.items.armor.cloth.linen.hand": ( left: ( - vox_spec: ("armor.cloth.linen.hand", (-1.5, -2.0, -3.0)), + vox_spec: ("armor.cloth.linen.hand", (-1.5, -1.5, -2.5)), color: None ), right: ( - vox_spec: ("armor.cloth.linen.hand", (-1.5, -2.0, -3.0)), + vox_spec: ("armor.cloth.linen.hand", (-1.5, -1.5, -2.5)), color: None ) ), "common.items.armor.cloth.woolen.hand": ( left: ( - vox_spec: ("armor.cloth.woolen.hand", (-2.5, -2.5, -3.5)), + vox_spec: ("armor.cloth.woolen.hand", (-2.5, -2.5, -2.5)), color: None ), right: ( - vox_spec: ("armor.cloth.woolen.hand", (-2.5, -2.5, -3.5)), + vox_spec: ("armor.cloth.woolen.hand", (-2.5, -2.5, -2.5)), color: None ) ), "common.items.armor.cloth.silken.hand": ( left: ( - vox_spec: ("armor.cloth.silken.hand", (-2.5, -2.5, -4.0)), + vox_spec: ("armor.cloth.silken.hand", (-2.5, -2.5, -3.5)), color: None ), right: ( - vox_spec: ("armor.cloth.silken.hand", (-1.5, -2.5, -4.0)), + vox_spec: ("armor.cloth.silken.hand", (-1.5, -2.5, -3.5)), color: None ) ), "common.items.armor.cloth.druid.hand": ( left: ( - vox_spec: ("armor.cloth.druid.hand", (-2.5, -1.0, -3.0)), + vox_spec: ("armor.cloth.druid.hand", (-1.5, -1.5, -2.5)), color: None ), right: ( - vox_spec: ("armor.cloth.druid.hand", (-1.5, -1.0, -3.0)), + vox_spec: ("armor.cloth.druid.hand", (-1.5, -1.5, -2.5)), color: None ) ), "common.items.armor.cloth.moonweave.hand": ( left: ( - vox_spec: ("armor.cloth.moonweave.hand", (-2.5, -2.0, -4.0)), + vox_spec: ("armor.cloth.moonweave.hand", (-1.5, -1.5, -2.5)), color: None ), right: ( - vox_spec: ("armor.cloth.moonweave.hand", (-1.5, -2.0, -4.0)), + vox_spec: ("armor.cloth.moonweave.hand", (-1.5, -1.5, -2.5)), color: None ) ), "common.items.armor.cloth.sunsilk.hand": ( left: ( - vox_spec: ("armor.cloth.sunsilk.hand", (-2.5, -2.5, -4.0)), + vox_spec: ("armor.cloth.sunsilk.hand", (-2.5, -2.5, -3.5)), color: None ), right: ( - vox_spec: ("armor.cloth.sunsilk.hand", (-1.5, -2.5, -4.0)), + vox_spec: ("armor.cloth.sunsilk.hand", (-1.5, -2.5, -3.5)), color: None ) ), "common.items.armor.mail.bronze.hand": ( left: ( - vox_spec: ("armor.mail.bronze.hand", (-2.5, -2.0, -3.0)), + vox_spec: ("armor.mail.bronze.hand", (-1.5, -1.5, -2.5)), color: None ), right: ( - vox_spec: ("armor.mail.bronze.hand", (-1.5, -2.0, -3.0)), + vox_spec: ("armor.mail.bronze.hand", (-1.5, -1.5, -2.5)), color: None ) ), "common.items.armor.mail.iron.hand": ( left: ( - vox_spec: ("armor.mail.iron.hand", (-1.5, -1.5, -3.0)), + vox_spec: ("armor.mail.iron.hand", (-1.5, -1.5, -2.5)), color: None ), right: ( - vox_spec: ("armor.mail.iron.hand", (-1.5, -1.5, -3.0)), + vox_spec: ("armor.mail.iron.hand", (-1.5, -1.5, -2.5)), color: None ) ), "common.items.armor.mail.steel.hand": ( left: ( - vox_spec: ("armor.mail.steel.hand", (-2.5, -1.0, -4.0)), + vox_spec: ("armor.mail.steel.hand", (-1.5, -1.5, -2.5)), color: None ), right: ( - vox_spec: ("armor.mail.steel.hand", (-1.5, -1.0, -4.0)), + vox_spec: ("armor.mail.steel.hand", (-1.5, -1.5, -2.5)), color: None ) ), "common.items.armor.mail.cobalt.hand": ( left: ( - vox_spec: ("armor.mail.cobalt.hand", (-2.5, -2.0, -4.0)), + vox_spec: ("armor.mail.cobalt.hand", (-3.5, -2.5, -2.5)), color: None ), right: ( - vox_spec: ("armor.mail.cobalt.hand", (-1.5, -2.0, -4.0)), + vox_spec: ("armor.mail.cobalt.hand", (-1.5, -2.5, -2.5)), color: None ) ), "common.items.armor.mail.bloodsteel.hand": ( left: ( - vox_spec: ("armor.mail.bloodsteel.hand", (-5.0, -1.0, -4.0)), + vox_spec: ("armor.mail.bloodsteel.hand", (-4.5, -2.5, -2.5)), color: None ), right: ( - vox_spec: ("armor.mail.bloodsteel.hand", (-1.0, -1.0, -4.0)), + vox_spec: ("armor.mail.bloodsteel.hand", (-1.5, -2.5, -2.5)), color: None ) ), "common.items.armor.mail.orichalcum.hand": ( left: ( - vox_spec: ("armor.mail.orichalcum", (-4.5, -2.0, -4.0), 4), + vox_spec: ("armor.mail.orichalcum", (-4.5, -2.5, -3.5), 4), color: None ), right: ( - vox_spec: ("armor.mail.orichalcum", (-1.5, -2.0, -4.0), 4), + vox_spec: ("armor.mail.orichalcum", (-1.5, -2.5, -3.5), 4), color: None ) ), "common.items.armor.cardinal.hand": ( left: ( - vox_spec: ("armor.cardinal.hand", (-2.5, -2.5, -4.0)), + vox_spec: ("armor.cardinal.hand", (-2.5, -2.5, -3.5)), color: None ), right: ( - vox_spec: ("armor.cardinal.hand", (-1.5, -2.5, -4.0)), + vox_spec: ("armor.cardinal.hand", (-1.5, -2.5, -3.5)), color: None ) ), "common.items.armor.merchant.hand": ( left: ( - vox_spec: ("armor.merchant.hand", (-2.5, -2.0, -4.0)), + vox_spec: ("armor.merchant.hand", (-1.5, -1.5, -2.5)), color: None ), right:( - vox_spec: ("armor.merchant.hand", (-1.5, -2.0, -4.0)), + vox_spec: ("armor.merchant.hand", (-1.5, -1.5, -2.5)), color: None ) ), diff --git a/assets/voxygen/voxel/humanoid_armor_head_manifest.ron b/assets/voxygen/voxel/humanoid_armor_head_manifest.ron index 5302cd1829..187223a512 100644 --- a/assets/voxygen/voxel/humanoid_armor_head_manifest.ron +++ b/assets/voxygen/voxel/humanoid_armor_head_manifest.ron @@ -549,7 +549,7 @@ color: None ), (Danari, Female, "common.items.armor.misc.head.straw"): ( - vox_spec: ("armor.misc.head.straw", (-2.0, -5.0, 7.0)), + vox_spec: ("armor.misc.head.straw", (-2.0, -6.0, 7.0)), color: None ), (Draugr, Male, "common.items.armor.misc.head.straw"): ( @@ -647,7 +647,7 @@ color: None ), (Danari, Female, "common.items.armor.misc.head.mitre"): ( - vox_spec: ("armor.misc.head.mitre", (-2.0, -5.0, 7.0)), + vox_spec: ("armor.misc.head.mitre", (-2.0, -4.0, 7.0)), color: None ), (Draugr, Male, "common.items.armor.misc.head.mitre"): ( @@ -757,11 +757,11 @@ color: None ), (Danari, Female, "common.items.armor.misc.head.helmet"): ( - vox_spec: ("armor.misc.head.helmet", (-2.0, -5.0, 1.0)), + vox_spec: ("armor.misc.head.helmet", (-2.0, -6.0, 1.0)), color: None ), (Danari, Male, "common.items.armor.misc.head.helmet"): ( - vox_spec: ("armor.misc.head.helmet", (-2.0, -5.0, -1.0)), + vox_spec: ("armor.misc.head.helmet", (-2.0, -6.0, 1.0)), color: None ), // @@ -786,7 +786,7 @@ color: None ), (Human, Female, "common.items.armor.misc.head.bandana.red"): ( - vox_spec: ("armor.misc.head.bandana.red", (-4.0, -2.0, -10.0)), + vox_spec: ("armor.misc.head.bandana.red", (-4.0, -1.0, -10.0)), color: None ), (Draugr, Male, "common.items.armor.misc.head.bandana.red"): ( @@ -806,7 +806,7 @@ color: None ), (Orc, Male, "common.items.armor.misc.head.bandana.red"): ( - vox_spec: ("armor.misc.head.bandana.red", (-3.0, 0.0, -8.0)), + vox_spec: ("armor.misc.head.bandana.red", (-3.0, 0.0, -7.0)), color: None ), (Orc, Female, "common.items.armor.misc.head.bandana.red"): ( @@ -818,7 +818,7 @@ vox_spec: ("armor.misc.head.bandana.thief", (-2.0, -2.0, -8.0)), color: None ), - (Danari, Female, "Thicommon.items.armor.misc.head.bandana.thiefef"): ( + (Danari, Female, "common.items.armor.misc.head.bandana.thief"): ( vox_spec: ("armor.misc.head.bandana.thief", (-2.0, -2.0, -8.0)), color: None ), @@ -834,8 +834,8 @@ vox_spec: ("armor.misc.head.bandana.thief", (-4.0, -2.0, -10.0)), color: None ), - (Human, Female, "Thcommon.items.armor.misc.head.bandana.thiefief"): ( - vox_spec: ("armor.misc.head.bandana.thief", (-4.0, -2.0, -10.0)), + (Human, Female, "common.items.armor.misc.head.bandana.thief"): ( + vox_spec: ("armor.misc.head.bandana.thief", (-4.0, -1.0, -10.0)), color: None ), (Draugr, Male, "common.items.armor.misc.head.bandana.thief"): ( @@ -855,7 +855,7 @@ color: None ), (Orc, Male, "common.items.armor.misc.head.bandana.thief"): ( - vox_spec: ("armor.misc.head.bandana.thief", (-3.0, 0.0, -8.0)), + vox_spec: ("armor.misc.head.bandana.thief", (-3.0, 0.0, -7.0)), color: None ), (Orc, Female, "common.items.armor.misc.head.bandana.thief"): ( @@ -864,43 +864,43 @@ ), // (Danari, Male, "common.items.armor.cultist.bandana"): ( - vox_spec: ("armor.cultist.bandana", (-2.0, -1.0, -8.0)), + vox_spec: ("armor.cultist.bandana", (-2.0, -2.0, -8.0)), color: None ), (Danari, Female, "common.items.armor.cultist.bandana"): ( - vox_spec: ("armor.cultist.bandana", (-2.0, -1.0, -8.0)), + vox_spec: ("armor.cultist.bandana", (-2.0, -2.0, -8.0)), color: None ), (Dwarf, Male, "common.items.armor.cultist.bandana"): ( - vox_spec: ("armor.cultist.bandana", (-5.0, 0.0, -10.0)), + vox_spec: ("armor.cultist.bandana", (-5.0, -1.0, -10.0)), color: None ), (Dwarf, Female, "common.items.armor.cultist.bandana"): ( - vox_spec: ("armor.cultist.bandana", (-5.0, 0.0, -10.0)), + vox_spec: ("armor.cultist.bandana", (-5.0, -1.0, -10.0)), color: None ), (Human, Male, "common.items.armor.cultist.bandana"): ( - vox_spec: ("armor.cultist.bandana", (-4.0, -1.0, -10.0)), + vox_spec: ("armor.cultist.bandana", (-4.0, -2.0, -10.0)), color: None ), (Human, Female, "common.items.armor.cultist.bandana"): ( - vox_spec: ("armor.cultist.bandana", (-4.0, 0.0, -10.0)), + vox_spec: ("armor.cultist.bandana", (-4.0, -1.0, -10.0)), color: None ), (Draugr, Male, "common.items.armor.cultist.bandana"): ( - vox_spec: ("armor.cultist.bandana", (-6.0, -1.0, -8.0)), + vox_spec: ("armor.cultist.bandana", (-6.0, -2.0, -8.0)), color: None ), (Draugr, Female, "common.items.armor.cultist.bandana"): ( - vox_spec: ("armor.cultist.bandana", (-6.0, -1.0, -9.0)), + vox_spec: ("armor.cultist.bandana", (-6.0, -2.0, -9.0)), color: None ), (Elf, Male, "common.items.armor.cultist.bandana"): ( - vox_spec: ("armor.cultist.bandana", (-3.0, -1.0, -10.0)), + vox_spec: ("armor.cultist.bandana", (-3.0, -2.0, -10.0)), color: None ), (Elf, Female, "common.items.armor.cultist.bandana"): ( - vox_spec: ("armor.cultist.bandana", (-3.0, -1.0, -10.0)), + vox_spec: ("armor.cultist.bandana", (-3.0, -2.0, -10.0)), color: None ), (Orc, Male, "common.items.armor.cultist.bandana"): ( @@ -908,7 +908,7 @@ color: None ), (Orc, Female, "common.items.armor.cultist.bandana"): ( - vox_spec: ("armor.cultist.bandana", (-3.0, -2.0, -10.0)), + vox_spec: ("armor.cultist.bandana", (-3.0, -3.0, -10.0)), color: None ), // @@ -941,7 +941,7 @@ color: None ), (Danari, Female, "common.items.armor.misc.head.hood"): ( - vox_spec: ("armor.misc.head.hood", (-2.0, -6.0, -2.0)), + vox_spec: ("armor.misc.head.hood", (-2.0, -5.0, -2.0)), color: None ), (Draugr, Male, "common.items.armor.misc.head.hood"): ( @@ -990,7 +990,7 @@ color: None ), (Danari, Female, "common.items.armor.misc.head.hood_dark"): ( - vox_spec: ("armor.misc.head.hood_dark", (-2.0, -7.0, -3.0)), + vox_spec: ("armor.misc.head.hood_dark", (-2.0, -6.0, -3.0)), color: None ), (Draugr, Male, "common.items.armor.misc.head.hood_dark"): ( @@ -1035,15 +1035,15 @@ color: None ), (Danari, Male, "common.items.armor.misc.head.spikeguard"): ( - vox_spec: ("armor.misc.head.spikeguard", (-2.0, -4.0, 8.5)), + vox_spec: ("armor.misc.head.spikeguard", (-2.0, -5.0, 8.5)), color: None ), (Danari, Female, "common.items.armor.misc.head.spikeguard"): ( - vox_spec: ("armor.misc.head.spikeguard", (-2.0, -4.0, 9.0)), + vox_spec: ("armor.misc.head.spikeguard", (-2.0, -5.0, 9.0)), color: None ), (Draugr, Male, "common.items.armor.misc.head.spikeguard"): ( - vox_spec: ("armor.misc.head.spikeguard", (-6.0, -4.0, 7.0)), + vox_spec: ("armor.misc.head.spikeguard", (-6.0, -4.0, 8.0)), color: None ), (Draugr, Female, "common.items.armor.misc.head.spikeguard"): ( @@ -1137,7 +1137,7 @@ color: None ), (Danari, Female, "common.items.armor.cardinal.mitre"): ( - vox_spec: ("armor.cardinal.mitre", (-2.0, -5.0, 7.0)), + vox_spec: ("armor.cardinal.mitre", (-2.0, -4.0, 7.0)), color: None ), (Draugr, Male, "common.items.armor.cardinal.mitre"): ( @@ -1231,11 +1231,11 @@ color: None ), (Danari, Male, "common.items.armor.misc.head.winged_coronet"): ( - vox_spec: ("armor.misc.head.winged_coronet", (-2.0, -3.0, 0.0)), + vox_spec: ("armor.misc.head.winged_coronet", (-2.0, -4.0, 0.0)), color: None ), (Danari, Female, "common.items.armor.misc.head.winged_coronet"): ( - vox_spec: ("armor.misc.head.winged_coronet", (-2.0, -3.0, 0.0)), + vox_spec: ("armor.misc.head.winged_coronet", (-2.0, -4.0, 0.0)), color: None ), (Draugr, Male, "common.items.armor.misc.head.winged_coronet"): ( @@ -1337,7 +1337,7 @@ color: None ), (Draugr, Male, "common.items.armor.brinestone.crown"): ( - vox_spec: ("armor.brinestone.crown", (-6.0, -4.0, 2.0)), + vox_spec: ("armor.brinestone.crown", (-6.0, -4.0, 0.0)), color: None ), (Draugr, Female, "common.items.armor.brinestone.crown"): ( @@ -1345,7 +1345,7 @@ color: None ), (Orc, Male, "common.items.armor.brinestone.crown"): ( - vox_spec: ("armor.brinestone.crown", (-3.0, -2.0, 2.0)), + vox_spec: ("armor.brinestone.crown", (-3.0, -2.0, 1.0)), color: None ), (Orc, Female, "common.items.armor.brinestone.crown"): ( diff --git a/assets/voxygen/voxel/humanoid_armor_pants_manifest.ron b/assets/voxygen/voxel/humanoid_armor_pants_manifest.ron index ca807a95bd..bf60623f17 100644 --- a/assets/voxygen/voxel/humanoid_armor_pants_manifest.ron +++ b/assets/voxygen/voxel/humanoid_armor_pants_manifest.ron @@ -41,7 +41,7 @@ color: None ), "common.items.armor.brinestone.pants": ( - vox_spec: ("armor.brinestone.pants", (-7.0, -3.5, 0.0)), + vox_spec: ("armor.brinestone.pants", (-7.0, -3.5, -1.0)), color: None ), "common.items.npc_armor.pants.plate_red": ( @@ -77,7 +77,7 @@ color: Some((30, 0, 64)) ), "common.items.armor.leather_plate.pants": ( - vox_spec: ("armor.leather_plate.pants", (-5.0, -4.5, 1.0)), + vox_spec: ("armor.leather_plate.pants", (-5.0, -3.5, 1.0)), color: None ), "common.items.armor.twigs.pants": ( @@ -125,39 +125,39 @@ color: None ), "common.items.armor.hide.scale.pants": ( - vox_spec: ("armor.hide.scale.pants", (-5.0, -4.0, 0.0)), + vox_spec: ("armor.hide.scale.pants", (-5.0, -3.5, 0.0)), color: None ), "common.items.armor.hide.carapace.pants": ( - vox_spec: ("armor.hide.carapace.pants", (-6.0, -4.0, 0.5)), + vox_spec: ("armor.hide.carapace.pants", (-6.0, -3.5, 1.0)), color: None ), "common.items.armor.hide.primal.pants": ( - vox_spec: ("armor.hide.primal.pants", (-6.0, -4.0, 0.0)), + vox_spec: ("armor.hide.primal.pants", (-6.0, -3.5, 1.0)), color: None ), "common.items.armor.hide.dragonscale.pants": ( - vox_spec: ("armor.hide.dragonscale.pants", (-5.0, -3.5, -1.5)), + vox_spec: ("armor.hide.dragonscale.pants", (-5.0, -3.5, -1.0)), color: None ), "common.items.armor.savage.pants": ( - vox_spec: ("armor.savage.pants", (-5.0, -4.0, 0.5)), + vox_spec: ("armor.savage.pants", (-5.0, -3.5, 1.0)), color: None ), "common.items.armor.witch.pants": ( - vox_spec: ("armor.witch.pants", (-5.0, -4.0, 0.5)), + vox_spec: ("armor.witch.pants", (-5.0, -3.5, 0.0)), color: None ), "common.items.armor.pirate.pants": ( - vox_spec: ("armor.pirate.pants", (-5.0, -4.0, 1.5)), + vox_spec: ("armor.pirate.pants", (-5.0, -3.5, 0.0)), color: None ), "common.items.armor.alchemist.pants": ( - vox_spec: ("armor.alchemist", (-5.0, -4.0, 0.5), 3), + vox_spec: ("armor.alchemist", (-5.0, -3.5, 0.0), 3), color: None ), "common.items.armor.blacksmith.pants": ( - vox_spec: ("armor.blacksmith.pants", (-5.0, -4.0, 0.5)), + vox_spec: ("armor.blacksmith.pants", (-5.0, -3.5, 0.0)), color: None ), "common.items.armor.chef.pants": ( @@ -165,59 +165,59 @@ color: None ), "common.items.armor.cloth.linen.pants": ( - vox_spec: ("armor.cloth.linen.pants", (-5.0, -4.0, 0.5)), + vox_spec: ("armor.cloth.linen.pants", (-5.0, -3.5, 0.0)), color: None ), "common.items.armor.cloth.woolen.pants": ( - vox_spec: ("armor.cloth.woolen.pants", (-6.0, -5.0, 0.5)), + vox_spec: ("armor.cloth.woolen.pants", (-6.0, -4.5, 1.0)), color: None ), "common.items.armor.cloth.silken.pants": ( - vox_spec: ("armor.cloth.silken.pants", (-5.0, -4.0, 0.5)), + vox_spec: ("armor.cloth.silken.pants", (-5.0, -3.5, 0.0)), color: None ), "common.items.armor.cloth.druid.pants": ( - vox_spec: ("armor.cloth.druid.pants", (-5.0, -4.0, 0.5)), + vox_spec: ("armor.cloth.druid.pants", (-5.0, -3.5, -1.0)), color: None ), "common.items.armor.cloth.moonweave.pants": ( - vox_spec: ("armor.cloth.moonweave.pants", (-6.0, -5.5, 0.5)), + vox_spec: ("armor.cloth.moonweave.pants", (-6.0, -4.5, 0.0)), color: None ), "common.items.armor.cloth.sunsilk.pants": ( - vox_spec: ("armor.cloth.sunsilk.pants", (-6.0, -5.0, 0.5)), + vox_spec: ("armor.cloth.sunsilk.pants", (-6.0, -4.5, 0.0)), color: None ), "common.items.armor.mail.bronze.pants": ( - vox_spec: ("armor.mail.bronze.pants", (-5.0, -4.0, 1.0)), + vox_spec: ("armor.mail.bronze.pants", (-5.0, -3.5, 1.0)), color: None ), "common.items.armor.mail.iron.pants": ( - vox_spec: ("armor.mail.iron.pants", (-5.0, -4.0, 1.5)), + vox_spec: ("armor.mail.iron.pants", (-5.0, -3.5, 1.0)), color: None ), "common.items.armor.mail.steel.pants": ( - vox_spec: ("armor.mail.steel.pants", (-6.0, -4.0, 0.0)), + vox_spec: ("armor.mail.steel.pants", (-6.0, -3.5, 1.0)), color: None ), "common.items.armor.mail.cobalt.pants": ( - vox_spec: ("armor.mail.cobalt.pants", (-6.0, -5.0, 0.5)), + vox_spec: ("armor.mail.cobalt.pants", (-6.0, -5.5, 1.0)), color: None ), "common.items.armor.mail.bloodsteel.pants": ( - vox_spec: ("armor.mail.bloodsteel.pants", (-7.0, -4.0, 0.5)), + vox_spec: ("armor.mail.bloodsteel.pants", (-7.0, -4.5, 0.0)), color: None ), "common.items.armor.mail.orichalcum.pants": ( - vox_spec: ("armor.mail.orichalcum", (-6.0, -4.0, 0.5), 1), + vox_spec: ("armor.mail.orichalcum", (-6.0, -3.5, -1.0), 1), color: None ), "common.items.armor.cardinal.pants": ( - vox_spec: ("armor.cardinal.pants", (-5.0, -4.0, -0.4)), + vox_spec: ("armor.cardinal.pants", (-5.0, -3.5, 0.0)), color: None ), "common.items.armor.merchant.pants": ( - vox_spec: ("armor.merchant.pants", (-6.0, -4.0, 0.5)), + vox_spec: ("armor.merchant.pants", (-5.0, -3.5, 0.0)), color: None ), }, diff --git a/assets/voxygen/voxel/humanoid_armor_shoulder_manifest.ron b/assets/voxygen/voxel/humanoid_armor_shoulder_manifest.ron index e6e0c3c659..ca0f4baf83 100644 --- a/assets/voxygen/voxel/humanoid_armor_shoulder_manifest.ron +++ b/assets/voxygen/voxel/humanoid_armor_shoulder_manifest.ron @@ -23,11 +23,11 @@ ), "common.items.armor.assassin.shoulder": ( left: ( - vox_spec: ("armor.assassin.shoulder", (-4.0, -3.5, 1.0)), + vox_spec: ("armor.assassin.shoulder", (-5.0, -3.5, 0.0)), color: None ), right: ( - vox_spec: ("armor.assassin.shoulder", (-2.0, -3.5, 1.0)), + vox_spec: ("armor.assassin.shoulder", (-1.0, -3.5, 0.0)), color: None ) ), @@ -53,121 +53,121 @@ ), "common.items.armor.boreal.shoulder": ( left: ( - vox_spec: ("armor.boreal.shoulder", (-3.5, -3.5, -3.0)), + vox_spec: ("armor.boreal.shoulder", (-4.0, -3.5, -1.0)), color: None ), right: ( - vox_spec: ("armor.boreal.shoulder", (-1.5, -3.5, -3.0)), + vox_spec: ("armor.boreal.shoulder", (-1.0, -3.5, -1.0)), color: None ) ), "common.items.armor.brinestone.shoulder": ( left: ( - vox_spec: ("armor.brinestone.shoulder", (-5.0, -3.5, -2.0)), + vox_spec: ("armor.brinestone.shoulder", (-6.0, -3.5, -1.0)), color: None ), right: ( - vox_spec: ("armor.brinestone.shoulder", (-3.0, -3.5, -2.0)), + vox_spec: ("armor.brinestone.shoulder", (-2.0, -3.5, -1.0)), color: None ) ), "common.items.armor.cloth_purple.shoulder": ( left: ( - vox_spec: ("armor.cloth_purple.shoulder", (-3.2, -3.5, 0.0)), + vox_spec: ("armor.cloth_purple.shoulder", (-4.0, -3.5, 0.0)), color: None ), right: ( - vox_spec: ("armor.cloth_purple.shoulder", (-1.8, -3.5, 0.0)), + vox_spec: ("armor.cloth_purple.shoulder", (-1.0, -3.5, 0.0)), color: None ) ), "common.items.armor.cloth_blue.shoulder_0": ( left: ( - vox_spec: ("armor.cloth_blue.shoulder_0", (-3.2, -3.5, 0.0)), + vox_spec: ("armor.cloth_blue.shoulder_0", (-4.0, -3.5, 0.0)), color: None ), right: ( - vox_spec: ("armor.cloth_blue.shoulder_0", (-1.8, -3.5, 0.0)), + vox_spec: ("armor.cloth_blue.shoulder_0", (-1.0, -3.5, 0.0)), color: None ) ), "common.items.armor.cloth_green.shoulder": ( left: ( - vox_spec: ("armor.cloth_green.shoulder", (-3.2, -3.5, 0.0)), + vox_spec: ("armor.cloth_green.shoulder", (-4.0, -3.5, 0.0)), color: None ), right: ( - vox_spec: ("armor.cloth_green.shoulder", (-1.8, -3.5, 0.0)), + vox_spec: ("armor.cloth_green.shoulder", (-1.0, -3.5, 0.0)), color: None ) ), "common.items.armor.cultist.shoulder": ( left: ( - vox_spec: ("armor.cultist.shoulder", (-2.0, -3.5, 0.0)), + vox_spec: ("armor.cultist.shoulder", (-3.0, -3.5, -1.0)), color: Some((30, 0, 64)) ), right: ( - vox_spec: ("armor.cultist.shoulder", (-2.9, -3.5, 0.0)), + vox_spec: ("armor.cultist.shoulder", (-2.0, -3.5, -1.0)), color: Some((30, 0, 64)) ) ), "common.items.armor.leather_plate.shoulder": ( left: ( - vox_spec: ("armor.leather_plate.shoulder", (-4.0, -4.5 , 0.0)), + vox_spec: ("armor.leather_plate.shoulder", (-4.0, -3.5 , 0.0)), color: None ), right: ( - vox_spec: ("armor.leather_plate.shoulder", (-0.9, -4.5, 0.0)), + vox_spec: ("armor.leather_plate.shoulder", (-0.9, -3.5, 0.0)), color: None ) ), "common.items.armor.twigs.shoulder": ( left: ( - vox_spec: ("armor.twigs.shoulder", (-5.0, -4.5 , -1.0)), + vox_spec: ("armor.twigs.shoulder", (-5.0, -4.0 , -1.0)), color: None ), right: ( - vox_spec: ("armor.twigs.shoulder", (-1.0, -4.5, -1.0)), + vox_spec: ("armor.twigs.shoulder", (-1.0, -4.0, -1.0)), color: None ) ), "common.items.armor.twigsleaves.shoulder": ( left: ( - vox_spec: ("armor.twigsleaves.shoulder", (-5.5, -5.0 , 0.0)), + vox_spec: ("armor.twigsleaves.shoulder", (-6.0, -5.0 , -1.0)), color: None ), right: ( - vox_spec: ("armor.twigsleaves.shoulder", (-1.5, -5.0, 0.0)), + vox_spec: ("armor.twigsleaves.shoulder", (-1.0, -5.0, -1.0)), color: None ) ), "common.items.armor.twigsflowers.shoulder": ( left: ( - vox_spec: ("armor.twigsflowers.shoulder", (-5.5, -5.0 , 0.0)), + vox_spec: ("armor.twigsflowers.shoulder", (-6.0, -4.0 , -2.0)), color: None ), right: ( - vox_spec: ("armor.twigsflowers.shoulder", (-1.5, -5.0, 0.0)), + vox_spec: ("armor.twigsflowers.shoulder", (-1.0, -4.0, -2.0)), color: None ), ), "common.items.armor.cloth_blue.shoulder_1": ( left: ( - vox_spec: ("armor.cloth_blue.shoulder_1", (-4.0, -2.5, -0.5)), + vox_spec: ("armor.cloth_blue.shoulder_1", (-4.0, -2.5, 0.0)), color: None ), right: ( - vox_spec: ("armor.cloth_blue.shoulder_1", (-1.0, -2.5, -0.5)), + vox_spec: ("armor.cloth_blue.shoulder_1", (-1.0, -2.5, 0.0)), color: None ) ), "common.items.armor.misc.shoulder.iron_spikes": ( left: ( - vox_spec: ("armor.misc.shoulder.iron_spikes", (-5.5, -3.8, -2.0)), + vox_spec: ("armor.misc.shoulder.iron_spikes", (-6.0, -3.5, -2.0)), color: None ), right: ( - vox_spec: ("armor.misc.shoulder.iron_spikes", (-1.5, -3.8, -2.0)), + vox_spec: ("armor.misc.shoulder.iron_spikes", (-1.0, -3.5, -2.0)), color: None ) ), @@ -183,31 +183,31 @@ ), "common.items.armor.misc.shoulder.leather_iron_2": ( left: ( - vox_spec: ("armor.misc.shoulder.leather_iron_2", (-5.0, -2.5, -0.5)), + vox_spec: ("armor.misc.shoulder.leather_iron_2", (-5.0, -2.5, 0.0)), color: None ), right: ( - vox_spec: ("armor.misc.shoulder.leather_iron_2", (-2.0, -2.5, -0.5)), + vox_spec: ("armor.misc.shoulder.leather_iron_2", (-2.0, -2.5, 0.0)), color: None ) ), "common.items.armor.misc.shoulder.leather_iron_1": ( left: ( - vox_spec: ("armor.misc.shoulder.leather_iron_1", (-5.0, -2.5, -0.5)), + vox_spec: ("armor.misc.shoulder.leather_iron_1", (-5.0, -2.5, 0.0)), color: None ), right: ( - vox_spec: ("armor.misc.shoulder.leather_iron_1", (-2.0, -2.5, -0.5)), + vox_spec: ("armor.misc.shoulder.leather_iron_1", (-2.0, -2.5, 0.0)), color: None ) ), "common.items.armor.misc.shoulder.leather_iron_0": ( left: ( - vox_spec: ("armor.misc.shoulder.leather_iron_0", (-6.0, -2.5, -0.5)), + vox_spec: ("armor.misc.shoulder.leather_iron_0", (-6.0, -2.5, 0.0)), color: None ), right: ( - vox_spec: ("armor.misc.shoulder.leather_iron_0", (-2.0, -2.5, -0.5)), + vox_spec: ("armor.misc.shoulder.leather_iron_0", (-2.0, -2.5, 0.0)), color: None ) ), @@ -223,21 +223,21 @@ ), "common.items.armor.tarasque.shoulder": ( left: ( - vox_spec: ("armor.tarasque.shoulder", (-5.0, -3.5 , 0.0)), + vox_spec: ("armor.tarasque.shoulder", (-4.0, -3.5 , -1.0)), color: None ), right: ( - vox_spec: ("armor.tarasque.shoulder", (-0.0, -3.5, 0.0)), + vox_spec: ("armor.tarasque.shoulder", (-1.0, -3.5, -1.0)), color: None ) ), "common.items.armor.bonerattler.shoulder": ( left: ( - vox_spec: ("armor.bonerattler.shoulder", (-4.0, -3.5 , 1.0)), + vox_spec: ("armor.bonerattler.shoulder", (-4.0, -3.5 , 0.0)), color: None ), right: ( - vox_spec: ("armor.bonerattler.shoulder", (-1.0, -3.5, 1.0)), + vox_spec: ("armor.bonerattler.shoulder", (-1.0, -3.5, 0.0)), color: None ) ), @@ -263,97 +263,97 @@ ), "common.items.armor.hide.rawhide.shoulder": ( left: ( - vox_spec: ("armor.hide.rawhide.shoulder", (-4.0, -3.2, -0.5)), + vox_spec: ("armor.hide.rawhide.shoulder", (-4.0, -3.5, 0.0)), color: None ), right: ( - vox_spec: ("armor.hide.rawhide.shoulder", (-1.0, -3.2, -0.5)), + vox_spec: ("armor.hide.rawhide.shoulder", (-1.0, -3.5, 0.0)), color: None ) ), "common.items.armor.hide.leather.shoulder": ( left: ( - vox_spec: ("armor.hide.leather.shoulder", (-5.5, -3.2, -1.8)), + vox_spec: ("armor.hide.leather.shoulder", (-5.0, -3.5, -2.0)), color: None ), right: ( - vox_spec: ("armor.hide.leather.shoulder", (-0.5, -3.2, -1.8)), + vox_spec: ("armor.hide.leather.shoulder", (-1.0, -3.5, -2.0)), color: None ) ), "common.items.armor.miner.shoulder": ( left: ( - vox_spec: ("armor.hide.leather.shoulder", (-5.5, -3.2, -1.8)), + vox_spec: ("armor.hide.leather.shoulder", (-5.0, -3.5, -2.0)), color: None ), right: ( - vox_spec: ("armor.hide.leather.shoulder", (-0.5, -3.2, -1.8)), + vox_spec: ("armor.hide.leather.shoulder", (-1.0, -3.5, -2.0)), color: None ) ), "common.items.armor.hide.scale.shoulder": ( left: ( - vox_spec: ("armor.hide.scale.shoulder", (-3.2, -3.5 , 0.0)), + vox_spec: ("armor.hide.scale.shoulder", (-5.0, -3.5, -1.0)), color: None ), right: ( - vox_spec: ("armor.hide.scale.shoulder", (-1.4, -3.5, -0.5)), + vox_spec: ("armor.hide.scale.shoulder", (-1.0, -3.5, -1.0)), color: None ) ), "common.items.armor.hide.carapace.shoulder": ( left: ( - vox_spec: ("armor.hide.carapace.shoulder", (-6.0, -4.0 , -2.0)), + vox_spec: ("armor.hide.carapace.shoulder", (-6.0, -3.5, -3.0)), color: None ), right: ( - vox_spec: ("armor.hide.carapace.shoulder", (-1.0, -4.0, -2.0)), + vox_spec: ("armor.hide.carapace.shoulder", (-1.0, -3.5, -3.0)), color: None ) ), "common.items.armor.hide.primal.shoulder": ( left: ( - vox_spec: ("armor.hide.primal.shoulder", (-6.0, -4.0 , -3.0)), + vox_spec: ("armor.hide.primal.shoulder", (-6.0, -3.5, -3.0)), color: None ), right: ( - vox_spec: ("armor.hide.primal.shoulder", (-1.0, -4.0, -3.0)), + vox_spec: ("armor.hide.primal.shoulder", (-1.0, -3.5, -3.0)), color: None ) ), "common.items.armor.hide.dragonscale.shoulder": ( left: ( - vox_spec: ("armor.hide.dragonscale.shoulder", (-9.0, -3.5 , -1.0)), + vox_spec: ("armor.hide.dragonscale.shoulder", (-8.0, -3.5 , -2.0)), color: None ), right: ( - vox_spec: ("armor.hide.dragonscale.shoulder", (0.0, -3.5, -1.0)), + vox_spec: ("armor.hide.dragonscale.shoulder", (-1.0, -3.5, -2.0)), color: None ) ), "common.items.armor.savage.shoulder": ( left: ( - vox_spec: ("armor.savage.shoulder", (-5.5, -4.0 , -2.0)), + vox_spec: ("armor.savage.shoulder", (-5.0, -3.5 , -2.0)), color: None ), right: ( - vox_spec: ("armor.savage.shoulder", (-0.5, -4.0, -2.0)), + vox_spec: ("armor.savage.shoulder", (-1.0, -3.5, -2.0)), color: None ) ), "common.items.armor.witch.shoulder": ( left: ( - vox_spec: ("armor.witch.shoulder", (-5.0, -4.0 , -2.0)), + vox_spec: ("armor.witch.shoulder", (-5.0, -3.5, -1.0)), color: None ), right: ( - vox_spec: ("armor.witch.shoulder", (-1.0, -4.0 , -2.0)), + vox_spec: ("armor.witch.shoulder", (-1.0, -3.5, -1.0)), color: None ) ), "common.items.armor.pirate.shoulder": ( left: ( - vox_spec: ("armor.pirate.shoulder", (-5.0, -4.0 , -2.0)), + vox_spec: ("armor.pirate.shoulder", (-5.0, -3.5 , -1.0)), color: None ), right: ( @@ -363,127 +363,127 @@ ), "common.items.armor.cloth.linen.shoulder": ( left: ( - vox_spec: ("armor.cloth.linen.shoulder", (-3.5, -4.0 , -1.0)), + vox_spec: ("armor.cloth.linen.shoulder", (-3.0, -3.5 , 0.0)), color: None ), right: ( - vox_spec: ("armor.cloth.linen.shoulder", (-0.5, -4.0, -1.0)), + vox_spec: ("armor.cloth.linen.shoulder", (-1.0, -3.5, 0.0)), color: None ) ), "common.items.armor.cloth.woolen.shoulder": ( left: ( - vox_spec: ("armor.cloth.woolen.shoulder", (-5.5, -4.0 , -3.0)), + vox_spec: ("armor.cloth.woolen.shoulder", (-5.0, -3.5, -2.0)), color: None ), right: ( - vox_spec: ("armor.cloth.woolen.shoulder", (-0.5, -4.0, -3.0)), + vox_spec: ("armor.cloth.woolen.shoulder", (-1.0, -3.5, -2.0)), color: None ) ), "common.items.armor.cloth.silken.shoulder": ( left: ( - vox_spec: ("armor.cloth.silken.shoulder", (-5.0, -4.0 , -2.0)), + vox_spec: ("armor.cloth.silken.shoulder", (-5.0, -3.5 , -1.0)), color: None ), right: ( - vox_spec: ("armor.cloth.silken.shoulder", (-1.0, -4.0, -2.0)), + vox_spec: ("armor.cloth.silken.shoulder", (-1.0, -3.5, -1.0)), color: None ) ), "common.items.armor.cloth.druid.shoulder": ( left: ( - vox_spec: ("armor.cloth.druid.shoulder", (-4.5, -4.0 , -3.5)), + vox_spec: ("armor.cloth.druid.shoulder", (-5.0, -4.5 , -4.0)), color: None ), right: ( - vox_spec: ("armor.cloth.druid.shoulder", (-1.5, -4.0, -3.5)), + vox_spec: ("armor.cloth.druid.shoulder", (-1.0, -4.5, -4.0)), color: None ) ), "common.items.armor.cloth.moonweave.shoulder": ( left: ( - vox_spec: ("armor.cloth.moonweave.shoulder", (-4.5, -4.0 , -3.0)), + vox_spec: ("armor.cloth.moonweave.shoulder", (-5.0, -3.5 , -3.0)), color: None ), right: ( - vox_spec: ("armor.cloth.moonweave.shoulder", (-1.5, -4.0, -3.0)), + vox_spec: ("armor.cloth.moonweave.shoulder", (-1.0, -3.5, -3.0)), color: None ) ), "common.items.armor.cloth.sunsilk.shoulder": ( left: ( - vox_spec: ("armor.cloth.sunsilk.shoulder", (-6.5, -4.0 , -2.0)), + vox_spec: ("armor.cloth.sunsilk.shoulder", (-6.0, -3.5 , -1.0)), color: None ), right: ( - vox_spec: ("armor.cloth.sunsilk.shoulder", (-0.5, -4.0, -2.0)), + vox_spec: ("armor.cloth.sunsilk.shoulder", (-1.0, -3.5, -1.0)), color: None ) ), "common.items.armor.mail.bronze.shoulder": ( left: ( - vox_spec: ("armor.mail.bronze.shoulder", (-4.5, -4.0 , 0.0)), + vox_spec: ("armor.mail.bronze.shoulder", (-5.0, -3.5 , 0.0)), color: None ), right: ( - vox_spec: ("armor.mail.bronze.shoulder", (-1.5, -4.0, 0.0)), + vox_spec: ("armor.mail.bronze.shoulder", (-1.0, -3.5, 0.0)), color: None ) ), "common.items.armor.mail.iron.shoulder": ( left: ( - vox_spec: ("armor.mail.iron.shoulder", (-5.5, -4.0 , -1.0)), + vox_spec: ("armor.mail.iron.shoulder", (-5.0, -3.5, -1.0)), color: None ), right: ( - vox_spec: ("armor.mail.iron.shoulder", (-0.5, -4.0, -1.0)), + vox_spec: ("armor.mail.iron.shoulder", (-1.0, -3.5, -1.0)), color: None ) ), "common.items.armor.mail.steel.shoulder": ( left: ( - vox_spec: ("armor.mail.steel.shoulder", (-5.5, -3.0 , -2.0)), + vox_spec: ("armor.mail.steel.shoulder", (-6.0, -3.5 , -1.0)), color: None ), right: ( - vox_spec: ("armor.mail.steel.shoulder", (-1.5, -3.0, -2.0)), + vox_spec: ("armor.mail.steel.shoulder", (-1.0, -3.5, -1.0)), color: None ) ), "common.items.armor.mail.cobalt.shoulder": ( left: ( - vox_spec: ("armor.mail.cobalt.shoulder", (-5.5, -4.0 , -1.0)), + vox_spec: ("armor.mail.cobalt.shoulder", (-6.0, -4.5 , -1.0)), color: None ), right: ( - vox_spec: ("armor.mail.cobalt.shoulder", (-1.5, -4.0, -1.0)), + vox_spec: ("armor.mail.cobalt.shoulder", (-1.0, -4.5, -1.0)), color: None ) ), "common.items.armor.mail.bloodsteel.shoulder": ( left: ( - vox_spec: ("armor.mail.bloodsteel.shoulder", (-6.5, -5.0 , -3.0)), + vox_spec: ("armor.mail.bloodsteel.shoulder", (-8.0, -5.5, -3.0)), color: None ), right: ( - vox_spec: ("armor.mail.bloodsteel.shoulder", (-2.5, -5.0, -3.0)), + vox_spec: ("armor.mail.bloodsteel.shoulder", (-1.0, -5.5, -3.0)), color: None ) ), "common.items.armor.mail.orichalcum.shoulder": ( left: ( - vox_spec: ("armor.mail.orichalcum", (-7.5, -3.0 , -2.0), 5), + vox_spec: ("armor.mail.orichalcum", (-8.0, -3.5, -2.0), 5), color: None ), right: ( - vox_spec: ("armor.mail.orichalcum", (-1.5, -3.0, -2.0), 5), + vox_spec: ("armor.mail.orichalcum", (-1.0, -3.5, -2.0), 5), color: None ) ), "common.items.armor.cardinal.shoulder": ( left: ( - vox_spec: ("armor.cardinal.shoulder", (-5.0, -4.0, -2.0)), + vox_spec: ("armor.cardinal.shoulder", (-5.0, -2.5, -1.0)), color: None ), right: ( diff --git a/assets/voxygen/voxel/npc/crab/crab.vox b/assets/voxygen/voxel/npc/crab/crab.vox new file mode 100644 index 0000000000..0f66c21bad --- /dev/null +++ b/assets/voxygen/voxel/npc/crab/crab.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:284544e0c847991458fdf59ca0c82be58577e0b38b44d2377813a57a59f330ec +size 5100 diff --git a/assets/voxygen/voxel/sprite/furniture/barrel.vox b/assets/voxygen/voxel/sprite/furniture/barrel.vox new file mode 100644 index 0000000000..78858b9262 --- /dev/null +++ b/assets/voxygen/voxel/sprite/furniture/barrel.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e5bf9f6b005a46ec55e2155434257c783020e5eb62f2f9ea582a3801f9a14e8 +size 3416 diff --git a/assets/voxygen/voxel/sprite/furniture/crate_block.vox b/assets/voxygen/voxel/sprite/furniture/crate_block.vox new file mode 100644 index 0000000000..ec905a9392 --- /dev/null +++ b/assets/voxygen/voxel/sprite/furniture/crate_block.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ab958279e6c8b97055721ac2cce177614c591e62cf12a606af2a76def0090b13 +size 5700 diff --git a/assets/voxygen/voxel/sprite/furniture/hirdrasil-antler-1.vox b/assets/voxygen/voxel/sprite/furniture/hirdrasil-antler-1.vox new file mode 100644 index 0000000000..0351935493 --- /dev/null +++ b/assets/voxygen/voxel/sprite/furniture/hirdrasil-antler-1.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b39740b7f67224a120682db2fab437ce436c7e9c23aac4b9e5eb4ae0b83b5e81 +size 1920 diff --git a/assets/voxygen/voxel/sprite/furniture/hirdrasil-antler.vox b/assets/voxygen/voxel/sprite/furniture/hirdrasil-antler.vox new file mode 100644 index 0000000000..542f1a9867 --- /dev/null +++ b/assets/voxygen/voxel/sprite/furniture/hirdrasil-antler.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0b22c2011b06c33bb07b9697cc969aa8c6f731e025eae21ab43575693ea15050 +size 3799 diff --git a/assets/voxygen/voxel/sprite_manifest.ron b/assets/voxygen/voxel/sprite_manifest.ron index 8566f8668c..c855ee56c1 100644 --- a/assets/voxygen/voxel/sprite_manifest.ron +++ b/assets/voxygen/voxel/sprite_manifest.ron @@ -2240,6 +2240,16 @@ ChristmasOrnament: Some(( offset: (-5.5, 0.5, 0.0), lod_axes: (1.0, 1.0, 1.0), ), + ( + model: "voxygen.voxel.sprite.furniture.hirdrasil-antler", + offset: (-10.5, -2.5, -3.0), + lod_axes: (1.0, 1.0, 1.0), + ), + ( + model: "voxygen.voxel.sprite.furniture.hirdrasil-antler-1", + offset: (-6.5, -2.5, -3.0), + lod_axes: (1.0, 1.0, 1.0), + ), ( model: "voxygen.voxel.sprite.furniture.moravian-star-orange", offset: (-5.5, -7.5, 0.0), @@ -4609,4 +4619,24 @@ HotSurface: Some(( variations: [], wind_sway: 0.0, )), +Barrel: Some(( + variations: [ + ( + model: "voxygen.voxel.sprite.furniture.barrel", + offset: (-4.5, -4.5, 0.0), + lod_axes: (1.0, 1.0, 1.0), + ), + ], + wind_sway: 0.0, +)), +CrateBlock: Some(( + variations: [ + ( + model: "voxygen.voxel.sprite.furniture.crate_block", + offset: (-5.5, -5.5, 0.0), + lod_axes: (1.0, 1.0, 1.0), + ), + ], + wind_sway: 0.0, +)), } diff --git a/assets/world/wildlife/spawn/tropical/beach.ron b/assets/world/wildlife/spawn/tropical/beach.ron index 3890ed270c..2282be4118 100644 --- a/assets/world/wildlife/spawn/tropical/beach.ron +++ b/assets/world/wildlife/spawn/tropical/beach.ron @@ -5,6 +5,7 @@ SpawnEntry ( Pack( groups: [ (3, (1, 3, "common.entity.wild.aggressive.sea_crocodile")), + (3, (8, 16, "common.entity.wild.peaceful.crab")), (1, (1, 1, "common.entity.wild.aggressive.reefsnapper")), ], spawn_mode: Land, diff --git a/assets/world/wildlife/spawn/tropical/river.ron b/assets/world/wildlife/spawn/tropical/river.ron index 948abacd78..b9d8988d81 100644 --- a/assets/world/wildlife/spawn/tropical/river.ron +++ b/assets/world/wildlife/spawn/tropical/river.ron @@ -14,6 +14,7 @@ SpawnEntry ( Pack( groups: [ (2, (1, 1, "common.entity.wild.peaceful.kelpie")), + (2, (8, 16, "common.entity.wild.peaceful.crab")), (2, (1, 1, "common.entity.wild.aggressive.crocodile")), ], spawn_mode: Land, diff --git a/common/src/bin/csv_export/main.rs b/common/src/bin/csv_export/main.rs index cb191e3a03..24e18b6a6a 100644 --- a/common/src/bin/csv_export/main.rs +++ b/common/src/bin/csv_export/main.rs @@ -326,8 +326,11 @@ fn entity_drops(entity_config: &str) -> Result<(), Box> { asset_path: &str, ) -> Result<(), Box> { let entity_config = EntityConfig::load_expect(asset_path).read(); - let entity_info = EntityInfo::at(Vec3::new(0.0, 0.0, 0.0)) - .with_asset_expect(asset_path, &mut rand::thread_rng()); + let entity_info = EntityInfo::at(Vec3::new(0.0, 0.0, 0.0)).with_asset_expect( + asset_path, + &mut rand::thread_rng(), + None, + ); let name = entity_info.name.unwrap_or_default(); // Create initial entry in drop table diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index a6669cad24..20560ef8de 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -615,7 +615,7 @@ pub enum CharacterAbilityType { ChargedRanged, DashMelee(StageSection), BasicBlock, - ComboMelee(StageSection, u32), + ComboMeleeDeprecated(StageSection, u32), ComboMelee2(StageSection), FinisherMelee(StageSection), DiveMelee(StageSection), @@ -642,7 +642,9 @@ impl From<&CharacterState> for CharacterAbilityType { CharacterState::BasicBlock(_) => Self::BasicBlock, CharacterState::LeapMelee(data) => Self::LeapMelee(data.stage_section), CharacterState::LeapShockwave(data) => Self::LeapShockwave(data.stage_section), - CharacterState::ComboMelee(data) => Self::ComboMelee(data.stage_section, data.stage), + CharacterState::ComboMeleeDeprecated(data) => { + Self::ComboMeleeDeprecated(data.stage_section, data.stage) + }, CharacterState::ComboMelee2(data) => Self::ComboMelee2(data.stage_section), CharacterState::FinisherMelee(data) => Self::FinisherMelee(data.stage_section), CharacterState::DiveMelee(data) => Self::DiveMelee(data.stage_section), @@ -771,7 +773,7 @@ pub enum CharacterAbility { #[serde(default)] meta: AbilityMeta, }, - ComboMelee { + ComboMeleeDeprecated { stage_data: Vec>, initial_energy_gain: f32, max_energy_gain: f32, @@ -1071,7 +1073,6 @@ impl CharacterAbility { && match self { CharacterAbility::Roll { energy_cost, .. } => { data.physics.on_ground.is_some() - && data.inputs.move_dir.magnitude_squared() > 0.25 && update.energy.try_change_by(-*energy_cost).is_ok() }, CharacterAbility::DashMelee { energy_cost, .. } @@ -1135,7 +1136,7 @@ impl CharacterAbility { (data.physics.on_ground.is_none() || buildup_duration.is_some()) && update.energy.try_change_by(-*energy_cost).is_ok() }, - CharacterAbility::ComboMelee { .. } + CharacterAbility::ComboMeleeDeprecated { .. } | CharacterAbility::Boost { .. } | CharacterAbility::BasicBeam { .. } | CharacterAbility::Blink { .. } @@ -1304,7 +1305,7 @@ impl CharacterAbility { *recover_duration /= stats.speed; *energy_cost /= stats.energy_efficiency; }, - ComboMelee { + ComboMeleeDeprecated { ref mut stage_data, initial_energy_gain: _, max_energy_gain: _, @@ -1721,7 +1722,7 @@ impl CharacterAbility { } }, Boost { .. } - | ComboMelee { .. } + | ComboMeleeDeprecated { .. } | Blink { .. } | Music { .. } | BasicSummon { .. } @@ -1769,7 +1770,7 @@ impl CharacterAbility { | RiposteMelee { .. } | BasicBeam { .. } | Boost { .. } - | ComboMelee { .. } + | ComboMeleeDeprecated { .. } | Blink { .. } | Music { .. } | BasicSummon { .. } @@ -1796,7 +1797,7 @@ impl CharacterAbility { | SelfBuff { meta, .. } | BasicBeam { meta, .. } | Boost { meta, .. } - | ComboMelee { meta, .. } + | ComboMeleeDeprecated { meta, .. } | ComboMelee2 { meta, .. } | Blink { meta, .. } | BasicSummon { meta, .. } @@ -1873,7 +1874,7 @@ impl CharacterAbility { use skills::{HammerSkill::*, Skill::Hammer}; match self { - CharacterAbility::ComboMelee { + CharacterAbility::ComboMeleeDeprecated { ref mut speed_increase, ref mut max_speed_increase, ref mut stage_data, @@ -2386,9 +2387,8 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { was_wielded: false, // false by default. utils might set it to true prev_aimed_dir: None, is_sneaking: false, - was_combo: None, }), - CharacterAbility::ComboMelee { + CharacterAbility::ComboMeleeDeprecated { stage_data, initial_energy_gain, max_energy_gain, @@ -2398,7 +2398,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { scales_from_combo, ori_modifier, meta: _, - } => CharacterState::ComboMelee(combo_melee::Data { + } => CharacterState::ComboMeleeDeprecated(combo_melee::Data { static_data: combo_melee::StaticData { num_stages: stage_data.len() as u32, stage_data: stage_data.iter().map(|stage| stage.to_duration()).collect(), diff --git a/common/src/comp/agent.rs b/common/src/comp/agent.rs index 8f4a3d4476..0e5c5e3621 100644 --- a/common/src/comp/agent.rs +++ b/common/src/comp/agent.rs @@ -380,6 +380,7 @@ impl<'a> From<&'a Body> for Psyche { arthropod::Species::Dagonite => 0.2, arthropod::Species::Emberfly => 0.1, }, + Body::Crustacean(_) => 0.0, }, sight_dist: match body { Body::BirdLarge(_) => 250.0, diff --git a/common/src/comp/body.rs b/common/src/comp/body.rs index 9331aff0dd..ef58087c45 100644 --- a/common/src/comp/body.rs +++ b/common/src/comp/body.rs @@ -3,6 +3,7 @@ pub mod biped_large; pub mod biped_small; pub mod bird_large; pub mod bird_medium; +pub mod crustacean; pub mod dragon; pub mod fish_medium; pub mod fish_small; @@ -52,6 +53,7 @@ make_case_elim!( Ship(body: ship::Body) = 14, Arthropod(body: arthropod::Body) = 15, ItemDrop(body: item_drop::Body) = 16, + Crustacean(body: crustacean::Body) = 17, } ); @@ -101,6 +103,7 @@ pub struct AllBodies { pub quadruped_low: BodyData>, pub ship: BodyData, pub arthropod: BodyData>, + pub crustacean: BodyData>, } impl AllBodies { @@ -124,6 +127,7 @@ impl AllBodies { Body::Theropod(b) => &self.theropod.species[&b.species], Body::QuadrupedLow(b) => &self.quadruped_low.species[&b.species], Body::Arthropod(b) => &self.arthropod.species[&b.species], + Body::Crustacean(b) => &self.crustacean.species[&b.species], _ => return None, }) } @@ -150,6 +154,7 @@ impl core::ops::Index for AllBodies &self.dragon.body, NpcKind::Crocodile => &self.quadruped_low.body, NpcKind::Tarantula => &self.arthropod.body, + NpcKind::Crab => &self.crustacean.body, } } } @@ -178,6 +183,7 @@ impl<'a, BodyMeta, SpeciesMeta> core::ops::Index<&'a Body> for AllBodies &self.quadruped_low.body, Body::Arthropod(_) => &self.arthropod.body, Body::Ship(_) => &self.ship.body, + Body::Crustacean(_) => &self.crustacean.body, } } } @@ -254,6 +260,10 @@ impl Body { _ => false, }, Body::Ship(_) => false, + Body::Crustacean(b1) => match other { + Body::Crustacean(b2) => b1.species == b2.species, + _ => false, + }, } } @@ -469,6 +479,8 @@ impl Body { }, Body::Ship(ship) => ship.mass().0, Body::Arthropod(_) => 200.0, + // TODO: mass + Body::Crustacean(_) => 50.0, }; Mass(m) } @@ -641,6 +653,7 @@ impl Body { bird_medium::Species::Puffin => Vec3::new(1.0, 1.0, 1.0), bird_medium::Species::Toucan => Vec3::new(2.1, 1.1, 1.2), }, + Body::Crustacean(_) => Vec3::new(1.2, 1.2, 0.7), } } @@ -965,6 +978,7 @@ impl Body { _ => 70, }, Body::Ship(_) => 1000, + Body::Crustacean(_) => 40, } } @@ -1116,7 +1130,83 @@ impl Body { biped_small::Species::Flamekeeper => 250, _ => 100, }, + Body::BirdLarge(b) => match b.species { + bird_large::Species::FlameWyvern + | bird_large::Species::FrostWyvern + | bird_large::Species::CloudWyvern + | bird_large::Species::SeaWyvern + | bird_large::Species::WealdWyvern => 185, + _ => 140, + }, Body::Golem(_) => 300, + Body::QuadrupedMedium(b) => match b.species { + quadruped_medium::Species::Bear | quadruped_medium::Species::Grolgar => 165, + quadruped_medium::Species::Cattle + | quadruped_medium::Species::Llama + | quadruped_medium::Species::Alpaca + | quadruped_medium::Species::Camel + | quadruped_medium::Species::Zebra + | quadruped_medium::Species::Donkey + | quadruped_medium::Species::Highland + | quadruped_medium::Species::Horse + | quadruped_medium::Species::Kelpie + | quadruped_medium::Species::Hirdrasil + | quadruped_medium::Species::Antelope => 140, + quadruped_medium::Species::Deer => 120, + quadruped_medium::Species::Wolf + | quadruped_medium::Species::Tiger + | quadruped_medium::Species::Barghest + | quadruped_medium::Species::Bonerattler + | quadruped_medium::Species::Darkhound + | quadruped_medium::Species::Moose + | quadruped_medium::Species::Snowleopard + | quadruped_medium::Species::Akhlut + | quadruped_medium::Species::Bristleback + | quadruped_medium::Species::Catoblepas + | quadruped_medium::Species::Lion => 160, + quadruped_medium::Species::Panda => 130, + quadruped_medium::Species::Saber + | quadruped_medium::Species::Yak + | quadruped_medium::Species::Frostfang + | quadruped_medium::Species::Tarasque + | quadruped_medium::Species::Tuskram + | quadruped_medium::Species::Mouflon + | quadruped_medium::Species::Roshwalr + | quadruped_medium::Species::Dreadhorn => 175, + quadruped_medium::Species::Mammoth | quadruped_medium::Species::Ngoubou => 195, + }, + Body::QuadrupedLow(b) => match b.species { + quadruped_low::Species::Dagon => 225, + quadruped_low::Species::Crocodile + | quadruped_low::Species::Deadwood + | quadruped_low::Species::SeaCrocodile + | quadruped_low::Species::Alligator + | quadruped_low::Species::Sandshark + | quadruped_low::Species::HermitAlligator + | quadruped_low::Species::Asp => 160, + quadruped_low::Species::Tortoise + | quadruped_low::Species::Rocksnapper + | quadruped_low::Species::Rootsnapper + | quadruped_low::Species::Reefsnapper + | quadruped_low::Species::Maneater + | quadruped_low::Species::Hakulaq + | quadruped_low::Species::Lavadrake + | quadruped_low::Species::Icedrake + | quadruped_low::Species::Basilisk + | quadruped_low::Species::Mossdrake => 175, + quadruped_low::Species::Elbst + | quadruped_low::Species::Salamander + | quadruped_low::Species::Monitor + | quadruped_low::Species::Pangolin + | quadruped_low::Species::Driggle => 115, + }, + Body::Theropod(b) => match b.species { + theropod::Species::Archaeos + | theropod::Species::Ntouka + | theropod::Species::Odonto => 200, + theropod::Species::Yale => 185, + _ => 165, + }, _ => 100, } } @@ -1135,7 +1225,13 @@ impl Body { pub fn can_strafe(&self) -> bool { matches!( self, - Body::Humanoid(_) | Body::BipedSmall(_) | Body::BipedLarge(_) + Body::Humanoid(_) + | Body::BipedSmall(_) + | Body::BipedLarge(_) + | Body::Crustacean(crustacean::Body { + species: crustacean::Species::Crab, + .. + }) ) } diff --git a/common/src/comp/body/crustacean.rs b/common/src/comp/body/crustacean.rs new file mode 100644 index 0000000000..eb2c4ccad3 --- /dev/null +++ b/common/src/comp/body/crustacean.rs @@ -0,0 +1,105 @@ +use crate::{make_case_elim, make_proj_elim}; +use rand::{seq::SliceRandom, thread_rng}; +use serde::{Deserialize, Serialize}; +use strum::{Display, EnumString}; + +make_proj_elim!( + body, + #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] + pub struct Body { + pub species: Species, + pub body_type: BodyType, + } +); + +impl Body { + pub fn random() -> Self { + let mut rng = thread_rng(); + let species = *ALL_SPECIES.choose(&mut rng).unwrap(); + Self::random_with(&mut rng, &species) + } + + #[inline] + pub fn random_with(rng: &mut impl rand::Rng, &species: &Species) -> Self { + let body_type = *ALL_BODY_TYPES.choose(rng).unwrap(); + Self { species, body_type } + } +} + +impl From for super::Body { + fn from(body: Body) -> Self { super::Body::Crustacean(body) } +} + +// Renaming any enum entries here (re-ordering is fine) will require a +// database migration to ensure pets correctly de-serialize on player login. +make_case_elim!( + species, + #[derive( + Copy, + Clone, + Debug, + Display, + EnumString, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Serialize, + Deserialize, + )] + #[repr(u32)] + pub enum Species { + Crab = 0, + } +); + +/// Data representing per-species generic data. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct AllSpecies { + pub crab: SpeciesMeta, +} + +impl<'a, SpeciesMeta> core::ops::Index<&'a Species> for AllSpecies { + type Output = SpeciesMeta; + + #[inline] + fn index(&self, &index: &'a Species) -> &Self::Output { + match index { + Species::Crab => &self.crab, + } + } +} + +pub const ALL_SPECIES: [Species; 1] = [Species::Crab]; + +impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies { + type IntoIter = std::iter::Copied>; + type Item = Species; + + fn into_iter(self) -> Self::IntoIter { ALL_SPECIES.iter().copied() } +} + +make_case_elim!( + body_type, + #[derive( + Copy, + Clone, + Debug, + Display, + EnumString, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Serialize, + Deserialize, + )] + #[repr(u32)] + pub enum BodyType { + Female = 0, + Male = 1, + } +); +pub const ALL_BODY_TYPES: [BodyType; 2] = [BodyType::Female, BodyType::Male]; diff --git a/common/src/comp/character_state.rs b/common/src/comp/character_state.rs index 60fdf33870..2e2d74b2b5 100644 --- a/common/src/comp/character_state.rs +++ b/common/src/comp/character_state.rs @@ -95,7 +95,7 @@ pub enum CharacterState { DashMelee(dash_melee::Data), /// A three-stage attack where each attack pushes player forward /// and successive attacks increase in damage, while player holds button. - ComboMelee(combo_melee::Data), + ComboMeleeDeprecated(combo_melee::Data), /// A state where you progress through multiple melee attacks ComboMelee2(combo_melee2::Data), /// A leap followed by a small aoe ground attack @@ -154,7 +154,7 @@ impl CharacterState { | CharacterState::BasicMelee(_) | CharacterState::BasicRanged(_) | CharacterState::DashMelee(_) - | CharacterState::ComboMelee(_) + | CharacterState::ComboMeleeDeprecated(_) | CharacterState::ComboMelee2(_) | CharacterState::BasicBlock(_) | CharacterState::LeapMelee(_) @@ -220,7 +220,7 @@ impl CharacterState { CharacterState::BasicMelee(_) | CharacterState::BasicRanged(_) | CharacterState::DashMelee(_) - | CharacterState::ComboMelee(_) + | CharacterState::ComboMeleeDeprecated(_) | CharacterState::ComboMelee2(_) | CharacterState::LeapMelee(_) | CharacterState::LeapShockwave(_) @@ -247,7 +247,7 @@ impl CharacterState { CharacterState::BasicMelee(_) | CharacterState::BasicRanged(_) | CharacterState::DashMelee(_) - | CharacterState::ComboMelee(_) + | CharacterState::ComboMeleeDeprecated(_) | CharacterState::ComboMelee2(_) | CharacterState::BasicBlock(_) | CharacterState::LeapMelee(_) @@ -377,7 +377,7 @@ impl CharacterState { pub fn is_forced_movement(&self) -> bool { matches!(self, - CharacterState::ComboMelee(s) if s.stage_section == StageSection::Action) + CharacterState::ComboMeleeDeprecated(s) if s.stage_section == StageSection::Action) || matches!(self, CharacterState::ComboMelee2(s) if s.stage_section == StageSection::Action) || matches!(self, CharacterState::DashMelee(s) if s.stage_section == StageSection::Charge) || matches!(self, CharacterState::LeapMelee(s) if s.stage_section == StageSection::Movement) @@ -403,7 +403,7 @@ impl CharacterState { | CharacterState::Wielding(_) | CharacterState::BasicMelee(_) | CharacterState::BasicRanged(_) - | CharacterState::ComboMelee(_) + | CharacterState::ComboMeleeDeprecated(_) | CharacterState::ComboMelee2(_) | CharacterState::ChargedRanged(_) | CharacterState::RepeaterRanged(_) @@ -458,7 +458,7 @@ impl CharacterState { CharacterState::Roll(data) => data.behavior(j, output_events), CharacterState::Wielding(data) => data.behavior(j, output_events), CharacterState::Equipping(data) => data.behavior(j, output_events), - CharacterState::ComboMelee(data) => data.behavior(j, output_events), + CharacterState::ComboMeleeDeprecated(data) => data.behavior(j, output_events), CharacterState::ComboMelee2(data) => data.behavior(j, output_events), CharacterState::BasicMelee(data) => data.behavior(j, output_events), CharacterState::BasicRanged(data) => data.behavior(j, output_events), @@ -511,7 +511,9 @@ impl CharacterState { CharacterState::Roll(data) => data.handle_event(j, output_events, action), CharacterState::Wielding(data) => data.handle_event(j, output_events, action), CharacterState::Equipping(data) => data.handle_event(j, output_events, action), - CharacterState::ComboMelee(data) => data.handle_event(j, output_events, action), + CharacterState::ComboMeleeDeprecated(data) => { + data.handle_event(j, output_events, action) + }, CharacterState::ComboMelee2(data) => data.handle_event(j, output_events, action), CharacterState::BasicMelee(data) => data.handle_event(j, output_events, action), CharacterState::BasicRanged(data) => data.handle_event(j, output_events, action), @@ -564,7 +566,7 @@ impl CharacterState { CharacterState::Roll(data) => Some(data.static_data.ability_info), CharacterState::Wielding(_) => None, CharacterState::Equipping(_) => None, - CharacterState::ComboMelee(data) => Some(data.static_data.ability_info), + CharacterState::ComboMeleeDeprecated(data) => Some(data.static_data.ability_info), CharacterState::ComboMelee2(data) => Some(data.static_data.ability_info), CharacterState::BasicMelee(data) => Some(data.static_data.ability_info), CharacterState::BasicRanged(data) => Some(data.static_data.ability_info), @@ -608,7 +610,7 @@ impl CharacterState { CharacterState::Roll(data) => Some(data.stage_section), CharacterState::Equipping(_) => Some(StageSection::Buildup), CharacterState::Wielding(_) => None, - CharacterState::ComboMelee(data) => Some(data.stage_section), + CharacterState::ComboMeleeDeprecated(data) => Some(data.stage_section), CharacterState::ComboMelee2(data) => Some(data.stage_section), CharacterState::BasicMelee(data) => Some(data.stage_section), CharacterState::BasicRanged(data) => Some(data.stage_section), @@ -668,7 +670,7 @@ impl CharacterState { buildup: Some(data.static_data.buildup_duration), ..Default::default() }), - CharacterState::ComboMelee(data) => { + CharacterState::ComboMeleeDeprecated(data) => { let stage_index = data.stage_index(); let stage = data.static_data.stage_data[stage_index]; Some(DurationsInfo { @@ -840,7 +842,7 @@ impl CharacterState { CharacterState::Roll(data) => Some(data.timer), CharacterState::Wielding(_) => None, CharacterState::Equipping(data) => Some(data.timer), - CharacterState::ComboMelee(data) => Some(data.timer), + CharacterState::ComboMeleeDeprecated(data) => Some(data.timer), CharacterState::ComboMelee2(data) => Some(data.timer), CharacterState::BasicMelee(data) => Some(data.timer), CharacterState::BasicRanged(data) => Some(data.timer), @@ -884,7 +886,7 @@ impl CharacterState { CharacterState::Roll(_) => None, CharacterState::Wielding(_) => None, CharacterState::Equipping(_) => None, - CharacterState::ComboMelee(_) => Some(AttackSource::Melee), + CharacterState::ComboMeleeDeprecated(_) => Some(AttackSource::Melee), CharacterState::ComboMelee2(_) => Some(AttackSource::Melee), CharacterState::BasicMelee(_) => Some(AttackSource::Melee), CharacterState::BasicRanged(data) => { @@ -986,6 +988,10 @@ pub struct CharacterActivity { /// `None` means that the look direction should be derived from the /// orientation pub look_dir: Option, + /// If the character is using a Helm, this is the y direction the + /// character steering. If the character is not steering this is + /// a stale value. + pub steer_dir: f32, /// If true, the owner has set this pet to stay at a fixed location and /// to not engage in combat pub is_pet_staying: bool, diff --git a/common/src/comp/fluid_dynamics.rs b/common/src/comp/fluid_dynamics.rs index 0ab43892ec..97968be1b6 100644 --- a/common/src/comp/fluid_dynamics.rs +++ b/common/src/comp/fluid_dynamics.rs @@ -263,7 +263,7 @@ impl Body { }, // Cross-section, zero-lift angle; exclude the fins (width * 0.2) - Body::FishMedium(_) | Body::FishSmall(_) => { + Body::FishMedium(_) | Body::FishSmall(_) | Body::Crustacean(_) => { let dim = self.dimensions().map(|a| a * 0.5 * scale); // "A Simple Method to Determine Drag Coefficients in Aquatic Animals", // D. Bilo and W. Nachtigall, 1980 diff --git a/common/src/comp/inventory/loadout_builder.rs b/common/src/comp/inventory/loadout_builder.rs index 3bdcf6ed44..6d29df89b9 100644 --- a/common/src/comp/inventory/loadout_builder.rs +++ b/common/src/comp/inventory/loadout_builder.rs @@ -1,5 +1,6 @@ use crate::{ assets::{self, AssetExt}, + calendar::{Calendar, CalendarEvent}, comp::{ arthropod, biped_large, biped_small, bird_large, bird_medium, golem, inventory::{ @@ -9,7 +10,7 @@ use crate::{ item::{self, Item}, object, quadruped_low, quadruped_medium, quadruped_small, theropod, Body, }, - resources::Time, + resources::{Time, TimeOfDay}, trade::SiteInformation, }; use rand::{self, distributions::WeightedError, seq::SliceRandom, Rng}; @@ -48,10 +49,15 @@ enum ItemSpec { hands: Option, }, Choice(Vec<(Weight, Option)>), + Seasonal(Vec<(Option, ItemSpec)>), } impl ItemSpec { - fn try_to_item(&self, rng: &mut impl Rng) -> Result, SpecError> { + fn try_to_item( + &self, + rng: &mut impl Rng, + time: Option<&(TimeOfDay, Calendar)>, + ) -> Result, SpecError> { match self { ItemSpec::Item(item_asset) => { let item = Item::new_from_asset(item_asset).map_err(SpecError::ItemAssetError)?; @@ -63,7 +69,7 @@ impl ItemSpec { .map_err(SpecError::ItemChoiceError)?; let item = if let Some(item_spec) = item_spec { - item_spec.try_to_item(rng)? + item_spec.try_to_item(rng, time)? } else { None }; @@ -76,6 +82,20 @@ impl ItemSpec { } => item::modular::random_weapon(*tool, *material, *hands, rng) .map(Some) .map_err(SpecError::ModularWeaponCreationError), + ItemSpec::Seasonal(specs) => specs + .iter() + .find_map(|(season, spec)| match (season, time) { + (Some(season), Some((_time, calendar))) => { + if calendar.is_event(*season) { + Some(spec.try_to_item(rng, time)) + } else { + None + } + }, + (Some(_season), None) => None, + (None, _) => Some(spec.try_to_item(rng, time)), + }) + .unwrap_or(Ok(None)), } } @@ -103,6 +123,9 @@ impl ItemSpec { } => item::modular::random_weapon(*tool, *material, *hands, &mut rng) .map(drop) .map_err(ValidationError::ModularWeaponCreationError), + ItemSpec::Seasonal(specs) => { + specs.iter().try_for_each(|(_season, spec)| spec.validate()) + }, } } } @@ -116,10 +139,14 @@ enum Hands { } impl Hands { - fn try_to_pair(&self, rng: &mut impl Rng) -> Result<(Option, Option), SpecError> { + fn try_to_pair( + &self, + rng: &mut impl Rng, + time: Option<&(TimeOfDay, Calendar)>, + ) -> Result<(Option, Option), SpecError> { match self { Hands::InHands((mainhand, offhand)) => { - let mut from_spec = |i: &ItemSpec| i.try_to_item(rng); + let mut from_spec = |i: &ItemSpec| i.try_to_item(rng, time); let mainhand = mainhand.as_ref().map(&mut from_spec).transpose()?.flatten(); let offhand = offhand.as_ref().map(&mut from_spec).transpose()?.flatten(); @@ -130,7 +157,7 @@ impl Hands { .choose_weighted(rng, |(weight, _)| *weight) .map_err(SpecError::ItemChoiceError)?; - pair_spec.try_to_pair(rng) + pair_spec.try_to_pair(rng, time) }, } } @@ -678,7 +705,7 @@ fn default_main_tool(body: &Body) -> Item { arthropod::Species::Dagonite => Some(Item::new_from_asset_expect( "common.items.npc_weapons.unique.arthropods.dagonite", )), - _ => Some(Item::new_from_asset_expect( + arthropod::Species::Leafbeetle => Some(Item::new_from_asset_expect( "common.items.npc_weapons.unique.arthropods.leafbeetle", )), }, @@ -855,6 +882,10 @@ fn default_main_tool(body: &Body) -> Item { "common.items.npc_weapons.unique.birdmediumbasic", )), }, + Body::Crustacean(_) => Some(Item::new_from_asset_expect( + "common.items.npc_weapons.unique.crab_pincer", + )), + _ => None, }; @@ -893,14 +924,22 @@ impl LoadoutBuilder { #[must_use] /// Construct new `LoadoutBuilder` from `asset_specifier` /// Will panic if asset is broken - pub fn from_asset_expect(asset_specifier: &str, rng: &mut impl Rng) -> Self { - Self::from_asset(asset_specifier, rng).expect("failed to load loadut config") + pub fn from_asset_expect( + asset_specifier: &str, + rng: &mut impl Rng, + time: Option<&(TimeOfDay, Calendar)>, + ) -> Self { + Self::from_asset(asset_specifier, rng, time).expect("failed to load loadut config") } /// Construct new `LoadoutBuilder` from `asset_specifier` - pub fn from_asset(asset_specifier: &str, rng: &mut impl Rng) -> Result { + pub fn from_asset( + asset_specifier: &str, + rng: &mut impl Rng, + time: Option<&(TimeOfDay, Calendar)>, + ) -> Result { let loadout = Self::empty(); - loadout.with_asset(asset_specifier, rng) + loadout.with_asset(asset_specifier, rng, time) } #[must_use] @@ -919,17 +958,22 @@ impl LoadoutBuilder { pub fn from_loadout_spec( loadout_spec: LoadoutSpec, rng: &mut impl Rng, + time: Option<&(TimeOfDay, Calendar)>, ) -> Result { let loadout = Self::empty(); - loadout.with_loadout_spec(loadout_spec, rng) + loadout.with_loadout_spec(loadout_spec, rng, time) } #[must_use] /// Construct new `LoadoutBuilder` from `asset_specifier` /// /// Will panic if asset is broken - pub fn from_loadout_spec_expect(loadout_spec: LoadoutSpec, rng: &mut impl Rng) -> Self { - Self::from_loadout_spec(loadout_spec, rng).expect("failed to load loadout spec") + pub fn from_loadout_spec_expect( + loadout_spec: LoadoutSpec, + rng: &mut impl Rng, + time: Option<&(TimeOfDay, Calendar)>, + ) -> Self { + Self::from_loadout_spec(loadout_spec, rng, time).expect("failed to load loadout spec") } #[must_use = "Method consumes builder and returns updated builder."] @@ -1045,14 +1089,18 @@ impl LoadoutBuilder { let rng = &mut rand::thread_rng(); match preset { Preset::HuskSummon => { - self = self.with_asset_expect("common.loadout.dungeon.cultist.husk", rng); + self = self.with_asset_expect("common.loadout.dungeon.cultist.husk", rng, None); }, Preset::BorealSummon => { - self = self.with_asset_expect("common.loadout.world.boreal.boreal_warrior", rng); + self = + self.with_asset_expect("common.loadout.world.boreal.boreal_warrior", rng, None); }, Preset::ClockworkSummon => { - self = - self.with_asset_expect("common.loadout.dungeon.dwarven_quarry.clockwork", rng); + self = self.with_asset_expect( + "common.loadout.dungeon.dwarven_quarry.clockwork", + rng, + None, + ); }, } @@ -1062,10 +1110,15 @@ impl LoadoutBuilder { #[must_use = "Method consumes builder and returns updated builder."] pub fn with_creator( mut self, - creator: fn(LoadoutBuilder, Option<&SiteInformation>) -> LoadoutBuilder, + creator: fn( + LoadoutBuilder, + Option<&SiteInformation>, + time: Option<&(TimeOfDay, Calendar)>, + ) -> LoadoutBuilder, economy: Option<&SiteInformation>, + time: Option<&(TimeOfDay, Calendar)>, ) -> LoadoutBuilder { - self = creator(self, economy); + self = creator(self, economy, time); self } @@ -1075,6 +1128,7 @@ impl LoadoutBuilder { mut self, spec: LoadoutSpec, rng: &mut R, + time: Option<&(TimeOfDay, Calendar)>, ) -> Result { // Include any inheritance let spec = spec.eval(rng)?; @@ -1082,7 +1136,7 @@ impl LoadoutBuilder { // Utility function to unwrap our itemspec let mut to_item = |maybe_item: Option| { if let Some(item) = maybe_item { - item.try_to_item(rng) + item.try_to_item(rng, time) } else { Ok(None) } @@ -1090,7 +1144,7 @@ impl LoadoutBuilder { let to_pair = |maybe_hands: Option, rng: &mut R| { if let Some(hands) = maybe_hands { - hands.try_to_pair(rng) + hands.try_to_pair(rng, time) } else { Ok((None, None)) } @@ -1170,10 +1224,15 @@ impl LoadoutBuilder { } #[must_use = "Method consumes builder and returns updated builder."] - pub fn with_asset(self, asset_specifier: &str, rng: &mut impl Rng) -> Result { + pub fn with_asset( + self, + asset_specifier: &str, + rng: &mut impl Rng, + time: Option<&(TimeOfDay, Calendar)>, + ) -> Result { let spec = LoadoutSpec::load_cloned(asset_specifier).map_err(SpecError::LoadoutAssetError)?; - self.with_loadout_spec(spec, rng) + self.with_loadout_spec(spec, rng, time) } /// # Usage @@ -1184,8 +1243,13 @@ impl LoadoutBuilder { /// 1) Will panic if there is no asset with such `asset_specifier` /// 2) Will panic if path to item specified in loadout file doesn't exist #[must_use = "Method consumes builder and returns updated builder."] - pub fn with_asset_expect(self, asset_specifier: &str, rng: &mut impl Rng) -> Self { - self.with_asset(asset_specifier, rng) + pub fn with_asset_expect( + self, + asset_specifier: &str, + rng: &mut impl Rng, + time: Option<&(TimeOfDay, Calendar)>, + ) -> Self { + self.with_asset(asset_specifier, rng, time) .expect("failed loading loadout config") } @@ -1194,7 +1258,7 @@ impl LoadoutBuilder { #[must_use = "Method consumes builder and returns updated builder."] pub fn defaults(self) -> Self { let rng = &mut rand::thread_rng(); - self.with_asset_expect("common.loadout.default", rng) + self.with_asset_expect("common.loadout.default", rng, None) } #[must_use = "Method consumes builder and returns updated builder."] diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index 58ed61cd91..29ff961ce7 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -52,9 +52,9 @@ pub use self::{ aura::{Aura, AuraChange, AuraKind, Auras}, beam::Beam, body::{ - arthropod, biped_large, biped_small, bird_large, bird_medium, dragon, fish_medium, - fish_small, golem, humanoid, item_drop, object, quadruped_low, quadruped_medium, - quadruped_small, ship, theropod, AllBodies, Body, BodyData, + arthropod, biped_large, biped_small, bird_large, bird_medium, crustacean, dragon, + fish_medium, fish_small, golem, humanoid, item_drop, object, quadruped_low, + quadruped_medium, quadruped_small, ship, theropod, AllBodies, Body, BodyData, }, buff::{ Buff, BuffCategory, BuffChange, BuffData, BuffEffect, BuffKey, BuffKind, BuffSource, Buffs, diff --git a/common/src/comp/pet.rs b/common/src/comp/pet.rs index e954eff273..a3a8a7eb67 100755 --- a/common/src/comp/pet.rs +++ b/common/src/comp/pet.rs @@ -52,7 +52,10 @@ pub fn is_tameable(body: &Body) -> bool { | quadruped_medium::Species::Hirdrasil ) }, - Body::QuadrupedLow(_) | Body::QuadrupedSmall(_) | Body::BirdMedium(_) => true, + Body::QuadrupedLow(_) + | Body::QuadrupedSmall(_) + | Body::BirdMedium(_) + | Body::Crustacean(_) => true, _ => false, } } diff --git a/common/src/consts.rs b/common/src/consts.rs index 8da03b3598..ea0017acdd 100644 --- a/common/src/consts.rs +++ b/common/src/consts.rs @@ -35,3 +35,6 @@ pub const ENERGY_PER_LEVEL: u16 = 5; pub const HP_PER_LEVEL: u16 = 5; pub const TELEPORTER_RADIUS: f32 = 3.; + +// Map settings +pub const DAY_LENGTH_DEFAULT: f64 = 30.0; diff --git a/common/src/generation.rs b/common/src/generation.rs index c33202ca0e..2f50b2ceb8 100644 --- a/common/src/generation.rs +++ b/common/src/generation.rs @@ -1,5 +1,6 @@ use crate::{ assets::{self, AssetExt, Error}, + calendar::Calendar, comp::{ self, agent, humanoid, inventory::loadout_builder::{LoadoutBuilder, LoadoutSpec}, @@ -8,6 +9,7 @@ use crate::{ }, lottery::LootSpec, npc::{self, NPC_NAMES}, + resources::TimeOfDay, rtsim, trade::SiteInformation, }; @@ -97,8 +99,11 @@ pub enum Meta { /// let dummy_position = Vec3::new(0.0, 0.0, 0.0); /// // rng is required because some elements may be randomly generated /// let mut dummy_rng = rand::thread_rng(); -/// let entity = -/// EntityInfo::at(dummy_position).with_asset_expect("common.entity.template", &mut dummy_rng); +/// let entity = EntityInfo::at(dummy_position).with_asset_expect( +/// "common.entity.template", +/// &mut dummy_rng, +/// None, +/// ); /// ``` #[derive(Debug, Deserialize, Clone)] #[serde(deny_unknown_fields)] @@ -189,7 +194,13 @@ pub struct EntityInfo { // Loadout pub inventory: Vec<(u32, Item)>, pub loadout: LoadoutBuilder, - pub make_loadout: Option) -> LoadoutBuilder>, + pub make_loadout: Option< + fn( + LoadoutBuilder, + Option<&SiteInformation>, + time: Option<&(TimeOfDay, Calendar)>, + ) -> LoadoutBuilder, + >, // Skills pub skillset_asset: Option, @@ -234,13 +245,18 @@ impl EntityInfo { /// Helper function for applying config from asset /// with specified Rng for managing loadout. #[must_use] - pub fn with_asset_expect(self, asset_specifier: &str, loadout_rng: &mut R) -> Self + pub fn with_asset_expect( + self, + asset_specifier: &str, + loadout_rng: &mut R, + time: Option<&(TimeOfDay, Calendar)>, + ) -> Self where R: rand::Rng, { let config = EntityConfig::load_expect_cloned(asset_specifier); - self.with_entity_config(config, Some(asset_specifier), loadout_rng) + self.with_entity_config(config, Some(asset_specifier), loadout_rng, time) } /// Evaluate and apply EntityConfig @@ -250,6 +266,7 @@ impl EntityInfo { config: EntityConfig, config_asset: Option<&str>, loadout_rng: &mut R, + time: Option<&(TimeOfDay, Calendar)>, ) -> Self where R: rand::Rng, @@ -297,7 +314,7 @@ impl EntityInfo { self = self.with_loot_drop(loot); // NOTE: set loadout after body, as it's used with default equipement - self = self.with_inventory(inventory, config_asset, loadout_rng); + self = self.with_inventory(inventory, config_asset, loadout_rng, time); // Prefer the new configuration, if possible let AgentConfig { @@ -330,6 +347,7 @@ impl EntityInfo { inventory: InventorySpec, config_asset: Option<&str>, rng: &mut R, + time: Option<&(TimeOfDay, Calendar)>, ) -> Self where R: rand::Rng, @@ -350,14 +368,14 @@ impl EntityInfo { self = self.with_default_equip(); }, LoadoutKind::Asset(loadout) => { - let loadout = LoadoutBuilder::from_asset(&loadout, rng).unwrap_or_else(|e| { + let loadout = LoadoutBuilder::from_asset(&loadout, rng, time).unwrap_or_else(|e| { panic!("failed to load loadout for {config_asset}: {e:?}"); }); self.loadout = loadout; }, LoadoutKind::Inline(loadout_spec) => { - let loadout = - LoadoutBuilder::from_loadout_spec(*loadout_spec, rng).unwrap_or_else(|e| { + let loadout = LoadoutBuilder::from_loadout_spec(*loadout_spec, rng, time) + .unwrap_or_else(|e| { panic!("failed to load loadout for {config_asset}: {e:?}"); }); self.loadout = loadout; @@ -436,7 +454,11 @@ impl EntityInfo { #[must_use] pub fn with_lazy_loadout( mut self, - creator: fn(LoadoutBuilder, Option<&SiteInformation>) -> LoadoutBuilder, + creator: fn( + LoadoutBuilder, + Option<&SiteInformation>, + time: Option<&(TimeOfDay, Calendar)>, + ) -> LoadoutBuilder, ) -> Self { self.make_loadout = Some(creator); self @@ -469,6 +491,7 @@ impl EntityInfo { Body::Golem(body) => Some(get_npc_name(&npc_names.golem, body.species)), Body::BipedLarge(body) => Some(get_npc_name(&npc_names.biped_large, body.species)), Body::Arthropod(body) => Some(get_npc_name(&npc_names.arthropod, body.species)), + Body::Crustacean(body) => Some(get_npc_name(&npc_names.crustacean, body.species)), _ => None, }; self.name = name.map(|name| { diff --git a/common/src/mounting.rs b/common/src/mounting.rs index 79b666b0d3..6b25985bb4 100644 --- a/common/src/mounting.rs +++ b/common/src/mounting.rs @@ -298,6 +298,12 @@ pub struct VolumeMounting { pub rider: Uid, } +impl VolumeMounting { + pub fn is_steering_entity(&self) -> bool { + matches!(self.pos.kind, Volume::Entity(..)) && self.block.is_controller() + } +} + impl Link for VolumeMounting { type CreateData<'a> = ( Write<'a, VolumeRiders>, diff --git a/common/src/npc.rs b/common/src/npc.rs index 0d40aafa1e..2d7f27ba27 100644 --- a/common/src/npc.rs +++ b/common/src/npc.rs @@ -23,9 +23,10 @@ pub enum NpcKind { Reddragon, Crocodile, Tarantula, + Crab, } -pub const ALL_NPCS: [NpcKind; 14] = [ +pub const ALL_NPCS: [NpcKind; 15] = [ NpcKind::Humanoid, NpcKind::Wolf, NpcKind::Pig, @@ -40,6 +41,7 @@ pub const ALL_NPCS: [NpcKind; 14] = [ NpcKind::Reddragon, NpcKind::Crocodile, NpcKind::Tarantula, + NpcKind::Crab, ]; /// Body-specific NPC name metadata. @@ -136,6 +138,7 @@ pub fn kind_to_body(kind: NpcKind) -> Body { NpcKind::Reddragon => comp::dragon::Body::random().into(), NpcKind::Crocodile => comp::quadruped_low::Body::random().into(), NpcKind::Tarantula => comp::arthropod::Body::random().into(), + NpcKind::Crab => comp::crustacean::Body::random().into(), } } @@ -314,6 +317,14 @@ impl NpcBody { comp::arthropod::Body::random_with, ) }) + .or_else(|| { + parse( + s, + NpcKind::Crab, + &npc_names.crustacean, + comp::crustacean::Body::random_with, + ) + }) .ok_or(()) } } diff --git a/common/src/resources.rs b/common/src/resources.rs index a85b4e564c..007f34d0bd 100644 --- a/common/src/resources.rs +++ b/common/src/resources.rs @@ -7,6 +7,10 @@ use std::ops::{Mul, MulAssign}; #[derive(Copy, Clone, Debug, Serialize, Deserialize, Default)] pub struct TimeOfDay(pub f64); +impl TimeOfDay { + pub fn day(&self) -> f64 { self.0.rem_euclid(24.0 * 3600.0) } +} + /// A resource that stores the tick (i.e: physics) time. #[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq)] pub struct Time(pub f64); diff --git a/common/src/rtsim.rs b/common/src/rtsim.rs index 9dd2cd4a84..dc661ec1e0 100644 --- a/common/src/rtsim.rs +++ b/common/src/rtsim.rs @@ -252,7 +252,7 @@ pub enum NpcActivity { HuntAnimals, Dance(Option), Cheer(Option), - Sit(Option), + Sit(Option, Option>), } /// Represents event-like actions that rtsim NPCs can perform to interact with diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs index 63c370afc8..a1a6aef699 100644 --- a/common/src/states/combo_melee.rs +++ b/common/src/states/combo_melee.rs @@ -170,14 +170,14 @@ impl CharacterBehavior for Data { ); // Build up - update.character = CharacterState::ComboMelee(Data { + update.character = CharacterState::ComboMeleeDeprecated(Data { static_data: self.static_data.clone(), timer: tick_attack_or_default(data, self.timer, Some(speed_modifier)), ..*self }); } else { // Transitions to swing section of stage - update.character = CharacterState::ComboMelee(Data { + update.character = CharacterState::ComboMeleeDeprecated(Data { static_data: self.static_data.clone(), timer: Duration::default(), stage_section: StageSection::Action, @@ -194,7 +194,7 @@ impl CharacterBehavior for Data { && !self.exhausted { // Swing - update.character = CharacterState::ComboMelee(Data { + update.character = CharacterState::ComboMeleeDeprecated(Data { static_data: self.static_data.clone(), timer: tick_attack_or_default(data, self.timer, None), exhausted: true, @@ -304,14 +304,14 @@ impl CharacterBehavior for Data { ); // Swings - update.character = CharacterState::ComboMelee(Data { + update.character = CharacterState::ComboMeleeDeprecated(Data { static_data: self.static_data.clone(), timer: tick_attack_or_default(data, self.timer, Some(speed_modifier)), ..*self }); } else { // Transitions to recover section of stage - update.character = CharacterState::ComboMelee(Data { + update.character = CharacterState::ComboMeleeDeprecated(Data { static_data: self.static_data.clone(), timer: Duration::default(), stage_section: StageSection::Recover, @@ -328,7 +328,7 @@ impl CharacterBehavior for Data { None, ); // Recovers - update.character = CharacterState::ComboMelee(Data { + update.character = CharacterState::ComboMeleeDeprecated(Data { static_data: self.static_data.clone(), timer: tick_attack_or_default(data, self.timer, Some(speed_modifier)), ..*self @@ -380,7 +380,7 @@ fn reset_state( data.static_data.ability_info.input, ); - if let CharacterState::ComboMelee(c) = &mut update.character { + if let CharacterState::ComboMeleeDeprecated(c) = &mut update.character { c.stage = (data.stage % data.static_data.num_stages) + 1; } } diff --git a/common/src/states/roll.rs b/common/src/states/roll.rs index 24a7af4c5a..1741cc19e7 100644 --- a/common/src/states/roll.rs +++ b/common/src/states/roll.rs @@ -2,7 +2,7 @@ use crate::{ comp::{ buff::{BuffChange, BuffKind}, character_state::{AttackFilters, OutputEvents}, - CharacterState, InputKind, StateUpdate, + CharacterState, StateUpdate, }, event::ServerEvent, states::{ @@ -46,8 +46,6 @@ pub struct Data { pub prev_aimed_dir: Option, /// Is sneaking, true if previous state was also considered sneaking pub is_sneaking: bool, - /// Was in state with combo - pub was_combo: Option<(InputKind, u32)>, } impl CharacterBehavior for Data { @@ -126,20 +124,7 @@ impl CharacterBehavior for Data { }); } else { // Done - if let Some((input, stage)) = self.was_combo { - if input_is_pressed(data, input) { - handle_input(data, output_events, &mut update, input); - // If other states are introduced that progress through stages, add them - // here - if let CharacterState::ComboMelee(c) = &mut update.character { - c.stage = stage; - } - } else { - end_ability(data, &mut update); - } - } else { - end_ability(data, &mut update); - } + end_ability(data, &mut update); } }, _ => { diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index fefe896ea7..9140a33cf9 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -166,6 +166,7 @@ impl Body { arthropod::Species::Dagonite => 70.0, arthropod::Species::Emberfly => 75.0, }, + Body::Crustacean(_) => 80.0, } } @@ -232,6 +233,7 @@ impl Body { Body::Ship(ship) if ship.has_water_thrust() => 5.0 / self.dimensions().y, Body::Ship(_) => 6.0 / self.dimensions().y, Body::Arthropod(_) => 3.5, + Body::Crustacean(_) => 3.5, } } @@ -276,6 +278,7 @@ impl Body { }, Body::QuadrupedSmall(_) => 1500.0 * self.mass().0, Body::Arthropod(_) => 500.0 * self.mass().0, + Body::Crustacean(_) => 400.0 * self.mass().0, } * front_profile, ) } @@ -1240,16 +1243,11 @@ fn handle_ability( } } if let CharacterState::Roll(roll) = &mut update.character { - if let CharacterState::ComboMelee(c) = data.character { - roll.was_combo = Some((c.static_data.ability_info.input, c.stage)); + if data.character.is_wield() || data.character.was_wielded() { roll.was_wielded = true; - } else { - if data.character.is_wield() || data.character.was_wielded() { - roll.was_wielded = true; - } - if data.character.is_stealthy() { - roll.is_sneaking = true; - } + } + if data.character.is_stealthy() { + roll.is_sneaking = true; } if data.character.is_aimed() { roll.prev_aimed_dir = Some(data.controller.inputs.look_dir); diff --git a/common/src/terrain/site.rs b/common/src/terrain/site.rs index e857268f77..4734f18e5e 100644 --- a/common/src/terrain/site.rs +++ b/common/src/terrain/site.rs @@ -14,6 +14,7 @@ pub enum SiteKindMeta { pub enum DungeonKindMeta { Old, Gnarling, + Adlet, } #[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)] diff --git a/common/src/terrain/sprite.rs b/common/src/terrain/sprite.rs index 125a4c60ac..381f9eb279 100644 --- a/common/src/terrain/sprite.rs +++ b/common/src/terrain/sprite.rs @@ -268,6 +268,8 @@ make_case_elim!( Quench0 = 0xEF, IronSpike = 0xF0, HotSurface = 0xF1, + Barrel = 0xF2, + CrateBlock = 0xF3, } ); @@ -419,6 +421,8 @@ impl SpriteKind { SpriteKind::GearWheel0 => 3.0 / 11.0, SpriteKind::Quench0 => 8.0 / 11.0, SpriteKind::HotSurface => 0.01, + SpriteKind::Barrel => 1.0, + SpriteKind::CrateBlock => 1.0, _ => return None, }) } @@ -566,22 +570,15 @@ impl SpriteKind { #[inline] pub fn mount_offset(&self) -> Option<(Vec3, Vec3)> { match self { - SpriteKind::ChairSingle | SpriteKind::ChairDouble | SpriteKind::Bench => Some(( - Vec3 { - x: 0.0, - y: 0.0, - z: 0.5, - }, - -Vec3::unit_y(), - )), - SpriteKind::Helm => Some(( - Vec3 { - x: 0.0, - y: -0.6, - z: 0.2, - }, - Vec3::unit_y(), - )), + SpriteKind::ChairSingle | SpriteKind::ChairDouble | SpriteKind::Bench => { + Some((Vec3::new(0.0, 0.0, 0.5), -Vec3::unit_y())) + }, + SpriteKind::Helm => Some((Vec3::new(0.0, -1.0, 0.0), Vec3::unit_y())), + SpriteKind::Bed => Some((Vec3::new(0.0, 0.0, 0.6), -Vec3::unit_y())), + SpriteKind::BedrollSnow | SpriteKind::BedrollPirate => { + Some((Vec3::new(0.0, 0.0, 0.1), -Vec3::unit_x())) + }, + SpriteKind::Bedroll => Some((Vec3::new(0.0, 0.0, 0.1), Vec3::unit_y())), _ => None, } } diff --git a/common/systems/src/beam.rs b/common/systems/src/beam.rs index 3d25e5b54a..83fee8cb68 100644 --- a/common/systems/src/beam.rs +++ b/common/systems/src/beam.rs @@ -121,6 +121,10 @@ impl<'a> System<'a> for Sys { sound: Sound::new(SoundKind::Beam, pos.0, 13.0, read_data.time.0), }); } + outcomes.push(Outcome::Beam { + pos: pos.0, + specifier: beam.specifier, + }); // Group to ignore collisions with // Might make this more nuanced if beams are used for non damage effects diff --git a/common/systems/src/mount.rs b/common/systems/src/mount.rs index ce6a7c46e4..ed1b7f3c46 100644 --- a/common/systems/src/mount.rs +++ b/common/systems/src/mount.rs @@ -1,5 +1,8 @@ use common::{ - comp::{Body, Collider, ControlAction, Controller, InputKind, Ori, Pos, Scale, Vel}, + comp::{ + Body, CharacterActivity, Collider, ControlAction, Controller, InputKind, Ori, Pos, Scale, + Vel, + }, link::Is, mounting::{Mount, VolumeRider}, terrain::TerrainGrid, @@ -24,6 +27,7 @@ impl<'a> System<'a> for Sys { WriteStorage<'a, Pos>, WriteStorage<'a, Vel>, WriteStorage<'a, Ori>, + WriteStorage<'a, CharacterActivity>, ReadStorage<'a, Body>, ReadStorage<'a, Scale>, ReadStorage<'a, Collider>, @@ -45,6 +49,7 @@ impl<'a> System<'a> for Sys { mut positions, mut velocities, mut orientations, + mut character_activity, bodies, scales, colliders, @@ -174,6 +179,12 @@ impl<'a> System<'a> for Sys { if is_volume_rider.block.is_controller() { if let Some((actions, inputs)) = inputs { + if let Some(mut character_activity) = character_activity + .get_mut(entity) + .filter(|c| c.steer_dir != inputs.move_dir.y) + { + character_activity.steer_dir = inputs.move_dir.y; + } match is_volume_rider.pos.kind { common::mounting::Volume::Entity(uid) => { if let Some(controller) = diff --git a/common/systems/src/phys.rs b/common/systems/src/phys.rs index b0ab8fa0a1..31c2e0477b 100644 --- a/common/systems/src/phys.rs +++ b/common/systems/src/phys.rs @@ -562,10 +562,11 @@ impl<'a> PhysicsData<'a> { let radius_cutoff = 64; let mut spatial_grid = SpatialGrid::new(lg2_cell_size, lg2_large_cell_size, radius_cutoff); // TODO: give voxel colliders their own component type - for (entity, pos, collider, ori) in ( + for (entity, pos, collider, scale, ori) in ( &read.entities, &write.positions, &read.colliders, + read.scales.maybe(), &write.orientations, ) .join() @@ -573,7 +574,7 @@ impl<'a> PhysicsData<'a> { let vol = collider.get_vol(&voxel_colliders_manifest); if let Some(vol) = vol { - let sphere = voxel_collider_bounding_sphere(vol, pos, ori); + let sphere = voxel_collider_bounding_sphere(vol, pos, ori, scale); let radius = sphere.radius.ceil() as u32; let pos_2d = sphere.center.xy().map(|e| e as i32); const POS_TRUNCATION_ERROR: u32 = 1; @@ -1084,15 +1085,17 @@ impl<'a> PhysicsData<'a> { voxel_collider_spatial_grid .in_circle_aabr(query_center, query_radius) .filter_map(|entity| { - positions - .get(entity) - .and_then(|l| velocities.get(entity).map(|r| (l, r))) - .and_then(|l| previous_phys_cache.get(entity).map(|r| (l, r))) - .and_then(|l| read.colliders.get(entity).map(|r| (l, r))) - .and_then(|l| orientations.get(entity).map(|r| (l, r))) - .map(|((((pos, vel), previous_cache), collider), ori)| { - (entity, pos, vel, previous_cache, collider, ori) - }) + positions.get(entity).and_then(|pos| { + Some(( + entity, + pos, + velocities.get(entity)?, + previous_phys_cache.get(entity)?, + read.colliders.get(entity)?, + read.scales.get(entity), + orientations.get(entity)?, + )) + }) }) .for_each( |( @@ -1101,6 +1104,7 @@ impl<'a> PhysicsData<'a> { vel_other, previous_cache_other, collider_other, + scale_other, ori_other, )| { if entity == entity_other { @@ -1126,6 +1130,7 @@ impl<'a> PhysicsData<'a> { voxel_collider, pos_other, ori_other, + scale_other, ); // Early check if voxel_sphere.center.distance_squared(path_sphere.center) @@ -1942,6 +1947,7 @@ fn voxel_collider_bounding_sphere( voxel_collider: &VoxelCollider, pos: &Pos, ori: &Ori, + scale: Option<&Scale>, ) -> Sphere { let origin_offset = voxel_collider.translation; use common::vol::SizedVol; @@ -1964,7 +1970,7 @@ fn voxel_collider_bounding_sphere( Sphere { center: wpos_center, - radius, + radius: radius * scale.map_or(1.0, |s| s.0), } } diff --git a/common/systems/src/stats.rs b/common/systems/src/stats.rs index 6c0f10d216..27457b697a 100644 --- a/common/systems/src/stats.rs +++ b/common/systems/src/stats.rs @@ -174,7 +174,7 @@ impl<'a> System<'a> for Sys { | CharacterState::DashMelee(_) | CharacterState::LeapMelee(_) | CharacterState::LeapShockwave(_) - | CharacterState::ComboMelee(_) + | CharacterState::ComboMeleeDeprecated(_) | CharacterState::ComboMelee2(_) | CharacterState::BasicRanged(_) | CharacterState::Music(_) diff --git a/rtsim/src/data/npc.rs b/rtsim/src/data/npc.rs index 1912667c61..0f7ef02cb9 100644 --- a/rtsim/src/data/npc.rs +++ b/rtsim/src/data/npc.rs @@ -79,7 +79,9 @@ impl Controller { pub fn do_cheer(&mut self, dir: Option) { self.activity = Some(NpcActivity::Cheer(dir)); } - pub fn do_sit(&mut self, dir: Option) { self.activity = Some(NpcActivity::Sit(dir)); } + pub fn do_sit(&mut self, dir: Option, pos: Option>) { + self.activity = Some(NpcActivity::Sit(dir, pos)); + } pub fn say(&mut self, target: impl Into>, content: comp::Content) { self.actions.push(NpcAction::Say(target.into(), content)); diff --git a/rtsim/src/gen/mod.rs b/rtsim/src/gen/mod.rs index 67213bdaca..d2e0a5b355 100644 --- a/rtsim/src/gen/mod.rs +++ b/rtsim/src/gen/mod.rs @@ -113,6 +113,7 @@ impl Data { PlotKind::House(_) | PlotKind::Workshop(_) | PlotKind::AirshipDock(_) + | PlotKind::Tavern(_) | PlotKind::Plaza | PlotKind::SavannahPit(_) | PlotKind::SavannahHut(_) diff --git a/rtsim/src/rule/npc_ai.rs b/rtsim/src/rule/npc_ai.rs index 8609dea34a..eedc7796c3 100644 --- a/rtsim/src/rule/npc_ai.rs +++ b/rtsim/src/rule/npc_ai.rs @@ -38,7 +38,7 @@ use vek::*; use world::{ civ::{self, Track}, site::{Site as WorldSite, SiteKind}, - site2::{self, PlotKind, TileKind}, + site2::{self, plot::tavern, PlotKind, TileKind}, util::NEIGHBORS, IndexRef, World, }; @@ -325,7 +325,9 @@ impl Rule for NpcAi { } } -fn idle() -> impl Action { just(|ctx, _| ctx.controller.do_idle()).debug(|| "idle") } +fn idle() -> impl Action + Clone { + just(|ctx, _| ctx.controller.do_idle()).debug(|| "idle") +} /// Try to walk toward a 3D position without caring for obstacles. fn goto(wpos: Vec3, speed_factor: f32, goal_dist: f32) -> impl Action { @@ -578,7 +580,7 @@ fn travel_to_site(tgt_site: SiteId, speed_factor: f32) -> impl Action< .map(|_, _| ()) } -fn talk_to(tgt: Actor, _subject: Option) -> impl Action { +fn talk_to(tgt: Actor, _subject: Option) -> impl Action + Clone { now(move |ctx, _| { if matches!(tgt, Actor::Npc(_)) && ctx.rng.gen_bool(0.2) { // Cut off the conversation sometimes to avoid infinite conversations (but only @@ -630,7 +632,7 @@ fn talk_to(tgt: Actor, _subject: Option) -> impl Action { }) } -fn socialize() -> impl Action { +fn socialize() -> impl Action + Clone { now(move |ctx, socialize: &mut EveryRange| { // Skip most socialising actions if we're not loaded if matches!(ctx.npc.mode, SimulationMode::Loaded) && socialize.should(ctx) { @@ -758,6 +760,8 @@ fn choose_plaza(ctx: &mut NpcCtx, site: SiteId) -> Option> { }) } +const WALKING_SPEED: f32 = 0.35; + fn villager(visiting_site: SiteId) -> impl Action { choose(move |ctx, state: &mut DefaultState| { // Consider moving home if the home site gets too full @@ -804,8 +808,9 @@ fn villager(visiting_site: SiteId) -> impl Action { .then(travel_to_site(new_home, 0.5)) .then(just(move |ctx, _| ctx.controller.set_new_home(new_home)))); } - - if DayPeriod::from(ctx.time_of_day.0).is_dark() + let day_period = DayPeriod::from(ctx.time_of_day.0); + let is_weekend = ctx.time_of_day.day() as u64 % 6 == 0; + if day_period.is_dark() && !matches!(ctx.npc.profession(), Some(Profession::Guard)) { return important( @@ -845,51 +850,142 @@ fn villager(visiting_site: SiteId) -> impl Action { }) .debug(|| "find somewhere to sleep"), ); - // Villagers with roles should perform those roles } - // Visiting villagers in DesertCity who are not Merchants should sit down in the Arena during the day - else if matches!(ctx.state.data().sites[visiting_site].world_site.map(|ws| &ctx.index.sites.get(ws).kind), Some(SiteKind::DesertCity(_))) - && !matches!(ctx.npc.profession(), Some(Profession::Merchant | Profession::Guard)) - && ctx.rng.gen_bool(1.0 / 3.0) - { - let wait_time = ctx.rng.gen_range(100.0..300.0); + // Go do something fun on evenings and holidays, or on random days. + else if + // Ain't no rest for the wicked + !matches!(ctx.npc.profession(), Some(Profession::Guard)) + && (matches!(day_period, DayPeriod::Evening) || is_weekend || ctx.rng.gen_bool(0.05)) { + let mut fun_stuff = Vec::new(); + if let Some(ws_id) = ctx.state.data().sites[visiting_site].world_site - && let Some(ws) = ctx.index.sites.get(ws_id).site2() - && let Some(arena) = ws.plots().find_map(|p| match p.kind() { PlotKind::DesertCityArena(a) => Some(a), _ => None}) - { - // We don't use Z coordinates for seats because they are complicated to calculate from the Ramp procedural generation - // and using goto_2d seems to work just fine. However it also means that NPC will never go seat on the stands - // on the first floor of the arena. This is a compromise that was made because in the current arena procedural generation - // there is also no pathways to the stands on the first floor for NPCs. - let arena_center = Vec3::new(arena.center.x, arena.center.y, arena.base).as_::(); - let stand_dist = arena.stand_dist as f32; - let seat_var_width = ctx.rng.gen_range(0..arena.stand_width) as f32; - let seat_var_length = ctx.rng.gen_range(-arena.stand_length..arena.stand_length) as f32; - // Select a seat on one of the 4 arena stands - let seat = match ctx.rng.gen_range(0..4) { - 0 => Vec3::new(arena_center.x - stand_dist + seat_var_width, arena_center.y + seat_var_length, arena_center.z), - 1 => Vec3::new(arena_center.x + stand_dist - seat_var_width, arena_center.y + seat_var_length, arena_center.z), - 2 => Vec3::new(arena_center.x + seat_var_length, arena_center.y - stand_dist + seat_var_width, arena_center.z), - _ => Vec3::new(arena_center.x + seat_var_length, arena_center.y + stand_dist - seat_var_width, arena_center.z), - }; - let look_dir = Dir::from_unnormalized(arena_center - seat); - // Walk to an arena seat, cheer, sit and dance - return casual(just(move |ctx, _| ctx.controller.say(None, Content::localized("npc-speech-arena"))) - .then(goto_2d(seat.xy(), 0.6, 1.0).debug(|| "go to arena")) - // Turn toward the centre of the arena and watch the action! - .then(choose(move |ctx, _| if ctx.rng.gen_bool(0.3) { - casual(just(move |ctx,_| ctx.controller.do_cheer(look_dir)).repeat().stop_if(timeout(5.0))) - } else if ctx.rng.gen_bool(0.15) { - casual(just(move |ctx,_| ctx.controller.do_dance(look_dir)).repeat().stop_if(timeout(5.0))) - } else { - casual(just(move |ctx,_| ctx.controller.do_sit(look_dir)).repeat().stop_if(timeout(15.0))) - }) + && let Some(ws) = ctx.index.sites.get(ws_id).site2() { + if let Some(arena) = ws.plots().find_map(|p| match p.kind() { PlotKind::DesertCityArena(a) => Some(a), _ => None}) { + let wait_time = ctx.rng.gen_range(100.0..300.0); + // We don't use Z coordinates for seats because they are complicated to calculate from the Ramp procedural generation + // and using goto_2d seems to work just fine. However it also means that NPC will never go seat on the stands + // on the first floor of the arena. This is a compromise that was made because in the current arena procedural generation + // there is also no pathways to the stands on the first floor for NPCs. + let arena_center = Vec3::new(arena.center.x, arena.center.y, arena.base).as_::(); + let stand_dist = arena.stand_dist as f32; + let seat_var_width = ctx.rng.gen_range(0..arena.stand_width) as f32; + let seat_var_length = ctx.rng.gen_range(-arena.stand_length..arena.stand_length) as f32; + // Select a seat on one of the 4 arena stands + let seat = match ctx.rng.gen_range(0..4) { + 0 => Vec3::new(arena_center.x - stand_dist + seat_var_width, arena_center.y + seat_var_length, arena_center.z), + 1 => Vec3::new(arena_center.x + stand_dist - seat_var_width, arena_center.y + seat_var_length, arena_center.z), + 2 => Vec3::new(arena_center.x + seat_var_length, arena_center.y - stand_dist + seat_var_width, arena_center.z), + _ => Vec3::new(arena_center.x + seat_var_length, arena_center.y + stand_dist - seat_var_width, arena_center.z), + }; + let look_dir = Dir::from_unnormalized(arena_center - seat); + // Walk to an arena seat, cheer, sit and dance + let action = casual(just(move |ctx, _| ctx.controller.say(None, Content::localized("npc-speech-arena"))) + .then(goto_2d(seat.xy(), 0.6, 1.0).debug(|| "go to arena")) + // Turn toward the centre of the arena and watch the action! + .then(choose(move |ctx, _| if ctx.rng.gen_bool(0.3) { + casual(just(move |ctx,_| ctx.controller.do_cheer(look_dir)).repeat().stop_if(timeout(5.0))) + } else if ctx.rng.gen_bool(0.15) { + casual(just(move |ctx,_| ctx.controller.do_dance(look_dir)).repeat().stop_if(timeout(5.0))) + } else { + casual(just(move |ctx,_| ctx.controller.do_sit(look_dir, None)).repeat().stop_if(timeout(15.0))) + }) + .repeat() + .stop_if(timeout(wait_time))) + .map(|_, _| ()) + .boxed()); + fun_stuff.push(action); + } + if let Some(tavern) = ws.plots().filter_map(|p| match p.kind() { PlotKind::Tavern(a) => Some(a), _ => None }).choose(&mut ctx.rng) { + let wait_time = ctx.rng.gen_range(100.0..300.0); + + let (stage_aabr, stage_z) = tavern.rooms.values().flat_map(|room| { + room.details.iter().filter_map(|detail| match detail { + tavern::Detail::Stage { aabr } => Some((*aabr, room.bounds.min.z + 1)), + _ => None, + }) + }).choose(&mut ctx.rng).unwrap_or((tavern.bounds, tavern.door_wpos.z)); + + let bar_pos = tavern.rooms.values().flat_map(|room| + room.details.iter().filter_map(|detail| match detail { + tavern::Detail::Bar { aabr } => { + let side = site2::util::Dir::from_vec2(room.bounds.center().xy() - aabr.center()); + let pos = side.select_aabr_with(*aabr, aabr.center()) + side.to_vec2(); + + Some(pos.with_z(room.bounds.min.z)) + } + _ => None, + }) + ).choose(&mut ctx.rng).unwrap_or(stage_aabr.center().with_z(stage_z)); + + // Pick a chair that is theirs for the stay + let chair_pos = tavern.rooms.values().flat_map(|room| { + let z = room.bounds.min.z; + room.details.iter().filter_map(move |detail| match detail { + tavern::Detail::Table { pos, chairs } => Some(chairs.into_iter().map(move |dir| pos.with_z(z) + dir.to_vec2())), + _ => None, + }) + .flatten() + } + ).choose(&mut ctx.rng) + // This path is possible, but highly unlikely. + .unwrap_or(bar_pos); + + let stage_aabr = stage_aabr.as_::(); + let stage_z = stage_z as f32; + + let action = casual(travel_to_point(tavern.door_wpos.xy().as_() + 0.5, 0.8).then(choose(move |ctx, (last_action, _)| { + let action = [0, 1, 2].into_iter().filter(|i| *last_action != Some(*i)).choose(&mut ctx.rng).expect("We have at least 2 elements"); + let socialize = socialize().map_state(|(_, timer)| timer).repeat(); + match action { + // Go and dance on a stage. + 0 => { + casual(now(move |ctx, (last_action, _)| { + *last_action = Some(action); + goto(stage_aabr.min.map2(stage_aabr.max, |a, b| ctx.rng.gen_range(a..b)).with_z(stage_z), WALKING_SPEED, 1.0) + }) + .then(just(move |ctx,_| ctx.controller.do_dance(None)).repeat().stop_if(timeout(ctx.rng.gen_range(20.0..30.0)))) + .map(|_, _| ()) + ) + }, + // Go and sit at a table. + 1 => { + casual( + now(move |ctx, (last_action, _)| { + *last_action = Some(action); + goto(chair_pos.as_() + 0.5, WALKING_SPEED, 1.0).then(just(move |ctx, _| ctx.controller.do_sit(None, Some(chair_pos)))).then(socialize.clone().stop_if(timeout(ctx.rng.gen_range(30.0..60.0)))).map(|_, _| ()) + }) + ) + }, + // Go to the bar. + _ => { + casual( + now(move |ctx, (last_action, _)| { + *last_action = Some(action); + goto(bar_pos.as_() + 0.5, WALKING_SPEED, 1.0).then(socialize.clone().stop_if(timeout(ctx.rng.gen_range(10.0..25.0)))).map(|_, _| ()) + }) + ) + }, + } + }) + .with_state((None::, every_range(5.0..10.0))) .repeat() .stop_if(timeout(wait_time))) - .map(|_, _| ()) - .boxed()); + .map(|_, _| ()) + .boxed() + ); + + fun_stuff.push(action); + } } - } else if matches!(ctx.npc.profession(), Some(Profession::Herbalist)) && ctx.rng.gen_bool(0.8) + + + if !fun_stuff.is_empty() { + let i = ctx.rng.gen_range(0..fun_stuff.len()); + return fun_stuff.swap_remove(i); + } + } + // Villagers with roles should perform those roles + else if matches!(ctx.npc.profession(), Some(Profession::Herbalist)) && ctx.rng.gen_bool(0.8) { if let Some(forest_wpos) = find_forest(ctx) { return casual( diff --git a/rtsim/src/rule/simulate_npcs.rs b/rtsim/src/rule/simulate_npcs.rs index c32faff891..f1b25dcfec 100644 --- a/rtsim/src/rule/simulate_npcs.rs +++ b/rtsim/src/rule/simulate_npcs.rs @@ -254,7 +254,7 @@ fn on_tick(ctx: EventCtx) { | NpcActivity::HuntAnimals | NpcActivity::Dance(_) | NpcActivity::Cheer(_) - | NpcActivity::Sit(_), + | NpcActivity::Sit(..), ) => { // TODO: Maybe they should walk around randomly // when gathering resources? diff --git a/server/agent/src/action_nodes.rs b/server/agent/src/action_nodes.rs index abf3ab97e3..8e8f8017a0 100644 --- a/server/agent/src/action_nodes.rs +++ b/server/agent/src/action_nodes.rs @@ -29,6 +29,7 @@ use common::{ consts::MAX_MOUNT_RANGE, effect::{BuffEffect, Effect}, event::{Emitter, ServerEvent}, + mounting::VolumePos, path::TraversalConfig, rtsim::NpcActivity, states::basic_beam, @@ -51,9 +52,7 @@ impl<'a> AgentData<'a> { //////////////////////////////////////// pub fn glider_fall(&self, controller: &mut Controller, read_data: &ReadData) { - if read_data.is_riders.contains(*self.entity) { - controller.push_event(ControlEvent::Unmount); - } + self.dismount(controller, read_data); controller.push_action(ControlAction::GlideWield); @@ -73,9 +72,7 @@ impl<'a> AgentData<'a> { } pub fn fly_upward(&self, controller: &mut Controller, read_data: &ReadData) { - if read_data.is_riders.contains(*self.entity) { - controller.push_event(ControlEvent::Unmount); - } + self.dismount(controller, read_data); controller.push_basic_input(InputKind::Fly); controller.inputs.move_z = 1.0; @@ -96,9 +93,7 @@ impl<'a> AgentData<'a> { path: Path, speed_multiplier: Option, ) -> bool { - if read_data.is_riders.contains(*self.entity) { - controller.push_event(ControlEvent::Unmount); - } + self.dismount(controller, read_data); let partial_path_tgt_pos = |pos_difference: Vec3| { self.pos.0 @@ -242,6 +237,14 @@ impl<'a> AgentData<'a> { 'activity: { match agent.rtsim_controller.activity { Some(NpcActivity::Goto(travel_to, speed_factor)) => { + if read_data + .is_volume_riders + .get(*self.entity) + .map_or(false, |r| !r.is_steering_entity()) + { + controller.push_event(ControlEvent::Unmount); + } + // If it has an rtsim destination and can fly, then it should. // If it is flying and bumps something above it, then it should move down. if self.traversal_config.can_fly @@ -399,17 +402,26 @@ impl<'a> AgentData<'a> { controller.push_action(ControlAction::Talk); break 'activity; // Don't fall through to idle wandering }, - Some(NpcActivity::Sit(dir)) => { - if let Some(look_dir) = dir { - controller.inputs.look_dir = look_dir; - if self.ori.look_dir().dot(look_dir.to_vec()) < 0.95 { - controller.inputs.move_dir = look_dir.to_vec().xy() * 0.01; - break 'activity; - } else { - controller.inputs.move_dir = Vec2::zero(); + Some(NpcActivity::Sit(dir, pos)) => { + if let Some(pos) = + pos.filter(|p| read_data.terrain.get(*p).is_ok_and(|b| b.is_mountable())) + { + if !read_data.is_volume_riders.contains(*self.entity) { + controller + .push_event(ControlEvent::MountVolume(VolumePos::terrain(pos))); } + } else { + if let Some(look_dir) = dir { + controller.inputs.look_dir = look_dir; + if self.ori.look_dir().dot(look_dir.to_vec()) < 0.95 { + controller.inputs.move_dir = look_dir.to_vec().xy() * 0.01; + break 'activity; + } else { + controller.inputs.move_dir = Vec2::zero(); + } + } + controller.push_action(ControlAction::Sit); } - controller.push_action(ControlAction::Sit); break 'activity; // Don't fall through to idle wandering }, Some(NpcActivity::HuntAnimals) => { @@ -581,7 +593,12 @@ impl<'a> AgentData<'a> { read_data: &ReadData, tgt_pos: &Pos, ) { - if read_data.is_riders.contains(*self.entity) { + if read_data.is_riders.contains(*self.entity) + || read_data + .is_volume_riders + .get(*self.entity) + .map_or(false, |r| !r.is_steering_entity()) + { controller.push_event(ControlEvent::Unmount); } @@ -637,7 +654,12 @@ impl<'a> AgentData<'a> { // Proportion of full speed const MAX_FLEE_SPEED: f32 = 0.65; - if read_data.is_riders.contains(*self.entity) { + if read_data.is_riders.contains(*self.entity) + || read_data + .is_volume_riders + .get(*self.entity) + .map_or(false, |r| !r.is_steering_entity()) + { controller.push_event(ControlEvent::Unmount); } @@ -993,9 +1015,7 @@ impl<'a> AgentData<'a> { #[cfg(feature = "be-dyn-lib")] let rng = &mut thread_rng(); - if read_data.is_riders.contains(*self.entity) { - controller.push_event(ControlEvent::Unmount); - } + self.dismount(controller, read_data); let tool_tactic = |tool_kind| match tool_kind { ToolKind::Bow => Tactic::Bow, @@ -1999,4 +2019,15 @@ impl<'a> AgentData<'a> { } } } + + pub fn dismount(&self, controller: &mut Controller, read_data: &ReadData) { + if read_data.is_riders.contains(*self.entity) + || read_data + .is_volume_riders + .get(*self.entity) + .map_or(false, |r| !r.is_steering_entity()) + { + controller.push_event(ControlEvent::Unmount); + } + } } diff --git a/server/agent/src/attack.rs b/server/agent/src/attack.rs index c3e5bf1bc7..b4c00451aa 100644 --- a/server/agent/src/attack.rs +++ b/server/agent/src/attack.rs @@ -3410,7 +3410,7 @@ impl<'a> AgentData<'a> { { // If already in dash, keep dashing if not in recover controller.push_basic_input(InputKind::Ability(0)); - } else if matches!(self.char_state, CharacterState::ComboMelee(c) if matches!(c.stage_section, StageSection::Recover)) + } else if matches!(self.char_state, CharacterState::ComboMelee2(c) if matches!(c.stage_section, StageSection::Recover)) { // If already in combo keep comboing if not in recover controller.push_basic_input(InputKind::Primary); diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 664e85acdb..d7c7ae24c2 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -26,8 +26,7 @@ use common::{ }, comp::{ self, - aura::{Aura, AuraKind, AuraTarget}, - buff::{Buff, BuffCategory, BuffData, BuffKind, BuffSource}, + buff::{Buff, BuffData, BuffKind, BuffSource}, inventory::{ item::{tool::AbilityMap, MaterialStatManifest, Quality}, slot::Slot, @@ -654,6 +653,7 @@ fn handle_make_npc( config.clone(), Some(&entity_config), &mut loadout_rng, + None, ); match NpcData::from_entity_info(entity_info) { @@ -1940,44 +1940,11 @@ fn handle_spawn_campfire( _action: &ServerChatCommand, ) -> CmdResult<()> { let pos = position(server, target, "target")?; - let time = server.state.get_time(); server .state - .create_object(pos, comp::object::Body::CampfireLit) - .with(LightEmitter { - col: Rgb::new(1.0, 0.65, 0.2), - strength: 2.0, - flicker: 1.0, - animated: true, - }) - .with(WaypointArea::default()) - .with(comp::Auras::new(vec![ - Aura::new( - AuraKind::Buff { - kind: BuffKind::CampfireHeal, - data: BuffData::new(0.02, Some(Secs(1.0))), - category: BuffCategory::Natural, - source: BuffSource::World, - }, - 5.0, - None, - AuraTarget::All, - Time(time), - ), - Aura::new( - AuraKind::Buff { - kind: BuffKind::Burning, - data: BuffData::new(2.0, Some(Secs(10.0))), - category: BuffCategory::Natural, - source: BuffSource::World, - }, - 0.7, - None, - AuraTarget::All, - Time(time), - ), - ])) - .build(); + .ecs() + .read_resource::>() + .emit_now(ServerEvent::CreateWaypoint(pos.0)); server.notify_client( client, diff --git a/server/src/persistence/character/conversions.rs b/server/src/persistence/character/conversions.rs index 6629cd7a9a..5636487573 100644 --- a/server/src/persistence/character/conversions.rs +++ b/server/src/persistence/character/conversions.rs @@ -220,6 +220,10 @@ pub fn convert_body_to_database_json( "bird_medium", serde_json::to_string(&GenericBody::from(body))?, ), + Body::Crustacean(body) => ( + "crustacean", + serde_json::to_string(&GenericBody::from(body))?, + ), _ => { return Err(PersistenceError::ConversionError(format!( "Unsupported body type for persistence: {:?}", @@ -597,6 +601,9 @@ pub fn convert_body_from_database( "bird_medium" => { deserialize_body!(body_data, BirdMedium, bird_medium) }, + "crustacean" => { + deserialize_body!(body_data, Crustacean, crustacean) + }, _ => { return Err(PersistenceError::ConversionError(format!( "{} is not a supported body type for deserialization", diff --git a/server/src/persistence/json_models.rs b/server/src/persistence/json_models.rs index 58f80ea109..59706f7d43 100644 --- a/server/src/persistence/json_models.rs +++ b/server/src/persistence/json_models.rs @@ -60,6 +60,7 @@ generic_body_from_impl!(comp::quadruped_low::Body); generic_body_from_impl!(comp::quadruped_medium::Body); generic_body_from_impl!(comp::quadruped_small::Body); generic_body_from_impl!(comp::bird_medium::Body); +generic_body_from_impl!(comp::crustacean::Body); #[derive(Serialize, Deserialize)] pub struct CharacterPosition { diff --git a/server/src/rtsim/tick.rs b/server/src/rtsim/tick.rs index 7a997be35b..aefa074732 100644 --- a/server/src/rtsim/tick.rs +++ b/server/src/rtsim/tick.rs @@ -3,6 +3,7 @@ use super::*; use crate::sys::terrain::NpcData; use common::{ + calendar::Calendar, comp::{self, Agent, Body, Presence, PresenceKind}, event::{EventBus, NpcBuilder, ServerEvent}, generation::{BodyBuilder, EntityConfig, EntityInfo}, @@ -53,13 +54,18 @@ fn humanoid_config(profession: &Profession) -> &'static str { } } -fn loadout_default(loadout: LoadoutBuilder, _economy: Option<&SiteInformation>) -> LoadoutBuilder { +fn loadout_default( + loadout: LoadoutBuilder, + _economy: Option<&SiteInformation>, + _time: Option<&(TimeOfDay, Calendar)>, +) -> LoadoutBuilder { loadout } fn merchant_loadout( loadout_builder: LoadoutBuilder, economy: Option<&SiteInformation>, + _time: Option<&(TimeOfDay, Calendar)>, ) -> LoadoutBuilder { trader_loadout(loadout_builder, economy, |_| true) } @@ -67,6 +73,7 @@ fn merchant_loadout( fn farmer_loadout( loadout_builder: LoadoutBuilder, economy: Option<&SiteInformation>, + _time: Option<&(TimeOfDay, Calendar)>, ) -> LoadoutBuilder { trader_loadout(loadout_builder, economy, |good| matches!(good, Good::Food)) } @@ -74,6 +81,7 @@ fn farmer_loadout( fn herbalist_loadout( loadout_builder: LoadoutBuilder, economy: Option<&SiteInformation>, + _time: Option<&(TimeOfDay, Calendar)>, ) -> LoadoutBuilder { trader_loadout(loadout_builder, economy, |good| { matches!(good, Good::Ingredients) @@ -83,6 +91,7 @@ fn herbalist_loadout( fn chef_loadout( loadout_builder: LoadoutBuilder, economy: Option<&SiteInformation>, + _time: Option<&(TimeOfDay, Calendar)>, ) -> LoadoutBuilder { trader_loadout(loadout_builder, economy, |good| matches!(good, Good::Food)) } @@ -90,6 +99,7 @@ fn chef_loadout( fn blacksmith_loadout( loadout_builder: LoadoutBuilder, economy: Option<&SiteInformation>, + _time: Option<&(TimeOfDay, Calendar)>, ) -> LoadoutBuilder { trader_loadout(loadout_builder, economy, |good| { matches!(good, Good::Tools | Good::Armor) @@ -99,6 +109,7 @@ fn blacksmith_loadout( fn alchemist_loadout( loadout_builder: LoadoutBuilder, economy: Option<&SiteInformation>, + _time: Option<&(TimeOfDay, Calendar)>, ) -> LoadoutBuilder { trader_loadout(loadout_builder, economy, |good| { matches!(good, Good::Potions) @@ -107,7 +118,11 @@ fn alchemist_loadout( fn profession_extra_loadout( profession: Option<&Profession>, -) -> fn(LoadoutBuilder, Option<&SiteInformation>) -> LoadoutBuilder { +) -> fn( + LoadoutBuilder, + Option<&SiteInformation>, + time: Option<&(TimeOfDay, Calendar)>, +) -> LoadoutBuilder { match profession { Some(Profession::Merchant) => merchant_loadout, Some(Profession::Farmer) => farmer_loadout, @@ -134,7 +149,12 @@ fn profession_agent_mark(profession: Option<&Profession>) -> Option EntityInfo { +fn get_npc_entity_info( + npc: &Npc, + sites: &Sites, + index: IndexRef, + time: Option<&(TimeOfDay, Calendar)>, +) -> EntityInfo { let pos = comp::Pos(npc.wpos); let mut rng = npc.rng(Npc::PERM_ENTITY_CONFIG); @@ -149,7 +169,7 @@ fn get_npc_entity_info(npc: &Npc, sites: &Sites, index: IndexRef) -> EntityInfo let entity_config = EntityConfig::from_asset_expect_owned(config_asset) .with_body(BodyBuilder::Exact(npc.body)); EntityInfo::at(pos.0) - .with_entity_config(entity_config, Some(config_asset), &mut rng) + .with_entity_config(entity_config, Some(config_asset), &mut rng, time) .with_alignment(if matches!(profession, Profession::Cultist) { comp::Alignment::Enemy } else { @@ -204,7 +224,7 @@ fn get_npc_entity_info(npc: &Npc, sites: &Sites, index: IndexRef) -> EntityInfo let entity_config = EntityConfig::from_asset_expect_owned(config_asset) .with_body(BodyBuilder::Exact(npc.body)); - EntityInfo::at(pos.0).with_entity_config(entity_config, Some(config_asset), &mut rng) + EntityInfo::at(pos.0).with_entity_config(entity_config, Some(config_asset), &mut rng, time) } } @@ -225,6 +245,7 @@ impl<'a> System<'a> for Sys { ReadStorage<'a, RtSimEntity>, WriteStorage<'a, comp::Agent>, ReadStorage<'a, Presence>, + ReadExpect<'a, Calendar>, ); const NAME: &'static str = "rtsim::tick"; @@ -247,10 +268,12 @@ impl<'a> System<'a> for Sys { rtsim_entities, mut agents, presences, + calendar, ): Self::SystemData, ) { let mut emitter = server_event_bus.emitter(); let rtsim = &mut *rtsim; + let calendar_data = (*time_of_day, (*calendar).clone()); // Set up rtsim inputs { @@ -303,7 +326,12 @@ impl<'a> System<'a> for Sys { }); }, _ => { - let entity_info = get_npc_entity_info(npc, &data.sites, index.as_index_ref()); + let entity_info = get_npc_entity_info( + npc, + &data.sites, + index.as_index_ref(), + Some(&calendar_data), + ); emitter.emit(match NpcData::from_entity_info(entity_info) { NpcData::Data { @@ -359,8 +387,12 @@ impl<'a> System<'a> for Sys { let npc = data.npcs.npcs.get_mut(npc_id)?; if matches!(npc.mode, SimulationMode::Simulated) { npc.mode = SimulationMode::Loaded; - let entity_info = - get_npc_entity_info(npc, &data.sites, index.as_index_ref()); + let entity_info = get_npc_entity_info( + npc, + &data.sites, + index.as_index_ref(), + Some(&calendar_data), + ); Some(match NpcData::from_entity_info(entity_info) { NpcData::Data { diff --git a/server/src/settings.rs b/server/src/settings.rs index 4756011a66..011f4e32f3 100644 --- a/server/src/settings.rs +++ b/server/src/settings.rs @@ -16,6 +16,7 @@ pub use whitelist::{Whitelist, WhitelistInfo, WhitelistRecord}; use chrono::Utc; use common::{ calendar::{Calendar, CalendarEvent}, + consts::DAY_LENGTH_DEFAULT, resources::BattleMode, rtsim::WorldSettings, }; @@ -205,7 +206,7 @@ impl Default for Settings { world_seed: DEFAULT_WORLD_SEED, server_name: "Veloren Server".into(), max_players: 100, - day_length: 30.0, + day_length: DAY_LENGTH_DEFAULT, start_time: 9.0 * 3600.0, map_file: None, max_view_distance: Some(65), diff --git a/server/src/sys/terrain.rs b/server/src/sys/terrain.rs index 5bdee93589..928ebce205 100644 --- a/server/src/sys/terrain.rs +++ b/server/src/sys/terrain.rs @@ -476,7 +476,8 @@ impl NpcData { let inventory = { // Evaluate lazy function for loadout creation if let Some(make_loadout) = make_loadout { - loadout_builder = loadout_builder.with_creator(make_loadout, economy.as_ref()); + loadout_builder = + loadout_builder.with_creator(make_loadout, economy.as_ref(), None); } let loadout = loadout_builder.build(); let mut inventory = comp::inventory::Inventory::with_loadout(loadout, body); diff --git a/voxygen/anim/src/arthropod/alpha.rs b/voxygen/anim/src/arthropod/combomelee.rs similarity index 93% rename from voxygen/anim/src/arthropod/alpha.rs rename to voxygen/anim/src/arthropod/combomelee.rs index a90f507e0f..d767d4e7fc 100644 --- a/voxygen/anim/src/arthropod/alpha.rs +++ b/voxygen/anim/src/arthropod/combomelee.rs @@ -6,19 +6,19 @@ use super::{ }; use common::states::utils::StageSection; -pub struct AlphaAnimation; +pub struct ComboAnimation; -impl Animation for AlphaAnimation { - type Dependency<'a> = (f32, f32, Option, f32); +impl Animation for ComboAnimation { + type Dependency<'a> = (Option<&'a str>, StageSection, usize, f32, f32); type Skeleton = ArthropodSkeleton; #[cfg(feature = "use-dyn-lib")] - const UPDATE_FN: &'static [u8] = b"arthropod_alpha\0"; + const UPDATE_FN: &'static [u8] = b"arthropod_combo\0"; - #[cfg_attr(feature = "be-dyn-lib", export_name = "arthropod_alpha")] + #[cfg_attr(feature = "be-dyn-lib", export_name = "arthropod_combo")] fn update_skeleton_inner( skeleton: &Self::Skeleton, - (_velocity, global_time, stage_section, timer): Self::Dependency<'_>, + (_ability_id, stage_section, _current_strike, global_time, timer): Self::Dependency<'_>, anim_time: f32, _rate: &mut f32, s_a: &SkeletonAttr, @@ -26,9 +26,9 @@ impl Animation for AlphaAnimation { let mut next = (*skeleton).clone(); let (movement1, movement2, movement3) = match stage_section { - Some(StageSection::Buildup) => (anim_time.powi(2), 0.0, 0.0), - Some(StageSection::Action) => (1.0, anim_time.powi(4), 0.0), - Some(StageSection::Recover) => (1.0, 1.0, anim_time), + StageSection::Buildup => (anim_time.powi(2), 0.0, 0.0), + StageSection::Action => (1.0, anim_time.powi(4), 0.0), + StageSection::Recover => (1.0, 1.0, anim_time), _ => (0.0, 0.0, 0.0), }; let pullback = 1.0 - movement3; diff --git a/voxygen/anim/src/arthropod/mod.rs b/voxygen/anim/src/arthropod/mod.rs index 9bc370a1b8..e44831d840 100644 --- a/voxygen/anim/src/arthropod/mod.rs +++ b/voxygen/anim/src/arthropod/mod.rs @@ -1,4 +1,4 @@ -pub mod alpha; +pub mod combomelee; pub mod dash; pub mod idle; pub mod jump; @@ -11,7 +11,7 @@ pub mod summon; // Reexports pub use self::{ - alpha::AlphaAnimation, dash::DashAnimation, idle::IdleAnimation, jump::JumpAnimation, + combomelee::ComboAnimation, dash::DashAnimation, idle::IdleAnimation, jump::JumpAnimation, leapmelee::LeapMeleeAnimation, leapshockwave::LeapShockAnimation, run::RunAnimation, shoot::ShootAnimation, stunned::StunnedAnimation, summon::SummonAnimation, }; diff --git a/voxygen/anim/src/biped_large/alpha.rs b/voxygen/anim/src/biped_large/alpha.rs index ebc8f5f84a..070530669a 100644 --- a/voxygen/anim/src/biped_large/alpha.rs +++ b/voxygen/anim/src/biped_large/alpha.rs @@ -1,6 +1,7 @@ use super::{ super::{vek::*, Animation}, - BipedLargeSkeleton, SkeletonAttr, + biped_large_alpha_axe, biped_large_alpha_hammer, biped_large_alpha_sword, + init_biped_large_alpha, BipedLargeSkeleton, SkeletonAttr, }; use common::{ comp::item::tool::{AbilitySpec, ToolKind}, @@ -45,17 +46,7 @@ impl Animation for AlphaAnimation { ) -> Self::Skeleton { *rate = 1.0; let mut next = (*skeleton).clone(); - let speed = Vec2::::from(velocity).magnitude(); - let lab: f32 = 0.65 * s_a.tempo; - let speednorm = (speed / 12.0).powf(0.4); - let foothoril = (acc_vel * lab + PI * 1.45).sin() * speednorm; - let foothorir = (acc_vel * lab + PI * (0.45)).sin() * speednorm; - let footrotl = ((1.0 / (0.5 + (0.5) * ((acc_vel * lab + PI * 1.4).sin()).powi(2))).sqrt()) - * ((acc_vel * lab + PI * 1.4).sin()); - - let footrotr = ((1.0 / (0.5 + (0.5) * ((acc_vel * lab + PI * 0.4).sin()).powi(2))).sqrt()) - * ((acc_vel * lab + PI * 0.4).sin()); let (move1base, move2base, move3) = match stage_section { Some(StageSection::Buildup) => (anim_time.powf(0.25), 0.0, 0.0), Some(StageSection::Action) => (1.0, anim_time, 0.0), @@ -65,85 +56,20 @@ impl Animation for AlphaAnimation { let pullback = 1.0 - move3; let move1 = move1base * pullback; let move2 = move2base * pullback; + let subtract = global_time - timer; let check = subtract - subtract.trunc(); let mirror = (check - 0.5).signum(); - next.second.position = Vec3::new(0.0, 0.0, 0.0); - next.second.orientation = Quaternion::rotation_x(0.0); - next.shoulder_l.position = Vec3::new( - -s_a.shoulder.0, - s_a.shoulder.1, - s_a.shoulder.2 - foothorir * 1.0, - ); - next.shoulder_l.orientation = - Quaternion::rotation_x(move1 * 0.8 + 0.6 * speednorm + (footrotr * -0.2) * speednorm); + let speed = Vec2::::from(velocity).magnitude(); - next.shoulder_r.position = Vec3::new( - s_a.shoulder.0, - s_a.shoulder.1, - s_a.shoulder.2 - foothoril * 1.0, - ); - next.shoulder_r.orientation = - Quaternion::rotation_x(move1 * 0.8 + 0.6 * speednorm + (footrotl * -0.2) * speednorm); - - next.main.position = Vec3::new(0.0, 0.0, 0.0); - next.main.orientation = Quaternion::rotation_x(0.0); - - next.hand_l.position = Vec3::new(0.0, 0.0, s_a.grip.0); - next.hand_r.position = Vec3::new(0.0, 0.0, s_a.grip.0); - - next.hand_l.orientation = Quaternion::rotation_x(0.0); - next.hand_r.orientation = Quaternion::rotation_x(0.0); + let foothorir = init_biped_large_alpha(&mut next, s_a, speed, acc_vel, move1); match active_tool_kind { Some(ToolKind::Sword) => { - next.control_l.position = Vec3::new(-1.0, 1.0, 1.0); - next.control_r.position = Vec3::new(0.0, 2.0, -3.0); - next.head.orientation = Quaternion::rotation_x(move1 * -0.25) - * Quaternion::rotation_z(move1 * -0.2 + move2 * 0.6); - next.control.position = Vec3::new( - -3.0 + move1 * -4.0 + move2 * 5.0, - 5.0 + s_a.grip.0 / 1.2 + move1 * -4.0 + move2 * 8.0, - -4.0 + -s_a.grip.0 / 2.0 + move2 * -5.0, - ); - next.upper_torso.orientation = Quaternion::rotation_z(move1 * 0.5 + move2 * -0.7); - next.lower_torso.orientation = Quaternion::rotation_z(move1 * -0.5 + move2 * 0.7); - next.control_l.orientation = - Quaternion::rotation_x(PI / 2.0 + move1 * -0.5 + move2 * 1.5) - * Quaternion::rotation_y(-0.2); - next.control_r.orientation = - Quaternion::rotation_x(PI / 2.2 + move1 * -0.5 + move2 * 1.5) - * Quaternion::rotation_y(0.2) - * Quaternion::rotation_z(0.0); - - next.control.orientation = - Quaternion::rotation_x(-0.2 + move1 * 0.5 + move2 * -2.0) - * Quaternion::rotation_y(-0.1 + move1 * -0.5 + move2 * 1.0); + biped_large_alpha_sword(&mut next, s_a, move1, move2); }, Some(ToolKind::Hammer) => { - next.control_l.position = Vec3::new(-1.0, 2.0, 12.0 + move2 * -10.0); - next.control_r.position = Vec3::new(1.0, 2.0, -2.0); - - next.control.position = Vec3::new( - 4.0 + move1 * -12.0 + move2 * 20.0, - (s_a.grip.0 / 1.0) + move1 * -3.0 + move2 * 5.0, - (-s_a.grip.0 / 0.8) + move1 * -2.0 + move2 * 8.0, - ); - next.head.orientation = Quaternion::rotation_x(move1 * -0.25) - * Quaternion::rotation_z(move1 * -0.2 + move2 * 0.6); - next.upper_torso.orientation = Quaternion::rotation_z(move1 * 0.2 + move2 * -0.4); - next.lower_torso.orientation = Quaternion::rotation_z(move1 * -0.2 + move2 * 0.2); - - next.control_l.orientation = - Quaternion::rotation_x(PI / 2.0 + move2 * 0.8) * Quaternion::rotation_y(-0.0); - next.control_r.orientation = Quaternion::rotation_x(PI / 2.0 + 0.2 + move2 * 0.8) - * Quaternion::rotation_y(0.0) - * Quaternion::rotation_z(0.0); - - next.control.orientation = - Quaternion::rotation_x(-1.0 + move1 * -0.5 + move2 * -0.3) - * Quaternion::rotation_y(-1.8 + move1 * -0.8 + move2 * 3.0) - * Quaternion::rotation_z(move1 * -0.8 + move2 * -0.8); + biped_large_alpha_hammer(&mut next, s_a, move1, move2); }, Some(ToolKind::Axe) => match ability_id { Some("common.abilities.custom.gigas_frost.cleave") => { @@ -257,32 +183,7 @@ impl Animation for AlphaAnimation { next.main.orientation = Quaternion::rotation_y(move1 * 0.4 + move2 * -1.2); }, _ => { - next.control_l.position = Vec3::new(-1.0, 2.0, 12.0 + move2 * -10.0); - next.control_r.position = Vec3::new(1.0, 2.0, -2.0); - - next.control.position = Vec3::new( - 4.0 + move1 * -12.0 + move2 * 28.0, - (s_a.grip.0 / 1.0) + move1 * -3.0 + move2 * -5.0, - (-s_a.grip.0 / 0.8) + move1 * 2.0 + move2 * 8.0, - ); - next.head.orientation = Quaternion::rotation_x(move1 * -0.25) - * Quaternion::rotation_z(move1 * -0.2 + move2 * 0.6); - next.upper_torso.orientation = - Quaternion::rotation_z(move1 * 0.6 + move2 * -0.9); - next.lower_torso.orientation = - Quaternion::rotation_z(move1 * -0.6 + move2 * 0.9); - - next.control_l.orientation = Quaternion::rotation_x(PI / 2.0 + move2 * 0.8) - * Quaternion::rotation_y(-0.0); - next.control_r.orientation = - Quaternion::rotation_x(PI / 2.0 + 0.2 + move2 * 0.8) - * Quaternion::rotation_y(0.0) - * Quaternion::rotation_z(0.0); - - next.control.orientation = - Quaternion::rotation_x(-1.0 + move1 * -0.5 + move2 * -0.3) - * Quaternion::rotation_y(-1.8 + move1 * -0.4 + move2 * 3.5) - * Quaternion::rotation_z(move1 * -1.0 + move2 * -1.5); + biped_large_alpha_axe(&mut next, s_a, move1, move2); }, }, Some(ToolKind::Natural) => match ability_id { @@ -306,7 +207,6 @@ impl Animation for AlphaAnimation { * Quaternion::rotation_z(move1 * -0.5 + move2 * 0.6); next.head.orientation = Quaternion::rotation_x(move1 * 0.3); }, - Some("common.abilities.custom.tidalwarrior.pincer") => { if mirror > 0.0 { next.head.orientation = Quaternion::rotation_z(move1 * 0.75); diff --git a/voxygen/anim/src/biped_large/beta.rs b/voxygen/anim/src/biped_large/beta.rs index 75eaa37bfe..34065d6542 100644 --- a/voxygen/anim/src/biped_large/beta.rs +++ b/voxygen/anim/src/biped_large/beta.rs @@ -1,5 +1,6 @@ use super::{ super::{vek::*, Animation}, + biped_large_beta_axe, biped_large_beta_hammer, biped_large_beta_sword, init_biped_large_beta, BipedLargeSkeleton, SkeletonAttr, }; use common::{ @@ -43,17 +44,7 @@ impl Animation for BetaAnimation { ) -> Self::Skeleton { *rate = 1.0; let mut next = (*skeleton).clone(); - let speed = Vec2::::from(velocity).magnitude(); - let lab: f32 = 0.65 * s_a.tempo; - let speednorm = (speed / 12.0).powf(0.4); - let foothoril = (acc_vel * lab + PI * 1.45).sin() * speednorm; - let foothorir = (acc_vel * lab + PI * (0.45)).sin() * speednorm; - let footrotl = ((1.0 / (0.5 + (0.5) * ((acc_vel * lab + PI * 1.4).sin()).powi(2))).sqrt()) - * ((acc_vel * lab + PI * 1.4).sin()); - - let footrotr = ((1.0 / (0.5 + (0.5) * ((acc_vel * lab + PI * 0.4).sin()).powi(2))).sqrt()) - * ((acc_vel * lab + PI * 0.4).sin()); let (move1base, move2base, move3) = match stage_section { Some(StageSection::Buildup) => (anim_time.powf(0.25), 0.0, 0.0), Some(StageSection::Action) => (1.0, anim_time, 0.0), @@ -64,108 +55,19 @@ impl Animation for BetaAnimation { let move1 = move1base * pullback; let move2 = move2base * pullback; - next.shoulder_l.position = Vec3::new( - -s_a.shoulder.0, - s_a.shoulder.1, - s_a.shoulder.2 - foothorir * 1.0, - ); - next.shoulder_l.orientation = - Quaternion::rotation_x(move1 * 0.8 + 0.6 * speednorm + (footrotr * -0.2) * speednorm); + let speed = Vec2::::from(velocity).magnitude(); - next.shoulder_r.position = Vec3::new( - s_a.shoulder.0, - s_a.shoulder.1, - s_a.shoulder.2 - foothoril * 1.0, - ); - next.shoulder_r.orientation = - Quaternion::rotation_x(move1 * 0.8 + 0.6 * speednorm + (footrotl * -0.2) * speednorm); - next.torso.orientation = Quaternion::rotation_z(0.0); - - next.main.position = Vec3::new(0.0, 0.0, 0.0); - next.main.orientation = Quaternion::rotation_x(0.0); - - next.hand_l.position = Vec3::new(0.0, 0.0, s_a.grip.0); - next.hand_r.position = Vec3::new(0.0, 0.0, s_a.grip.0); - - next.hand_l.orientation = Quaternion::rotation_x(0.0); - next.hand_r.orientation = Quaternion::rotation_x(0.0); + init_biped_large_beta(&mut next, s_a, speed, acc_vel, move1); match active_tool_kind { Some(ToolKind::Sword) => { - next.control_l.position = Vec3::new(-1.0, 1.0, 1.0); - next.control_r.position = Vec3::new(0.0, 2.0, -3.0); - next.head.orientation = Quaternion::rotation_x(move1 * -0.25) - * Quaternion::rotation_z(move1 * -0.2 + move2 * 0.6); - next.control.position = Vec3::new( - -3.0 + move1 * -4.0 + move2 * 5.0, - 5.0 + s_a.grip.0 / 1.2 + move1 * -4.0 + move2 * 8.0, - -4.0 + -s_a.grip.0 / 2.0 + move2 * -5.0, - ); - next.upper_torso.orientation = - Quaternion::rotation_z(move1base * 0.5 + move2 * -0.7); - next.lower_torso.orientation = - Quaternion::rotation_z(move1base * -0.5 + move2 * 0.7); - next.control_l.orientation = - Quaternion::rotation_x(PI / 2.0 + move1 * -0.5 + move2 * 1.5) - * Quaternion::rotation_y(-0.2); - next.control_r.orientation = - Quaternion::rotation_x(PI / 2.2 + move1 * -0.5 + move2 * 1.5) - * Quaternion::rotation_y(0.2) - * Quaternion::rotation_z(0.0); - - next.control.orientation = - Quaternion::rotation_x(-0.2 + move1 * 0.5 + move2 * -1.5) - * Quaternion::rotation_y(-0.1 + move1 * -0.5 + move2 * 1.0); + biped_large_beta_sword(&mut next, s_a, move1base, move1, move2); }, Some(ToolKind::Hammer) => { - next.control_l.position = Vec3::new(-1.0, 2.0, 12.0 + move2 * -10.0); - next.control_r.position = Vec3::new(1.0, 2.0, -2.0); - - next.control.position = Vec3::new( - 4.0 + move1 * -12.0 + move2 * 20.0, - (s_a.grip.0 / 1.0) + move1 * -3.0 + move2 * 5.0, - (-s_a.grip.0 / 0.8) + move1 * 6.0 + move2 * 8.0, - ); - next.head.orientation = Quaternion::rotation_x(move1 * -0.25) - * Quaternion::rotation_z(move1 * -0.2 + move2 * 0.6); - next.upper_torso.orientation = Quaternion::rotation_z(move1 * 0.6 + move2 * -1.5); - next.lower_torso.orientation = Quaternion::rotation_z(move1 * -0.6 + move2 * 1.5); - - next.control_l.orientation = - Quaternion::rotation_x(PI / 2.0 + move2 * 0.8) * Quaternion::rotation_y(-0.0); - next.control_r.orientation = Quaternion::rotation_x(PI / 2.0 + 0.2 + move2 * 0.8) - * Quaternion::rotation_y(0.0) - * Quaternion::rotation_z(0.0); - - next.control.orientation = - Quaternion::rotation_x(-1.0 + move1 * -1.5 + move2 * -0.3) - * Quaternion::rotation_y(-1.8 + move1 * -0.8 + move2 * 3.0) - * Quaternion::rotation_z(move1 * -0.8 + move2 * -0.8); + biped_large_beta_hammer(&mut next, s_a, move1, move2); }, Some(ToolKind::Axe) => { - next.control_l.position = Vec3::new(-1.0, 2.0, 12.0 + move2 * -10.0); - next.control_r.position = Vec3::new(1.0, 2.0, -2.0); - - next.control.position = Vec3::new( - 4.0 + move1 * -18.0 + move2 * 20.0, - (s_a.grip.0 / 1.0) + move1 * -3.0 + move2 * 12.0, - (-s_a.grip.0 / 0.8) + move1 * -2.0 + move2 * 4.0, - ); - next.head.orientation = Quaternion::rotation_x(move1 * -0.25) - * Quaternion::rotation_z(move1 * -0.9 + move2 * 0.6); - next.upper_torso.orientation = Quaternion::rotation_z(move1 * 1.2 + move2 * -1.0); - next.lower_torso.orientation = Quaternion::rotation_z(move1 * -1.2 + move2 * 1.0); - - next.control_l.orientation = - Quaternion::rotation_x(PI / 2.0 + move2 * 0.8) * Quaternion::rotation_y(-0.0); - next.control_r.orientation = Quaternion::rotation_x(PI / 2.0 + 0.2 + move2 * 0.8) - * Quaternion::rotation_y(0.0) - * Quaternion::rotation_z(0.0); - - next.control.orientation = - Quaternion::rotation_x(-1.0 + move1 * 0.0 + move2 * -0.8) - * Quaternion::rotation_y(-1.8 + move1 * 3.0 + move2 * -0.9) - * Quaternion::rotation_z(move1 * -0.2 + move2 * -1.5); + biped_large_beta_axe(&mut next, s_a, move1, move2); }, Some(ToolKind::Natural) => match ability_id { Some("common.abilities.custom.wendigomagic.singlestrike") => { diff --git a/voxygen/anim/src/biped_large/combomelee.rs b/voxygen/anim/src/biped_large/combomelee.rs index f5255e2450..2629238eab 100644 --- a/voxygen/anim/src/biped_large/combomelee.rs +++ b/voxygen/anim/src/biped_large/combomelee.rs @@ -1,5 +1,7 @@ use super::{ super::{vek::*, Animation}, + biped_large_alpha_axe, biped_large_alpha_hammer, biped_large_alpha_sword, biped_large_beta_axe, + biped_large_beta_hammer, biped_large_beta_sword, init_biped_large_alpha, init_biped_large_beta, BipedLargeSkeleton, SkeletonAttr, }; use common::states::utils::{AbilityInfo, StageSection}; @@ -13,6 +15,8 @@ impl Animation for ComboAnimation { Option, usize, Vec2, + Vec3, + f32, ); type Skeleton = BipedLargeSkeleton; @@ -22,7 +26,7 @@ impl Animation for ComboAnimation { #[cfg_attr(feature = "be-dyn-lib", export_name = "biped_large_combo")] fn update_skeleton_inner( skeleton: &Self::Skeleton, - (ability_id, stage_section, _ability_info, current_strike, _move_dir): Self::Dependency<'_>, + (ability_id, stage_section, _ability_info, current_strike, _move_dir, velocity, acc_vel): Self::Dependency<'_>, anim_time: f32, rate: &mut f32, s_a: &SkeletonAttr, @@ -108,6 +112,114 @@ impl Animation for ComboAnimation { _ => {}, } }, + Some( + "common.abilities.custom.cyclops.doublestrike" + | "common.abilities.hammersimple.doublestrike", + ) => { + let speed = Vec2::::from(velocity).magnitude(); + match strike { + 0 => { + let (move1base, move2base, move3) = match stage_section { + Some(StageSection::Buildup) => (anim_time.powf(0.25), 0.0, 0.0), + Some(StageSection::Action) => (1.0, anim_time, 0.0), + Some(StageSection::Recover) => (1.0, 1.0, anim_time.powi(4)), + _ => (0.0, 0.0, 0.0), + }; + let pullback = 1.0 - move3; + let move1 = move1base * pullback; + let move2 = move2base * pullback; + + init_biped_large_alpha(&mut next, s_a, speed, acc_vel, move1); + biped_large_alpha_hammer(&mut next, s_a, move1, move2); + }, + 1 => { + let (move1base, move2base, move3) = match stage_section { + Some(StageSection::Buildup) => (anim_time.powf(0.25), 0.0, 0.0), + Some(StageSection::Action) => (1.0, anim_time, 0.0), + Some(StageSection::Recover) => (1.0, 1.0, anim_time.powi(6)), + _ => (0.0, 0.0, 0.0), + }; + let pullback = 1.0 - move3; + let move1 = move1base * pullback; + let move2 = move2base * pullback; + + init_biped_large_beta(&mut next, s_a, speed, acc_vel, move1); + biped_large_beta_hammer(&mut next, s_a, move1, move2); + }, + _ => {}, + } + }, + Some( + "common.abilities.custom.dullahan.melee" + | "common.abilities.swordsimple.doublestrike", + ) => { + let speed = Vec2::::from(velocity).magnitude(); + match strike { + 0 => { + let (move1base, move2base, move3) = match stage_section { + Some(StageSection::Buildup) => (anim_time.powf(0.25), 0.0, 0.0), + Some(StageSection::Action) => (1.0, anim_time, 0.0), + Some(StageSection::Recover) => (1.0, 1.0, anim_time.powi(4)), + _ => (0.0, 0.0, 0.0), + }; + let pullback = 1.0 - move3; + let move1 = move1base * pullback; + let move2 = move2base * pullback; + + init_biped_large_alpha(&mut next, s_a, speed, acc_vel, move1); + biped_large_alpha_sword(&mut next, s_a, move1, move2); + }, + 1 => { + let (move1base, move2base, move3) = match stage_section { + Some(StageSection::Buildup) => (anim_time.powf(0.25), 0.0, 0.0), + Some(StageSection::Action) => (1.0, anim_time, 0.0), + Some(StageSection::Recover) => (1.0, 1.0, anim_time.powi(6)), + _ => (0.0, 0.0, 0.0), + }; + let pullback = 1.0 - move3; + let move1 = move1base * pullback; + let move2 = move2base * pullback; + + init_biped_large_beta(&mut next, s_a, speed, acc_vel, move1); + biped_large_beta_sword(&mut next, s_a, move1base, move1, move2); + }, + _ => {}, + } + }, + Some("common.abilities.custom.oni.doublestrike") => { + let speed = Vec2::::from(velocity).magnitude(); + match strike { + 0 => { + let (move1base, move2base, move3) = match stage_section { + Some(StageSection::Buildup) => (anim_time.powf(0.25), 0.0, 0.0), + Some(StageSection::Action) => (1.0, anim_time, 0.0), + Some(StageSection::Recover) => (1.0, 1.0, anim_time.powi(4)), + _ => (0.0, 0.0, 0.0), + }; + let pullback = 1.0 - move3; + let move1 = move1base * pullback; + let move2 = move2base * pullback; + + init_biped_large_alpha(&mut next, s_a, speed, acc_vel, move1); + biped_large_alpha_axe(&mut next, s_a, move1, move2); + }, + 1 => { + let (move1base, move2base, move3) = match stage_section { + Some(StageSection::Buildup) => (anim_time.powf(0.25), 0.0, 0.0), + Some(StageSection::Action) => (1.0, anim_time, 0.0), + Some(StageSection::Recover) => (1.0, 1.0, anim_time.powi(6)), + _ => (0.0, 0.0, 0.0), + }; + let pullback = 1.0 - move3; + let move1 = move1base * pullback; + let move2 = move2base * pullback; + + init_biped_large_beta(&mut next, s_a, speed, acc_vel, move1); + biped_large_beta_axe(&mut next, s_a, move1, move2); + }, + _ => {}, + } + }, _ => {}, } } diff --git a/voxygen/anim/src/biped_large/mod.rs b/voxygen/anim/src/biped_large/mod.rs index cd4f435069..d851f0e4a6 100644 --- a/voxygen/anim/src/biped_large/mod.rs +++ b/voxygen/anim/src/biped_large/mod.rs @@ -633,3 +633,268 @@ fn mount_point(body: &Body) -> Vec3 { } .into() } + +pub fn init_biped_large_alpha( + next: &mut BipedLargeSkeleton, + s_a: &SkeletonAttr, + speed: f32, + acc_vel: f32, + move1: f32, +) -> f32 { + let lab: f32 = 0.65 * s_a.tempo; + let speednorm = (speed / 12.0).powf(0.4); + let foothoril = (acc_vel * lab + PI * 1.45).sin() * speednorm; + let foothorir = (acc_vel * lab + PI * (0.45)).sin() * speednorm; + let footrotl = ((1.0 / (0.5 + (0.5) * ((acc_vel * lab + PI * 1.4).sin()).powi(2))).sqrt()) + * ((acc_vel * lab + PI * 1.4).sin()); + + let footrotr = ((1.0 / (0.5 + (0.5) * ((acc_vel * lab + PI * 0.4).sin()).powi(2))).sqrt()) + * ((acc_vel * lab + PI * 0.4).sin()); + next.second.position = Vec3::new(0.0, 0.0, 0.0); + next.second.orientation = Quaternion::rotation_x(0.0); + next.shoulder_l.position = Vec3::new( + -s_a.shoulder.0, + s_a.shoulder.1, + s_a.shoulder.2 - foothorir * 1.0, + ); + next.shoulder_l.orientation = + Quaternion::rotation_x(move1 * 0.8 + 0.6 * speednorm + (footrotr * -0.2) * speednorm); + + next.shoulder_r.position = Vec3::new( + s_a.shoulder.0, + s_a.shoulder.1, + s_a.shoulder.2 - foothoril * 1.0, + ); + next.shoulder_r.orientation = + Quaternion::rotation_x(move1 * 0.8 + 0.6 * speednorm + (footrotl * -0.2) * speednorm); + + next.main.position = Vec3::new(0.0, 0.0, 0.0); + next.main.orientation = Quaternion::rotation_x(0.0); + + next.hand_l.position = Vec3::new(0.0, 0.0, s_a.grip.0); + next.hand_r.position = Vec3::new(0.0, 0.0, s_a.grip.0); + + next.hand_l.orientation = Quaternion::rotation_x(0.0); + next.hand_r.orientation = Quaternion::rotation_x(0.0); + + foothorir +} + +pub fn init_biped_large_beta( + next: &mut BipedLargeSkeleton, + s_a: &SkeletonAttr, + speed: f32, + acc_vel: f32, + move1: f32, +) { + let lab: f32 = 0.65 * s_a.tempo; + let speednorm = (speed / 12.0).powf(0.4); + let foothoril = (acc_vel * lab + PI * 1.45).sin() * speednorm; + let foothorir = (acc_vel * lab + PI * (0.45)).sin() * speednorm; + let footrotl = ((1.0 / (0.5 + (0.5) * ((acc_vel * lab + PI * 1.4).sin()).powi(2))).sqrt()) + * ((acc_vel * lab + PI * 1.4).sin()); + + let footrotr = ((1.0 / (0.5 + (0.5) * ((acc_vel * lab + PI * 0.4).sin()).powi(2))).sqrt()) + * ((acc_vel * lab + PI * 0.4).sin()); + + next.shoulder_l.position = Vec3::new( + -s_a.shoulder.0, + s_a.shoulder.1, + s_a.shoulder.2 - foothorir * 1.0, + ); + next.shoulder_l.orientation = + Quaternion::rotation_x(move1 * 0.8 + 0.6 * speednorm + (footrotr * -0.2) * speednorm); + + next.shoulder_r.position = Vec3::new( + s_a.shoulder.0, + s_a.shoulder.1, + s_a.shoulder.2 - foothoril * 1.0, + ); + next.shoulder_r.orientation = + Quaternion::rotation_x(move1 * 0.8 + 0.6 * speednorm + (footrotl * -0.2) * speednorm); + next.torso.orientation = Quaternion::rotation_z(0.0); + + next.main.position = Vec3::new(0.0, 0.0, 0.0); + next.main.orientation = Quaternion::rotation_x(0.0); + + next.hand_l.position = Vec3::new(0.0, 0.0, s_a.grip.0); + next.hand_r.position = Vec3::new(0.0, 0.0, s_a.grip.0); + + next.hand_l.orientation = Quaternion::rotation_x(0.0); + next.hand_r.orientation = Quaternion::rotation_x(0.0); +} + +pub fn biped_large_alpha_hammer( + next: &mut BipedLargeSkeleton, + s_a: &SkeletonAttr, + move1: f32, + move2: f32, +) { + next.control_l.position = Vec3::new(-1.0, 2.0, 12.0 + move2 * -10.0); + next.control_r.position = Vec3::new(1.0, 2.0, -2.0); + + next.control.position = Vec3::new( + 4.0 + move1 * -12.0 + move2 * 20.0, + (s_a.grip.0 / 1.0) + move1 * -3.0 + move2 * 5.0, + (-s_a.grip.0 / 0.8) + move1 * -2.0 + move2 * 8.0, + ); + next.head.orientation = + Quaternion::rotation_x(move1 * -0.25) * Quaternion::rotation_z(move1 * -0.2 + move2 * 0.6); + next.upper_torso.orientation = Quaternion::rotation_z(move1 * 0.2 + move2 * -0.4); + next.lower_torso.orientation = Quaternion::rotation_z(move1 * -0.2 + move2 * 0.2); + + next.control_l.orientation = + Quaternion::rotation_x(PI / 2.0 + move2 * 0.8) * Quaternion::rotation_y(-0.0); + next.control_r.orientation = Quaternion::rotation_x(PI / 2.0 + 0.2 + move2 * 0.8) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(0.0); + + next.control.orientation = Quaternion::rotation_x(-1.0 + move1 * -0.5 + move2 * -0.3) + * Quaternion::rotation_y(-1.8 + move1 * -0.8 + move2 * 3.0) + * Quaternion::rotation_z(move1 * -0.8 + move2 * -0.8); +} + +pub fn biped_large_beta_hammer( + next: &mut BipedLargeSkeleton, + s_a: &SkeletonAttr, + move1: f32, + move2: f32, +) { + next.control_l.position = Vec3::new(-1.0, 2.0, 12.0 + move2 * -10.0); + next.control_r.position = Vec3::new(1.0, 2.0, -2.0); + + next.control.position = Vec3::new( + 4.0 + move1 * -12.0 + move2 * 20.0, + (s_a.grip.0 / 1.0) + move1 * -3.0 + move2 * 5.0, + (-s_a.grip.0 / 0.8) + move1 * 6.0 + move2 * 8.0, + ); + next.head.orientation = + Quaternion::rotation_x(move1 * -0.25) * Quaternion::rotation_z(move1 * -0.2 + move2 * 0.6); + next.upper_torso.orientation = Quaternion::rotation_z(move1 * 0.6 + move2 * -1.5); + next.lower_torso.orientation = Quaternion::rotation_z(move1 * -0.6 + move2 * 1.5); + + next.control_l.orientation = + Quaternion::rotation_x(PI / 2.0 + move2 * 0.8) * Quaternion::rotation_y(-0.0); + next.control_r.orientation = Quaternion::rotation_x(PI / 2.0 + 0.2 + move2 * 0.8) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(0.0); + + next.control.orientation = Quaternion::rotation_x(-1.0 + move1 * -1.5 + move2 * -0.3) + * Quaternion::rotation_y(-1.8 + move1 * -0.8 + move2 * 3.0) + * Quaternion::rotation_z(move1 * -0.8 + move2 * -0.8); +} + +pub fn biped_large_alpha_sword( + next: &mut BipedLargeSkeleton, + s_a: &SkeletonAttr, + move1: f32, + move2: f32, +) { + next.control_l.position = Vec3::new(-1.0, 1.0, 1.0); + next.control_r.position = Vec3::new(0.0, 2.0, -3.0); + next.head.orientation = + Quaternion::rotation_x(move1 * -0.25) * Quaternion::rotation_z(move1 * -0.2 + move2 * 0.6); + next.control.position = Vec3::new( + -3.0 + move1 * -4.0 + move2 * 5.0, + 5.0 + s_a.grip.0 / 1.2 + move1 * -4.0 + move2 * 8.0, + -4.0 + -s_a.grip.0 / 2.0 + move2 * -5.0, + ); + next.upper_torso.orientation = Quaternion::rotation_z(move1 * 0.5 + move2 * -0.7); + next.lower_torso.orientation = Quaternion::rotation_z(move1 * -0.5 + move2 * 0.7); + next.control_l.orientation = Quaternion::rotation_x(PI / 2.0 + move1 * -0.5 + move2 * 1.5) + * Quaternion::rotation_y(-0.2); + next.control_r.orientation = Quaternion::rotation_x(PI / 2.2 + move1 * -0.5 + move2 * 1.5) + * Quaternion::rotation_y(0.2) + * Quaternion::rotation_z(0.0); + + next.control.orientation = Quaternion::rotation_x(-0.2 + move1 * 0.5 + move2 * -2.0) + * Quaternion::rotation_y(-0.1 + move1 * -0.5 + move2 * 1.0); +} + +pub fn biped_large_beta_sword( + next: &mut BipedLargeSkeleton, + s_a: &SkeletonAttr, + move1base: f32, + move1: f32, + move2: f32, +) { + next.control_l.position = Vec3::new(-1.0, 1.0, 1.0); + next.control_r.position = Vec3::new(0.0, 2.0, -3.0); + next.head.orientation = + Quaternion::rotation_x(move1 * -0.25) * Quaternion::rotation_z(move1 * -0.2 + move2 * 0.6); + next.control.position = Vec3::new( + -3.0 + move1 * -4.0 + move2 * 5.0, + 5.0 + s_a.grip.0 / 1.2 + move1 * -4.0 + move2 * 8.0, + -4.0 + -s_a.grip.0 / 2.0 + move2 * -5.0, + ); + next.upper_torso.orientation = Quaternion::rotation_z(move1base * 0.5 + move2 * -0.7); + next.lower_torso.orientation = Quaternion::rotation_z(move1base * -0.5 + move2 * 0.7); + next.control_l.orientation = Quaternion::rotation_x(PI / 2.0 + move1 * -0.5 + move2 * 1.5) + * Quaternion::rotation_y(-0.2); + next.control_r.orientation = Quaternion::rotation_x(PI / 2.2 + move1 * -0.5 + move2 * 1.5) + * Quaternion::rotation_y(0.2) + * Quaternion::rotation_z(0.0); + + next.control.orientation = Quaternion::rotation_x(-0.2 + move1 * 0.5 + move2 * -1.5) + * Quaternion::rotation_y(-0.1 + move1 * -0.5 + move2 * 1.0); +} + +pub fn biped_large_alpha_axe( + next: &mut BipedLargeSkeleton, + s_a: &SkeletonAttr, + move1: f32, + move2: f32, +) { + next.control_l.position = Vec3::new(-1.0, 2.0, 12.0 + move2 * -10.0); + next.control_r.position = Vec3::new(1.0, 2.0, -2.0); + + next.control.position = Vec3::new( + 4.0 + move1 * -12.0 + move2 * 28.0, + (s_a.grip.0 / 1.0) + move1 * -3.0 + move2 * -5.0, + (-s_a.grip.0 / 0.8) + move1 * 2.0 + move2 * 8.0, + ); + next.head.orientation = + Quaternion::rotation_x(move1 * -0.25) * Quaternion::rotation_z(move1 * -0.2 + move2 * 0.6); + next.upper_torso.orientation = Quaternion::rotation_z(move1 * 0.6 + move2 * -0.9); + next.lower_torso.orientation = Quaternion::rotation_z(move1 * -0.6 + move2 * 0.9); + + next.control_l.orientation = + Quaternion::rotation_x(PI / 2.0 + move2 * 0.8) * Quaternion::rotation_y(-0.0); + next.control_r.orientation = Quaternion::rotation_x(PI / 2.0 + 0.2 + move2 * 0.8) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(0.0); + + next.control.orientation = Quaternion::rotation_x(-1.0 + move1 * -0.5 + move2 * -0.3) + * Quaternion::rotation_y(-1.8 + move1 * -0.4 + move2 * 3.5) + * Quaternion::rotation_z(move1 * -1.0 + move2 * -1.5); +} + +pub fn biped_large_beta_axe( + next: &mut BipedLargeSkeleton, + s_a: &SkeletonAttr, + move1: f32, + move2: f32, +) { + next.control_l.position = Vec3::new(-1.0, 2.0, 12.0 + move2 * -10.0); + next.control_r.position = Vec3::new(1.0, 2.0, -2.0); + + next.control.position = Vec3::new( + 4.0 + move1 * -18.0 + move2 * 20.0, + (s_a.grip.0 / 1.0) + move1 * -3.0 + move2 * 12.0, + (-s_a.grip.0 / 0.8) + move1 * -2.0 + move2 * 4.0, + ); + next.head.orientation = + Quaternion::rotation_x(move1 * -0.25) * Quaternion::rotation_z(move1 * -0.9 + move2 * 0.6); + next.upper_torso.orientation = Quaternion::rotation_z(move1 * 1.2 + move2 * -1.0); + next.lower_torso.orientation = Quaternion::rotation_z(move1 * -1.2 + move2 * 1.0); + + next.control_l.orientation = + Quaternion::rotation_x(PI / 2.0 + move2 * 0.8) * Quaternion::rotation_y(-0.0); + next.control_r.orientation = Quaternion::rotation_x(PI / 2.0 + 0.2 + move2 * 0.8) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(0.0); + + next.control.orientation = Quaternion::rotation_x(-1.0 + move1 * 0.0 + move2 * -0.8) + * Quaternion::rotation_y(-1.8 + move1 * 3.0 + move2 * -0.9) + * Quaternion::rotation_z(move1 * -0.2 + move2 * -1.5); +} diff --git a/voxygen/anim/src/biped_small/alpha.rs b/voxygen/anim/src/biped_small/alpha.rs index 3c1effd0b6..874b75cb0d 100644 --- a/voxygen/anim/src/biped_small/alpha.rs +++ b/voxygen/anim/src/biped_small/alpha.rs @@ -1,6 +1,7 @@ use super::{ super::{vek::*, Animation}, - BipedSmallSkeleton, SkeletonAttr, + biped_small_alpha_axe, biped_small_alpha_dagger, biped_small_alpha_spear, + init_biped_small_alpha, BipedSmallSkeleton, SkeletonAttr, }; use common::{comp::item::ToolKind, states::utils::StageSection}; use std::f32::consts::PI; @@ -49,12 +50,12 @@ impl Animation for AlphaAnimation { ) -> Self::Skeleton { let mut next = (*skeleton).clone(); let speed = Vec2::::from(velocity).magnitude(); + let speednorm = speed / 9.4; + let speednormcancel = 1.0 - speednorm; let fast = (anim_time * 10.0).sin(); let fastalt = (anim_time * 10.0 + PI / 2.0).sin(); - let speednorm = speed / 9.4; - let speednormcancel = 1.0 - speednorm; let anim_time = anim_time.min(1.0); let (move1base, move2base, move3) = match stage_section { Some(StageSection::Buildup) => (anim_time.sqrt(), 0.0, 0.0), @@ -70,105 +71,26 @@ impl Animation for AlphaAnimation { let move2 = move2base * pullback * mirror; let move1abs = move1base * pullback; let move2abs = move2base * pullback; - next.hand_l.position = Vec3::new(s_a.grip.0 * 4.0, 0.0, s_a.grip.2); - next.hand_r.position = Vec3::new(-s_a.grip.0 * 4.0, 0.0, s_a.grip.2); - next.main.position = Vec3::new(0.0, 0.0, 0.0); - next.main.orientation = Quaternion::rotation_x(0.0); - next.hand_l.orientation = Quaternion::rotation_x(0.0); - next.hand_r.orientation = Quaternion::rotation_x(0.0); + + init_biped_small_alpha(&mut next, s_a); + match active_tool_kind { Some(ToolKind::Spear) => { - next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1); - next.head.orientation = Quaternion::rotation_x(move1abs * 0.2 + move2abs * 0.3) - * Quaternion::rotation_z(move1abs * -0.2 + move2abs * 0.6) - * Quaternion::rotation_y(move1abs * 0.3 + move2abs * -0.5); - next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1); - next.chest.orientation = Quaternion::rotation_x(move1abs * -0.2 + move2abs * 0.3) - * Quaternion::rotation_z(move1abs * 0.5 + move2abs * -0.6); - - next.pants.position = Vec3::new(0.0, s_a.pants.0, s_a.pants.1); - next.pants.orientation = Quaternion::rotation_x(move1abs * 0.2 + move2abs * -0.3) - * Quaternion::rotation_z(move1abs * -0.2 + move2abs * 0.2); - - next.control_l.position = Vec3::new(1.0 - s_a.grip.0 * 2.0, 2.0, -2.0); - next.control_r.position = Vec3::new(-1.0 + s_a.grip.0 * 2.0, 2.0, 2.0); - - next.control.position = Vec3::new( - -3.0 + move1abs * -3.0 + move2abs * 5.0, - s_a.grip.2 + move1abs * -12.0 + move2abs * 17.0, - -s_a.grip.2 / 2.5 + s_a.grip.0 * -2.0 + move2abs * 5.0, + biped_small_alpha_spear( + &mut next, + s_a, + move1abs, + move2abs, + fast, + fastalt, + speednormcancel, ); - - next.control_l.orientation = - Quaternion::rotation_x(PI / 1.5 + move1abs * -1.5 + move2abs * 2.5) - * Quaternion::rotation_y(-0.3); - next.control_r.orientation = Quaternion::rotation_x( - PI / 1.5 + s_a.grip.0 * 0.2 + move1abs * -1.5 + move2abs * 2.5, - ) * Quaternion::rotation_y(0.5 + s_a.grip.0 * 0.2); - - next.control.orientation = - Quaternion::rotation_x(-1.35 + move1abs * -0.3 + move2abs * 0.5) - * Quaternion::rotation_z(move1abs * 1.0 + move2abs * -1.0) - * Quaternion::rotation_y(move2abs * 0.0); - - next.tail.position = Vec3::new(0.0, s_a.tail.0, s_a.tail.1); - next.tail.orientation = Quaternion::rotation_x(0.05 * fastalt * speednormcancel) - * Quaternion::rotation_z(fast * 0.15 * speednormcancel); }, Some(ToolKind::Axe | ToolKind::Hammer | ToolKind::Pick | ToolKind::Shovel) => { - next.head.orientation = Quaternion::rotation_z(move1abs * 0.3 + move2abs * -0.6); - next.control_l.position = Vec3::new(2.0 - s_a.grip.0 * 2.0, 1.0, 3.0); - next.control_r.position = Vec3::new( - 9.0 + move1abs * -10.0 + s_a.grip.0 * 2.0, - -1.0 + move1abs * 2.0, - move1abs * 3.0 - 2.0, - ); - - next.control.position = Vec3::new( - -5.0 + move1abs * 5.0, - -1.0 + s_a.grip.2, - -1.0 + move1abs * 3.0 + -s_a.grip.2 / 2.5 + s_a.grip.0 * -2.0, - ); - - next.control_l.orientation = Quaternion::rotation_x(PI / 2.0 + move2abs * 1.0) - * Quaternion::rotation_y(-0.0) - * Quaternion::rotation_z(-0.0); - next.control_r.orientation = - Quaternion::rotation_x(0.5 + move1abs * 1.5 + s_a.grip.0 * 0.2) - * Quaternion::rotation_y(0.2 + s_a.grip.0 * 0.2) - * Quaternion::rotation_z(-0.0); - - next.control.orientation = Quaternion::rotation_x(-0.3 + move2abs * -1.0) - * Quaternion::rotation_y(move1abs * -0.9 + move2abs * 2.0) - * Quaternion::rotation_z(-0.3); + biped_small_alpha_axe(&mut next, s_a, move1abs, move2abs); }, Some(ToolKind::Dagger) => { - next.head.orientation = Quaternion::rotation_x(move1abs * 0.15 + move2abs * -0.15) - * Quaternion::rotation_z(move1abs * 0.15 + move2abs * -0.3); - next.control_l.position = Vec3::new(2.0 - s_a.grip.0 * 2.0, 1.0, 3.0); - next.control_r.position = Vec3::new( - 9.0 + move1abs * -7.0 + s_a.grip.0 * 2.0, - -1.0 + move1abs * 6.0, - -2.0, - ); - - next.control.position = Vec3::new( - -5.0 + move1abs * 5.0 + move2abs * 9.0, - -1.0 + move2abs * -3.0 + s_a.grip.2, - -1.0 + move1abs * 3.0 + -s_a.grip.2 / 2.5 + s_a.grip.0 * -2.0, - ); - - next.control_l.orientation = Quaternion::rotation_x(PI / 2.0) - * Quaternion::rotation_y(-0.0) - * Quaternion::rotation_z(-0.0); - next.control_r.orientation = - Quaternion::rotation_x(0.5 + move1abs * 1.5 + s_a.grip.0 * 0.2) - * Quaternion::rotation_y(0.2 + s_a.grip.0 * 0.2) - * Quaternion::rotation_z(-0.0); - - next.control.orientation = Quaternion::rotation_x(-0.3 + move2abs * -1.0) - * Quaternion::rotation_y(move1abs * -0.4 + move2abs * 1.0) - * Quaternion::rotation_z(-0.3 + move2abs * -2.2); + biped_small_alpha_dagger(&mut next, s_a, move1abs, move2abs); }, Some(ToolKind::Staff) => match ability_id { Some("common.abilities.custom.dwarves.flamekeeper.flamecrush") => { diff --git a/voxygen/anim/src/biped_small/combomelee.rs b/voxygen/anim/src/biped_small/combomelee.rs index e8c546513b..8a0ff7cbe8 100644 --- a/voxygen/anim/src/biped_small/combomelee.rs +++ b/voxygen/anim/src/biped_small/combomelee.rs @@ -1,18 +1,14 @@ use super::{ super::{vek::*, Animation}, - BipedSmallSkeleton, SkeletonAttr, + biped_small_alpha_axe, biped_small_alpha_dagger, biped_small_alpha_spear, + init_biped_small_alpha, BipedSmallSkeleton, SkeletonAttr, }; -use common::states::utils::{AbilityInfo, StageSection}; +use common::states::utils::StageSection; +use std::f32::consts::PI; pub struct ComboAnimation; impl Animation for ComboAnimation { - type Dependency<'a> = ( - Option<&'a str>, - Option, - Option, - usize, - Vec2, - ); + type Dependency<'a> = (Option<&'a str>, StageSection, usize, Vec3, f32, f32); type Skeleton = BipedSmallSkeleton; #[cfg(feature = "use-dyn-lib")] @@ -21,7 +17,7 @@ impl Animation for ComboAnimation { #[cfg_attr(feature = "be-dyn-lib", export_name = "biped_small_combo")] fn update_skeleton_inner( skeleton: &Self::Skeleton, - (ability_id, stage_section, _ability_info, current_strike, _move_dir): Self::Dependency<'_>, + (ability_id, stage_section, current_strike, velocity, _global_time, _timer): Self::Dependency<'_>, anim_time: f32, rate: &mut f32, s_a: &SkeletonAttr, @@ -32,7 +28,7 @@ impl Animation for ComboAnimation { next.main.position = Vec3::new(0.0, 0.0, 0.0); next.main.orientation = Quaternion::rotation_z(0.0); let multi_strike_pullback = 1.0 - - if matches!(stage_section, Some(StageSection::Recover)) { + - if matches!(stage_section, StageSection::Recover) { anim_time.powi(4) } else { 0.0 @@ -50,11 +46,11 @@ impl Animation for ComboAnimation { ) => { let (move1, move2) = if strike == current_strike { match stage_section { - Some(StageSection::Buildup) => { + StageSection::Buildup => { (((anim_time.max(0.4) - 0.4) * 1.5).powf(0.5), 0.0) }, - Some(StageSection::Action) => (1.0, (anim_time.min(0.4) * 2.5).powi(2)), - Some(StageSection::Recover) => (1.0, 1.0), + StageSection::Action => (1.0, (anim_time.min(0.4) * 2.5).powi(2)), + StageSection::Recover => (1.0, 1.0), _ => (0.0, 0.0), } } else { @@ -81,6 +77,68 @@ impl Animation for ComboAnimation { _ => {}, } }, + Some( + "common.abilities.axesimple.doublestrike" + | "common.abilities.custom.boreal_warrior.hammer", + ) => { + let anim_time = anim_time.min(1.0); + let (move1base, move2base, move3) = match stage_section { + StageSection::Buildup => (anim_time.sqrt(), 0.0, 0.0), + StageSection::Action => (1.0, anim_time.powi(4), 0.0), + StageSection::Recover => (1.0, 1.0, anim_time), + _ => (0.0, 0.0, 0.0), + }; + let pullback = 1.0 - move3; + let move1abs = move1base * pullback; + let move2abs = move2base * pullback; + + init_biped_small_alpha(&mut next, s_a); + biped_small_alpha_axe(&mut next, s_a, move1abs, move2abs); + }, + Some("common.abilities.daggersimple.singlestrike") => { + let anim_time = anim_time.min(1.0); + let (move1base, move2base, move3) = match stage_section { + StageSection::Buildup => (anim_time.sqrt(), 0.0, 0.0), + StageSection::Action => (1.0, anim_time.powi(4), 0.0), + StageSection::Recover => (1.0, 1.0, anim_time), + _ => (0.0, 0.0, 0.0), + }; + let pullback = 1.0 - move3; + let move1abs = move1base * pullback; + let move2abs = move2base * pullback; + + init_biped_small_alpha(&mut next, s_a); + biped_small_alpha_dagger(&mut next, s_a, move1abs, move2abs); + }, + Some("common.abilities.spear.doublestrike") => { + let anim_time = anim_time.min(1.0); + let speed = Vec2::::from(velocity).magnitude(); + let speednorm = speed / 9.4; + let speednormcancel = 1.0 - speednorm; + let fast = (anim_time * 10.0).sin(); + let fastalt = (anim_time * 10.0 + PI / 2.0).sin(); + + let (move1base, move2base, move3) = match stage_section { + StageSection::Buildup => (anim_time.sqrt(), 0.0, 0.0), + StageSection::Action => (1.0, anim_time.powi(4), 0.0), + StageSection::Recover => (1.0, 1.0, anim_time), + _ => (0.0, 0.0, 0.0), + }; + let pullback = 1.0 - move3; + let move1abs = move1base * pullback; + let move2abs = move2base * pullback; + + init_biped_small_alpha(&mut next, s_a); + biped_small_alpha_spear( + &mut next, + s_a, + move1abs, + move2abs, + fast, + fastalt, + speednormcancel, + ); + }, _ => {}, } } diff --git a/voxygen/anim/src/biped_small/mod.rs b/voxygen/anim/src/biped_small/mod.rs index 893b8ec20c..ead28a2d8f 100644 --- a/voxygen/anim/src/biped_small/mod.rs +++ b/voxygen/anim/src/biped_small/mod.rs @@ -22,6 +22,7 @@ pub use self::{ use super::{make_bone, vek::*, FigureBoneData, Offsets, Skeleton}; use common::comp::{self}; use core::convert::TryFrom; +use std::f32::consts::PI; pub type Body = comp::biped_small::Body; @@ -280,3 +281,123 @@ impl<'a> From<&'a Body> for SkeletonAttr { } } } + +pub fn init_biped_small_alpha(next: &mut BipedSmallSkeleton, s_a: &SkeletonAttr) { + next.hand_l.position = Vec3::new(s_a.grip.0 * 4.0, 0.0, s_a.grip.2); + next.hand_r.position = Vec3::new(-s_a.grip.0 * 4.0, 0.0, s_a.grip.2); + next.main.position = Vec3::new(0.0, 0.0, 0.0); + next.main.orientation = Quaternion::rotation_x(0.0); + next.hand_l.orientation = Quaternion::rotation_x(0.0); + next.hand_r.orientation = Quaternion::rotation_x(0.0); +} + +pub fn biped_small_alpha_spear( + next: &mut BipedSmallSkeleton, + s_a: &SkeletonAttr, + move1abs: f32, + move2abs: f32, + fast: f32, + fastalt: f32, + speednormcancel: f32, +) { + next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1); + next.head.orientation = Quaternion::rotation_x(move1abs * 0.2 + move2abs * 0.3) + * Quaternion::rotation_z(move1abs * -0.2 + move2abs * 0.6) + * Quaternion::rotation_y(move1abs * 0.3 + move2abs * -0.5); + next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1); + next.chest.orientation = Quaternion::rotation_x(move1abs * -0.2 + move2abs * 0.3) + * Quaternion::rotation_z(move1abs * 0.5 + move2abs * -0.6); + + next.pants.position = Vec3::new(0.0, s_a.pants.0, s_a.pants.1); + next.pants.orientation = Quaternion::rotation_x(move1abs * 0.2 + move2abs * -0.3) + * Quaternion::rotation_z(move1abs * -0.2 + move2abs * 0.2); + + next.control_l.position = Vec3::new(1.0 - s_a.grip.0 * 2.0, 2.0, -2.0); + next.control_r.position = Vec3::new(-1.0 + s_a.grip.0 * 2.0, 2.0, 2.0); + + next.control.position = Vec3::new( + -3.0 + move1abs * -3.0 + move2abs * 5.0, + s_a.grip.2 + move1abs * -12.0 + move2abs * 17.0, + -s_a.grip.2 / 2.5 + s_a.grip.0 * -2.0 + move2abs * 5.0, + ); + + next.control_l.orientation = + Quaternion::rotation_x(PI / 1.5 + move1abs * -1.5 + move2abs * 2.5) + * Quaternion::rotation_y(-0.3); + next.control_r.orientation = + Quaternion::rotation_x(PI / 1.5 + s_a.grip.0 * 0.2 + move1abs * -1.5 + move2abs * 2.5) + * Quaternion::rotation_y(0.5 + s_a.grip.0 * 0.2); + + next.control.orientation = Quaternion::rotation_x(-1.35 + move1abs * -0.3 + move2abs * 0.5) + * Quaternion::rotation_z(move1abs * 1.0 + move2abs * -1.0) + * Quaternion::rotation_y(move2abs * 0.0); + + next.tail.position = Vec3::new(0.0, s_a.tail.0, s_a.tail.1); + next.tail.orientation = Quaternion::rotation_x(0.05 * fastalt * speednormcancel) + * Quaternion::rotation_z(fast * 0.15 * speednormcancel); +} + +pub fn biped_small_alpha_axe( + next: &mut BipedSmallSkeleton, + s_a: &SkeletonAttr, + move1abs: f32, + move2abs: f32, +) { + next.head.orientation = Quaternion::rotation_z(move1abs * 0.3 + move2abs * -0.6); + next.control_l.position = Vec3::new(2.0 - s_a.grip.0 * 2.0, 1.0, 3.0); + next.control_r.position = Vec3::new( + 9.0 + move1abs * -10.0 + s_a.grip.0 * 2.0, + -1.0 + move1abs * 2.0, + move1abs * 3.0 - 2.0, + ); + + next.control.position = Vec3::new( + -5.0 + move1abs * 5.0, + -1.0 + s_a.grip.2, + -1.0 + move1abs * 3.0 + -s_a.grip.2 / 2.5 + s_a.grip.0 * -2.0, + ); + + next.control_l.orientation = Quaternion::rotation_x(PI / 2.0 + move2abs * 1.0) + * Quaternion::rotation_y(-0.0) + * Quaternion::rotation_z(-0.0); + next.control_r.orientation = Quaternion::rotation_x(0.5 + move1abs * 1.5 + s_a.grip.0 * 0.2) + * Quaternion::rotation_y(0.2 + s_a.grip.0 * 0.2) + * Quaternion::rotation_z(-0.0); + + next.control.orientation = Quaternion::rotation_x(-0.3 + move2abs * -1.0) + * Quaternion::rotation_y(move1abs * -0.9 + move2abs * 2.0) + * Quaternion::rotation_z(-0.3); +} + +pub fn biped_small_alpha_dagger( + next: &mut BipedSmallSkeleton, + s_a: &SkeletonAttr, + move1abs: f32, + move2abs: f32, +) { + next.head.orientation = Quaternion::rotation_x(move1abs * 0.15 + move2abs * -0.15) + * Quaternion::rotation_z(move1abs * 0.15 + move2abs * -0.3); + next.control_l.position = Vec3::new(2.0 - s_a.grip.0 * 2.0, 1.0, 3.0); + next.control_r.position = Vec3::new( + 9.0 + move1abs * -7.0 + s_a.grip.0 * 2.0, + -1.0 + move1abs * 6.0, + -2.0, + ); + + next.control.position = Vec3::new( + -5.0 + move1abs * 5.0 + move2abs * 9.0, + -1.0 + move2abs * -3.0 + s_a.grip.2, + -1.0 + move1abs * 3.0 + -s_a.grip.2 / 2.5 + s_a.grip.0 * -2.0, + ); + + next.control_l.orientation = Quaternion::rotation_x(PI / 2.0) + * Quaternion::rotation_y(-0.0) + * Quaternion::rotation_z(-0.0); + next.control_r.orientation = Quaternion::rotation_x(0.5 + move1abs * 1.5 + s_a.grip.0 * 0.2) + * Quaternion::rotation_y(0.2 + s_a.grip.0 * 0.2) + * Quaternion::rotation_z(-0.0); + + next.control.orientation = Quaternion::rotation_x(-0.3 + move2abs * -1.0) + * Quaternion::rotation_y(move1abs * -0.4 + move2abs * 1.0) + * Quaternion::rotation_z(-0.3 + move2abs * -2.2); +} diff --git a/voxygen/anim/src/character/mod.rs b/voxygen/anim/src/character/mod.rs index 0c14bfc1a2..661b6e97c4 100644 --- a/voxygen/anim/src/character/mod.rs +++ b/voxygen/anim/src/character/mod.rs @@ -28,11 +28,13 @@ pub mod selfbuff; pub mod shockwave; pub mod shoot; pub mod sit; +pub mod sleep; pub mod sneak; pub mod sneakequip; pub mod sneakwield; pub mod staggered; pub mod stand; +pub mod steer; pub mod stunned; pub mod swim; pub mod swimwield; @@ -51,11 +53,11 @@ pub use self::{ mount::MountAnimation, music::MusicAnimation, rapidmelee::RapidMeleeAnimation, repeater::RepeaterAnimation, ripostemelee::RiposteMeleeAnimation, roll::RollAnimation, run::RunAnimation, selfbuff::SelfBuffAnimation, shockwave::ShockwaveAnimation, - shoot::ShootAnimation, sit::SitAnimation, sneak::SneakAnimation, + shoot::ShootAnimation, sit::SitAnimation, sleep::SleepAnimation, sneak::SneakAnimation, sneakequip::SneakEquipAnimation, sneakwield::SneakWieldAnimation, - staggered::StaggeredAnimation, stand::StandAnimation, stunned::StunnedAnimation, - swim::SwimAnimation, swimwield::SwimWieldAnimation, talk::TalkAnimation, - wallrun::WallrunAnimation, wield::WieldAnimation, + staggered::StaggeredAnimation, stand::StandAnimation, steer::SteerAnimation, + stunned::StunnedAnimation, swim::SwimAnimation, swimwield::SwimWieldAnimation, + talk::TalkAnimation, wallrun::WallrunAnimation, wield::WieldAnimation, }; use super::{make_bone, vek::*, FigureBoneData, Offsets, Skeleton, TrailSource}; use common::comp::{ @@ -431,8 +433,8 @@ impl CharacterSkeleton { * ((acc_vel * lab * 1.6).sin()); self.lantern.position = Vec3::new(s_a.lantern.0, s_a.lantern.1, s_a.lantern.2); - self.lantern.orientation = - Quaternion::rotation_x(shorte * 0.7 + 0.4) * Quaternion::rotation_y(shorte * 0.4); + self.lantern.orientation = Quaternion::rotation_x(shorte * 0.7 * speednorm.powi(2) + 0.4) + * Quaternion::rotation_y(shorte * 0.4 * speednorm.powi(2)); self.lantern.scale = Vec3::one() * 0.65; self.hold.scale = Vec3::one() * 0.0; diff --git a/voxygen/anim/src/character/run.rs b/voxygen/anim/src/character/run.rs index acd671cd97..a77c5cd096 100644 --- a/voxygen/anim/src/character/run.rs +++ b/voxygen/anim/src/character/run.rs @@ -152,7 +152,7 @@ impl Animation for RunAnimation { next.back.position = Vec3::new(0.0, s_a.back.0, s_a.back.1); next.back.orientation = Quaternion::rotation_x(-0.05 + short * 0.02 + noisea * 0.02 + noiseb * 0.02) - * Quaternion::rotation_y(foothorir * 0.2); + * Quaternion::rotation_y(foothorir * 0.35 * speednorm.powi(2)); next.shorts.position = Vec3::new(0.0, 0.65 + s_a.shorts.0, 0.65 * speednorm + s_a.shorts.1); next.shorts.orientation = Quaternion::rotation_x(0.2 * speednorm) @@ -163,22 +163,24 @@ impl Animation for RunAnimation { -s_a.hand.0 * 1.2 - foothorir * 1.3 * speednorm + (foothoril.abs().powi(2) - 0.5) * speednorm * 4.0, s_a.hand.1 * 1.3 + foothorir * -7.0 * speednorm.powi(2) * (1.0 - sideabs), - s_a.hand.2 - foothorir * 2.75 * speednorm + foothoril.abs().powi(3) * speednorm * 8.0, + s_a.hand.2 - foothorir * 2.75 * speednorm + + foothoril.abs().powi(3) * speednorm.powi(2) * 8.0, ); next.hand_l.orientation = Quaternion::rotation_x( - 0.6 * speednorm + (footrotr * -1.5 + 0.5) * speednorm * (1.0 - sideabs), + 0.6 * speednorm + (footrotr * -1.5 + 0.5) * speednorm.powi(2) * (1.0 - sideabs), ) * Quaternion::rotation_y(footrotr * 0.4 * speednorm + PI * 0.07); next.hand_r.position = Vec3::new( s_a.hand.0 * 1.2 + foothoril * 1.3 * speednorm - (foothorir.abs().powi(2) - 0.5) * speednorm * 4.0, s_a.hand.1 * 1.3 + foothoril * -7.0 * speednorm.powi(2) * (1.0 - sideabs), - s_a.hand.2 - foothoril * 2.75 * speednorm + foothorir.abs().powi(3) * speednorm * 8.0, + s_a.hand.2 - foothoril * 2.75 * speednorm + + foothorir.abs().powi(3) * speednorm.powi(2) * 8.0, ); next.hand_r.orientation = Quaternion::rotation_x( - 0.6 * speednorm + (footrotl * -1.5 + 0.5) * speednorm * (1.0 - sideabs), + 0.6 * speednorm + (footrotl * -1.5 + 0.5) * speednorm.powi(2) * (1.0 - sideabs), ) * Quaternion::rotation_y(footrotl * -0.4 * speednorm - PI * 0.07); next.foot_l.position = Vec3::new( diff --git a/voxygen/anim/src/character/sleep.rs b/voxygen/anim/src/character/sleep.rs new file mode 100644 index 0000000000..abeaa6ba96 --- /dev/null +++ b/voxygen/anim/src/character/sleep.rs @@ -0,0 +1,114 @@ +use super::{ + super::{vek::*, Animation}, + CharacterSkeleton, SkeletonAttr, +}; +use common::comp::item::ToolKind; +use std::{f32::consts::PI, ops::Mul}; + +pub struct SleepAnimation; + +impl Animation for SleepAnimation { + type Dependency<'a> = (Option, Option, f32); + type Skeleton = CharacterSkeleton; + + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"character_sleep\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "character_sleep")] + fn update_skeleton_inner( + skeleton: &Self::Skeleton, + (_active_tool_kind, _second_tool_kind, global_time): Self::Dependency<'_>, + anim_time: f32, + _rate: &mut f32, + s_a: &SkeletonAttr, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + let slow = (anim_time * 1.0).sin(); + let slowa = (anim_time * 1.0 + PI / 2.0).sin(); + let stop = (anim_time * 3.0).min(PI / 2.0).sin(); + + let head_look = Vec2::new( + (global_time * 0.05 + anim_time / 15.0) + .floor() + .mul(7331.0) + .sin() + * 0.25, + (global_time * 0.05 + anim_time / 15.0) + .floor() + .mul(1337.0) + .sin() + * 0.125, + ); + next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1 + slow * 0.1 + stop * -0.8); + next.head.orientation = Quaternion::rotation_z(head_look.x + slow * 0.2 - slow * 0.1) + * Quaternion::rotation_x((slowa * -0.1 + slow * 0.1 + head_look.y).abs()); + + next.chest.position = Vec3::new( + 0.0, + s_a.chest.0 + stop * -0.4, + s_a.chest.1 + slow * 0.1 + stop * -0.8, + ); + next.chest.orientation = Quaternion::rotation_x(stop * 0.15 + 1.0); + + next.belt.position = Vec3::new(0.0, s_a.belt.0 + stop * 1.2, s_a.belt.1); + next.belt.orientation = Quaternion::rotation_x(stop * 0.3); + + next.back.position = Vec3::new(0.0, s_a.back.0, s_a.back.1); + + next.shorts.position = Vec3::new(0.0, s_a.shorts.0 + stop * 2.5, s_a.shorts.1 + stop * 0.6); + next.shorts.orientation = Quaternion::rotation_x(stop * 0.6); + + next.hand_l.position = Vec3::new( + -s_a.hand.0 - 1.0, + s_a.hand.1 + slowa * 0.15 + 2.0, + s_a.hand.2 + slow * 0.7 + stop * -2.0, + ); + next.hand_l.orientation = + Quaternion::rotation_x(slowa * -0.1 + slow * 0.1) * Quaternion::rotation_y(PI * 0.15); + + next.hand_r.position = Vec3::new( + s_a.hand.0 + 1.0, + s_a.hand.1 + slowa * 0.15 + 2.0, + s_a.hand.2 + slow * 0.7 + stop * -2.0, + ); + next.hand_r.orientation = + Quaternion::rotation_x(slow * -0.1 + slowa * 0.1) * Quaternion::rotation_y(PI * -0.15); + + next.foot_l.position = Vec3::new(-s_a.foot.0, 6.0 + s_a.foot.1, 6.0 + s_a.foot.2); + next.foot_l.orientation = Quaternion::rotation_x(slow * 0.1 + stop * 1.2 + slow * 0.1); + + next.foot_r.position = Vec3::new(s_a.foot.0, 6.0 + s_a.foot.1, 6.0 + s_a.foot.2); + next.foot_r.orientation = Quaternion::rotation_x(slowa * 0.1 + stop * 1.2 + slowa * 0.1); + + next.shoulder_l.position = Vec3::new(-s_a.shoulder.0, s_a.shoulder.1, s_a.shoulder.2); + next.shoulder_l.orientation = Quaternion::rotation_x(0.0); + + next.shoulder_r.position = Vec3::new(s_a.shoulder.0, s_a.shoulder.1, s_a.shoulder.2); + next.shoulder_r.orientation = Quaternion::rotation_x(0.0); + + next.torso.position = Vec3::new(0.0, -2.2, stop * -1.76); + + if skeleton.holding_lantern { + next.hand_r.position = Vec3::new( + s_a.hand.0 + 1.0 - head_look.x * 8.0, + s_a.hand.1 + 5.0 + head_look.x * 6.0, + s_a.hand.2 + 9.0 + head_look.y * 6.0, + ); + next.hand_r.orientation = Quaternion::rotation_x(2.25) + * Quaternion::rotation_z(0.9) + * Quaternion::rotation_y(head_look.x * 3.0) + * Quaternion::rotation_x(head_look.y * 3.0); + + let fast = (anim_time * 5.0).sin(); + let fast2 = (anim_time * 4.5 + 8.0).sin(); + + next.lantern.position = Vec3::new(-0.5, -0.5, -2.5); + next.lantern.orientation = next.hand_r.orientation.inverse() + * Quaternion::rotation_x(fast * 0.1) + * Quaternion::rotation_y(fast2 * 0.1); + } + + next + } +} diff --git a/voxygen/anim/src/character/steer.rs b/voxygen/anim/src/character/steer.rs new file mode 100644 index 0000000000..f1d270ef1f --- /dev/null +++ b/voxygen/anim/src/character/steer.rs @@ -0,0 +1,118 @@ +use super::{ + super::{vek::*, Animation}, + CharacterSkeleton, SkeletonAttr, +}; +use common::comp::item::ToolKind; +use std::{f32::consts::PI, ops::Mul}; + +pub struct SteerAnimation; + +impl Animation for SteerAnimation { + type Dependency<'a> = (Option, Option, f32, f32); + type Skeleton = CharacterSkeleton; + + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"character_steer\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "character_steer")] + fn update_skeleton_inner( + skeleton: &Self::Skeleton, + (_active_tool_kind, _second_tool_kind, steer_dir, global_time): Self::Dependency<'_>, + anim_time: f32, + _rate: &mut f32, + s_a: &SkeletonAttr, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + let slow = (anim_time * 1.0).sin(); + let head_look = Vec2::new( + (global_time + anim_time / 12.0).floor().mul(7331.0).sin() * 0.1, + (global_time + anim_time / 12.0).floor().mul(1337.0).sin() * 0.05, + ); + next.head.scale = Vec3::one() * s_a.head_scale; + next.chest.scale = Vec3::one() * 1.01; + next.hand_l.scale = Vec3::one() * 1.04; + next.hand_r.scale = Vec3::one() * 1.04; + next.back.scale = Vec3::one() * 1.02; + next.hold.scale = Vec3::one() * 0.0; + next.lantern.scale = Vec3::one() * 0.65; + next.shoulder_l.scale = Vec3::one() * 1.1; + next.shoulder_r.scale = Vec3::one() * 1.1; + + next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1 + slow * 0.3); + next.head.orientation = + Quaternion::rotation_z(head_look.x) * Quaternion::rotation_x(head_look.y.abs()); + + next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1 + slow * 0.3); + next.chest.orientation = Quaternion::rotation_z(head_look.x * 0.06); + + next.belt.position = Vec3::new(0.0, s_a.belt.0, s_a.belt.1); + next.belt.orientation = Quaternion::rotation_z(head_look.x * -0.1); + + next.back.position = Vec3::new(0.0, s_a.back.0, s_a.back.1); + + next.shorts.position = Vec3::new(0.0, s_a.shorts.0, s_a.shorts.1); + next.shorts.orientation = Quaternion::rotation_z(head_look.x * -0.2); + + next.hand_l.position = Vec3::new( + -s_a.hand.0, + s_a.hand.1 + slow * 0.15, + s_a.hand.2 + slow * 0.5, + ); + + let helm_center = Vec3::new(0.0, 0.6, 0.75) / s_a.scaler * 11.0; + + let rot = steer_dir * 0.5; + + let hand_rotation = Quaternion::rotation_y(rot) * Quaternion::rotation_x(PI / 2.0); + + let hand_offset = Vec3::new(rot.cos(), 0.0, -rot.sin()) * 0.4 / s_a.scaler * 11.0; + + next.hand_l.position = helm_center - hand_offset; + next.hand_r.position = helm_center + hand_offset; + + let ori_l = Quaternion::rotation_x( + PI / 2.0 + (next.hand_l.position.z / next.hand_l.position.x).atan(), + ); + let ori_r = Quaternion::rotation_x( + PI / 2.0 - (next.hand_r.position.z / next.hand_r.position.x).atan(), + ); + + next.hand_l.orientation = hand_rotation * ori_l; + next.hand_r.orientation = -hand_rotation * ori_r; + + next.shoulder_l.position = Vec3::new(-s_a.shoulder.0, s_a.shoulder.1, s_a.shoulder.2); + next.shoulder_l.orientation = ori_r; + next.shoulder_r.position = Vec3::new(s_a.shoulder.0, s_a.shoulder.1, s_a.shoulder.2); + next.shoulder_r.orientation = ori_l; + + next.foot_l.position = Vec3::new(-s_a.foot.0, s_a.foot.1, s_a.foot.2); + next.foot_l.orientation = Quaternion::identity(); + + next.foot_r.position = Vec3::new(s_a.foot.0, s_a.foot.1, s_a.foot.2); + next.foot_r.orientation = Quaternion::identity(); + + next.glider.position = Vec3::new(0.0, 0.0, 10.0); + next.glider.scale = Vec3::one() * 0.0; + next.hold.position = Vec3::new(0.4, -0.3, -5.8); + + if skeleton.holding_lantern { + next.hand_r.position = Vec3::new( + s_a.hand.0 - head_look.x * 6.0, + s_a.hand.1 + 5.0 - head_look.y * 10.0 + slow * 0.15, + s_a.hand.2 + 12.0 + head_look.y * 6.0 + slow * 0.5, + ); + next.hand_r.orientation = Quaternion::rotation_x(2.25 + slow * -0.06) + * Quaternion::rotation_z(0.9) + * Quaternion::rotation_y(head_look.x * 1.5) + * Quaternion::rotation_x(head_look.y * 1.5); + + next.lantern.position = Vec3::new(-0.5, -0.5, -2.5); + next.lantern.orientation = next.hand_r.orientation.inverse(); + } + + next.torso.position = Vec3::new(0.0, 0.0, 0.0); + + next + } +} diff --git a/voxygen/anim/src/crustacean/alpha.rs b/voxygen/anim/src/crustacean/alpha.rs new file mode 100644 index 0000000000..a176939bc7 --- /dev/null +++ b/voxygen/anim/src/crustacean/alpha.rs @@ -0,0 +1,56 @@ +use super::{ + super::{vek::*, Animation}, + CrustaceanSkeleton, SkeletonAttr, +}; +use common::states::utils::StageSection; + +pub struct AlphaAnimation; + +impl Animation for AlphaAnimation { + type Dependency<'a> = (f32, f32, Option, f32); + type Skeleton = CrustaceanSkeleton; + + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"crustacean_alpha\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "crustacean_alpha")] + fn update_skeleton_inner( + skeleton: &Self::Skeleton, + (_velocity, global_time, stage_section, timer): Self::Dependency<'_>, + anim_time: f32, + _rate: &mut f32, + s_a: &SkeletonAttr, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + let (movement1, movement2, movement3) = match stage_section { + Some(StageSection::Buildup) => (anim_time.powi(2), 0.0, 0.0), + Some(StageSection::Action) => (1.0, anim_time.powi(4), 0.0), + Some(StageSection::Recover) => (1.0, 1.0, anim_time), + _ => (0.0, 0.0, 0.0), + }; + let pullback = 1.0 - movement3; + let subtract = global_time - timer; + let check = subtract - subtract.trunc(); + let _mirror = (check - 0.5).signum(); + let _movement1abs = movement1 * pullback; + let _movement2abs = movement2 * pullback; + let _movement3abs = movement3 * pullback; + + next.arm_l.orientation = Quaternion::rotation_x(anim_time); + + next.chest.scale = Vec3::one() * s_a.scaler; + + next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1); + + next.leg_fl.position = Vec3::new(-s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2); + next.leg_fr.position = Vec3::new(s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2); + + next.leg_cl.position = Vec3::new(-s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2); + next.leg_cr.position = Vec3::new(s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2); + + next.leg_bl.position = Vec3::new(-s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2); + next.leg_br.position = Vec3::new(s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2); + next + } +} diff --git a/voxygen/anim/src/crustacean/combomelee.rs b/voxygen/anim/src/crustacean/combomelee.rs new file mode 100644 index 0000000000..4062ec32fe --- /dev/null +++ b/voxygen/anim/src/crustacean/combomelee.rs @@ -0,0 +1,93 @@ +use super::{ + super::{vek::*, Animation}, + CrustaceanSkeleton, SkeletonAttr, +}; +use common::states::utils::{AbilityInfo, StageSection}; + +pub struct ComboAnimation; +impl Animation for ComboAnimation { + type Dependency<'a> = ( + Option<&'a str>, + Option, + Option, + usize, + f32, + Vec3, + f32, + ); + type Skeleton = CrustaceanSkeleton; + + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"crustacean_combo\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "crustacean_combo")] + fn update_skeleton_inner( + skeleton: &Self::Skeleton, + (ability_id, stage_section, _ability_info, current_strike, global_time, velocity, timer): Self::Dependency<'_>, + anim_time: f32, + rate: &mut f32, + _s_a: &SkeletonAttr, + ) -> Self::Skeleton { + *rate = 1.0; + let mut next = (*skeleton).clone(); + + let multi_strike_pullback = 1.0 + - if matches!(stage_section, Some(StageSection::Recover)) { + anim_time.powi(4) + } else { + 0.0 + }; + for strike in 0..=current_strike { + match ability_id { + Some("common.abilities.custom.crab.triplestrike") => { + let (movement1base, movement2base, movement3) = match stage_section { + Some(StageSection::Buildup) => (anim_time.sqrt(), 0.0, 0.0), + Some(StageSection::Action) => (1.0, anim_time.powi(4), 0.0), + Some(StageSection::Recover) => (1.0, 1.0, anim_time), + _ => (0.0, 0.0, 0.0), + }; + let pullback = multi_strike_pullback; + let subtract = global_time - timer; + let check = subtract - subtract.trunc(); + let mirror = (check - 0.5).signum(); + let twitch3 = (mirror * movement3 * 9.0).sin(); + let _movement1 = mirror * movement1base * pullback; + let _movement2 = mirror * movement2base * pullback; + let movement1abs = movement1base * pullback; + let movement2abs = movement2base * pullback; + let mirror_var = if strike == 1 { -mirror } else { mirror }; + if velocity.xy().magnitude() > 0.1 { + next.chest.orientation = Quaternion::rotation_z(0.0); + } + + next.chest.orientation = Quaternion::rotation_x( + movement1abs * 0.3 + movement2abs * -0.2 + (twitch3 / 5.0), + ); + next.arm_r.orientation = + Quaternion::rotation_z(movement1abs * -0.8 + movement2abs * 1.0) + * Quaternion::rotation_x(movement1abs * 0.4 + movement2abs * 0.3); + next.arm_r.position = Vec3::new( + 0.0, + 7.0 * movement1abs - 3.0 * movement2abs, + -0.8 * mirror_var, + ); + next.pincer_r1.position = + Vec3::new(0.0, -3.0 * movement1abs + 4.0 * movement2abs, 0.0); + + next.arm_l.orientation = + Quaternion::rotation_z(movement1abs * 0.8 + movement2abs * -1.0) + * Quaternion::rotation_x(movement1abs * 0.4 + movement2abs * 0.3); + next.arm_l.position = Vec3::new( + 0.0, + 7.0 * movement1abs - 3.0 * movement2abs, + 0.8 * mirror_var, + ); + next.pincer_l1.position = + Vec3::new(0.0, -3.0 * movement1abs + 4.0 * movement2abs, 0.0); + }, + _ => {}, + } + } + next + } +} diff --git a/voxygen/anim/src/crustacean/idle.rs b/voxygen/anim/src/crustacean/idle.rs new file mode 100644 index 0000000000..98f7a0c34e --- /dev/null +++ b/voxygen/anim/src/crustacean/idle.rs @@ -0,0 +1,65 @@ +use super::{ + super::{vek::*, Animation}, + CrustaceanSkeleton, SkeletonAttr, +}; + +pub struct IdleAnimation; + +impl Animation for IdleAnimation { + type Dependency<'a> = f32; + type Skeleton = CrustaceanSkeleton; + + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"crustacean_idle\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "crustacean_idle")] + fn update_skeleton_inner( + skeleton: &Self::Skeleton, + _global_time: Self::Dependency<'_>, + anim_time: f32, + _rate: &mut f32, + s_a: &SkeletonAttr, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + next.chest.scale = Vec3::one() * s_a.scaler; + + next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1); + + let arm = (anim_time * 0.2).sin() * 0.03; + let clasp_l = + (((anim_time * 0.1).fract() * 2.0 - 1.0) * (anim_time * 2.0).sin().powi(2)).powi(16); + let clasp_r = (((anim_time * 0.105 + 33.0).fract() * 2.0 - 1.0) + * (anim_time * 1.95 + 20.0).sin().powi(2)) + .powi(16); + + next.arm_l.position = Vec3::zero(); + next.arm_l.orientation = Quaternion::rotation_x(arm); + next.arm_r.position = Vec3::zero(); + next.arm_r.orientation = Quaternion::rotation_x(arm); + + next.pincer_l0.position = Vec3::zero(); + next.pincer_l1.position = Vec3::zero(); + next.pincer_l1.orientation = Quaternion::rotation_z(clasp_l * 0.15); + next.pincer_r0.position = Vec3::zero(); + next.pincer_r1.position = Vec3::zero(); + next.pincer_r1.orientation = Quaternion::rotation_z(-clasp_r * 0.15); + + next.leg_fl.position = Vec3::new(-s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2); + next.leg_fr.position = Vec3::new(s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2); + next.leg_fl.orientation = Quaternion::rotation_z(s_a.leg_ori.0); + next.leg_fr.orientation = Quaternion::rotation_z(-s_a.leg_ori.0); + + next.leg_cl.position = Vec3::new(-s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2); + next.leg_cr.position = Vec3::new(s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2); + next.leg_cl.orientation = Quaternion::rotation_z(s_a.leg_ori.1); + next.leg_cr.orientation = Quaternion::rotation_z(-s_a.leg_ori.1); + + next.leg_bl.position = Vec3::new(-s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2); + next.leg_br.position = Vec3::new(s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2); + next.leg_bl.orientation = Quaternion::rotation_z(s_a.leg_ori.2); + next.leg_br.orientation = Quaternion::rotation_z(-s_a.leg_ori.2); + + next + } +} diff --git a/voxygen/anim/src/crustacean/jump.rs b/voxygen/anim/src/crustacean/jump.rs new file mode 100644 index 0000000000..6a9027a68c --- /dev/null +++ b/voxygen/anim/src/crustacean/jump.rs @@ -0,0 +1,54 @@ +use super::{ + super::{vek::*, Animation}, + CrustaceanSkeleton, SkeletonAttr, +}; + +pub struct JumpAnimation; + +impl Animation for JumpAnimation { + type Dependency<'a> = (f32, Vec3, Vec3, f32, Vec3); + type Skeleton = CrustaceanSkeleton; + + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"crustacean_jump\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "crustacean_jump")] + fn update_skeleton_inner( + skeleton: &Self::Skeleton, + (_velocity, _orientation, _last_ori, _global_time, _avg_vel): Self::Dependency<'_>, + _anim_time: f32, + _rate: &mut f32, + s_a: &SkeletonAttr, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + next.chest.scale = Vec3::one() * s_a.scaler; + + next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1); + + let up_rot = 0.2; + + next.leg_fl.position = Vec3::new(-s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2); + next.leg_fr.position = Vec3::new(s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2); + next.leg_fl.orientation = + Quaternion::rotation_z(s_a.leg_ori.0) * Quaternion::rotation_y(up_rot); + next.leg_fr.orientation = + Quaternion::rotation_z(-s_a.leg_ori.0) * Quaternion::rotation_y(-up_rot); + + next.leg_cl.position = Vec3::new(-s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2); + next.leg_cr.position = Vec3::new(s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2); + next.leg_cl.orientation = + Quaternion::rotation_z(s_a.leg_ori.1) * Quaternion::rotation_y(up_rot); + next.leg_cr.orientation = + Quaternion::rotation_z(-s_a.leg_ori.1) * Quaternion::rotation_y(-up_rot); + + next.leg_bl.position = Vec3::new(-s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2); + next.leg_br.position = Vec3::new(s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2); + next.leg_bl.orientation = + Quaternion::rotation_z(s_a.leg_ori.2) * Quaternion::rotation_y(up_rot); + next.leg_br.orientation = + Quaternion::rotation_z(-s_a.leg_ori.2) * Quaternion::rotation_y(-up_rot); + + next + } +} diff --git a/voxygen/anim/src/crustacean/mod.rs b/voxygen/anim/src/crustacean/mod.rs new file mode 100644 index 0000000000..6e3cb93323 --- /dev/null +++ b/voxygen/anim/src/crustacean/mod.rs @@ -0,0 +1,143 @@ +mod alpha; +mod combomelee; +mod idle; +mod jump; +mod run; +mod stunned; +mod swim; + +// Reexports +pub use self::{ + alpha::AlphaAnimation, combomelee::ComboAnimation, idle::IdleAnimation, jump::JumpAnimation, + run::RunAnimation, stunned::StunnedAnimation, swim::SwimAnimation, +}; + +use common::comp::{self}; + +use super::{make_bone, vek::*, FigureBoneData, Offsets, Skeleton}; + +pub type Body = comp::crustacean::Body; + +skeleton_impls!(struct CrustaceanSkeleton { + + chest, + + tail_f, + + tail_b, + + arm_l, + + pincer_l0, + + pincer_l1, + + arm_r, + + pincer_r0, + + pincer_r1, + + leg_fl, + + leg_cl, + + leg_bl, + + leg_fr, + + leg_cr, + + leg_br, +}); + +impl Skeleton for CrustaceanSkeleton { + type Attr = SkeletonAttr; + type Body = Body; + + const BONE_COUNT: usize = 15; + #[cfg(feature = "use-dyn-lib")] + const COMPUTE_FN: &'static [u8] = b"crustacean_compute_s\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "crustacean_compute_s")] + + fn compute_matrices_inner( + &self, + base_mat: Mat4, + buf: &mut [FigureBoneData; super::MAX_BONE_COUNT], + body: Self::Body, + ) -> Offsets { + let base_mat = base_mat * Mat4::scaling_3d(SkeletonAttr::from(&body).scaler / 6.0); + + let chest_mat = base_mat * Mat4::::from(self.chest); + let tail_f_mat = chest_mat * Mat4::::from(self.tail_f); + let tail_b_mat = chest_mat * Mat4::::from(self.tail_b); + let arm_l_mat = chest_mat * Mat4::::from(self.arm_l); + let pincer_l0_mat = arm_l_mat * Mat4::::from(self.pincer_l0); + let pincer_l1_mat = pincer_l0_mat * Mat4::::from(self.pincer_l1); + let arm_r_mat = chest_mat * Mat4::::from(self.arm_r); + let pincer_r0_mat = arm_r_mat * Mat4::::from(self.pincer_r0); + let pincer_r1_mat = pincer_r0_mat * Mat4::::from(self.pincer_r1); + let leg_fl_mat = chest_mat * Mat4::::from(self.leg_fl); + let leg_cl_mat = chest_mat * Mat4::::from(self.leg_cl); + let leg_bl_mat = chest_mat * Mat4::::from(self.leg_bl); + let leg_fr_mat = chest_mat * Mat4::::from(self.leg_fr); + let leg_cr_mat = chest_mat * Mat4::::from(self.leg_cr); + let leg_br_mat = chest_mat * Mat4::::from(self.leg_br); + + *(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [ + make_bone(chest_mat), + make_bone(tail_f_mat), + make_bone(tail_b_mat), + make_bone(arm_l_mat), + make_bone(pincer_l0_mat), + make_bone(pincer_l1_mat), + make_bone(arm_r_mat), + make_bone(pincer_r0_mat), + make_bone(pincer_r1_mat), + make_bone(leg_fl_mat), + make_bone(leg_cl_mat), + make_bone(leg_bl_mat), + make_bone(leg_fr_mat), + make_bone(leg_cr_mat), + make_bone(leg_br_mat), + ]; + + // TODO: mount points + //use comp::arthropod::Species::*; + let (mount_bone_mat, mount_bone_ori) = (chest_mat, self.chest.orientation); + // Offset from the mounted bone's origin. + // Note: This could be its own bone if we need to animate it independently. + let mount_position = (mount_bone_mat * Vec4::from_point(mount_point(&body))) + .homogenized() + .xyz(); + // NOTE: We apply the ori from base_mat externally so we don't need to worry + // about it here for now. + let mount_orientation = mount_bone_ori; + + Offsets { + lantern: None, + viewpoint: Some((chest_mat * Vec4::new(0.0, 7.0, 0.0, 1.0)).xyz()), + mount_bone: Transform { + position: mount_position, + orientation: mount_orientation, + scale: Vec3::one(), + }, + primary_trail_mat: None, + secondary_trail_mat: None, + } + } +} + +pub struct SkeletonAttr { + chest: (f32, f32), + leg_f: (f32, f32, f32), + leg_c: (f32, f32, f32), + leg_b: (f32, f32, f32), + leg_ori: (f32, f32, f32), + scaler: f32, +} + +impl From<&Body> for SkeletonAttr { + fn from(_value: &Body) -> Self { + Self { + chest: (0.0, 0.0), + leg_f: (0.0, 0.0, 0.0), + leg_c: (0.0, 0.0, 0.0), + leg_b: (0.0, 0.0, 0.0), + leg_ori: (-0.4, 0.0, 0.4), + scaler: 0.62, + } + } +} + +fn mount_point(_body: &Body) -> Vec3 { + // TODO: mount points + //use comp::arthropod::{BodyType::*, Species::*}; + (0.0, -6.0, 6.0).into() +} diff --git a/voxygen/anim/src/crustacean/run.rs b/voxygen/anim/src/crustacean/run.rs new file mode 100644 index 0000000000..caabbbec4f --- /dev/null +++ b/voxygen/anim/src/crustacean/run.rs @@ -0,0 +1,100 @@ +use super::{ + super::{vek::*, Animation}, + CrustaceanSkeleton, SkeletonAttr, +}; +use std::f32::consts::PI; + +pub struct RunAnimation; + +impl Animation for RunAnimation { + type Dependency<'a> = (Vec3, Vec3, Vec3, f32, Vec3, f32); + type Skeleton = CrustaceanSkeleton; + + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"crustacean_run\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "crustacean_run")] + fn update_skeleton_inner( + skeleton: &Self::Skeleton, + (velocity, orientation, _last_ori, _global_time, avg_vel, acc_vel): Self::Dependency<'_>, + anim_time: f32, + rate: &mut f32, + s_a: &SkeletonAttr, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + let speed = (Vec2::::from(velocity).magnitude()).min(22.0); + *rate = 1.0; + + let speednorm = speed / 13.0; + + let direction = velocity.y * 0.098 * orientation.y + velocity.x * 0.098 * orientation.x; + + let side = + (velocity.x * -0.098 * orientation.y + velocity.y * 0.098 * orientation.x) * -1.0; + let sideabs = side.abs(); + + let mixed_vel = (acc_vel + anim_time * 6.0) * 0.8; //sets run frequency using speed, with anim_time setting a floor + + //create a mix between a sine and a square wave + //(controllable with ratio variable) + let ratio = 0.1; + let wave1 = (mixed_vel).sin(); + let wave2 = (mixed_vel - PI / 2.0).sin(); + let wave3 = (mixed_vel + PI / 2.0).sin(); + let wave4 = (mixed_vel + PI).sin(); + let slow_wave = (mixed_vel / 20.0).sin(); + let foot1 = wave1.abs().powf(ratio) * wave1.signum(); + let foot2 = wave2.abs().powf(ratio) * wave2.signum(); + let foot3 = wave3.abs().powf(ratio) * wave3.signum(); + let foot4 = wave4.abs().powf(ratio) * wave4.signum(); + let turn = slow_wave.abs().powf(ratio) * slow_wave.signum(); + + let x_tilt = avg_vel.z.atan2(avg_vel.xy().magnitude()) * speednorm; + + next.chest.scale = Vec3::one() * s_a.scaler; + + let up_rot = 0.3; + let sideways = (PI / 2.0) * turn; + + next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1 + x_tilt); + next.chest.orientation = Quaternion::rotation_x((mixed_vel).sin().max(0.0) * 0.06 + x_tilt) + * Quaternion::rotation_z(sideways + ((mixed_vel + PI / 2.0).sin() * 0.06)); + + next.arm_l.orientation = Quaternion::rotation_x(1.0) + * Quaternion::rotation_y(foot4.max(sideabs * -0.5) * up_rot) + * Quaternion::rotation_z(0.3 - foot2 * 0.1 * direction); + next.arm_r.orientation = Quaternion::rotation_x(1.0) + * Quaternion::rotation_y(-foot1.max(sideabs * -0.5) * up_rot) + * Quaternion::rotation_z(-0.2 - foot3 * 0.1 * direction); + + next.arm_l.position = Vec3::new(0.0, 5.0, 0.0); + next.arm_r.position = Vec3::new(0.0, 5.0, 0.0); + + next.leg_fl.position = Vec3::new(-s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2); + next.leg_fr.position = Vec3::new(s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2); + next.leg_fl.orientation = Quaternion::rotation_y(foot4.max(sideabs * -0.5) * up_rot) + * Quaternion::rotation_z(s_a.leg_ori.0 + foot2 * 0.1 * direction); + next.leg_fr.orientation = Quaternion::rotation_y(-foot1.max(sideabs * -0.5) * up_rot) + * Quaternion::rotation_z(-s_a.leg_ori.0 - foot3 * 0.1 * direction); + + next.leg_cl.position = Vec3::new(-s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2); + next.leg_cr.position = Vec3::new(s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2); + next.leg_cl.orientation = Quaternion::rotation_x(foot4 * 0.1 * direction) + * Quaternion::rotation_y(foot1.max(sideabs * -0.5) * up_rot) + * Quaternion::rotation_z(s_a.leg_ori.1 + foot3 * 0.2 * direction); + next.leg_cr.orientation = Quaternion::rotation_x(foot1 * 0.1 * direction) + * Quaternion::rotation_y(foot1.min(sideabs * -0.5) * up_rot) + * Quaternion::rotation_z(-s_a.leg_ori.1 - foot2 * 0.2 * direction); + + next.leg_bl.position = Vec3::new(-s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2); + next.leg_br.position = Vec3::new(s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2); + next.leg_bl.orientation = Quaternion::rotation_x(foot4 * 0.2) + * Quaternion::rotation_y(foot4.max(sideabs * -0.5) * up_rot) + * Quaternion::rotation_z(s_a.leg_ori.2 + foot3 * 0.2 * -direction); + next.leg_br.orientation = Quaternion::rotation_x(foot1 * 0.2 * direction) + * Quaternion::rotation_y(foot4.min(sideabs * -0.5) * up_rot) + * Quaternion::rotation_z(-s_a.leg_ori.2 - foot2 * 0.2 * -direction); + + next + } +} diff --git a/voxygen/anim/src/crustacean/stunned.rs b/voxygen/anim/src/crustacean/stunned.rs new file mode 100644 index 0000000000..332d47b52c --- /dev/null +++ b/voxygen/anim/src/crustacean/stunned.rs @@ -0,0 +1,72 @@ +use super::{ + super::{vek::*, Animation}, + CrustaceanSkeleton, SkeletonAttr, +}; +use common::states::utils::StageSection; + +pub struct StunnedAnimation; + +impl Animation for StunnedAnimation { + type Dependency<'a> = (f32, f32, Option, f32); + type Skeleton = CrustaceanSkeleton; + + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"crustacean_stunned\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "crustacean_stunned")] + fn update_skeleton_inner( + skeleton: &Self::Skeleton, + (_velocity, global_time, stage_section, timer): Self::Dependency<'_>, + anim_time: f32, + _rate: &mut f32, + s_a: &SkeletonAttr, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + let (_movement1base, movement2, twitch) = match stage_section { + Some(StageSection::Buildup) => (anim_time.powf(0.1), 0.0, anim_time), + Some(StageSection::Recover) => (1.0, anim_time.powf(4.0), 1.0), + _ => (0.0, 0.0, 0.0), + }; + + let pullback = (1.0 - movement2) * 0.1; + + let subtract = global_time - timer; + let check = subtract - subtract.trunc(); + let mirror = (check - 0.5).signum(); + let twitch1 = mirror * (twitch * 5.0).cos() * pullback; + let twitch2 = mirror * (twitch * 5.0).sin() * pullback; + + next.chest.scale = Vec3::one() * s_a.scaler; + + next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1); + + next.arm_l.orientation = Quaternion::rotation_x(-twitch2 * 1.2); + next.arm_r.orientation = Quaternion::rotation_x(twitch2 * 1.2); + next.pincer_l1.orientation = Quaternion::rotation_z(0.17); + next.pincer_r1.orientation = Quaternion::rotation_z(-0.17); + + next.leg_fl.position = Vec3::new(-s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2); + next.leg_fr.position = Vec3::new(s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2); + next.leg_fl.orientation = + Quaternion::rotation_z(s_a.leg_ori.0) * Quaternion::rotation_x(twitch1 * 0.8 + 0.4); + next.leg_fr.orientation = + Quaternion::rotation_z(-s_a.leg_ori.0) * Quaternion::rotation_x(-twitch1 * 0.8 - 0.4); + + next.leg_cl.position = Vec3::new(-s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2); + next.leg_cr.position = Vec3::new(s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2); + next.leg_cl.orientation = + Quaternion::rotation_z(s_a.leg_ori.1) * Quaternion::rotation_y(twitch2 * 0.4 + 0.4); + next.leg_cr.orientation = + Quaternion::rotation_z(-s_a.leg_ori.1) * Quaternion::rotation_y(-twitch2 * 0.4 - 0.4); + + next.leg_bl.position = Vec3::new(-s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2); + next.leg_br.position = Vec3::new(s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2); + next.leg_bl.orientation = + Quaternion::rotation_z(s_a.leg_ori.2) * Quaternion::rotation_y(twitch2 * 0.4 + 0.4); + next.leg_br.orientation = + Quaternion::rotation_z(-s_a.leg_ori.2) * Quaternion::rotation_y(-twitch2 * 0.4 - 0.4); + + next + } +} diff --git a/voxygen/anim/src/crustacean/swim.rs b/voxygen/anim/src/crustacean/swim.rs new file mode 100644 index 0000000000..043a580c11 --- /dev/null +++ b/voxygen/anim/src/crustacean/swim.rs @@ -0,0 +1,99 @@ +use super::{ + super::{vek::*, Animation}, + CrustaceanSkeleton, SkeletonAttr, +}; +use std::f32::consts::PI; + +pub struct SwimAnimation; + +impl Animation for SwimAnimation { + type Dependency<'a> = (Vec3, Vec3, Vec3, f32, Vec3, f32); + type Skeleton = CrustaceanSkeleton; + + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"crustacean_swim\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "crustacean_swim")] + fn update_skeleton_inner( + skeleton: &Self::Skeleton, + (velocity, orientation, _last_ori, _global_time, avg_vel, acc_vel): Self::Dependency<'_>, + anim_time: f32, + rate: &mut f32, + s_a: &SkeletonAttr, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + let speed = (Vec2::::from(velocity).magnitude()).min(22.0); + *rate = 1.0; + + let speednorm = speed / 13.0; + + let direction = velocity.y * 0.098 * orientation.y + velocity.x * 0.098 * orientation.x; + + let side = + (velocity.x * -0.098 * orientation.y + velocity.y * 0.098 * orientation.x) * -1.0; + let sideabs = side.abs(); + + let mixed_vel = (acc_vel + anim_time * 6.0) * 0.8; //sets run frequency using speed, with anim_time setting a floor + + //create a mix between a sine and a square wave + //(controllable with ratio variable) + let ratio = 0.1; + let wave1 = (mixed_vel).sin(); + let wave2 = (mixed_vel - PI / 2.0).sin(); + let wave3 = (mixed_vel + PI / 2.0).sin(); + let wave4 = (mixed_vel + PI).sin(); + + let foot1 = wave1.abs().powf(ratio) * wave1.signum(); + let foot2 = wave2.abs().powf(ratio) * wave2.signum(); + let foot3 = wave3.abs().powf(ratio) * wave3.signum(); + let foot4 = wave4.abs().powf(ratio) * wave4.signum(); + + let x_tilt = avg_vel.z.atan2(avg_vel.xy().magnitude()) * speednorm; + + next.chest.scale = Vec3::one() * s_a.scaler; + + let up_rot = 0.3; + let turnaround = PI; + let swim = -0.3 * foot2; + + next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1 + x_tilt); + next.chest.orientation = Quaternion::rotation_x((mixed_vel).sin().max(0.0) * 0.06 + x_tilt) + * Quaternion::rotation_z(turnaround + ((mixed_vel + PI / 2.0).sin() * 0.06)); + + next.arm_l.orientation = Quaternion::rotation_x(0.1 * foot3) + * Quaternion::rotation_y(foot4.max(sideabs * -1.0) * up_rot) + * Quaternion::rotation_z((PI / -5.0) + 0.3 - foot2 * 0.1 * direction); + next.arm_r.orientation = Quaternion::rotation_x(0.1 * foot3) + * Quaternion::rotation_y(-foot1.max(sideabs * -1.0) * up_rot) + * Quaternion::rotation_z((PI / 5.0) + -0.2 - foot3 * 0.1 * direction); + + next.arm_l.position = Vec3::new(0.0, -1.0, 0.0); + next.arm_r.position = Vec3::new(0.0, -1.0, 0.0); + next.leg_fl.position = Vec3::new(-s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2 + 1.0); + next.leg_fr.position = Vec3::new(s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2 + 1.0); + next.leg_fl.orientation = Quaternion::rotation_y(foot4.max(sideabs * -0.5) * up_rot) + * Quaternion::rotation_z(swim + s_a.leg_ori.0 + foot2 * 0.1 * -direction); + next.leg_fr.orientation = Quaternion::rotation_y(-foot1.max(sideabs * -0.5) * up_rot) + * Quaternion::rotation_z(-swim + -s_a.leg_ori.0 - foot3 * 0.1 * -direction); + + next.leg_cl.position = Vec3::new(-s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2); + next.leg_cr.position = Vec3::new(s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2); + next.leg_cl.orientation = Quaternion::rotation_x(foot4 * 0.1 * -direction) + * Quaternion::rotation_y(foot1.max(sideabs * -0.5) * up_rot) + * Quaternion::rotation_z(swim + s_a.leg_ori.1 + foot3 * 0.2 * -direction); + next.leg_cr.orientation = Quaternion::rotation_x(foot1 * 0.1 * -direction) + * Quaternion::rotation_y(foot1.min(sideabs * -0.5) * up_rot) + * Quaternion::rotation_z(-swim + -s_a.leg_ori.1 - foot2 * 0.2 * -direction); + + next.leg_bl.position = Vec3::new(-s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2); + next.leg_br.position = Vec3::new(s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2); + next.leg_bl.orientation = Quaternion::rotation_x(foot4 * 0.2) + * Quaternion::rotation_y(foot4.max(sideabs * -0.5) * up_rot) + * Quaternion::rotation_z(swim + s_a.leg_ori.2 + foot3 * 0.2 * direction); + next.leg_br.orientation = Quaternion::rotation_x(foot1 * 0.2 * -direction) + * Quaternion::rotation_y(foot4.min(sideabs * -0.5) * up_rot) + * Quaternion::rotation_z(-swim + -s_a.leg_ori.2 - foot2 * 0.2 * direction); + + next + } +} diff --git a/voxygen/anim/src/golem/combomelee.rs b/voxygen/anim/src/golem/combomelee.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/voxygen/anim/src/lib.rs b/voxygen/anim/src/lib.rs index b3b11e9135..4e8285547c 100644 --- a/voxygen/anim/src/lib.rs +++ b/voxygen/anim/src/lib.rs @@ -53,6 +53,7 @@ pub mod biped_small; pub mod bird_large; pub mod bird_medium; pub mod character; +pub mod crustacean; pub mod dragon; pub mod fish_medium; pub mod fish_small; diff --git a/voxygen/anim/src/quadruped_low/alpha.rs b/voxygen/anim/src/quadruped_low/alpha.rs deleted file mode 100644 index 3633c95869..0000000000 --- a/voxygen/anim/src/quadruped_low/alpha.rs +++ /dev/null @@ -1,60 +0,0 @@ -use super::{ - super::{vek::*, Animation}, - QuadrupedLowSkeleton, SkeletonAttr, -}; -use common::states::utils::StageSection; -//use std::ops::Rem; - -pub struct AlphaAnimation; - -impl Animation for AlphaAnimation { - type Dependency<'a> = (f32, f32, Option, f32); - type Skeleton = QuadrupedLowSkeleton; - - #[cfg(feature = "use-dyn-lib")] - const UPDATE_FN: &'static [u8] = b"quadruped_low_alpha\0"; - - #[cfg_attr(feature = "be-dyn-lib", export_name = "quadruped_low_alpha")] - fn update_skeleton_inner( - skeleton: &Self::Skeleton, - (_velocity, global_time, stage_section, timer): Self::Dependency<'_>, - anim_time: f32, - _rate: &mut f32, - _s_a: &SkeletonAttr, - ) -> Self::Skeleton { - let mut next = (*skeleton).clone(); - - let (movement1base, movement2base, movement3) = match stage_section { - Some(StageSection::Buildup) => (anim_time.sqrt(), 0.0, 0.0), - Some(StageSection::Action) => (1.0, anim_time.powi(4), 0.0), - Some(StageSection::Recover) => (1.0, 1.0, anim_time), - _ => (0.0, 0.0, 0.0), - }; - let pullback = 1.0 - movement3; - let subtract = global_time - timer; - let check = subtract - subtract.trunc(); - let mirror = (check - 0.5).signum(); - let twitch3 = (mirror * movement3 * 9.0).sin(); - let movement1 = mirror * movement1base * pullback; - let movement2 = mirror * movement2base * pullback; - let movement1abs = movement1base * pullback; - let movement2abs = movement2base * pullback; - - next.head_upper.orientation = Quaternion::rotation_z(twitch3 * -0.7); - - next.head_lower.orientation = - Quaternion::rotation_x(movement1abs * 0.35 + movement2abs * -0.9) - * Quaternion::rotation_y(movement1 * 0.7 + movement2 * -1.0); - - next.jaw.orientation = Quaternion::rotation_x(movement1abs * -0.5 + movement2abs * 0.5); - next.chest.orientation = Quaternion::rotation_y(movement1 * -0.08 + movement2 * 0.15) - * Quaternion::rotation_z(movement1 * -0.2 + movement2 * 0.6); - - next.tail_front.orientation = Quaternion::rotation_x(0.15) - * Quaternion::rotation_z(movement1 * -0.4 + movement2 * -0.2); - - next.tail_rear.orientation = Quaternion::rotation_x(-0.12) - * Quaternion::rotation_z(movement1 * -0.4 + movement2 * -0.2); - next - } -} diff --git a/voxygen/anim/src/quadruped_low/beta.rs b/voxygen/anim/src/quadruped_low/beta.rs index 70dd80948c..287c252d0b 100644 --- a/voxygen/anim/src/quadruped_low/beta.rs +++ b/voxygen/anim/src/quadruped_low/beta.rs @@ -1,14 +1,11 @@ -use super::{ - super::{vek::*, Animation}, - QuadrupedLowSkeleton, SkeletonAttr, -}; +use super::{super::Animation, quadruped_low_beta, QuadrupedLowSkeleton, SkeletonAttr}; use common::states::utils::StageSection; //use std::ops::Rem; pub struct BetaAnimation; impl Animation for BetaAnimation { - type Dependency<'a> = (f32, f32, Option, f32); + type Dependency<'a> = (f32, f32, StageSection, f32); type Skeleton = QuadrupedLowSkeleton; #[cfg(feature = "use-dyn-lib")] @@ -20,41 +17,12 @@ impl Animation for BetaAnimation { (_velocity, global_time, stage_section, timer): Self::Dependency<'_>, anim_time: f32, _rate: &mut f32, - _s_a: &SkeletonAttr, + s_a: &SkeletonAttr, ) -> Self::Skeleton { let mut next = (*skeleton).clone(); - let (movement1base, movement2base, movement3) = match stage_section { - Some(StageSection::Buildup) => (anim_time.sqrt(), 0.0, 0.0), - Some(StageSection::Action) => (1.0, anim_time.powi(4), 0.0), - Some(StageSection::Recover) => (1.0, 1.0, anim_time), - _ => (0.0, 0.0, 0.0), - }; - let pullback = 1.0 - movement3; - let subtract = global_time - timer; - let check = subtract - subtract.trunc(); - let mirror = (check - 0.5).signum(); - let twitch3 = (mirror * movement3 * 9.0).sin(); - let movement1 = mirror * movement1base * pullback; - let movement2 = mirror * movement2base * pullback; - let movement1abs = movement1base * pullback; - let movement2abs = movement2base * pullback; + quadruped_low_beta(&mut next, s_a, stage_section, anim_time, global_time, timer); - next.head_upper.orientation = Quaternion::rotation_z(twitch3 * 0.2); - - next.head_lower.orientation = - Quaternion::rotation_x(movement1abs * 0.15 + movement2abs * -0.6) - * Quaternion::rotation_y(movement1 * -0.1 + movement2 * 0.15); - - next.jaw.orientation = Quaternion::rotation_x(movement1abs * -0.9 + movement2abs * 0.9); - next.chest.orientation = Quaternion::rotation_y(movement1 * 0.08 + movement2 * -0.15) - * Quaternion::rotation_z(movement1 * 0.2 + movement2 * -0.3); - - next.tail_front.orientation = Quaternion::rotation_x(0.15) - * Quaternion::rotation_z(movement1 * 0.4 + movement2 * 0.2); - - next.tail_rear.orientation = Quaternion::rotation_x(-0.12) - * Quaternion::rotation_z(movement1 * 0.4 + movement2 * 0.2); next } } diff --git a/voxygen/anim/src/quadruped_low/combomelee.rs b/voxygen/anim/src/quadruped_low/combomelee.rs index cc874bdea9..81dfd9b709 100644 --- a/voxygen/anim/src/quadruped_low/combomelee.rs +++ b/voxygen/anim/src/quadruped_low/combomelee.rs @@ -1,19 +1,12 @@ use super::{ super::{vek::*, Animation}, - QuadrupedLowSkeleton, SkeletonAttr, + quadruped_low_alpha, quadruped_low_beta, QuadrupedLowSkeleton, SkeletonAttr, }; -use common::states::utils::{AbilityInfo, StageSection}; +use common::states::utils::StageSection; pub struct ComboAnimation; impl Animation for ComboAnimation { - type Dependency<'a> = ( - Option<&'a str>, - Option, - Option, - usize, - f32, - f32, - ); + type Dependency<'a> = (Option<&'a str>, StageSection, usize, f32, f32); type Skeleton = QuadrupedLowSkeleton; #[cfg(feature = "use-dyn-lib")] @@ -22,16 +15,16 @@ impl Animation for ComboAnimation { #[cfg_attr(feature = "be-dyn-lib", export_name = "quadruped_low_combo")] fn update_skeleton_inner( skeleton: &Self::Skeleton, - (ability_id, stage_section, _ability_info, current_strike, global_time, timer): Self::Dependency<'_>, + (ability_id, stage_section, current_strike, global_time, timer): Self::Dependency<'_>, anim_time: f32, rate: &mut f32, - _s_a: &SkeletonAttr, + s_a: &SkeletonAttr, ) -> Self::Skeleton { *rate = 1.0; let mut next = (*skeleton).clone(); let _multi_strike_pullback = 1.0 - - if matches!(stage_section, Some(StageSection::Recover)) { + - if matches!(stage_section, StageSection::Recover) { anim_time.powi(4) } else { 0.0 @@ -45,9 +38,9 @@ impl Animation for ComboAnimation { | "common.abilities.custom.driggle.bite", ) => { let (movement1base, movement2base, movement3) = match stage_section { - Some(StageSection::Buildup) => (anim_time.sqrt(), 0.0, 0.0), - Some(StageSection::Action) => (1.0, anim_time.powi(4), 0.0), - Some(StageSection::Recover) => (1.0, 1.0, anim_time), + StageSection::Buildup => (anim_time.sqrt(), 0.0, 0.0), + StageSection::Action => (1.0, anim_time.powi(4), 0.0), + StageSection::Recover => (1.0, 1.0, anim_time), _ => (0.0, 0.0, 0.0), }; let pullback = 1.0 - movement3; @@ -102,6 +95,71 @@ impl Animation for ComboAnimation { _ => {}, } }, + Some( + "common.abilities.custom.asp.singlestrike" + | "comon.abilities.custom.maneater.singlestrike" + | "common.abilities.custom.quadlowbasic.singlestrike", + ) => { + quadruped_low_alpha( + &mut next, + s_a, + stage_section, + anim_time, + global_time, + timer, + ); + }, + Some( + "common.abilities.custom.basilisk.triplestrike" + | "common.abilities.custom.quadlowbasic.triplestrike" + | "common.abilities.custom.quadlowbreathe.triplestrike" + | "common.abilities.custom.quadlowtail.triplestrike", + ) => match strike { + 0 | 2 => { + quadruped_low_alpha( + &mut next, + s_a, + stage_section, + anim_time, + global_time, + timer, + ); + }, + 1 => { + quadruped_low_beta( + &mut next, + s_a, + stage_section, + anim_time, + global_time, + timer, + ); + }, + _ => {}, + }, + Some("common.abilities.custom.quadlowquick.quadstrike") => match strike { + 0 | 2 | 3 => { + quadruped_low_alpha( + &mut next, + s_a, + stage_section, + anim_time, + global_time, + timer, + ); + }, + 1 => { + quadruped_low_beta( + &mut next, + s_a, + stage_section, + anim_time, + global_time, + timer, + ); + }, + _ => {}, + }, _ => {}, } } diff --git a/voxygen/anim/src/quadruped_low/mod.rs b/voxygen/anim/src/quadruped_low/mod.rs index d301aa0655..2c309316b0 100644 --- a/voxygen/anim/src/quadruped_low/mod.rs +++ b/voxygen/anim/src/quadruped_low/mod.rs @@ -1,4 +1,3 @@ -pub mod alpha; pub mod beta; pub mod breathe; pub mod combomelee; @@ -14,14 +13,17 @@ pub mod tailwhip; // Reexports pub use self::{ - alpha::AlphaAnimation, beta::BetaAnimation, breathe::BreatheAnimation, - combomelee::ComboAnimation, dash::DashAnimation, idle::IdleAnimation, jump::JumpAnimation, - run::RunAnimation, shockwave::ShockwaveAnimation, shoot::ShootAnimation, - spritesummon::SpriteSummonAnimation, stunned::StunnedAnimation, tailwhip::TailwhipAnimation, + beta::BetaAnimation, breathe::BreatheAnimation, combomelee::ComboAnimation, + dash::DashAnimation, idle::IdleAnimation, jump::JumpAnimation, run::RunAnimation, + shockwave::ShockwaveAnimation, shoot::ShootAnimation, spritesummon::SpriteSummonAnimation, + stunned::StunnedAnimation, tailwhip::TailwhipAnimation, }; use super::{make_bone, vek::*, FigureBoneData, Offsets, Skeleton}; -use common::comp::{self}; +use common::{ + comp::{self}, + states::utils::StageSection, +}; use core::convert::TryFrom; pub type Body = comp::quadruped_low::Body; @@ -435,3 +437,83 @@ fn mount_point(body: &Body) -> Vec3 { } .into() } + +pub fn quadruped_low_alpha( + next: &mut QuadrupedLowSkeleton, + _s_a: &SkeletonAttr, + stage_section: StageSection, + anim_time: f32, + global_time: f32, + timer: f32, +) { + let (movement1base, movement2base, movement3) = match stage_section { + StageSection::Buildup => (anim_time.sqrt(), 0.0, 0.0), + StageSection::Action => (1.0, anim_time.powi(4), 0.0), + StageSection::Recover => (1.0, 1.0, anim_time), + _ => (0.0, 0.0, 0.0), + }; + let pullback = 1.0 - movement3; + let subtract = global_time - timer; + let check = subtract - subtract.trunc(); + let mirror = (check - 0.5).signum(); + let twitch3 = (mirror * movement3 * 9.0).sin(); + let movement1 = mirror * movement1base * pullback; + let movement2 = mirror * movement2base * pullback; + let movement1abs = movement1base * pullback; + let movement2abs = movement2base * pullback; + + next.head_upper.orientation = Quaternion::rotation_z(twitch3 * -0.7); + + next.head_lower.orientation = Quaternion::rotation_x(movement1abs * 0.35 + movement2abs * -0.9) + * Quaternion::rotation_y(movement1 * 0.7 + movement2 * -1.0); + + next.jaw.orientation = Quaternion::rotation_x(movement1abs * -0.5 + movement2abs * 0.5); + next.chest.orientation = Quaternion::rotation_y(movement1 * -0.08 + movement2 * 0.15) + * Quaternion::rotation_z(movement1 * -0.2 + movement2 * 0.6); + + next.tail_front.orientation = + Quaternion::rotation_x(0.15) * Quaternion::rotation_z(movement1 * -0.4 + movement2 * -0.2); + + next.tail_rear.orientation = + Quaternion::rotation_x(-0.12) * Quaternion::rotation_z(movement1 * -0.4 + movement2 * -0.2); +} + +pub fn quadruped_low_beta( + next: &mut QuadrupedLowSkeleton, + _s_a: &SkeletonAttr, + stage_section: StageSection, + anim_time: f32, + global_time: f32, + timer: f32, +) { + let (movement1base, movement2base, movement3) = match stage_section { + StageSection::Buildup => (anim_time.sqrt(), 0.0, 0.0), + StageSection::Action => (1.0, anim_time.powi(4), 0.0), + StageSection::Recover => (1.0, 1.0, anim_time), + _ => (0.0, 0.0, 0.0), + }; + let pullback = 1.0 - movement3; + let subtract = global_time - timer; + let check = subtract - subtract.trunc(); + let mirror = (check - 0.5).signum(); + let twitch3 = (mirror * movement3 * 9.0).sin(); + let movement1 = mirror * movement1base * pullback; + let movement2 = mirror * movement2base * pullback; + let movement1abs = movement1base * pullback; + let movement2abs = movement2base * pullback; + + next.head_upper.orientation = Quaternion::rotation_z(twitch3 * 0.2); + + next.head_lower.orientation = Quaternion::rotation_x(movement1abs * 0.15 + movement2abs * -0.6) + * Quaternion::rotation_y(movement1 * -0.1 + movement2 * 0.15); + + next.jaw.orientation = Quaternion::rotation_x(movement1abs * -0.9 + movement2abs * 0.9); + next.chest.orientation = Quaternion::rotation_y(movement1 * 0.08 + movement2 * -0.15) + * Quaternion::rotation_z(movement1 * 0.2 + movement2 * -0.3); + + next.tail_front.orientation = + Quaternion::rotation_x(0.15) * Quaternion::rotation_z(movement1 * 0.4 + movement2 * 0.2); + + next.tail_rear.orientation = + Quaternion::rotation_x(-0.12) * Quaternion::rotation_z(movement1 * 0.4 + movement2 * 0.2); +} diff --git a/voxygen/anim/src/quadruped_medium/alpha.rs b/voxygen/anim/src/quadruped_medium/alpha.rs deleted file mode 100644 index 32bb388f2a..0000000000 --- a/voxygen/anim/src/quadruped_medium/alpha.rs +++ /dev/null @@ -1,99 +0,0 @@ -use super::{ - super::{vek::*, Animation}, - QuadrupedMediumSkeleton, SkeletonAttr, -}; -use common::states::utils::StageSection; - -pub struct AlphaAnimation; - -impl Animation for AlphaAnimation { - type Dependency<'a> = (f32, f32, Option, f32); - type Skeleton = QuadrupedMediumSkeleton; - - #[cfg(feature = "use-dyn-lib")] - const UPDATE_FN: &'static [u8] = b"quadruped_medium_alpha\0"; - - #[cfg_attr(feature = "be-dyn-lib", export_name = "quadruped_medium_alpha")] - fn update_skeleton_inner( - skeleton: &Self::Skeleton, - (velocity, global_time, stage_section, timer): Self::Dependency<'_>, - anim_time: f32, - _rate: &mut f32, - s_a: &SkeletonAttr, - ) -> Self::Skeleton { - let mut next = (*skeleton).clone(); - let speed = (Vec2::::from(velocity).magnitude()).min(24.0); - - let (movement1base, movement2base, movement3) = match stage_section { - Some(StageSection::Buildup) => (anim_time.powf(0.25), 0.0, 0.0), - Some(StageSection::Action) => (1.0, anim_time.powf(0.25), 0.0), - Some(StageSection::Recover) => (1.0, 1.0, anim_time.powi(4)), - _ => (0.0, 0.0, 0.0), - }; - let pullback = 1.0 - movement3; - let subtract = global_time - timer; - let check = subtract - subtract.trunc(); - let mirror = (check - 0.5).signum(); - let movement1 = movement1base * mirror * pullback; - let movement1abs = movement1base * pullback; - let movement2 = movement2base * mirror * pullback; - let movement2abs = movement2base * pullback; - let twitch1 = (movement1 * 10.0).sin() * pullback; - let twitch2 = (movement3 * 5.0).sin() * pullback; - let twitchmovement = twitch1 + twitch2; - - next.head.orientation = Quaternion::rotation_x(movement1abs * -0.3 + movement2abs * 0.6) - * Quaternion::rotation_y(movement1 * 0.35 + movement2 * -0.15) - * Quaternion::rotation_z(movement1 * 0.15 + movement2 * -0.5); - - next.neck.orientation = Quaternion::rotation_x(movement1abs * 0.2 + movement2abs * -0.2) - * Quaternion::rotation_y(movement1 * 0.0) - * Quaternion::rotation_z(movement1 * 0.10 + movement1 * -0.15); - - next.jaw.orientation = Quaternion::rotation_x(movement1abs * -0.4 + movement2abs * 0.4); - - next.tail.orientation = Quaternion::rotation_z( - movement1 * 0.5 + movement2 * -0.8 + twitchmovement * 0.2 * mirror, - ); - next.torso_front.position = Vec3::new( - 0.0, - s_a.torso_front.0 + movement1abs * -4.0, - s_a.torso_front.1, - ); - next.torso_front.orientation = Quaternion::rotation_y(movement1 * -0.25 * movement2 * 0.25) - * Quaternion::rotation_z(movement1 * 0.35 + movement2 * -0.45); - - next.torso_back.orientation = Quaternion::rotation_y(movement1 * 0.25 + movement1 * -0.25) - * Quaternion::rotation_z(movement1 * -0.4 + movement2 * 0.65); - - next.ears.orientation = Quaternion::rotation_x(twitchmovement * 0.2); - if speed < 0.5 { - next.leg_fl.orientation = - Quaternion::rotation_x(movement1abs * 0.8 + movement2abs * -0.6) - * Quaternion::rotation_y(movement1 * -0.3 + movement2 * 0.3) - * Quaternion::rotation_z(movement1 * -0.35 + movement2 * 0.45); - - next.leg_fr.orientation = - Quaternion::rotation_x(movement1abs * 0.8 + movement2abs * -0.6) - * Quaternion::rotation_y(movement1 * -0.3 + movement2 * 0.3) - * Quaternion::rotation_z(movement1 * -0.35 + movement2 * 0.45); - - next.leg_bl.orientation = Quaternion::rotation_x(movement1 * 0.1 + movement2 * -0.3); - - next.leg_br.orientation = Quaternion::rotation_x(movement1 * -0.1 + movement2 * 0.3); - - next.foot_fl.orientation = - Quaternion::rotation_x(movement1abs * -0.9 + movement2abs * 0.6); - - next.foot_fr.orientation = - Quaternion::rotation_x(movement1abs * -0.9 + movement2abs * 0.6); - - next.foot_bl.orientation = - Quaternion::rotation_x(movement1abs * -0.5 + movement2abs * -0.3); - - next.foot_br.orientation = - Quaternion::rotation_x(movement1abs * -0.5 + movement2abs * -0.3); - }; - next - } -} diff --git a/voxygen/anim/src/quadruped_medium/beta.rs b/voxygen/anim/src/quadruped_medium/beta.rs deleted file mode 100644 index 8d189b8eb8..0000000000 --- a/voxygen/anim/src/quadruped_medium/beta.rs +++ /dev/null @@ -1,99 +0,0 @@ -use super::{ - super::{vek::*, Animation}, - QuadrupedMediumSkeleton, SkeletonAttr, -}; -use common::states::utils::StageSection; - -pub struct BetaAnimation; - -impl Animation for BetaAnimation { - type Dependency<'a> = (f32, f32, Option, f32); - type Skeleton = QuadrupedMediumSkeleton; - - #[cfg(feature = "use-dyn-lib")] - const UPDATE_FN: &'static [u8] = b"quadruped_medium_beta\0"; - - #[cfg_attr(feature = "be-dyn-lib", export_name = "quadruped_medium_beta")] - fn update_skeleton_inner( - skeleton: &Self::Skeleton, - (velocity, global_time, stage_section, timer): Self::Dependency<'_>, - anim_time: f32, - _rate: &mut f32, - s_a: &SkeletonAttr, - ) -> Self::Skeleton { - let mut next = (*skeleton).clone(); - let speed = (Vec2::::from(velocity).magnitude()).min(24.0); - - let (movement1base, movement2base, movement3) = match stage_section { - Some(StageSection::Buildup) => (anim_time.powf(0.25), 0.0, 0.0), - Some(StageSection::Action) => (1.0, anim_time.sqrt(), 0.0), - Some(StageSection::Recover) => (1.0, 1.0, anim_time.powi(4)), - _ => (0.0, 0.0, 0.0), - }; - let pullback = 1.0 - movement3; - let subtract = global_time - timer; - let check = subtract - subtract.trunc(); - let mirror = (check - 0.5).signum(); - let movement1 = movement1base * mirror * pullback; - let movement1abs = movement1base * pullback; - let movement2 = movement2base * mirror * pullback; - let movement2abs = movement2base * pullback; - let twitch1 = (movement1 * 10.0).sin() * pullback; - let twitch2 = (movement2abs * -8.0).sin(); - let twitchmovement = twitch1 + twitch2; - - next.head.orientation = Quaternion::rotation_x(movement1abs * -0.4 + movement2abs * 1.1) - * Quaternion::rotation_y(movement1 * -0.35 + movement2 * 0.25) - * Quaternion::rotation_z(movement1 * -0.25 + movement2 * 0.5); - - next.neck.orientation = Quaternion::rotation_x(movement1abs * 0.0 + movement2abs * -0.2) - * Quaternion::rotation_y(movement1 * 0.0) - * Quaternion::rotation_z(movement1 * -0.10 + movement1 * 0.15); - - next.jaw.orientation = Quaternion::rotation_x(movement1abs * -0.5 + twitch2 * -0.4); - - next.tail.orientation = Quaternion::rotation_z( - movement1 * 0.5 + movement2 * -0.8 + twitchmovement * 0.2 * mirror, - ); - next.torso_front.position = Vec3::new( - 0.0, - s_a.torso_front.0 + movement1abs * -4.0, - s_a.torso_front.1, - ); - next.torso_front.orientation = Quaternion::rotation_y(movement1 * -0.25 * movement2 * 0.25) - * Quaternion::rotation_z(movement1 * 0.35 + movement2 * -0.45); - - next.torso_back.orientation = Quaternion::rotation_y(movement1 * 0.25 + movement1 * -0.25) - * Quaternion::rotation_z(movement1 * -0.4 + movement2 * 0.65); - - next.ears.orientation = Quaternion::rotation_x(twitchmovement * 0.2); - if speed < 0.5 { - next.leg_fl.orientation = - Quaternion::rotation_x(movement1abs * 0.8 + movement2abs * -0.6) - * Quaternion::rotation_y(movement1 * -0.3 + movement2 * 0.3) - * Quaternion::rotation_z(movement1 * -0.35 + movement2 * 0.45); - - next.leg_fr.orientation = - Quaternion::rotation_x(movement1abs * 0.8 + movement2abs * -0.6) - * Quaternion::rotation_y(movement1 * -0.3 + movement2 * 0.3) - * Quaternion::rotation_z(movement1 * -0.35 + movement2 * 0.45); - - next.leg_bl.orientation = Quaternion::rotation_x(movement1 * 0.1 + movement2 * -0.3); - - next.leg_br.orientation = Quaternion::rotation_x(movement1 * -0.1 + movement2 * 0.3); - - next.foot_fl.orientation = - Quaternion::rotation_x(movement1abs * -0.9 + movement2abs * 0.6); - - next.foot_fr.orientation = - Quaternion::rotation_x(movement1abs * -0.9 + movement2abs * 0.6); - - next.foot_bl.orientation = - Quaternion::rotation_x(movement1abs * -0.5 + movement2abs * -0.3); - - next.foot_br.orientation = - Quaternion::rotation_x(movement1abs * -0.5 + movement2abs * -0.3); - }; - next - } -} diff --git a/voxygen/anim/src/quadruped_medium/combomelee.rs b/voxygen/anim/src/quadruped_medium/combomelee.rs index c52a3a5304..18e10b452e 100644 --- a/voxygen/anim/src/quadruped_medium/combomelee.rs +++ b/voxygen/anim/src/quadruped_medium/combomelee.rs @@ -1,19 +1,12 @@ use super::{ super::{vek::*, Animation}, - QuadrupedMediumSkeleton, SkeletonAttr, + quadruped_medium_alpha, quadruped_medium_beta, QuadrupedMediumSkeleton, SkeletonAttr, }; -use common::states::utils::{AbilityInfo, StageSection}; +use common::states::utils::StageSection; pub struct ComboAnimation; impl Animation for ComboAnimation { - type Dependency<'a> = ( - Option<&'a str>, - Option, - Option, - usize, - f32, - f32, - ); + type Dependency<'a> = (Option<&'a str>, StageSection, usize, f32, f32, f32); type Skeleton = QuadrupedMediumSkeleton; #[cfg(feature = "use-dyn-lib")] @@ -22,16 +15,18 @@ impl Animation for ComboAnimation { #[cfg_attr(feature = "be-dyn-lib", export_name = "quadruped_medium_combo")] fn update_skeleton_inner( skeleton: &Self::Skeleton, - (ability_id, stage_section, _ability_info, current_strike, global_time, timer): Self::Dependency<'_>, + (ability_id, stage_section, current_strike, speed, global_time, timer): Self::Dependency< + '_, + >, anim_time: f32, rate: &mut f32, - _s_a: &SkeletonAttr, + s_a: &SkeletonAttr, ) -> Self::Skeleton { *rate = 1.0; let mut next = (*skeleton).clone(); let _multi_strike_pullback = 1.0 - - if matches!(stage_section, Some(StageSection::Recover)) { + - if matches!(stage_section, StageSection::Recover) { anim_time.powi(4) } else { 0.0 @@ -44,9 +39,9 @@ impl Animation for ComboAnimation { | "common.abilities.custom.frostfang.triplestrike", ) => { let (movement1base, movement2base, movement3) = match stage_section { - Some(StageSection::Buildup) => (anim_time.sqrt(), 0.0, 0.0), - Some(StageSection::Action) => (1.0, anim_time.powi(4), 0.0), - Some(StageSection::Recover) => (1.0, 1.0, anim_time), + StageSection::Buildup => (anim_time.sqrt(), 0.0, 0.0), + StageSection::Action => (1.0, anim_time.powi(4), 0.0), + StageSection::Recover => (1.0, 1.0, anim_time), _ => (0.0, 0.0, 0.0), }; let pullback = 1.0 - movement3; @@ -101,6 +96,77 @@ impl Animation for ComboAnimation { _ => {}, } }, + Some("common.abilities.custom.quadmedbasic.singlestrike") => match strike { + 0 => { + quadruped_medium_alpha( + &mut next, + s_a, + speed, + stage_section, + anim_time, + global_time, + timer, + ); + }, + _ => {}, + }, + Some( + "common.abilities.custom.quadmedbasic.triplestrike" + | "common.abilities.custom.quadmedquick.triplestrike", + ) => match strike { + 0 | 2 => { + quadruped_medium_alpha( + &mut next, + s_a, + speed, + stage_section, + anim_time, + global_time, + timer, + ); + }, + 1 => { + quadruped_medium_beta( + &mut next, + s_a, + speed, + stage_section, + anim_time, + global_time, + timer, + ); + }, + _ => {}, + }, + Some( + "common.abilities.custom.quadmedcharge.doublestrike" + | "common.abilities.custom.quadmedjump.doublestrike" + | "common.abilities.custom.roshwalr.doublehusk", + ) => match strike { + 0 => { + quadruped_medium_alpha( + &mut next, + s_a, + speed, + stage_section, + anim_time, + global_time, + timer, + ); + }, + 1 => { + quadruped_medium_beta( + &mut next, + s_a, + speed, + stage_section, + anim_time, + global_time, + timer, + ); + }, + _ => {}, + }, _ => {}, } } diff --git a/voxygen/anim/src/quadruped_medium/mod.rs b/voxygen/anim/src/quadruped_medium/mod.rs index cfc92e81a2..91b53198e4 100644 --- a/voxygen/anim/src/quadruped_medium/mod.rs +++ b/voxygen/anim/src/quadruped_medium/mod.rs @@ -1,5 +1,3 @@ -pub mod alpha; -pub mod beta; pub mod combomelee; pub mod dash; pub mod feed; @@ -13,14 +11,16 @@ pub mod stunned; // Reexports pub use self::{ - alpha::AlphaAnimation, beta::BetaAnimation, combomelee::ComboAnimation, dash::DashAnimation, - feed::FeedAnimation, hoof::HoofAnimation, idle::IdleAnimation, jump::JumpAnimation, - leapmelee::LeapMeleeAnimation, run::RunAnimation, shockwave::ShockwaveAnimation, - stunned::StunnedAnimation, + combomelee::ComboAnimation, dash::DashAnimation, feed::FeedAnimation, hoof::HoofAnimation, + idle::IdleAnimation, jump::JumpAnimation, leapmelee::LeapMeleeAnimation, run::RunAnimation, + shockwave::ShockwaveAnimation, stunned::StunnedAnimation, }; use super::{make_bone, vek::*, FigureBoneData, Offsets, Skeleton}; -use common::comp::{self}; +use common::{ + comp::{self}, + states::utils::StageSection, +}; use core::convert::TryFrom; pub type Body = comp::quadruped_medium::Body; @@ -512,7 +512,7 @@ impl<'a> From<&'a Body> for SkeletonAttr { (Highland, _) => (5.5, -2.5, 0.0), (Yak, _) => (4.5, -2.0, -1.5), (Panda, _) => (7.5, -5.5, -2.0), - (Bear, _) => (3.5, -4.5, -3.5), + (Bear, _) => (5.5, -4.5, -3.5), (Dreadhorn, _) => (8.5, -7.0, -0.5), (Moose, _) => (5.5, -4.0, 1.0), (Snowleopard, _) => (6.5, -4.0, -2.5), @@ -797,3 +797,159 @@ fn mount_point(body: &Body) -> Vec3 { } .into() } + +pub fn quadruped_medium_alpha( + next: &mut QuadrupedMediumSkeleton, + s_a: &SkeletonAttr, + speed: f32, + stage_section: StageSection, + anim_time: f32, + global_time: f32, + timer: f32, +) { + let speed = (Vec2::::from(speed).magnitude()).min(24.0); + + let (movement1base, movement2base, movement3) = match stage_section { + StageSection::Buildup => (anim_time.powf(0.25), 0.0, 0.0), + StageSection::Action => (1.0, anim_time.powf(0.25), 0.0), + StageSection::Recover => (1.0, 1.0, anim_time.powi(4)), + _ => (0.0, 0.0, 0.0), + }; + let pullback = 1.0 - movement3; + let subtract = global_time - timer; + let check = subtract - subtract.trunc(); + let mirror = (check - 0.5).signum(); + let movement1 = movement1base * mirror * pullback; + let movement1abs = movement1base * pullback; + let movement2 = movement2base * mirror * pullback; + let movement2abs = movement2base * pullback; + let twitch1 = (movement1 * 10.0).sin() * pullback; + let twitch2 = (movement3 * 5.0).sin() * pullback; + let twitchmovement = twitch1 + twitch2; + + next.head.orientation = Quaternion::rotation_x(movement1abs * -0.3 + movement2abs * 0.6) + * Quaternion::rotation_y(movement1 * 0.35 + movement2 * -0.15) + * Quaternion::rotation_z(movement1 * 0.15 + movement2 * -0.5); + + next.neck.orientation = Quaternion::rotation_x(movement1abs * 0.2 + movement2abs * -0.2) + * Quaternion::rotation_y(movement1 * 0.0) + * Quaternion::rotation_z(movement1 * 0.10 + movement1 * -0.15); + + next.jaw.orientation = Quaternion::rotation_x(movement1abs * -0.4 + movement2abs * 0.4); + + next.tail.orientation = + Quaternion::rotation_z(movement1 * 0.5 + movement2 * -0.8 + twitchmovement * 0.2 * mirror); + next.torso_front.position = Vec3::new( + 0.0, + s_a.torso_front.0 + movement1abs * -4.0, + s_a.torso_front.1, + ); + next.torso_front.orientation = Quaternion::rotation_y(movement1 * -0.25 * movement2 * 0.25) + * Quaternion::rotation_z(movement1 * 0.35 + movement2 * -0.45); + + next.torso_back.orientation = Quaternion::rotation_y(movement1 * 0.25 + movement1 * -0.25) + * Quaternion::rotation_z(movement1 * -0.4 + movement2 * 0.65); + + next.ears.orientation = Quaternion::rotation_x(twitchmovement * 0.2); + if speed < 0.5 { + next.leg_fl.orientation = Quaternion::rotation_x(movement1abs * 0.8 + movement2abs * -0.6) + * Quaternion::rotation_y(movement1 * -0.3 + movement2 * 0.3) + * Quaternion::rotation_z(movement1 * -0.35 + movement2 * 0.45); + + next.leg_fr.orientation = Quaternion::rotation_x(movement1abs * 0.8 + movement2abs * -0.6) + * Quaternion::rotation_y(movement1 * -0.3 + movement2 * 0.3) + * Quaternion::rotation_z(movement1 * -0.35 + movement2 * 0.45); + + next.leg_bl.orientation = Quaternion::rotation_x(movement1 * 0.1 + movement2 * -0.3); + + next.leg_br.orientation = Quaternion::rotation_x(movement1 * -0.1 + movement2 * 0.3); + + next.foot_fl.orientation = Quaternion::rotation_x(movement1abs * -0.9 + movement2abs * 0.6); + + next.foot_fr.orientation = Quaternion::rotation_x(movement1abs * -0.9 + movement2abs * 0.6); + + next.foot_bl.orientation = + Quaternion::rotation_x(movement1abs * -0.5 + movement2abs * -0.3); + + next.foot_br.orientation = + Quaternion::rotation_x(movement1abs * -0.5 + movement2abs * -0.3); + }; +} + +pub fn quadruped_medium_beta( + next: &mut QuadrupedMediumSkeleton, + s_a: &SkeletonAttr, + speed: f32, + stage_section: StageSection, + anim_time: f32, + global_time: f32, + timer: f32, +) { + let speed = (Vec2::::from(speed).magnitude()).min(24.0); + + let (movement1base, movement2base, movement3) = match stage_section { + StageSection::Buildup => (anim_time.powf(0.25), 0.0, 0.0), + StageSection::Action => (1.0, anim_time.sqrt(), 0.0), + StageSection::Recover => (1.0, 1.0, anim_time.powi(4)), + _ => (0.0, 0.0, 0.0), + }; + let pullback = 1.0 - movement3; + let subtract = global_time - timer; + let check = subtract - subtract.trunc(); + let mirror = (check - 0.5).signum(); + let movement1 = movement1base * mirror * pullback; + let movement1abs = movement1base * pullback; + let movement2 = movement2base * mirror * pullback; + let movement2abs = movement2base * pullback; + let twitch1 = (movement1 * 10.0).sin() * pullback; + let twitch2 = (movement2abs * -8.0).sin(); + let twitchmovement = twitch1 + twitch2; + + next.head.orientation = Quaternion::rotation_x(movement1abs * -0.4 + movement2abs * 1.1) + * Quaternion::rotation_y(movement1 * -0.35 + movement2 * 0.25) + * Quaternion::rotation_z(movement1 * -0.25 + movement2 * 0.5); + + next.neck.orientation = Quaternion::rotation_x(movement1abs * 0.0 + movement2abs * -0.2) + * Quaternion::rotation_y(movement1 * 0.0) + * Quaternion::rotation_z(movement1 * -0.10 + movement1 * 0.15); + + next.jaw.orientation = Quaternion::rotation_x(movement1abs * -0.5 + twitch2 * -0.4); + + next.tail.orientation = + Quaternion::rotation_z(movement1 * 0.5 + movement2 * -0.8 + twitchmovement * 0.2 * mirror); + next.torso_front.position = Vec3::new( + 0.0, + s_a.torso_front.0 + movement1abs * -4.0, + s_a.torso_front.1, + ); + next.torso_front.orientation = Quaternion::rotation_y(movement1 * -0.25 * movement2 * 0.25) + * Quaternion::rotation_z(movement1 * 0.35 + movement2 * -0.45); + + next.torso_back.orientation = Quaternion::rotation_y(movement1 * 0.25 + movement1 * -0.25) + * Quaternion::rotation_z(movement1 * -0.4 + movement2 * 0.65); + + next.ears.orientation = Quaternion::rotation_x(twitchmovement * 0.2); + if speed < 0.5 { + next.leg_fl.orientation = Quaternion::rotation_x(movement1abs * 0.8 + movement2abs * -0.6) + * Quaternion::rotation_y(movement1 * -0.3 + movement2 * 0.3) + * Quaternion::rotation_z(movement1 * -0.35 + movement2 * 0.45); + + next.leg_fr.orientation = Quaternion::rotation_x(movement1abs * 0.8 + movement2abs * -0.6) + * Quaternion::rotation_y(movement1 * -0.3 + movement2 * 0.3) + * Quaternion::rotation_z(movement1 * -0.35 + movement2 * 0.45); + + next.leg_bl.orientation = Quaternion::rotation_x(movement1 * 0.1 + movement2 * -0.3); + + next.leg_br.orientation = Quaternion::rotation_x(movement1 * -0.1 + movement2 * 0.3); + + next.foot_fl.orientation = Quaternion::rotation_x(movement1abs * -0.9 + movement2abs * 0.6); + + next.foot_fr.orientation = Quaternion::rotation_x(movement1abs * -0.9 + movement2abs * 0.6); + + next.foot_bl.orientation = + Quaternion::rotation_x(movement1abs * -0.5 + movement2abs * -0.3); + + next.foot_br.orientation = + Quaternion::rotation_x(movement1abs * -0.5 + movement2abs * -0.3); + }; +} diff --git a/voxygen/anim/src/quadruped_small/alpha.rs b/voxygen/anim/src/quadruped_small/alpha.rs index fa8f1e431c..69510a0d51 100644 --- a/voxygen/anim/src/quadruped_small/alpha.rs +++ b/voxygen/anim/src/quadruped_small/alpha.rs @@ -8,7 +8,7 @@ use common::states::utils::StageSection; pub struct AlphaAnimation; impl Animation for AlphaAnimation { - type Dependency<'a> = (f32, f32, Option, f32); + type Dependency<'a> = (f32, StageSection, f32); type Skeleton = QuadrupedSmallSkeleton; #[cfg(feature = "use-dyn-lib")] @@ -17,7 +17,7 @@ impl Animation for AlphaAnimation { #[cfg_attr(feature = "be-dyn-lib", export_name = "quadruped_small_alpha")] fn update_skeleton_inner( skeleton: &Self::Skeleton, - (_velocity, global_time, stage_section, timer): Self::Dependency<'_>, + (global_time, stage_section, timer): Self::Dependency<'_>, anim_time: f32, _rate: &mut f32, _s_a: &SkeletonAttr, @@ -25,9 +25,9 @@ impl Animation for AlphaAnimation { let mut next = (*skeleton).clone(); let (movement1base, movement2base, movement3) = match stage_section { - Some(StageSection::Buildup) => (anim_time.sqrt(), 0.0, 0.0), - Some(StageSection::Action) => (1.0, anim_time.powi(4), 0.0), - Some(StageSection::Recover) => (1.0, 1.0, anim_time), + StageSection::Buildup => (anim_time.sqrt(), 0.0, 0.0), + StageSection::Action => (1.0, anim_time.powi(4), 0.0), + StageSection::Recover => (1.0, 1.0, anim_time), _ => (0.0, 0.0, 0.0), }; let pullback = 1.0 - movement3; diff --git a/voxygen/anim/src/theropod/alpha.rs b/voxygen/anim/src/theropod/alpha.rs deleted file mode 100644 index ee9ecf8903..0000000000 --- a/voxygen/anim/src/theropod/alpha.rs +++ /dev/null @@ -1,66 +0,0 @@ -use super::{ - super::{vek::*, Animation}, - SkeletonAttr, TheropodSkeleton, -}; -use common::states::utils::StageSection; - -pub struct AlphaAnimation; - -impl Animation for AlphaAnimation { - type Dependency<'a> = (f32, f32, Option, f32); - type Skeleton = TheropodSkeleton; - - #[cfg(feature = "use-dyn-lib")] - const UPDATE_FN: &'static [u8] = b"theropod_alpha\0"; - - #[cfg_attr(feature = "be-dyn-lib", export_name = "theropod_alpha")] - fn update_skeleton_inner( - skeleton: &Self::Skeleton, - (_velocity, global_time, stage_section, timer): Self::Dependency<'_>, - anim_time: f32, - _rate: &mut f32, - _s_a: &SkeletonAttr, - ) -> Self::Skeleton { - let mut next = (*skeleton).clone(); - - let (movement1base, movement2base, movement3) = match stage_section { - Some(StageSection::Buildup) => (anim_time.powi(2), 0.0, 0.0), - Some(StageSection::Action) => (1.0, anim_time.powi(4), 0.0), - Some(StageSection::Recover) => (1.0, 1.0, anim_time), - _ => (0.0, 0.0, 0.0), - }; - let pullback = 1.0 - movement3; - let subtract = global_time - timer; - let check = subtract - subtract.trunc(); - let mirror = (check - 0.5).signum(); - let movement1 = mirror * movement1base * pullback; - let movement2 = mirror * movement2base * pullback; - let movement1abs = movement1base * pullback; - let movement2abs = movement2base * pullback; - - next.head.orientation = Quaternion::rotation_x(movement1abs * 0.2) - * Quaternion::rotation_y(movement1 * 0.1 + movement2 * 0.2); - next.neck.orientation = Quaternion::rotation_x(movement1abs * -0.3) - * Quaternion::rotation_y(movement1 * 0.1 + movement2 * 0.1); - - next.jaw.orientation = Quaternion::rotation_x(movement1abs * -0.5 + movement2abs * 0.5); - - next.chest_front.orientation = Quaternion::rotation_x(movement1abs * -0.2); - next.chest_back.orientation = Quaternion::rotation_x(movement1abs * 0.2); - - next.leg_l.orientation = Quaternion::rotation_x(movement1abs * -0.1); - - next.leg_r.orientation = Quaternion::rotation_x(movement1abs * -0.1); - next.foot_l.orientation = Quaternion::rotation_x(movement1abs * -0.3); - next.foot_r.orientation = Quaternion::rotation_x(movement1abs * -0.3); - - next.tail_front.orientation = - Quaternion::rotation_x(0.1 + movement1abs * -0.1 + movement2abs * -0.3) - * Quaternion::rotation_z(movement1 * -0.1 + movement2 * -0.2); - - next.tail_back.orientation = - Quaternion::rotation_x(0.1 + movement1abs * -0.1 + movement2abs * -0.3) - * Quaternion::rotation_z(movement1 * -0.1 + movement2 * -0.2); - next - } -} diff --git a/voxygen/anim/src/theropod/beta.rs b/voxygen/anim/src/theropod/beta.rs deleted file mode 100644 index 12f0db1367..0000000000 --- a/voxygen/anim/src/theropod/beta.rs +++ /dev/null @@ -1,65 +0,0 @@ -use super::{ - super::{vek::*, Animation}, - SkeletonAttr, TheropodSkeleton, -}; -use common::states::utils::StageSection; -//use std::ops::Rem; - -pub struct BetaAnimation; - -impl Animation for BetaAnimation { - type Dependency<'a> = (f32, f32, Option, f32); - type Skeleton = TheropodSkeleton; - - #[cfg(feature = "use-dyn-lib")] - const UPDATE_FN: &'static [u8] = b"theropod_beta\0"; - - #[cfg_attr(feature = "be-dyn-lib", export_name = "theropod_beta")] - fn update_skeleton_inner( - skeleton: &Self::Skeleton, - (_velocity, global_time, stage_section, timer): Self::Dependency<'_>, - anim_time: f32, - _rate: &mut f32, - _s_a: &SkeletonAttr, - ) -> Self::Skeleton { - let mut next = (*skeleton).clone(); - - let (movement1base, movement2base, movement3) = match stage_section { - Some(StageSection::Buildup) => (anim_time.powi(2), 0.0, 0.0), - Some(StageSection::Action) => (1.0, anim_time.powi(4), 0.0), - Some(StageSection::Recover) => (1.0, 1.0, anim_time), - _ => (0.0, 0.0, 0.0), - }; - let pullback = 1.0 - movement3; - let subtract = global_time - timer; - let check = subtract - subtract.trunc(); - let mirror = (check - 0.5).signum(); - let movement1 = mirror * movement1base * pullback; - let movement2 = mirror * movement2base * pullback; - let movement1abs = movement1base * pullback; - let movement2abs = movement2base * pullback; - - next.head.orientation = Quaternion::rotation_x(movement1abs * -0.4 + movement2abs * 1.2) - * Quaternion::rotation_y(movement1 * 0.1 + movement2 * -0.1); - next.neck.orientation = Quaternion::rotation_x(movement1abs * 0.4 + movement2abs * -1.2) - * Quaternion::rotation_y(movement1 * 0.1 + movement2 * -0.1); - - next.chest_front.orientation = - Quaternion::rotation_x(movement1abs * 0.6 + movement2abs * -1.5); - next.chest_back.orientation = - Quaternion::rotation_x(movement1abs * -0.6 + movement2abs * 1.5); - - next.leg_l.orientation = Quaternion::rotation_x(movement1abs * -0.5); - - next.leg_r.orientation = Quaternion::rotation_x(movement1abs * -0.5); - next.foot_l.orientation = Quaternion::rotation_x(movement1abs * 0.4); - next.foot_r.orientation = Quaternion::rotation_x(movement1abs * 0.4); - - next.tail_front.orientation = - Quaternion::rotation_x(0.1 + movement1abs * -0.1 + movement2abs * -0.3); - - next.tail_back.orientation = - Quaternion::rotation_x(0.1 + movement1abs * -0.1 + movement2abs * -0.3); - next - } -} diff --git a/voxygen/anim/src/theropod/combomelee.rs b/voxygen/anim/src/theropod/combomelee.rs new file mode 100644 index 0000000000..609091fbe8 --- /dev/null +++ b/voxygen/anim/src/theropod/combomelee.rs @@ -0,0 +1,118 @@ +use super::{ + super::{vek::*, Animation}, + SkeletonAttr, TheropodSkeleton, +}; +use common::states::utils::StageSection; + +pub struct ComboAnimation; + +impl Animation for ComboAnimation { + type Dependency<'a> = (Option<&'a str>, StageSection, usize, f32, f32); + type Skeleton = TheropodSkeleton; + + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"theropod_combo\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "theropod_combo")] + fn update_skeleton_inner( + skeleton: &Self::Skeleton, + (_ability_id, stage_section, current_strike, global_time, timer): Self::Dependency<'_>, + anim_time: f32, + _rate: &mut f32, + _s_a: &SkeletonAttr, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + let multi_strike_pullback = 1.0 + - if matches!(stage_section, StageSection::Recover) { + anim_time.powi(4) + } else { + 0.0 + }; + + for strike in 0..=current_strike { + match strike { + 0 => { + let (movement1base, movement2base) = match stage_section { + StageSection::Buildup => (anim_time.powi(2), 0.0), + StageSection::Action => (1.0, anim_time.powi(4)), + _ => (0.0, 0.0), + }; + let subtract = global_time - timer; + let check = subtract - subtract.trunc(); + let mirror = (check - 0.5).signum(); + let movement1 = mirror * movement1base * multi_strike_pullback; + let movement2 = mirror * movement2base * multi_strike_pullback; + let movement1abs = movement1base * multi_strike_pullback; + let movement2abs = movement2base * multi_strike_pullback; + + next.head.orientation = Quaternion::rotation_x(movement1abs * 0.2) + * Quaternion::rotation_y(movement1 * 0.1 + movement2 * 0.2); + next.neck.orientation = Quaternion::rotation_x(movement1abs * -0.3) + * Quaternion::rotation_y(movement1 * 0.1 + movement2 * 0.1); + + next.jaw.orientation = + Quaternion::rotation_x(movement1abs * -0.5 + movement2abs * 0.5); + + next.chest_front.orientation = Quaternion::rotation_x(movement1abs * -0.2); + next.chest_back.orientation = Quaternion::rotation_x(movement1abs * 0.2); + + next.leg_l.orientation = Quaternion::rotation_x(movement1abs * -0.1); + + next.leg_r.orientation = Quaternion::rotation_x(movement1abs * -0.1); + next.foot_l.orientation = Quaternion::rotation_x(movement1abs * -0.3); + next.foot_r.orientation = Quaternion::rotation_x(movement1abs * -0.3); + + next.tail_front.orientation = + Quaternion::rotation_x(0.1 + movement1abs * -0.1 + movement2abs * -0.3) + * Quaternion::rotation_z(movement1 * -0.1 + movement2 * -0.2); + + next.tail_back.orientation = + Quaternion::rotation_x(0.1 + movement1abs * -0.1 + movement2abs * -0.3) + * Quaternion::rotation_z(movement1 * -0.1 + movement2 * -0.2); + }, + 1 | 2 => { + let (movement1base, movement2base) = match stage_section { + StageSection::Buildup => (anim_time.powi(2), 0.0), + StageSection::Action => (1.0, anim_time.powi(4)), + _ => (0.0, 0.0), + }; + let subtract = global_time - timer; + let check = subtract - subtract.trunc(); + let mirror = (check - 0.5).signum(); + let movement1 = mirror * movement1base * multi_strike_pullback; + let movement2 = mirror * movement2base * multi_strike_pullback; + let movement1abs = movement1base * multi_strike_pullback; + let movement2abs = movement2base * multi_strike_pullback; + + next.head.orientation = + Quaternion::rotation_x(movement1abs * -0.4 + movement2abs * 1.2) + * Quaternion::rotation_y(movement1 * 0.1 + movement2 * -0.1); + next.neck.orientation = + Quaternion::rotation_x(movement1abs * 0.4 + movement2abs * -1.2) + * Quaternion::rotation_y(movement1 * 0.1 + movement2 * -0.1); + + next.chest_front.orientation = + Quaternion::rotation_x(movement1abs * 0.6 + movement2abs * -1.5); + next.chest_back.orientation = + Quaternion::rotation_x(movement1abs * -0.6 + movement2abs * 1.5); + + next.leg_l.orientation = Quaternion::rotation_x(movement1abs * -0.5); + + next.leg_r.orientation = Quaternion::rotation_x(movement1abs * -0.5); + next.foot_l.orientation = Quaternion::rotation_x(movement1abs * 0.4); + next.foot_r.orientation = Quaternion::rotation_x(movement1abs * 0.4); + + next.tail_front.orientation = + Quaternion::rotation_x(0.1 + movement1abs * -0.1 + movement2abs * -0.3); + + next.tail_back.orientation = + Quaternion::rotation_x(0.1 + movement1abs * -0.1 + movement2abs * -0.3); + }, + _ => {}, + } + } + + next + } +} diff --git a/voxygen/anim/src/theropod/mod.rs b/voxygen/anim/src/theropod/mod.rs index 51e1e4b130..18d8ebc100 100644 --- a/voxygen/anim/src/theropod/mod.rs +++ b/voxygen/anim/src/theropod/mod.rs @@ -1,5 +1,4 @@ -pub mod alpha; -pub mod beta; +pub mod combomelee; pub mod dash; pub mod idle; pub mod jump; @@ -7,8 +6,8 @@ pub mod run; // Reexports pub use self::{ - alpha::AlphaAnimation, beta::BetaAnimation, dash::DashAnimation, idle::IdleAnimation, - jump::JumpAnimation, run::RunAnimation, + combomelee::ComboAnimation, dash::DashAnimation, idle::IdleAnimation, jump::JumpAnimation, + run::RunAnimation, }; use super::{make_bone, vek::*, FigureBoneData, Offsets, Skeleton}; diff --git a/voxygen/egui/src/character_states.rs b/voxygen/egui/src/character_states.rs index b2dec83c46..81b8761999 100644 --- a/voxygen/egui/src/character_states.rs +++ b/voxygen/egui/src/character_states.rs @@ -1,7 +1,7 @@ use crate::{widgets::two_col_row, SelectedEntityInfo}; use common::{ comp::CharacterState, - states::{charged_melee, combo_melee, dash_melee, leap_melee}, + states::{charged_melee, dash_melee, leap_melee}, }; use egui::{Grid, Ui}; @@ -15,9 +15,6 @@ pub fn draw_char_state_group( ui.label(character_state.to_string()); }); match character_state { - CharacterState::ComboMelee(data) => { - combo_melee_grid(ui, data); - }, CharacterState::DashMelee(data) => dash_melee_grid(ui, data), CharacterState::ChargedMelee(data) => charged_melee_grid(ui, data), // Character states with no associated data to display @@ -47,18 +44,6 @@ fn charged_melee_grid(ui: &mut Ui, data: &charged_melee::Data) { }); } -fn combo_melee_grid(ui: &mut Ui, data: &combo_melee::Data) { - Grid::new("selected_entity_combo_melee_grid") - .spacing([40.0, 4.0]) - .max_col_width(100.0) - .striped(true) - .show(ui, |ui| #[rustfmt::skip] { - two_col_row(ui, "Stage", data.stage.to_string()); - two_col_row(ui, "Timer", format!("{}ms", data.timer.as_millis())); - two_col_row(ui, "num_stages", data.static_data.num_stages.to_string()); - }); -} - fn dash_melee_grid(ui: &mut Ui, data: &dash_melee::Data) { Grid::new("selected_entity_dash_melee_grid") .spacing([40.0, 4.0]) diff --git a/voxygen/egui/src/lib.rs b/voxygen/egui/src/lib.rs index 923e43dc21..895b1144ab 100644 --- a/voxygen/egui/src/lib.rs +++ b/voxygen/egui/src/lib.rs @@ -788,6 +788,7 @@ fn body_species(body: &Body) -> String { Body::QuadrupedLow(body) => format!("{:?}", body.species), Body::Arthropod(body) => format!("{:?}", body.species), Body::Ship(body) => format!("{:?}", body), + Body::Crustacean(body) => format!("{:?}", body.species), } } diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index 29499a264e..6c5868b4b8 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -165,8 +165,8 @@ pub struct MusicMgr { /// The previous track's activity kind, for transitions last_activity: MusicState, // For debug menu - pub current_track: String, - pub current_artist: String, + current_track: String, + current_artist: String, track_length: f32, } @@ -493,6 +493,17 @@ impl MusicMgr { } } + pub fn current_track(&self) -> String { self.current_track.clone() } + + pub fn current_artist(&self) -> String { self.current_artist.clone() } + + pub fn reset_track(&mut self) { + self.began_playing = Instant::now(); + self.next_track_change = 0.0; + self.current_artist = String::from("None"); + self.current_track = String::from("None"); + } + /// Loads default soundtrack if no events are active. Otherwise, attempts to /// compile and load all active event soundtracks, falling back to default /// if they are empty. diff --git a/voxygen/src/audio/sfx/event_mapper/combat/tests.rs b/voxygen/src/audio/sfx/event_mapper/combat/tests.rs index 6de8f43ecc..cb8e75dfef 100644 --- a/voxygen/src/audio/sfx/event_mapper/combat/tests.rs +++ b/voxygen/src/audio/sfx/event_mapper/combat/tests.rs @@ -1,7 +1,6 @@ use super::*; use crate::audio::sfx::SfxEvent; use common::{ - combat::DamageKind, comp::{ controller::InputKind, inventory::loadout_builder::LoadoutBuilder, item::tool::ToolKind, melee, CharacterAbilityType, CharacterState, Item, @@ -115,128 +114,6 @@ fn maps_basic_melee() { ); } -#[test] -fn matches_ability_stage() { - let loadout = LoadoutBuilder::empty() - .active_mainhand(Some(Item::new_from_asset_expect( - "common.items.weapons.sword.starter", - ))) - .build(); - let inventory = Inventory::with_loadout_humanoid(loadout); - - let result = CombatEventMapper::map_event( - &CharacterState::ComboMelee(states::combo_melee::Data { - static_data: states::combo_melee::StaticData { - num_stages: 1, - stage_data: vec![states::combo_melee::Stage { - stage: 1, - base_damage: 100.0, - base_poise_damage: 100.0, - damage_increase: 10.0, - poise_damage_increase: 10.0, - knockback: 10.0, - range: 4.0, - angle: 30.0, - base_buildup_duration: Duration::from_millis(500), - base_swing_duration: Duration::from_millis(200), - hit_timing: 0.5, - base_recover_duration: Duration::from_millis(400), - forward_movement: 0.5, - damage_kind: DamageKind::Slashing, - damage_effect: None, - }], - initial_energy_gain: 0.0, - max_energy_gain: 100.0, - energy_increase: 20.0, - speed_increase: 0.05, - max_speed_increase: 0.8, - scales_from_combo: 2, - ori_modifier: 1.0, - ability_info: empty_ability_info(), - }, - exhausted: false, - stage: 1, - timer: Duration::default(), - stage_section: states::utils::StageSection::Action, - }), - &PreviousEntityState { - event: SfxEvent::Idle, - time: Instant::now(), - weapon_drawn: true, - }, - &inventory, - ); - - assert_eq!( - result, - SfxEvent::Attack( - CharacterAbilityType::ComboMelee(states::utils::StageSection::Action, 1), - ToolKind::Sword - ) - ); -} - -#[test] -fn ignores_different_ability_stage() { - let loadout = LoadoutBuilder::empty() - .active_mainhand(Some(Item::new_from_asset_expect( - "common.items.weapons.axe.starter_axe", - ))) - .build(); - let inventory = Inventory::with_loadout_humanoid(loadout); - - let result = CombatEventMapper::map_event( - &CharacterState::ComboMelee(states::combo_melee::Data { - static_data: states::combo_melee::StaticData { - num_stages: 1, - stage_data: vec![states::combo_melee::Stage { - stage: 1, - base_damage: 100.0, - base_poise_damage: 100.0, - damage_increase: 100.0, - poise_damage_increase: 10.0, - knockback: 10.0, - range: 4.0, - angle: 30.0, - base_buildup_duration: Duration::from_millis(500), - base_swing_duration: Duration::from_millis(200), - hit_timing: 0.5, - base_recover_duration: Duration::from_millis(400), - forward_movement: 0.5, - damage_kind: DamageKind::Slashing, - damage_effect: None, - }], - initial_energy_gain: 0.0, - max_energy_gain: 100.0, - energy_increase: 20.0, - speed_increase: 0.05, - max_speed_increase: 0.8, - scales_from_combo: 2, - ori_modifier: 1.0, - ability_info: empty_ability_info(), - }, - exhausted: false, - stage: 1, - timer: Duration::default(), - stage_section: states::utils::StageSection::Action, - }), - &PreviousEntityState { - event: SfxEvent::Idle, - time: Instant::now(), - weapon_drawn: true, - }, - &inventory, - ); - - assert_ne!( - result, - SfxEvent::Attack( - CharacterAbilityType::ComboMelee(states::utils::StageSection::Action, 2), - ToolKind::Sword - ) - ); -} - fn empty_ability_info() -> states::utils::AbilityInfo { states::utils::AbilityInfo { tool: None, diff --git a/voxygen/src/audio/sfx/event_mapper/movement/tests.rs b/voxygen/src/audio/sfx/event_mapper/movement/tests.rs index 2e60775dc3..8c1c7de7b7 100644 --- a/voxygen/src/audio/sfx/event_mapper/movement/tests.rs +++ b/voxygen/src/audio/sfx/event_mapper/movement/tests.rs @@ -202,7 +202,6 @@ fn maps_roll() { was_wielded: true, prev_aimed_dir: None, is_sneaking: false, - was_combo: None, }), &PhysicsState { on_ground: Some(Block::empty()), diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index 4fccce9e88..c1b1dc29b2 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -71,13 +71,6 @@ //! ], //! threshold: 1.2, //! ), -//! // A multi-stage attack ability which depends on the weapon -//! Attack(ComboMelee(Swing, 1), Sword): ( -//! files: [ -//! "voxygen.audio.sfx.abilities.swing_sword", -//! ], -//! threshold: 0.5, -//! ), //! ``` mod event_mapper; diff --git a/voxygen/src/game_input.rs b/voxygen/src/game_input.rs index e84a93f88c..0a494a1b66 100644 --- a/voxygen/src/game_input.rs +++ b/voxygen/src/game_input.rs @@ -170,6 +170,8 @@ pub enum GameInput { MuteSfx, #[strum(serialize = "gameinput-muteambience")] MuteAmbience, + #[strum(serialize = "gameinput-togglewalk")] + ToggleWalk, } impl GameInput { diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 55b1647e2e..f25efa52ef 100755 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -342,6 +342,10 @@ widget_ids! { auto_walk_txt, auto_walk_bg, + // Walking speed indicator + walking_speed_txt, + walking_speed_bg, + // Temporal (fading) camera zoom lock indicator zoom_lock_txt, zoom_lock_bg, @@ -2149,6 +2153,7 @@ impl Hud { BlockInteraction::Mount => { let key = match block.get_sprite() { Some(SpriteKind::Helm) => "hud-steer", + Some(SpriteKind::Bed | SpriteKind::Bedroll | SpriteKind::BedrollSnow | SpriteKind::BedrollPirate) => "hud-lay", _ => "hud-sit", }; vec![(Some(GameInput::Mount), i18n.get_msg(key).to_string())] diff --git a/voxygen/src/hud/settings_window/gameplay.rs b/voxygen/src/hud/settings_window/gameplay.rs index 666f8ba573..d64d4614c6 100644 --- a/voxygen/src/hud/settings_window/gameplay.rs +++ b/voxygen/src/hud/settings_window/gameplay.rs @@ -31,6 +31,9 @@ widget_ids! { camera_clamp_slider, camera_clamp_label, camera_clamp_value, + walking_speed_slider, + walking_speed_label, + walking_speed_value, mouse_y_invert_button, mouse_y_invert_label, controller_y_invert_button, @@ -42,6 +45,8 @@ widget_ids! { free_look_behavior_list, auto_walk_behavior_text, auto_walk_behavior_list, + walking_speed_behavior_text, + walking_speed_behavior_list, camera_clamp_behavior_text, camera_clamp_behavior_list, zoom_lock_behavior_text, @@ -124,6 +129,7 @@ impl<'a> Widget for Gameplay<'a> { let display_pan = self.global_state.settings.gameplay.pan_sensitivity; let display_zoom = self.global_state.settings.gameplay.zoom_sensitivity; let display_clamp = self.global_state.settings.gameplay.camera_clamp_angle; + let display_walking_speed = self.global_state.settings.gameplay.walking_speed; // Mouse Pan Sensitivity Text::new( @@ -233,6 +239,38 @@ impl<'a> Widget for Gameplay<'a> { .color(TEXT_COLOR) .set(state.ids.camera_clamp_value, ui); + // Walking speed + Text::new(&self.localized_strings.get_msg("hud-settings-walking_speed")) + .down_from(state.ids.camera_clamp_slider, 10.0) + .font_size(self.fonts.cyri.scale(14)) + .font_id(self.fonts.cyri.conrod_id) + .color(TEXT_COLOR) + .set(state.ids.walking_speed_label, ui); + + if let Some(new_val) = ImageSlider::continuous( + display_walking_speed, + 0.0, + 1.0, + self.imgs.slider_indicator, + self.imgs.slider, + ) + .w_h(550.0, 22.0) + .down_from(state.ids.walking_speed_label, 10.0) + .track_breadth(30.0) + .slider_length(10.0) + .pad_track((5.0, 5.0)) + .set(state.ids.walking_speed_slider, ui) + { + events.push(AdjustWalkingSpeed(new_val)); + } + + Text::new(&format!("{:.2}", display_walking_speed)) + .right_from(state.ids.walking_speed_slider, 8.0) + .font_size(self.fonts.cyri.scale(14)) + .font_id(self.fonts.cyri.conrod_id) + .color(TEXT_COLOR) + .set(state.ids.walking_speed_value, ui); + // Zoom Inversion let zoom_inverted = ToggleButton::new( self.global_state.settings.gameplay.zoom_inversion, @@ -240,7 +278,7 @@ impl<'a> Widget for Gameplay<'a> { self.imgs.checkbox_checked, ) .w_h(18.0, 18.0) - .down_from(state.ids.camera_clamp_slider, 20.0) + .down_from(state.ids.walking_speed_slider, 20.0) .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo) .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked) .set(state.ids.mouse_zoom_invert_button, ui); @@ -420,13 +458,43 @@ impl<'a> Widget for Gameplay<'a> { } } + // Walking speed behavior + Text::new( + &self + .localized_strings + .get_msg("hud-settings-walking_speed_behavior"), + ) + .down_from(state.ids.free_look_behavior_list, 10.0) + .font_size(self.fonts.cyri.scale(14)) + .font_id(self.fonts.cyri.conrod_id) + .color(TEXT_COLOR) + .set(state.ids.walking_speed_behavior_text, ui); + + let walking_speed_selected = + self.global_state.settings.gameplay.walking_speed_behavior as usize; + + if let Some(clicked) = DropDownList::new(&mode_label_list, Some(walking_speed_selected)) + .w_h(200.0, 30.0) + .color(MENU_BG) + .label_color(TEXT_COLOR) + .label_font_id(self.fonts.cyri.conrod_id) + .down_from(state.ids.walking_speed_behavior_text, 8.0) + .set(state.ids.walking_speed_behavior_list, ui) + { + match clicked { + 0 => events.push(ChangeWalkingSpeedBehavior(PressBehavior::Toggle)), + 1 => events.push(ChangeWalkingSpeedBehavior(PressBehavior::Hold)), + _ => unreachable!(), + } + } + // Camera clamp behavior Text::new( &self .localized_strings .get_msg("hud-settings-camera_clamp_behavior"), ) - .down_from(state.ids.free_look_behavior_list, 10.0) + .down_from(state.ids.auto_walk_behavior_list, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) @@ -545,7 +613,7 @@ impl<'a> Widget for Gameplay<'a> { .localized_strings .get_msg("hud-settings-zoom_lock_behavior"), ) - .down_from(state.ids.auto_walk_behavior_list, 10.0) + .down_from(state.ids.walking_speed_behavior_list, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) @@ -599,7 +667,7 @@ impl<'a> Widget for Gameplay<'a> { .w_h(RESET_BUTTONS_WIDTH, RESET_BUTTONS_HEIGHT) .hover_image(self.imgs.button_hover) .press_image(self.imgs.button_press) - .down_from(state.ids.camera_clamp_behavior_list, 12.0) + .down_from(state.ids.zoom_lock_behavior_list, 12.0) .label( &self .localized_strings diff --git a/voxygen/src/hud/util.rs b/voxygen/src/hud/util.rs index bd73551ff2..63c655805e 100644 --- a/voxygen/src/hud/util.rs +++ b/voxygen/src/hud/util.rs @@ -417,6 +417,7 @@ pub fn ability_image(imgs: &img_ids::Imgs, ability_id: &str) -> image::Id { "veloren.core.pseudo_abilities.sword.secondary_ability" => imgs.sword_secondary_ability, "common.abilities.sword.basic_thrust" => imgs.sword_basic_thrust, "common.abilities.sword.heavy_slam" => imgs.sword_heavy_slam, + "common.abilities.sword.agile_perforate" => imgs.sword_agile_perforate, "common.abilities.sword.agile_dual_perforate" => imgs.sword_agile_perforate, "common.abilities.sword.defensive_vital_jab" => imgs.sword_defensive_vital_jab, "common.abilities.sword.crippling_deep_rend" => imgs.sword_crippling_deep_rend, diff --git a/voxygen/src/key_state.rs b/voxygen/src/key_state.rs index 0b9dfc155d..9d517e5131 100644 --- a/voxygen/src/key_state.rs +++ b/voxygen/src/key_state.rs @@ -11,6 +11,7 @@ pub struct KeyState { pub swim_down: bool, pub fly: bool, pub auto_walk: bool, + pub speed_mul: f32, pub trade: bool, pub analog_matrix: Vec2, } @@ -28,6 +29,7 @@ impl Default for KeyState { swim_down: false, fly: false, auto_walk: false, + speed_mul: 1.0, trade: false, analog_matrix: Vec2::zero(), } @@ -42,9 +44,11 @@ impl KeyState { if self.up || self.auto_walk { 1.0 } else { 0.0 } + if self.down { -1.0 } else { 0.0 }, ) + .try_normalized() + .unwrap_or_default() } else { self.analog_matrix - }; + } * self.speed_mul; if dir.magnitude_squared() <= 1.0 { dir diff --git a/voxygen/src/menu/main/ui/mod.rs b/voxygen/src/menu/main/ui/mod.rs index cf83b03dd3..ff5181d575 100644 --- a/voxygen/src/menu/main/ui/mod.rs +++ b/voxygen/src/menu/main/ui/mod.rs @@ -92,6 +92,7 @@ const BG_IMGS: [&str; 14] = [ pub enum WorldChange { Name(String), Seed(u32), + DayLength(f64), SizeX(u32), SizeY(u32), Scale(f64), @@ -108,6 +109,7 @@ impl WorldChange { match self { WorldChange::Name(name) => world.name = name, WorldChange::Seed(seed) => world.seed = seed, + WorldChange::DayLength(d) => world.day_length = d, WorldChange::SizeX(s) => gen_opts.x_lg = s, WorldChange::SizeY(s) => gen_opts.y_lg = s, WorldChange::Scale(scale) => gen_opts.scale = scale, diff --git a/voxygen/src/menu/main/ui/world_selector.rs b/voxygen/src/menu/main/ui/world_selector.rs index 1bff0c83db..1e4c36f19b 100644 --- a/voxygen/src/menu/main/ui/world_selector.rs +++ b/voxygen/src/menu/main/ui/world_selector.rs @@ -47,6 +47,7 @@ pub struct Screen { world_name: text_input::State, map_seed: text_input::State, + day_length: slider::State, random_seed_button: button::State, world_size_x: slider::State, world_size_y: slider::State, @@ -196,6 +197,9 @@ impl Screen { const SLIDER_BAR_PAD: u16 = 0; // Height of interactable area const SLIDER_HEIGHT: u16 = 30; + // Day length slider values + pub const DAY_LENGTH_MIN: f64 = 10.0; + pub const DAY_LENGTH_MAX: f64 = 60.0; let mut gen_content = vec![ BackgroundContainer::new( @@ -288,6 +292,42 @@ impl Screen { gen_content.push(Row::with_children(seed_content).into()); if let Some(gen_opts) = world.gen_opts.as_ref() { + // Day length setting label + gen_content.push( + Text::new(format!( + "{}: {}", + i18n.get_msg("main-singleplayer-day_length"), + world.day_length + )) + .size(SLIDER_TEXT_SIZE) + .horizontal_alignment(iced::HorizontalAlignment::Center) + .into(), + ); + + // Day length setting slider + if can_edit { + gen_content.push( + Row::with_children(vec![ + Slider::new( + &mut self.day_length, + DAY_LENGTH_MIN..=DAY_LENGTH_MAX, + world.day_length, + move |d| message(WorldChange::DayLength(d)), + ) + .height(SLIDER_HEIGHT) + .style(style::slider::Style::images( + imgs.slider_indicator, + imgs.slider_range, + SLIDER_BAR_PAD, + SLIDER_CURSOR_SIZE, + SLIDER_BAR_HEIGHT, + )) + .into(), + ]) + .into(), + ) + } + gen_content.push( Text::new(format!( "{}: x: {}, y: {}", diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 87ac68791f..c91ab2b3a7 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -1451,7 +1451,7 @@ impl Renderer { /// Queue to obtain a screenshot on the next frame render pub fn create_screenshot( &mut self, - screenshot_handler: impl FnOnce(Result) + Send + 'static, + screenshot_handler: impl FnOnce(Result) + Send + 'static, ) { // Queue screenshot self.take_screenshot = Some(Box::new(screenshot_handler)); diff --git a/voxygen/src/render/renderer/screenshot.rs b/voxygen/src/render/renderer/screenshot.rs index 672c1056d8..c5c73c833a 100644 --- a/voxygen/src/render/renderer/screenshot.rs +++ b/voxygen/src/render/renderer/screenshot.rs @@ -1,7 +1,8 @@ use super::super::pipelines::blit; +use common_base::prof_span; use tracing::error; -pub type ScreenshotFn = Box) + Send>; +pub type ScreenshotFn = Box) + Send>; pub struct TakeScreenshot { bind_group: blit::BindGroup, @@ -132,6 +133,7 @@ impl TakeScreenshot { } fn download_and_handle_internal(self) { + prof_span!("download_and_handle_internal"); // Calculate padded bytes per row let padded_bytes_per_row = padded_bytes_per_row(self.width, self.bytes_per_pixel); let singlethread_rt = match tokio::runtime::Builder::new_current_thread().build() { @@ -145,21 +147,19 @@ impl TakeScreenshot { // Map buffer let buffer_slice = self.buffer.slice(..); let buffer_map_future = buffer_slice.map_async(wgpu::MapMode::Read); + let padded_buffer; // Wait on buffer mapping - let mut pixel_bytes = match singlethread_rt.block_on(buffer_map_future) { + let rows = match singlethread_rt.block_on(buffer_map_future) { // Buffer is mapped and we can read it Ok(()) => { // Copy to a Vec - let padded_buffer = buffer_slice.get_mapped_range(); - let mut pixel_bytes = Vec::new(); + padded_buffer = buffer_slice.get_mapped_range(); padded_buffer .chunks(padded_bytes_per_row as usize) .map(|padded_chunk| { &padded_chunk[..self.width as usize * self.bytes_per_pixel as usize] }) - .for_each(|row| pixel_bytes.extend_from_slice(row)); - pixel_bytes }, // Error Err(err) => { @@ -171,36 +171,54 @@ impl TakeScreenshot { }, }; + // Note: we don't use bytes_per_pixel here since we expect only certain formats + // below. + let bytes_per_rgb = 3; + let mut pixel_bytes = + Vec::with_capacity(self.width as usize * self.height as usize * bytes_per_rgb); // Construct image let image = match self.tex_format { wgpu::TextureFormat::Bgra8UnormSrgb => { - let (pixels, rest) = pixel_bytes.as_chunks_mut(); - assert!( - rest.is_empty(), - "Always valid because each pixel uses four bytes" - ); - // Swap blue and red components to get a RGBA texture. - for [b, _g, r, _a] in pixels { - std::mem::swap(b, r); - } + prof_span!("copy image"); + rows.for_each(|row| { + let (pixels, rest) = row.as_chunks(); + assert!( + rest.is_empty(), + "Always valid because each pixel uses four bytes" + ); + // Swap blue and red components and drop alpha to get a RGB texture. + for &[b, g, r, _a] in pixels { + pixel_bytes.extend_from_slice(&[r, g, b]) + } + }); + + Ok(pixel_bytes) + }, + wgpu::TextureFormat::Rgba8UnormSrgb => { + prof_span!("copy image"); + rows.for_each(|row| { + let (pixels, rest) = row.as_chunks(); + assert!( + rest.is_empty(), + "Always valid because each pixel uses four bytes" + ); + // Drop alpha to get a RGB texture. + for &[r, g, b, _a] in pixels { + pixel_bytes.extend_from_slice(&[r, g, b]) + } + }); + Ok(pixel_bytes) }, - wgpu::TextureFormat::Rgba8UnormSrgb => Ok(pixel_bytes), format => Err(format!( "Unhandled format for screenshot texture: {:?}", format, )), } .map(|pixel_bytes| { - let image = image::ImageBuffer::, Vec>::from_vec( - self.width, - self.height, - pixel_bytes, - ) - .expect( + image::RgbImage::from_vec(self.width, self.height, pixel_bytes).expect( "Failed to create ImageBuffer! Buffer was not large enough. This should not occur", - ); - image::DynamicImage::ImageRgba8(image) + ) }); // Call supplied handler diff --git a/voxygen/src/scene/figure/load.rs b/voxygen/src/scene/figure/load.rs index 7ff430d1b2..b80b733035 100644 --- a/voxygen/src/scene/figure/load.rs +++ b/voxygen/src/scene/figure/load.rs @@ -9,6 +9,7 @@ use common::{ biped_small, bird_large::{self, BodyType as BLABodyType, Species as BLASpecies}, bird_medium::{self, BodyType as BMBodyType, Species as BMSpecies}, + crustacean::{self, BodyType as CBodyType, Species as CSpecies}, dragon::{self, BodyType as DBodyType, Species as DSpecies}, fish_medium::{self, BodyType as FMBodyType, Species as FMSpecies}, fish_small::{self, BodyType as FSBodyType, Species as FSSpecies}, @@ -2688,6 +2689,385 @@ impl ArthropodLateralSpec { } } ////// +#[derive(Deserialize)] +struct CrustaceanCentralSpec(HashMap<(CSpecies, CBodyType), CrustCentralVoxSpec>); +impl_concatenate_for_wrapper!(CrustaceanCentralSpec); + +#[derive(Deserialize)] +struct CrustCentralVoxSpec { + chest: CrustaceanCentralSubSpec, + tail_f: CrustaceanCentralSubSpec, + tail_b: CrustaceanCentralSubSpec, +} +#[derive(Deserialize)] +struct CrustaceanCentralSubSpec { + offset: [f32; 3], // Should be relative to initial origin + central: VoxSimple, + #[serde(default)] + model_index: u32, +} +#[derive(Deserialize)] +struct CrustaceanLateralSpec(HashMap<(CSpecies, CBodyType), CrustLateralVoxSpec>); +impl_concatenate_for_wrapper!(CrustaceanLateralSpec); + +#[derive(Deserialize)] +struct CrustLateralVoxSpec { + arm_l: CrustaceanLateralSubSpec, + pincer_l0: CrustaceanLateralSubSpec, + pincer_l1: CrustaceanLateralSubSpec, + arm_r: CrustaceanLateralSubSpec, + pincer_r0: CrustaceanLateralSubSpec, + pincer_r1: CrustaceanLateralSubSpec, + leg_fl: CrustaceanLateralSubSpec, + leg_cl: CrustaceanLateralSubSpec, + leg_bl: CrustaceanLateralSubSpec, + leg_fr: CrustaceanLateralSubSpec, + leg_cr: CrustaceanLateralSubSpec, + leg_br: CrustaceanLateralSubSpec, +} +#[derive(Deserialize)] +struct CrustaceanLateralSubSpec { + offset: [f32; 3], // Should be relative to initial origin + lateral: VoxSimple, + #[serde(default)] + model_index: u32, +} +make_vox_spec!( + crustacean::Body, + struct CrustaceanSpec { + central: CrustaceanCentralSpec = "voxygen.voxel.crustacean_central_manifest", + lateral: CrustaceanLateralSpec = "voxygen.voxel.crustacean_lateral_manifest", + }, + |FigureKey { body, extra, .. }, spec| { + let third_person = extra.as_ref().and_then(|loadout| loadout.third_person.as_ref()); + + [ + third_person.map(|_| { + spec.central.read().0.mesh_chest( + body.species, + body.body_type, + ) + }), + Some(spec.central.read().0.mesh_tail_f( + body.species, + body.body_type, + )), + Some(spec.central.read().0.mesh_tail_b( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_arm_l( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_pincer_l0( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_pincer_l1( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_arm_r( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_pincer_r0( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_pincer_r1( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_leg_fl( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_leg_cl( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_leg_bl( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_leg_fr( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_leg_cr( + body.species, + body.body_type, + )), + Some(spec.lateral.read().0.mesh_leg_br( + body.species, + body.body_type, + )), + None, + ] + }, +); + +impl CrustaceanCentralSpec { + fn mesh_chest(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No chest specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let central = graceful_load_segment(&spec.chest.central.0, spec.chest.model_index); + + (central, Vec3::from(spec.chest.offset)) + } + + fn mesh_tail_f(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No front tail specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let central = graceful_load_segment(&spec.tail_f.central.0, spec.tail_f.model_index); + + (central, Vec3::from(spec.tail_f.offset)) + } + + fn mesh_tail_b(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No back tail specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let central = graceful_load_segment(&spec.tail_b.central.0, spec.tail_b.model_index); + + (central, Vec3::from(spec.tail_b.offset)) + } +} +impl CrustaceanLateralSpec { + fn mesh_arm_l(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No left arm specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = + graceful_load_segment_flipped(&spec.arm_l.lateral.0, true, spec.arm_l.model_index); + + (lateral, Vec3::from(spec.arm_l.offset)) + } + + fn mesh_pincer_l0(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No left major pincer specification exists for the combination of {:?} and \ + {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment_flipped( + &spec.pincer_l0.lateral.0, + true, + spec.pincer_l0.model_index, + ); + + (lateral, Vec3::from(spec.pincer_l0.offset)) + } + + fn mesh_pincer_l1(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No left minor pincer specification exists for the combination of {:?} and \ + {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment_flipped( + &spec.pincer_l1.lateral.0, + true, + spec.pincer_l1.model_index, + ); + + (lateral, Vec3::from(spec.pincer_l1.offset)) + } + + fn mesh_arm_r(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No right arm specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment(&spec.arm_r.lateral.0, spec.arm_r.model_index); + + (lateral, Vec3::from(spec.arm_r.offset)) + } + + fn mesh_pincer_r0(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No right major pincer specification exists for the combination of {:?} and \ + {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment(&spec.pincer_r0.lateral.0, spec.pincer_r0.model_index); + + (lateral, Vec3::from(spec.pincer_r0.offset)) + } + + fn mesh_pincer_r1(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No right minor pincer specification exists for the combination of {:?} and \ + {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment(&spec.pincer_r1.lateral.0, spec.pincer_r1.model_index); + + (lateral, Vec3::from(spec.pincer_r1.offset)) + } + + fn mesh_leg_fl(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No front left leg specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = + graceful_load_segment_flipped(&spec.leg_fl.lateral.0, true, spec.leg_fl.model_index); + + (lateral, Vec3::from(spec.leg_fl.offset)) + } + + fn mesh_leg_cl(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No center left leg specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = + graceful_load_segment_flipped(&spec.leg_cl.lateral.0, true, spec.leg_cl.model_index); + + (lateral, Vec3::from(spec.leg_cl.offset)) + } + + fn mesh_leg_bl(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No back left leg specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = + graceful_load_segment_flipped(&spec.leg_bl.lateral.0, true, spec.leg_bl.model_index); + + (lateral, Vec3::from(spec.leg_bl.offset)) + } + + fn mesh_leg_fr(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No front right leg specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment(&spec.leg_fr.lateral.0, spec.leg_fr.model_index); + + (lateral, Vec3::from(spec.leg_fr.offset)) + } + + fn mesh_leg_cr(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No center right leg specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment(&spec.leg_cr.lateral.0, spec.leg_cr.model_index); + + (lateral, Vec3::from(spec.leg_cr.offset)) + } + + fn mesh_leg_br(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No back right leg specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5)); + }, + }; + let lateral = graceful_load_segment(&spec.leg_br.lateral.0, spec.leg_br.model_index); + + (lateral, Vec3::from(spec.leg_br.offset)) + } +} + #[derive(Deserialize)] struct FishMediumCentralSpec(HashMap<(FMSpecies, FMBodyType), SidedFMCentralVoxSpec>); impl_concatenate_for_wrapper!(FishMediumCentralSpec); diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 84f2d9d753..3683843c6b 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -28,11 +28,11 @@ use crate::{ use anim::{ arthropod::ArthropodSkeleton, biped_large::BipedLargeSkeleton, biped_small::BipedSmallSkeleton, bird_large::BirdLargeSkeleton, bird_medium::BirdMediumSkeleton, character::CharacterSkeleton, - dragon::DragonSkeleton, fish_medium::FishMediumSkeleton, fish_small::FishSmallSkeleton, - golem::GolemSkeleton, item_drop::ItemDropSkeleton, object::ObjectSkeleton, - quadruped_low::QuadrupedLowSkeleton, quadruped_medium::QuadrupedMediumSkeleton, - quadruped_small::QuadrupedSmallSkeleton, ship::ShipSkeleton, theropod::TheropodSkeleton, - Animation, Skeleton, + crustacean::CrustaceanSkeleton, dragon::DragonSkeleton, fish_medium::FishMediumSkeleton, + fish_small::FishSmallSkeleton, golem::GolemSkeleton, item_drop::ItemDropSkeleton, + object::ObjectSkeleton, quadruped_low::QuadrupedLowSkeleton, + quadruped_medium::QuadrupedMediumSkeleton, quadruped_small::QuadrupedSmallSkeleton, + ship::ShipSkeleton, theropod::TheropodSkeleton, Animation, Skeleton, }; use common::{ comp::{ @@ -213,6 +213,7 @@ struct FigureMgrStates { ship_states: HashMap>, volume_states: HashMap>, arthropod_states: HashMap>, + crustacean_states: HashMap>, } impl FigureMgrStates { @@ -236,6 +237,7 @@ impl FigureMgrStates { ship_states: HashMap::new(), volume_states: HashMap::new(), arthropod_states: HashMap::new(), + crustacean_states: HashMap::new(), } } @@ -311,6 +313,10 @@ impl FigureMgrStates { .arthropod_states .get_mut(entity) .map(DerefMut::deref_mut), + Body::Crustacean(_) => self + .crustacean_states + .get_mut(entity) + .map(DerefMut::deref_mut), } } @@ -345,6 +351,7 @@ impl FigureMgrStates { } }, Body::Arthropod(_) => self.arthropod_states.remove(entity).map(|e| e.meta), + Body::Crustacean(_) => self.crustacean_states.remove(entity).map(|e| e.meta), } } @@ -368,6 +375,7 @@ impl FigureMgrStates { self.ship_states.retain(|k, v| f(k, &mut *v)); self.volume_states.retain(|k, v| f(k, &mut *v)); self.arthropod_states.retain(|k, v| f(k, &mut *v)); + self.crustacean_states.retain(|k, v| f(k, &mut *v)); } fn count(&self) -> usize { @@ -390,6 +398,7 @@ impl FigureMgrStates { + self.ship_states.len() + self.volume_states.len() + self.arthropod_states.len() + + self.crustacean_states.len() } fn count_visible(&self) -> usize { @@ -472,6 +481,11 @@ impl FigureMgrStates { .iter() .filter(|(_, c)| c.visible()) .count() + + self + .crustacean_states + .iter() + .filter(|(_, c)| c.visible()) + .count() + self.ship_states.iter().filter(|(_, c)| c.visible()).count() + self .volume_states @@ -524,6 +538,7 @@ pub struct FigureMgr { golem_model_cache: FigureModelCache, volume_model_cache: FigureModelCache, arthropod_model_cache: FigureModelCache, + crustacean_model_cache: FigureModelCache, states: FigureMgrStates, } @@ -549,6 +564,7 @@ impl FigureMgr { golem_model_cache: FigureModelCache::new(), volume_model_cache: FigureModelCache::new(), arthropod_model_cache: FigureModelCache::new(), + crustacean_model_cache: FigureModelCache::new(), states: FigureMgrStates::default(), } } @@ -574,6 +590,7 @@ impl FigureMgr { || self.golem_model_cache.watcher_reloaded() || self.volume_model_cache.watcher_reloaded() || self.arthropod_model_cache.watcher_reloaded() + || self.crustacean_model_cache.watcher_reloaded() } pub fn clean(&mut self, tick: u64) { @@ -600,6 +617,7 @@ impl FigureMgr { self.golem_model_cache.clear_models(); self.volume_model_cache.clear_models(); self.arthropod_model_cache.clear_models(); + self.crustacean_model_cache.clear_models(); } self.model_cache.clean(&mut self.atlas, tick); @@ -622,6 +640,7 @@ impl FigureMgr { self.golem_model_cache.clean(&mut self.atlas, tick); self.volume_model_cache.clean(&mut self.atlas, tick); self.arthropod_model_cache.clean(&mut self.atlas, tick); + self.crustacean_model_cache.clean(&mut self.atlas, tick); } pub fn update_lighting(&mut self, scene_data: &SceneData) { @@ -1110,7 +1129,10 @@ impl FigureMgr { && matches!(active_tool_hand, Some(Hands::One))) || !character.map_or(false, |c| c.is_wield())) && !character.map_or(false, |c| c.is_using_hands()) - && physics.in_liquid().is_none(); + && physics.in_liquid().is_none() + && is_volume_rider.map_or(true, |volume_rider| { + !matches!(volume_rider.block.get_sprite(), Some(SpriteKind::Helm)) + }); let back_carry_offset = inventory .and_then(|i| i.equipped(EquipSlot::Armor(ArmorSlot::Back))) @@ -1813,7 +1835,7 @@ impl FigureMgr { skeleton_attr, ) }, - CharacterState::ComboMelee(s) => { + CharacterState::ComboMeleeDeprecated(s) => { let stage_index = (s.stage - 1) as usize; let stage_time = s.timer.as_secs_f32(); let stage_progress = @@ -2137,7 +2159,26 @@ impl FigureMgr { { match sprite { SpriteKind::Helm => { - anim::character::DanceAnimation::update_skeleton( + anim::character::SteerAnimation::update_skeleton( + &target_base, + ( + active_tool_kind, + second_tool_kind, + character_activity + .map(|a| a.steer_dir) + .unwrap_or(0.0), + time, + ), + state.state_time, + &mut state_animation_rate, + skeleton_attr, + ) + }, + SpriteKind::Bed + | SpriteKind::Bedroll + | SpriteKind::BedrollSnow + | SpriteKind::BedrollPirate => { + anim::character::SleepAnimation::update_skeleton( &target_base, (active_tool_kind, second_tool_kind, time), state.state_time, @@ -2272,40 +2313,29 @@ impl FigureMgr { ), }; let target_bones = match &character { - CharacterState::ComboMelee(s) => { - let stage_index = (s.stage - 1) as usize; + CharacterState::BasicMelee(s) => { let stage_time = s.timer.as_secs_f32(); - let stage_progress = - if let Some(stage) = s.static_data.stage_data.get(stage_index) { - match s.stage_section { - StageSection::Buildup => { - stage_time / stage.base_buildup_duration.as_secs_f32() - }, - StageSection::Action => { - stage_time / stage.base_swing_duration.as_secs_f32() - }, - StageSection::Recover => { - stage_time / stage.base_recover_duration.as_secs_f32() - }, - _ => 0.0, - } - } else { - 0.0 - }; - { - anim::quadruped_small::AlphaAnimation::update_skeleton( - &target_base, - ( - rel_vel.magnitude(), - time, - Some(s.stage_section), - state.state_time, - ), - stage_progress, - &mut state_animation_rate, - skeleton_attr, - ) - } + + let stage_progress = match s.stage_section { + StageSection::Buildup => { + stage_time / s.static_data.buildup_duration.as_secs_f32() + }, + StageSection::Action => { + stage_time / s.static_data.swing_duration.as_secs_f32() + }, + StageSection::Recover => { + stage_time / s.static_data.recover_duration.as_secs_f32() + }, + + _ => 0.0, + }; + anim::quadruped_small::AlphaAnimation::update_skeleton( + &target_base, + (time, s.stage_section, state.state_time), + stage_progress, + &mut state_animation_rate, + skeleton_attr, + ) }, CharacterState::ComboMelee2(s) => { let timer = s.timer.as_secs_f32(); @@ -2634,65 +2664,6 @@ impl FigureMgr { skeleton_attr, ) }, - CharacterState::ComboMelee(s) => { - let stage_index = (s.stage - 1) as usize; - let stage_time = s.timer.as_secs_f32(); - let stage_progress = - if let Some(stage) = s.static_data.stage_data.get(stage_index) { - match s.stage_section { - StageSection::Buildup => { - stage_time / stage.base_buildup_duration.as_secs_f32() - }, - StageSection::Action => { - stage_time / stage.base_swing_duration.as_secs_f32() - }, - StageSection::Recover => { - stage_time / stage.base_recover_duration.as_secs_f32() - }, - _ => 0.0, - } - } else { - 0.0 - }; - match s.stage { - 1 => anim::quadruped_medium::AlphaAnimation::update_skeleton( - &target_base, - ( - rel_vel.magnitude(), - time, - Some(s.stage_section), - state.state_time, - ), - stage_progress, - &mut state_animation_rate, - skeleton_attr, - ), - 2 => anim::quadruped_medium::BetaAnimation::update_skeleton( - &target_base, - ( - rel_vel.magnitude(), - time, - Some(s.stage_section), - state.state_time, - ), - stage_progress, - &mut state_animation_rate, - skeleton_attr, - ), - _ => anim::quadruped_medium::AlphaAnimation::update_skeleton( - &target_base, - ( - rel_vel.magnitude(), - time, - Some(s.stage_section), - state.state_time, - ), - stage_progress, - &mut state_animation_rate, - skeleton_attr, - ), - } - }, CharacterState::ComboMelee2(s) => { let timer = s.timer.as_secs_f32(); let current_strike = s.completed_strikes % s.static_data.strikes.len(); @@ -2714,9 +2685,9 @@ impl FigureMgr { &target_base, ( ability_id, - Some(s.stage_section), - Some(s.static_data.ability_info), + s.stage_section, current_strike, + rel_vel.magnitude(), time, state.state_time, ), @@ -2987,12 +2958,7 @@ impl FigureMgr { }; anim::quadruped_low::BetaAnimation::update_skeleton( &target_base, - ( - rel_vel.magnitude(), - time, - Some(s.stage_section), - state.state_time, - ), + (rel_vel.magnitude(), time, s.stage_section, state.state_time), stage_progress, &mut state_animation_rate, skeleton_attr, @@ -3100,8 +3066,7 @@ impl FigureMgr { &target_base, ( ability_id, - Some(s.stage_section), - Some(s.static_data.ability_info), + s.stage_section, current_strike, time, state.state_time, @@ -3111,65 +3076,6 @@ impl FigureMgr { skeleton_attr, ) }, - CharacterState::ComboMelee(s) => { - let stage_index = (s.stage - 1) as usize; - let stage_time = s.timer.as_secs_f32(); - let stage_progress = - if let Some(stage) = s.static_data.stage_data.get(stage_index) { - match s.stage_section { - StageSection::Buildup => { - stage_time / stage.base_buildup_duration.as_secs_f32() - }, - StageSection::Action => { - stage_time / stage.base_swing_duration.as_secs_f32() - }, - StageSection::Recover => { - stage_time / stage.base_recover_duration.as_secs_f32() - }, - _ => 0.0, - } - } else { - 0.0 - }; - match s.stage { - 1 => anim::quadruped_low::AlphaAnimation::update_skeleton( - &target_base, - ( - rel_vel.magnitude(), - time, - Some(s.stage_section), - state.state_time, - ), - stage_progress, - &mut state_animation_rate, - skeleton_attr, - ), - 2 => anim::quadruped_low::BetaAnimation::update_skeleton( - &target_base, - ( - rel_vel.magnitude(), - time, - Some(s.stage_section), - state.state_time, - ), - stage_progress, - &mut state_animation_rate, - skeleton_attr, - ), - _ => anim::quadruped_low::AlphaAnimation::update_skeleton( - &target_base, - ( - rel_vel.magnitude(), - time, - Some(s.stage_section), - state.state_time, - ), - stage_progress, - &mut state_animation_rate, - skeleton_attr, - ), - } - }, CharacterState::BasicBeam(s) => { let stage_time = s.timer.as_secs_f32(); let stage_progress = match s.stage_section { @@ -3376,27 +3282,20 @@ impl FigureMgr { skeleton_attr, ) }, - CharacterState::ComboMelee(s) => { - let stage_index = (s.stage - 1) as usize; + CharacterState::BasicMelee(s) => { let stage_time = s.timer.as_secs_f32(); - let stage_progress = - if let Some(stage) = s.static_data.stage_data.get(stage_index) { - match s.stage_section { - StageSection::Buildup => { - stage_time / stage.base_buildup_duration.as_secs_f32() - }, - StageSection::Action => { - stage_time / stage.base_swing_duration.as_secs_f32() - }, - StageSection::Recover => { - stage_time / stage.base_recover_duration.as_secs_f32() - }, - _ => 0.0, - } - } else { - 0.0 - }; - + let stage_progress = match s.stage_section { + StageSection::Buildup => { + stage_time / s.static_data.buildup_duration.as_secs_f32() + }, + StageSection::Action => { + stage_time / s.static_data.swing_duration.as_secs_f32() + }, + StageSection::Recover => { + stage_time / s.static_data.recover_duration.as_secs_f32() + }, + _ => 0.0, + }; anim::bird_medium::AlphaAnimation::update_skeleton( &target_base, ( @@ -3837,10 +3736,11 @@ impl FigureMgr { &target_base, ( ability_id, - Some(s.stage_section), - Some(s.static_data.ability_info), + s.stage_section, current_strike, - move_dir, + rel_vel, + time, + state.state_time, ), progress, &mut state_animation_rate, @@ -4013,65 +3913,6 @@ impl FigureMgr { skeleton_attr, ) }, - CharacterState::ComboMelee(s) => { - let stage_index = (s.stage - 1) as usize; - let stage_time = s.timer.as_secs_f32(); - let stage_progress = - if let Some(stage) = s.static_data.stage_data.get(stage_index) { - match s.stage_section { - StageSection::Buildup => { - stage_time / stage.base_buildup_duration.as_secs_f32() - }, - StageSection::Action => { - stage_time / stage.base_swing_duration.as_secs_f32() - }, - StageSection::Recover => { - stage_time / stage.base_recover_duration.as_secs_f32() - }, - _ => 0.0, - } - } else { - 0.0 - }; - match s.stage { - 1 => anim::biped_small::AlphaAnimation::update_skeleton( - &target_base, - ( - ability_id, - active_tool_kind, - rel_vel, - ori * anim::vek::Vec3::::unit_y(), - state.last_ori * anim::vek::Vec3::::unit_y(), - time, - rel_avg_vel, - state.acc_vel, - Some(s.stage_section), - state.state_time, - ), - stage_progress, - &mut state_animation_rate, - skeleton_attr, - ), - _ => anim::biped_small::AlphaAnimation::update_skeleton( - &target_base, - ( - ability_id, - active_tool_kind, - rel_vel, - ori * anim::vek::Vec3::::unit_y(), - state.last_ori * anim::vek::Vec3::::unit_y(), - time, - rel_avg_vel, - state.acc_vel, - Some(s.stage_section), - state.state_time, - ), - stage_progress, - &mut state_animation_rate, - skeleton_attr, - ), - } - }, CharacterState::BasicMelee(s) => { let stage_time = s.timer.as_secs_f32(); let stage_progress = match s.stage_section { @@ -4390,52 +4231,36 @@ impl FigureMgr { ), }; let target_bones = match &character { - CharacterState::ComboMelee(s) => { - let stage_index = (s.stage - 1) as usize; - let stage_time = s.timer.as_secs_f32(); - let stage_progress = - if let Some(stage) = s.static_data.stage_data.get(stage_index) { - match s.stage_section { - StageSection::Buildup => { - stage_time / stage.base_buildup_duration.as_secs_f32() - }, - StageSection::Action => { - stage_time / stage.base_swing_duration.as_secs_f32() - }, - StageSection::Recover => { - stage_time / stage.base_recover_duration.as_secs_f32() - }, - _ => 0.0, - } - } else { - 0.0 - }; - match s.stage { - 1 => anim::theropod::AlphaAnimation::update_skeleton( - &target_base, - ( - rel_vel.magnitude(), - time, - Some(s.stage_section), - state.state_time, - ), - stage_progress, - &mut state_animation_rate, - skeleton_attr, + CharacterState::ComboMelee2(s) => { + let timer = s.timer.as_secs_f32(); + let current_strike = s.completed_strikes % s.static_data.strikes.len(); + let strike_data = s.static_data.strikes[current_strike]; + let progress = match s.stage_section { + StageSection::Buildup => { + timer / strike_data.buildup_duration.as_secs_f32() + }, + StageSection::Action => { + timer / strike_data.swing_duration.as_secs_f32() + }, + StageSection::Recover => { + timer / strike_data.recover_duration.as_secs_f32() + }, + _ => 0.0, + }; + + anim::theropod::ComboAnimation::update_skeleton( + &target_base, + ( + ability_id, + s.stage_section, + current_strike, + time, + state.state_time, ), - _ => anim::theropod::BetaAnimation::update_skeleton( - &target_base, - ( - rel_vel.magnitude(), - time, - Some(s.stage_section), - state.state_time, - ), - stage_progress, - &mut state_animation_rate, - skeleton_attr, - ), - } + progress, + &mut state_animation_rate, + skeleton_attr, + ) }, CharacterState::DashMelee(s) => { let stage_time = s.timer.as_secs_f32(); @@ -4569,52 +4394,36 @@ impl FigureMgr { ), }; let target_bones = match &character { - CharacterState::ComboMelee(s) => { - let stage_index = (s.stage - 1) as usize; - let stage_time = s.timer.as_secs_f32(); - let stage_progress = - if let Some(stage) = s.static_data.stage_data.get(stage_index) { - match s.stage_section { - StageSection::Buildup => { - stage_time / stage.base_buildup_duration.as_secs_f32() - }, - StageSection::Action => { - stage_time / stage.base_swing_duration.as_secs_f32() - }, - StageSection::Recover => { - stage_time / stage.base_recover_duration.as_secs_f32() - }, - _ => 0.0, - } - } else { - 0.0 - }; - match s.stage { - 1 => anim::arthropod::AlphaAnimation::update_skeleton( - &target_base, - ( - rel_vel.magnitude(), - time, - Some(s.stage_section), - state.state_time, - ), - stage_progress, - &mut state_animation_rate, - skeleton_attr, + CharacterState::ComboMelee2(s) => { + let timer = s.timer.as_secs_f32(); + let current_strike = s.completed_strikes % s.static_data.strikes.len(); + let strike_data = s.static_data.strikes[current_strike]; + let progress = match s.stage_section { + StageSection::Buildup => { + timer / strike_data.buildup_duration.as_secs_f32() + }, + StageSection::Action => { + timer / strike_data.swing_duration.as_secs_f32() + }, + StageSection::Recover => { + timer / strike_data.recover_duration.as_secs_f32() + }, + _ => 0.0, + }; + + anim::arthropod::ComboAnimation::update_skeleton( + &target_base, + ( + ability_id, + s.stage_section, + current_strike, + time, + state.state_time, ), - _ => anim::arthropod::AlphaAnimation::update_skeleton( - &target_base, - ( - rel_vel.magnitude(), - time, - Some(s.stage_section), - state.state_time, - ), - stage_progress, - &mut state_animation_rate, - skeleton_attr, - ), - } + progress, + &mut state_animation_rate, + skeleton_attr, + ) }, CharacterState::LeapMelee(s) => { let stage_time = s.timer.as_secs_f32(); @@ -4806,6 +4615,182 @@ impl FigureMgr { body, ); }, + Body::Crustacean(body) => { + let (model, skeleton_attr) = self.crustacean_model_cache.get_or_create_model( + renderer, + &mut self.atlas, + body, + inventory, + (), + tick, + viewpoint_camera_mode, + viewpoint_character_state, + &slow_jobs, + None, + ); + + let state = self + .states + .crustacean_states + .entry(entity) + .or_insert_with(|| { + FigureState::new(renderer, CrustaceanSkeleton::default(), body) + }); + + // Average velocity relative to the current ground + let rel_avg_vel = state.avg_vel - physics.ground_vel; + + let (character, last_character) = match (character, last_character) { + (Some(c), Some(l)) => (c, l), + _ => continue, + }; + + if !character.same_variant(&last_character.0) { + state.state_time = 0.0; + } + + let target_base = match ( + physics.on_ground.is_some(), + rel_vel.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving + physics.in_liquid().is_some(), // In water + ) { + // Standing + (true, false, false) => anim::crustacean::IdleAnimation::update_skeleton( + &CrustaceanSkeleton::default(), + time, + state.state_time, + &mut state_animation_rate, + skeleton_attr, + ), + // Running + (true, true, false) => anim::crustacean::RunAnimation::update_skeleton( + &CrustaceanSkeleton::default(), + ( + rel_vel, + // TODO: Update to use the quaternion. + ori * anim::vek::Vec3::::unit_y(), + state.last_ori * anim::vek::Vec3::::unit_y(), + time, + rel_avg_vel, + state.acc_vel, + ), + state.state_time, + &mut state_animation_rate, + skeleton_attr, + ), + // In air + (false, _, false) => anim::crustacean::JumpAnimation::update_skeleton( + &CrustaceanSkeleton::default(), + ( + rel_vel.magnitude(), + // TODO: Update to use the quaternion. + ori * anim::vek::Vec3::::unit_y(), + state.last_ori * anim::vek::Vec3::::unit_y(), + time, + rel_avg_vel, + ), + state.state_time, + &mut state_animation_rate, + skeleton_attr, + ), + //Swimming + (_, _, true) => anim::crustacean::SwimAnimation::update_skeleton( + &CrustaceanSkeleton::default(), + ( + rel_vel, + // TODO: Update to use the quaternion. + ori * anim::vek::Vec3::::unit_y(), + state.last_ori * anim::vek::Vec3::::unit_y(), + time, + rel_avg_vel, + state.acc_vel, + ), + state.state_time, + &mut state_animation_rate, + skeleton_attr, + ), + }; + let target_bones = match &character { + CharacterState::ComboMelee2(s) => { + let timer = s.timer.as_secs_f32(); + let current_strike = s.completed_strikes % s.static_data.strikes.len(); + let strike_data = s.static_data.strikes[current_strike]; + let progress = match s.stage_section { + StageSection::Buildup => { + timer / strike_data.buildup_duration.as_secs_f32() + }, + StageSection::Action => { + timer / strike_data.swing_duration.as_secs_f32() + }, + StageSection::Recover => { + timer / strike_data.recover_duration.as_secs_f32() + }, + _ => 0.0, + }; + + anim::crustacean::ComboAnimation::update_skeleton( + &target_base, + ( + ability_id, + Some(s.stage_section), + Some(s.static_data.ability_info), + current_strike, + time, + rel_avg_vel, + state.state_time, + ), + progress, + &mut state_animation_rate, + skeleton_attr, + ) + }, + CharacterState::Stunned(s) => { + let stage_time = s.timer.as_secs_f32(); + let stage_progress = match s.stage_section { + StageSection::Buildup => { + stage_time / s.static_data.buildup_duration.as_secs_f32() + }, + StageSection::Recover => { + stage_time / s.static_data.recover_duration.as_secs_f32() + }, + _ => 0.0, + }; + match s.static_data.poise_state { + PoiseState::Normal + | PoiseState::Interrupted + | PoiseState::Stunned + | PoiseState::Dazed + | PoiseState::KnockedDown => { + anim::crustacean::StunnedAnimation::update_skeleton( + &target_base, + ( + rel_vel.magnitude(), + time, + Some(s.stage_section), + state.state_time, + ), + stage_progress, + &mut state_animation_rate, + skeleton_attr, + ) + }, + } + }, + // TODO! + _ => target_base, + }; + + state.skeleton = Lerp::lerp(&state.skeleton, &target_bones, dt_lerp); + state.update( + renderer, + trail_mgr, + &mut update_buf, + &common_params, + state_animation_rate, + model, + body, + ); + }, Body::BirdLarge(body) => { let (model, skeleton_attr) = self.bird_large_model_cache.get_or_create_model( renderer, @@ -5516,6 +5501,8 @@ impl FigureMgr { Some(s.static_data.ability_info), current_strike, move_dir, + rel_vel, + state.acc_vel, ), progress, &mut state_animation_rate, @@ -5682,75 +5669,6 @@ impl FigureMgr { skeleton_attr, ) }, - CharacterState::ComboMelee(s) => { - let stage_index = (s.stage - 1) as usize; - let stage_time = s.timer.as_secs_f32(); - let stage_progress = - if let Some(stage) = s.static_data.stage_data.get(stage_index) { - match s.stage_section { - StageSection::Buildup => { - stage_time / stage.base_buildup_duration.as_secs_f32() - }, - StageSection::Action => { - stage_time / stage.base_swing_duration.as_secs_f32() - }, - StageSection::Recover => { - stage_time / stage.base_recover_duration.as_secs_f32() - }, - _ => 0.0, - } - } else { - 0.0 - }; - match s.stage { - 1 => anim::biped_large::AlphaAnimation::update_skeleton( - &target_base, - ( - active_tool_kind, - (second_tool_kind, second_tool_spec), - rel_vel, - time, - Some(s.stage_section), - state.acc_vel, - state.state_time, - ability_id, - ), - stage_progress, - &mut state_animation_rate, - skeleton_attr, - ), - 2 => anim::biped_large::BetaAnimation::update_skeleton( - &target_base, - ( - active_tool_kind, - (second_tool_kind, second_tool_spec), - rel_vel, - time, - Some(s.stage_section), - state.acc_vel, - ability_id, - ), - stage_progress, - &mut state_animation_rate, - skeleton_attr, - ), - _ => anim::biped_large::BetaAnimation::update_skeleton( - &target_base, - ( - active_tool_kind, - (second_tool_kind, second_tool_spec), - rel_vel, - time, - Some(s.stage_section), - state.acc_vel, - ability_id, - ), - stage_progress, - &mut state_animation_rate, - skeleton_attr, - ), - } - }, CharacterState::RapidMelee(s) => { let stage_time = s.timer.as_secs_f32(); let stage_progress = match s.stage_section { @@ -6071,35 +5989,6 @@ impl FigureMgr { ), }; let target_bones = match &character { - CharacterState::ComboMelee(s) => { - let stage_index = (s.stage - 1) as usize; - let stage_time = s.timer.as_secs_f32(); - let stage_progress = - if let Some(stage) = s.static_data.stage_data.get(stage_index) { - match s.stage_section { - StageSection::Buildup => { - stage_time / stage.base_buildup_duration.as_secs_f32() - }, - StageSection::Action => { - stage_time / stage.base_swing_duration.as_secs_f32() - }, - StageSection::Recover => { - stage_time / stage.base_recover_duration.as_secs_f32() - }, - _ => 0.0, - } - } else { - 0.0 - }; - - anim::golem::AlphaAnimation::update_skeleton( - &target_base, - (Some(s.stage_section), time, state.state_time, ability_id), - stage_progress, - &mut state_animation_rate, - skeleton_attr, - ) - }, CharacterState::BasicRanged(s) => { let stage_time = s.timer.as_secs_f32(); @@ -6854,6 +6743,7 @@ impl FigureMgr { golem_model_cache, volume_model_cache, arthropod_model_cache, + crustacean_model_cache, states: FigureMgrStates { character_states, @@ -6874,6 +6764,7 @@ impl FigureMgr { ship_states, volume_states, arthropod_states, + crustacean_states, }, } = self; let atlas = atlas_; @@ -7144,6 +7035,25 @@ impl FigureMgr { .map(ModelEntryRef::Figure), ) }), + Body::Crustacean(body) => crustacean_states + .get(&entity) + .filter(|state| filter_state(state)) + .map(move |state| { + ( + state.bound(), + crustacean_model_cache + .get_model( + atlas, + body, + inventory, + tick, + viewpoint_camera_mode, + character_state, + None, + ) + .map(ModelEntryRef::Figure), + ) + }), Body::Object(body) => object_states .get(&entity) .filter(|state| filter_state(state)) @@ -7400,6 +7310,11 @@ impl FigureMgr { .item_drop_states .get(&entity) .and_then(|state| state.viewpoint_offset), + Body::Crustacean(_) => self + .states + .crustacean_states + .get(&entity) + .and_then(|state| state.viewpoint_offset), }) .map(|viewpoint| viewpoint.into()) .unwrap_or_else(Vec3::zero) diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 7a7ebd0a00..91534ea01c 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -270,9 +270,18 @@ pub fn get_sprite_instances<'a, I: 'a>( .overflowing_add((wpos.x as u64).overflowing_mul(wpos.y as u64).0) .0; // Awful PRNG - let ori = (block.get_ori().unwrap_or((seed % 4) as u8 * 2)) & 0b111; + // % 4 is non uniform, take 7 and combine two lesser probable outcomes + let ori = (block.get_ori().unwrap_or((((seed % 7) + 1) / 2) as u8 * 2)) & 0b111; if !cfg.variations.is_empty() { - let variation = seed as usize % cfg.variations.len(); + // try to make the variation more uniform as the PRNG is highly unfair + let variation = match cfg.variations.len() { + 1 => 0, + 2 => (seed as usize % 4) / 3, + 3 => (seed as usize % 5) / 2, + // for four use a different seed than for ori to not have them match always + 4 => (((seed.overflowing_add(wpos.x as u64).0) as usize % 7) + 1) / 2, + _ => seed as usize % cfg.variations.len(), + }; let key = (sprite, variation); // NOTE: Safe because we called sprite_config_for already. diff --git a/voxygen/src/scene/terrain/watcher.rs b/voxygen/src/scene/terrain/watcher.rs index cfb9a8e338..0109c06715 100644 --- a/voxygen/src/scene/terrain/watcher.rs +++ b/voxygen/src/scene/terrain/watcher.rs @@ -207,7 +207,9 @@ impl BlocksOfInterest { ) .with_z(0.0), )), - Some(SpriteKind::Sign) => interactables.push((pos, Interaction::Read)), + Some(SpriteKind::Sign | SpriteKind::HangingSign) => { + interactables.push((pos, Interaction::Read)) + }, _ if block.is_mountable() => interactables.push((pos, Interaction::Mount)), _ => {}, }, diff --git a/voxygen/src/session/mod.rs b/voxygen/src/session/mod.rs index a8eee89fd5..f918052c53 100644 --- a/voxygen/src/session/mod.rs +++ b/voxygen/src/session/mod.rs @@ -101,6 +101,7 @@ pub struct SessionState { walk_right_dir: Vec2, free_look: bool, auto_walk: bool, + walking_speed: bool, camera_clamp: bool, zoom_lock: bool, is_aiming: bool, @@ -171,6 +172,7 @@ impl SessionState { walk_right_dir, free_look: false, auto_walk: false, + walking_speed: false, camera_clamp: false, zoom_lock: false, is_aiming: false, @@ -410,7 +412,7 @@ impl SessionState { client::Event::CharacterCreated(_) => {}, client::Event::CharacterEdited(_) => {}, client::Event::CharacterError(_) => {}, - client::Event::CharacterJoined(_) => {}, + client::Event::CharacterJoined(_) => self.scene.music_mgr.reset_track(), client::Event::MapMarker(event) => { self.hud.show.update_map_markers(event); }, @@ -710,6 +712,7 @@ impl PlayState for SessionState { } match input { GameInput::Primary => { + self.walking_speed = false; let mut client = self.client.borrow_mut(); // Mine and build targets can be the same block. make building // take precedence. @@ -728,6 +731,7 @@ impl PlayState for SessionState { } }, GameInput::Secondary => { + self.walking_speed = false; let mut client = self.client.borrow_mut(); if let Some(build_target) = build_target.filter(|bt| { state && can_build && nearest_block_dist == Some(bt.distance) @@ -747,6 +751,7 @@ impl PlayState for SessionState { } }, GameInput::Block => { + self.walking_speed = false; self.client.borrow_mut().handle_input( InputKind::Block, state, @@ -755,6 +760,7 @@ impl PlayState for SessionState { ); }, GameInput::Roll => { + self.walking_speed = false; let mut client = self.client.borrow_mut(); if can_build { if state { @@ -779,12 +785,14 @@ impl PlayState for SessionState { } }, GameInput::Respawn => { + self.walking_speed = false; self.stop_auto_walk(); if state { self.client.borrow_mut().respawn(); } }, GameInput::Jump => { + self.walking_speed = false; self.client.borrow_mut().handle_input( InputKind::Jump, state, @@ -847,6 +855,7 @@ impl PlayState for SessionState { self.key_state.right = state }, GameInput::Glide => { + self.walking_speed = false; let is_trading = self.client.borrow().is_trading(); if state && !is_trading { if global_state.settings.gameplay.stop_auto_walk_on_input { @@ -877,7 +886,11 @@ impl PlayState for SessionState { }, GameInput::ToggleWield => { if state { - self.client.borrow_mut().toggle_wield(); + let mut client = self.client.borrow_mut(); + if client.is_wielding().is_some_and(|b| !b) { + self.walking_speed = false; + } + client.toggle_wield(); } }, GameInput::SwapLoadout => { @@ -1214,6 +1227,13 @@ impl PlayState for SessionState { } } }, + GameInput::ToggleWalk if state => { + global_state + .settings + .gameplay + .walking_speed_behavior + .update(state, &mut self.walking_speed, |_| {}); + }, _ => {}, } }, @@ -1423,6 +1443,12 @@ impl PlayState for SessionState { } } + if self.walking_speed { + self.key_state.speed_mul = global_state.settings.gameplay.walking_speed; + } else { + self.key_state.speed_mul = 1.0; + } + // Recompute dependents just in case some input modified the camera self.scene .camera_mut() @@ -1467,8 +1493,8 @@ impl PlayState for SessionState { num_particles: self.scene.particle_mgr().particle_count() as u32, num_particles_visible: self.scene.particle_mgr().particle_count_visible() as u32, - current_track: self.scene.music_mgr().current_track.clone(), - current_artist: self.scene.music_mgr().current_artist.clone(), + current_track: self.scene.music_mgr().current_track(), + current_artist: self.scene.music_mgr().current_artist(), } }); diff --git a/voxygen/src/session/settings_change.rs b/voxygen/src/session/settings_change.rs index 7315059f54..c624996aeb 100644 --- a/voxygen/src/session/settings_change.rs +++ b/voxygen/src/session/settings_change.rs @@ -59,6 +59,7 @@ pub enum Gameplay { AdjustMousePan(u32), AdjustMouseZoom(u32), AdjustCameraClamp(u32), + AdjustWalkingSpeed(f32), ToggleControllerYInvert(bool), ToggleMouseYInvert(bool), @@ -68,6 +69,7 @@ pub enum Gameplay { ChangeFreeLookBehavior(PressBehavior), ChangeAutoWalkBehavior(PressBehavior), + ChangeWalkingSpeedBehavior(PressBehavior), ChangeCameraClampBehavior(PressBehavior), ChangeZoomLockBehavior(AutoPressBehavior), ChangeStopAutoWalkOnInput(bool), @@ -379,6 +381,9 @@ impl SettingsChange { Gameplay::AdjustCameraClamp(angle) => { settings.gameplay.camera_clamp_angle = angle; }, + Gameplay::AdjustWalkingSpeed(speed) => { + settings.gameplay.walking_speed = speed; + }, Gameplay::ToggleControllerYInvert(controller_y_inverted) => { window.controller_settings.pan_invert_y = controller_y_inverted; settings.controller.pan_invert_y = controller_y_inverted; @@ -400,6 +405,9 @@ impl SettingsChange { Gameplay::ChangeAutoWalkBehavior(behavior) => { settings.gameplay.auto_walk_behavior = behavior; }, + Gameplay::ChangeWalkingSpeedBehavior(behavior) => { + settings.gameplay.walking_speed_behavior = behavior; + }, Gameplay::ChangeCameraClampBehavior(behavior) => { settings.gameplay.camera_clamp_behavior = behavior; }, diff --git a/voxygen/src/settings/control.rs b/voxygen/src/settings/control.rs index c7876901b7..a3a123def2 100644 --- a/voxygen/src/settings/control.rs +++ b/voxygen/src/settings/control.rs @@ -200,6 +200,7 @@ impl ControlSettings { GameInput::MuteMusic => Some(KeyMouse::Key(VirtualKeyCode::F8)), GameInput::MuteSfx => None, GameInput::MuteAmbience => None, + GameInput::ToggleWalk => Some(KeyMouse::Key(VirtualKeyCode::I)), } } } diff --git a/voxygen/src/settings/gameplay.rs b/voxygen/src/settings/gameplay.rs index 6a8fe35ce1..ebb06d6627 100644 --- a/voxygen/src/settings/gameplay.rs +++ b/voxygen/src/settings/gameplay.rs @@ -8,11 +8,13 @@ pub struct GameplaySettings { pub pan_sensitivity: u32, pub zoom_sensitivity: u32, pub camera_clamp_angle: u32, + pub walking_speed: f32, pub zoom_inversion: bool, pub mouse_y_inversion: bool, pub smooth_pan_enable: bool, pub free_look_behavior: PressBehavior, pub auto_walk_behavior: PressBehavior, + pub walking_speed_behavior: PressBehavior, pub camera_clamp_behavior: PressBehavior, pub zoom_lock_behavior: AutoPressBehavior, pub stop_auto_walk_on_input: bool, @@ -27,11 +29,13 @@ impl Default for GameplaySettings { pan_sensitivity: 100, zoom_sensitivity: 100, camera_clamp_angle: 45, + walking_speed: 0.35, zoom_inversion: false, mouse_y_inversion: false, smooth_pan_enable: false, free_look_behavior: PressBehavior::Toggle, auto_walk_behavior: PressBehavior::Toggle, + walking_speed_behavior: PressBehavior::Toggle, camera_clamp_behavior: PressBehavior::Toggle, zoom_lock_behavior: AutoPressBehavior::Auto, stop_auto_walk_on_input: true, diff --git a/voxygen/src/singleplayer/mod.rs b/voxygen/src/singleplayer/mod.rs index 6920188078..9c0280295c 100644 --- a/voxygen/src/singleplayer/mod.rs +++ b/voxygen/src/singleplayer/mod.rs @@ -87,6 +87,7 @@ impl SingleplayerState { settings.map_file = Some(file_opts); settings.world_seed = world.seed; + settings.day_length = world.day_length; let (stop_server_s, stop_server_r) = unbounded(); diff --git a/voxygen/src/singleplayer/singleplayer_world.rs b/voxygen/src/singleplayer/singleplayer_world.rs index 8885064b08..4f76ee1198 100644 --- a/voxygen/src/singleplayer/singleplayer_world.rs +++ b/voxygen/src/singleplayer/singleplayer_world.rs @@ -1,9 +1,10 @@ use std::{ fs, + io::Read, path::{Path, PathBuf}, }; -use common::assets::ASSETS_PATH; +use common::{assets::ASSETS_PATH, consts::DAY_LENGTH_DEFAULT}; use serde::{Deserialize, Serialize}; use server::{FileOpts, GenOpts, DEFAULT_WORLD_MAP}; use tracing::error; @@ -18,6 +19,7 @@ struct World0 { pub struct SingleplayerWorld { pub name: String, pub gen_opts: Option, + pub day_length: f64, pub seed: u32, pub is_generated: bool, pub path: PathBuf, @@ -40,7 +42,12 @@ fn load_map(path: &Path) -> Option { return None; }; - version::try_load(&f, path) + let Ok(bytes) = f.bytes().collect::, _>>() else { + error!("Failed to read {}", meta_path.to_string_lossy()); + return None; + }; + + version::try_load(std::io::Cursor::new(bytes), path) } fn write_world_meta(world: &SingleplayerWorld) { @@ -78,11 +85,13 @@ fn migrate_old_singleplayer(from: &Path, to: &Path) { } let mut seed = 0; + let mut day_length = DAY_LENGTH_DEFAULT; let (map_file, gen_opts) = fs::read_to_string(to.join("server_config/settings.ron")) .ok() .and_then(|settings| { let settings: server::Settings = ron::from_str(&settings).ok()?; seed = settings.world_seed; + day_length = settings.day_length; Some(match settings.map_file? { FileOpts::LoadOrGenerate { name, opts, .. } => { (Some(PathBuf::from(name)), Some(opts)) @@ -107,6 +116,7 @@ fn migrate_old_singleplayer(from: &Path, to: &Path) { name: "singleplayer world".to_string(), gen_opts, seed, + day_length, path: to.to_path_buf(), // Isn't persisted so doesn't matter what it's set to. is_generated: false, @@ -226,6 +236,7 @@ impl SingleplayerWorlds { let new_world = SingleplayerWorld { name: "New World".to_string(), gen_opts: None, + day_length: DAY_LENGTH_DEFAULT, seed: 0, is_generated: false, map_path: path.join("map.bin"), @@ -251,13 +262,13 @@ mod version { use super::*; - pub type Current = V1; + pub type Current = V2; type LoadWorldFn = fn(R, &Path) -> Result; fn loaders<'a, R: std::io::Read + Clone>() -> &'a [LoadWorldFn] { // Step [4] - &[load_raw::] + &[load_raw::, load_raw::] } #[derive(Deserialize, Serialize)] @@ -269,18 +280,6 @@ mod version { seed: u32, } - impl V1 { - /// This function is only needed for the current version - pub fn from_world(world: &SingleplayerWorld) -> Self { - V1 { - version: 1, - name: world.name.clone(), - gen_opts: world.gen_opts.clone(), - seed: world.seed, - } - } - } - impl ToWorld for V1 { fn to_world(self, path: PathBuf) -> SingleplayerWorld { let map_path = path.join("map.bin"); @@ -290,6 +289,46 @@ mod version { name: self.name, gen_opts: self.gen_opts, seed: self.seed, + day_length: DAY_LENGTH_DEFAULT, + is_generated, + path, + map_path, + } + } + } + + #[derive(Deserialize, Serialize)] + pub struct V2 { + #[serde(deserialize_with = "version::<_, 2>")] + version: u64, + name: String, + gen_opts: Option, + seed: u32, + day_length: f64, + } + + impl V2 { + pub fn from_world(world: &SingleplayerWorld) -> Self { + V2 { + version: 2, + name: world.name.clone(), + gen_opts: world.gen_opts.clone(), + seed: world.seed, + day_length: world.day_length, + } + } + } + + impl ToWorld for V2 { + fn to_world(self, path: PathBuf) -> SingleplayerWorld { + let map_path = path.join("map.bin"); + let is_generated = fs::metadata(&map_path).is_ok_and(|f| f.is_file()); + + SingleplayerWorld { + name: self.name, + gen_opts: self.gen_opts, + seed: self.seed, + day_length: self.day_length, is_generated, path, map_path, diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index c1cc1fb621..e2e5076562 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -1347,7 +1347,7 @@ impl Window { // Check if folder exists and create it if it does not if !path.exists() { if let Err(e) = std::fs::create_dir_all(&path) { - warn!(?e, "Couldn't create folder for screenshot"); + warn!(?e, ?path, "Couldn't create folder for screenshot"); let _result = sender.send(String::from("Couldn't create folder for screenshot")); } @@ -1360,8 +1360,8 @@ impl Window { .unwrap_or(0) )); // Try to save the image - if let Err(e) = image.into_rgba8().save(&path) { - warn!(?e, "Couldn't save screenshot"); + if let Err(e) = image.save(&path) { + warn!(?e, ?path, "Couldn't save screenshot"); let _result = sender.send(String::from("Couldn't save screenshot")); } else { let _result = diff --git a/world/Cargo.toml b/world/Cargo.toml index dba7579d06..353524e425 100644 --- a/world/Cargo.toml +++ b/world/Cargo.toml @@ -21,6 +21,7 @@ common-dynlib = {package = "veloren-common-dynlib", path = "../common/dynlib", o bincode = { workspace = true } bitvec = "1.0.1" enum-map = { workspace = true } +enumset = "1.1.3" fxhash = { workspace = true } image = { workspace = true } itertools = { workspace = true } diff --git a/world/src/canvas.rs b/world/src/canvas.rs index edc39f4f17..eb78226986 100644 --- a/world/src/canvas.rs +++ b/world/src/canvas.rs @@ -305,7 +305,7 @@ impl<'a> Canvas<'a> { } }); for (pos, spec) in entities.drain(..) { - self.spawn(EntityInfo::at(pos).with_asset_expect(&spec, &mut rng)); + self.spawn(EntityInfo::at(pos).with_asset_expect(&spec, &mut rng, None)); } } diff --git a/world/src/civ/mod.rs b/world/src/civ/mod.rs index 4f4609eaaa..31567ed27b 100644 --- a/world/src/civ/mod.rs +++ b/world/src/civ/mod.rs @@ -13,6 +13,7 @@ use crate::{ }; use common::{ astar::Astar, + calendar::Calendar, path::Path, spiral::Spiral2d, store::{Id, Store}, @@ -236,6 +237,7 @@ impl Civs { seed: u32, sim: &mut WorldSim, index: &mut Index, + calendar: Option<&Calendar>, report_stage: &dyn Fn(WorldCivStage), ) -> Self { prof_span!("Civs::generate"); @@ -539,9 +541,11 @@ impl Civs { let size = Lerp::lerp(0.03, 1.0, rng.gen_range(0.0..1f32).powi(5)); WorldSite::refactor(site2::Site::generate_city( &Land::from_sim(ctx.sim), + index_ref, &mut rng, wpos, size, + calendar, )) }, SiteKind::CliffTown => WorldSite::cliff_town(site2::Site::generate_cliff_town( diff --git a/world/src/layer/cave.rs b/world/src/layer/cave.rs index 8714a2284b..17788ada9d 100644 --- a/world/src/layer/cave.rs +++ b/world/src/layer/cave.rs @@ -942,8 +942,11 @@ fn apply_entity_spawns(canvas: &mut Canvas, wpos: Vec3, biome: &Bio .ok() .and_then(|s| s.0) { - canvas - .spawn(EntityInfo::at(wpos.map(|e| e as f32)).with_asset_expect(entity_asset, rng)); + canvas.spawn(EntityInfo::at(wpos.map(|e| e as f32)).with_asset_expect( + entity_asset, + rng, + None, + )); } } diff --git a/world/src/layer/mod.rs b/world/src/layer/mod.rs index 5e9a8c1233..9798dde111 100644 --- a/world/src/layer/mod.rs +++ b/world/src/layer/mod.rs @@ -668,7 +668,7 @@ pub fn apply_caves_supplement<'a>( _ => "common.entity.wild.aggressive.cave_troll", } }; - entity.with_asset_expect(asset, dynamic_rng) + entity.with_asset_expect(asset, dynamic_rng, None) }; supplement.add_entity(entity); diff --git a/world/src/layer/scatter.rs b/world/src/layer/scatter.rs index f676c75cb4..52c33d2a68 100644 --- a/world/src/layer/scatter.rs +++ b/world/src/layer/scatter.rs @@ -717,7 +717,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas, _rng: &mut impl Rng, calendar: Opti ScatterConfig { kind: Mud, water_mode: Underwater, - permit: |b| matches!(b, BlockKind::Earth), + permit: |b| matches!(b, BlockKind::Earth | BlockKind::Sand), f: |_, col| { ( MUSH_FACT @@ -735,7 +735,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas, _rng: &mut impl Rng, calendar: Opti ScatterConfig { kind: GrassBlue, water_mode: Underwater, - permit: |b| matches!(b, BlockKind::Grass), + permit: |b| matches!(b, BlockKind::Grass | BlockKind::Sand), f: |_, col| { ( MUSH_FACT @@ -753,7 +753,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas, _rng: &mut impl Rng, calendar: Opti ScatterConfig { kind: Seagrass, water_mode: Underwater, - permit: |b| matches!(b, BlockKind::Grass), + permit: |b| matches!(b, BlockKind::Grass | BlockKind::Sand), f: |_, col| { ( close(col.temp, CONFIG.temperate_temp, 0.8) @@ -774,7 +774,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas, _rng: &mut impl Rng, calendar: Opti ScatterConfig { kind: Seagrass, water_mode: Underwater, - permit: |b| matches!(b, BlockKind::Grass), + permit: |b| matches!(b, BlockKind::Grass | BlockKind::Sand), f: |_, col| { ( MUSH_FACT @@ -794,7 +794,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas, _rng: &mut impl Rng, calendar: Opti ScatterConfig { kind: SeaweedTemperate, water_mode: Underwater, - permit: |b| matches!(b, BlockKind::Grass), + permit: |b| matches!(b, BlockKind::Grass | BlockKind::Sand), f: |_, col| { ( close(col.temp, CONFIG.temperate_temp, 0.8) @@ -815,7 +815,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas, _rng: &mut impl Rng, calendar: Opti ScatterConfig { kind: SeaweedTropical, water_mode: Underwater, - permit: |b| matches!(b, BlockKind::Grass), + permit: |b| matches!(b, BlockKind::Grass | BlockKind::Sand), f: |_, col| { ( close(col.temp, 1.0, 0.95) @@ -836,7 +836,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas, _rng: &mut impl Rng, calendar: Opti ScatterConfig { kind: SeaGrapes, water_mode: Underwater, - permit: |b| matches!(b, BlockKind::Earth), + permit: |b| matches!(b, BlockKind::Earth | BlockKind::Sand), f: |_, col| { ( MUSH_FACT @@ -856,7 +856,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas, _rng: &mut impl Rng, calendar: Opti ScatterConfig { kind: WavyAlgae, water_mode: Underwater, - permit: |b| matches!(b, BlockKind::Earth), + permit: |b| matches!(b, BlockKind::Earth | BlockKind::Sand), f: |_, col| { ( MUSH_FACT @@ -876,7 +876,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas, _rng: &mut impl Rng, calendar: Opti ScatterConfig { kind: MermaidsFan, water_mode: Underwater, - permit: |b| matches!(b, BlockKind::Earth), + permit: |b| matches!(b, BlockKind::Earth | BlockKind::Sand), f: |_, col| { ( close(col.temp, 1.0, 0.95) @@ -897,7 +897,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas, _rng: &mut impl Rng, calendar: Opti ScatterConfig { kind: SeaAnemone, water_mode: Underwater, - permit: |b| matches!(b, BlockKind::Earth), + permit: |b| matches!(b, BlockKind::Earth | BlockKind::Sand), f: |_, col| { ( close(col.temp, CONFIG.temperate_temp, 0.8) @@ -918,7 +918,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas, _rng: &mut impl Rng, calendar: Opti ScatterConfig { kind: GiantKelp, water_mode: Underwater, - permit: |b| matches!(b, BlockKind::Earth), + permit: |b| matches!(b, BlockKind::Earth | BlockKind::Sand), f: |_, col| { ( close(col.temp, CONFIG.temperate_temp, 0.8) @@ -939,7 +939,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas, _rng: &mut impl Rng, calendar: Opti ScatterConfig { kind: BullKelp, water_mode: Underwater, - permit: |b| matches!(b, BlockKind::Earth), + permit: |b| matches!(b, BlockKind::Earth | BlockKind::Sand), f: |_, col| { ( close(col.temp, CONFIG.temperate_temp, 0.7) @@ -960,7 +960,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas, _rng: &mut impl Rng, calendar: Opti ScatterConfig { kind: StonyCoral, water_mode: Underwater, - permit: |b| matches!(b, BlockKind::Earth), + permit: |b| matches!(b, BlockKind::Earth | BlockKind::Sand), f: |_, col| { ( close(col.temp, 1.0, 0.9) @@ -981,7 +981,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas, _rng: &mut impl Rng, calendar: Opti ScatterConfig { kind: SoftCoral, water_mode: Underwater, - permit: |b| matches!(b, BlockKind::Earth), + permit: |b| matches!(b, BlockKind::Earth | BlockKind::Sand), f: |_, col| { ( close(col.temp, 1.0, 0.9) @@ -1002,7 +1002,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas, _rng: &mut impl Rng, calendar: Opti ScatterConfig { kind: Seashells, water_mode: Underwater, - permit: |b| matches!(b, BlockKind::Earth), + permit: |b| matches!(b, BlockKind::Earth | BlockKind::Sand), f: |c, col| { ( (c.rockiness - 0.5).max(0.0) @@ -1021,7 +1021,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas, _rng: &mut impl Rng, calendar: Opti ScatterConfig { kind: Stones, water_mode: Underwater, - permit: |b| matches!(b, BlockKind::Earth), + permit: |b| matches!(b, BlockKind::Earth | BlockKind::Sand), f: |c, col| { ( (c.rockiness - 0.5).max(0.0) diff --git a/world/src/layer/spot.rs b/world/src/layer/spot.rs index 53673276fa..1ae8cc01d6 100644 --- a/world/src/layer/spot.rs +++ b/world/src/layer/spot.rs @@ -618,7 +618,7 @@ pub fn apply_spots_to(canvas: &mut Canvas, _dynamic_rng: &mut impl Rng) { { canvas.spawn( EntityInfo::at(wpos.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0)) - .with_asset_expect(spec, &mut rng), + .with_asset_expect(spec, &mut rng, None), ); } } diff --git a/world/src/layer/wildlife.rs b/world/src/layer/wildlife.rs index fc54128c74..be8dd74c10 100644 --- a/world/src/layer/wildlife.rs +++ b/world/src/layer/wildlife.rs @@ -138,7 +138,7 @@ impl Pack { .groups .choose_weighted(dynamic_rng, |(p, _group)| *p) .expect("Failed to choose group"); - let entity = EntityInfo::at(pos).with_asset_expect(entity_asset, dynamic_rng); + let entity = EntityInfo::at(pos).with_asset_expect(entity_asset, dynamic_rng, None); let group_size = dynamic_rng.gen_range(*from..=*to); (entity, group_size) @@ -665,7 +665,8 @@ mod tests { let (_, (_, _, asset)) = group; let dummy_pos = Vec3::new(0.0, 0.0, 0.0); let mut dummy_rng = thread_rng(); - let entity = EntityInfo::at(dummy_pos).with_asset_expect(asset, &mut dummy_rng); + let entity = + EntityInfo::at(dummy_pos).with_asset_expect(asset, &mut dummy_rng, None); drop(entity); } } diff --git a/world/src/lib.rs b/world/src/lib.rs index 51afc9d525..02a4565a65 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -128,14 +128,16 @@ impl World { // is broken. threadpool.install(|| { let mut index = Index::new(seed); + let calendar = opts.calendar.clone(); let mut sim = sim::WorldSim::generate(seed, opts, threadpool, &|stage| { report_stage(WorldGenerateStage::WorldSimGenerate(stage)) }); - let civs = civ::Civs::generate(seed, &mut sim, &mut index, &|stage| { - report_stage(WorldGenerateStage::WorldCivGenerate(stage)) - }); + let civs = + civ::Civs::generate(seed, &mut sim, &mut index, calendar.as_ref(), &|stage| { + report_stage(WorldGenerateStage::WorldCivGenerate(stage)) + }); report_stage(WorldGenerateStage::EconomySimulation); sim2::simulate(&mut index, &mut sim); @@ -376,7 +378,18 @@ impl World { sim_chunk .sites .iter() - .find_map(|site| index.sites[*site].kind.convert_to_meta()), + .filter(|id| { + index.sites[**id] + .get_origin() + .distance_squared(chunk_center_wpos2d) as f32 + <= index.sites[**id].radius().powi(2) + }) + .min_by_key(|id| { + index.sites[**id] + .get_origin() + .distance_squared(chunk_center_wpos2d) + }) + .map(|id| index.sites[*id].kind.convert_to_meta().unwrap_or_default()), ); let mut chunk = TerrainChunk::new(base_z, stone, air, meta); @@ -542,6 +555,7 @@ impl World { sample_get, &mut supplement, site.id(), + time.as_ref(), ) }); diff --git a/world/src/site/economy/context.rs b/world/src/site/economy/context.rs index 7352613fda..68e74966e2 100644 --- a/world/src/site/economy/context.rs +++ b/world/src/site/economy/context.rs @@ -345,7 +345,7 @@ mod tests { info!("Index created"); let mut sim = sim::WorldSim::generate(seed, opts, &threadpool, &|_| {}); info!("World loaded"); - let _civs = crate::civ::Civs::generate(seed, &mut sim, &mut index, &|_| {}); + let _civs = crate::civ::Civs::generate(seed, &mut sim, &mut index, None, &|_| {}); info!("Civs created"); crate::sim2::simulate(&mut index, &mut sim); show_economy(&index.sites, &None); @@ -374,7 +374,7 @@ mod tests { let mut names = None; let regenerate_input = false; if regenerate_input { - let _civs = crate::civ::Civs::generate(seed, &mut sim, &mut index, &|_| {}); + let _civs = crate::civ::Civs::generate(seed, &mut sim, &mut index, None, &|_| {}); info!("Civs created"); let mut outarr: Vec = Vec::new(); for i in index.sites.values() { diff --git a/world/src/site/mod.rs b/world/src/site/mod.rs index 16945af6c0..c16ddf5143 100644 --- a/world/src/site/mod.rs +++ b/world/src/site/mod.rs @@ -13,7 +13,7 @@ pub use self::{ pub use common::terrain::site::{DungeonKindMeta, SettlementKindMeta, SiteKindMeta}; use crate::{column::ColumnSample, site2, Canvas}; -use common::generation::ChunkSupplement; +use common::{calendar::Calendar, generation::ChunkSupplement, resources::TimeOfDay}; use rand::Rng; use serde::Deserialize; use vek::*; @@ -378,13 +378,14 @@ impl Site { get_column: impl FnMut(Vec2) -> Option<&'a ColumnSample<'a>>, supplement: &mut ChunkSupplement, site_id: common::trade::SiteId, + time: Option<&(TimeOfDay, Calendar)>, ) { match &self.kind { SiteKind::Settlement(s) => { let economy = self .trade_information(site_id) .expect("Settlement has no economy"); - s.apply_supplement(dynamic_rng, wpos2d, get_column, supplement, economy) + s.apply_supplement(dynamic_rng, wpos2d, get_column, supplement, economy, time) }, SiteKind::Dungeon(d) => d.apply_supplement(dynamic_rng, wpos2d, supplement), SiteKind::Castle(c) => c.apply_supplement(dynamic_rng, wpos2d, get_column, supplement), @@ -466,6 +467,7 @@ impl SiteKind { }, SiteKind::Dungeon(_) => Some(SiteKindMeta::Dungeon(DungeonKindMeta::Old)), SiteKind::Gnarling(_) => Some(SiteKindMeta::Dungeon(DungeonKindMeta::Gnarling)), + SiteKind::Adlet(_) => Some(SiteKindMeta::Dungeon(DungeonKindMeta::Adlet)), _ => None, } } diff --git a/world/src/site/namegen.rs b/world/src/site/namegen.rs index 7ffde99f91..b1911fdbe4 100644 --- a/world/src/site/namegen.rs +++ b/world/src/site/namegen.rs @@ -689,4 +689,168 @@ impl<'a, R: Rng> NameGen<'a, R> { ]; self.generate_theme_from_parts(&start, &middle, &vowel, &end) } + + pub fn generate_tavern(&mut self) -> String { + let adjectives = [ + "Crazy", + "Big", + "Tiny", + "Slimy", + "Warm", + "Rigid", + "Soft", + "Wet", + "Humid", + "Smelly", + "Hidden", + "Smart", + "Fragile", + "Strong", + "Weak", + "Happy", + "Sad", + "Glad", + "Scared", + "Embarrassed", + "Goofy", + "Spicy", + "Salty", + "Peaceful", + "Awful", + "Sweet", + "Colossal", + "Puzzled", + "Cheap", + "Valuable", + "Rich", + "Obnoxious", + "Puzzled", + "Snoring", + "Fast", + "Quick", + "Magical", + "Violet", + "Red", + "Blue", + "Green", + "Yellow", + "Golden", + "Shiny", + "Tired", + "Twin", + "Incompetent", + "Light", + "Dark", + "Glorious", + "Best", + "Free", + "Odd", + "Juicy", + "Shaking", + "Tall", + "Short", + "Precious", + "Regular", + "Slow", + "Anxious", + "Naive", + "Sore", + "Next", + "Silver", + "Secret", + "Honorable", + "Rapid", + "Sleepy", + "Lying", + "Zesty", + "Fancy", + "Stylish", + "Thirsty", + "Dry", + "Dancing", + "Singing", + "Drunken", + ]; + let tavern_synonyms = ["Tavern", "Bar", "Pub"]; + let subjectives = [ + "Apple", + "Pumpkin", + "Cucumber", + "Squash", + "Demons", + "Mango", + "Coconut", + "Cats", + "Hill", + "Mountain", + "Squirrel", + "Rabbit", + "Moose", + "Driggle", + "Iron", + "Velorite", + "Plate", + "Eagle", + "Birds", + "Drumstick", + "Dog", + "Tiger", + "Knight", + "Leader", + "Huntress", + "Hunter", + "Dwarf", + "Toad", + "Clams", + "Bell", + "Avocado", + "Egg", + "Spade", + "Stream", + "Cabbage", + "Tomato", + "Rapier", + "Katana", + "Whisper", + "Hammer", + "Axe", + "Sword", + "Saurok", + "Danari", + "Elf", + "Human", + "Draugr", + "Orc", + "Pie", + "Stick", + "Rope", + "Knife", + "Shield", + "Bow", + "Spear", + "Staff", + "Crow", + "Crown", + "Parrot", + "Parrots", + "Pelican", + "Whale", + "Cube", + "Minotaur", + "Oni", + "Monster", + ]; + let kind = self.rng.gen_range(0..10); + let mut choose = |slice: &[&'static str]| *slice.choose(self.rng).unwrap(); + match kind { + 0 => format!("The {} {}", choose(&adjectives), choose(&tavern_synonyms)), + 1..=7 => format!("The {} {}", choose(&adjectives), choose(&subjectives)), + _ => format!( + "The {} {} {}", + choose(&adjectives), + choose(&subjectives), + choose(&tavern_synonyms) + ), + } + } } diff --git a/world/src/site/settlement/mod.rs b/world/src/site/settlement/mod.rs index 6ac38ebfa2..1027e3dd50 100644 --- a/world/src/site/settlement/mod.rs +++ b/world/src/site/settlement/mod.rs @@ -15,6 +15,7 @@ use crate::{ }; use common::{ astar::Astar, + calendar::Calendar, comp::{ self, agent, bird_medium, inventory::{ @@ -24,6 +25,7 @@ use common::{ }, generation::{ChunkSupplement, EntityInfo}, path::Path, + resources::TimeOfDay, spiral::Spiral2d, store::{Id, Store}, terrain::{Block, BlockKind, SpriteKind, TerrainChunkSize}, @@ -853,6 +855,7 @@ impl Settlement { mut get_column: impl FnMut(Vec2) -> Option<&'a ColumnSample<'a>>, supplement: &mut ChunkSupplement, economy: SiteInformation, + time: Option<&(TimeOfDay, Calendar)>, ) { // let economy: HashMap = SiteInformation::economy // .values @@ -893,12 +896,12 @@ impl Settlement { let entity = if is_dummy { EntityInfo::at(entity_wpos) .with_agency(false) - .with_asset_expect("common.entity.village.dummy", dynamic_rng) + .with_asset_expect("common.entity.village.dummy", dynamic_rng, time) } else { match dynamic_rng.gen_range(0..=4) { 0 => barnyard(entity_wpos, dynamic_rng), 1 => bird(entity_wpos, dynamic_rng), - _ => humanoid(entity_wpos, &economy, dynamic_rng), + _ => humanoid(entity_wpos, &economy, dynamic_rng, time), } }; @@ -993,27 +996,37 @@ fn bird(pos: Vec3, dynamic_rng: &mut impl Rng) -> EntityInfo { .with_automatic_name(None) } -fn humanoid(pos: Vec3, economy: &SiteInformation, dynamic_rng: &mut impl Rng) -> EntityInfo { +fn humanoid( + pos: Vec3, + economy: &SiteInformation, + dynamic_rng: &mut impl Rng, + time: Option<&(TimeOfDay, Calendar)>, +) -> EntityInfo { let entity = EntityInfo::at(pos); match dynamic_rng.gen_range(0..8) { 0 | 1 => entity .with_agent_mark(agent::Mark::Guard) - .with_asset_expect("common.entity.village.guard", dynamic_rng), + .with_asset_expect("common.entity.village.guard", dynamic_rng, time), 2 => entity .with_agent_mark(agent::Mark::Merchant) .with_economy(economy) .with_lazy_loadout(merchant_loadout) - .with_asset_expect("common.entity.village.merchant", dynamic_rng), - _ => entity.with_asset_expect("common.entity.village.villager", dynamic_rng), + .with_asset_expect("common.entity.village.merchant", dynamic_rng, time), + _ => entity.with_asset_expect("common.entity.village.villager", dynamic_rng, time), } } pub fn merchant_loadout( loadout_builder: LoadoutBuilder, economy: Option<&SiteInformation>, + time: Option<&(TimeOfDay, Calendar)>, ) -> LoadoutBuilder { trader_loadout( - loadout_builder.with_asset_expect("common.loadout.village.merchant", &mut thread_rng()), + loadout_builder.with_asset_expect( + "common.loadout.village.merchant", + &mut thread_rng(), + time, + ), economy, |_| true, ) diff --git a/world/src/site/tree.rs b/world/src/site/tree.rs index 1591544de7..d5f3e09dab 100644 --- a/world/src/site/tree.rs +++ b/world/src/site/tree.rs @@ -44,6 +44,7 @@ impl Tree { pub fn render(&self, canvas: &mut Canvas, dynamic_rng: &mut impl Rng) { let nz = FastNoise::new(self.seed); + let calendar = None; canvas.foreach_col(|canvas, wpos2d, col| { let rpos2d = wpos2d - self.origin; @@ -81,6 +82,7 @@ impl Tree { _ => "common.entity.wild.aggressive.maneater", }, dynamic_rng, + calendar, ), ); } else if above && dynamic_rng.gen_bool(0.0001) { @@ -89,6 +91,7 @@ impl Tree { .with_asset_expect( "common.entity.wild.aggressive.swamp_troll", dynamic_rng, + calendar, ), ); } diff --git a/world/src/site2/mod.rs b/world/src/site2/mod.rs index a9cfbd08ac..d8bac19dae 100644 --- a/world/src/site2/mod.rs +++ b/world/src/site2/mod.rs @@ -19,6 +19,7 @@ use crate::{ }; use common::{ astar::Astar, + calendar::Calendar, comp::Alignment, generation::EntityInfo, lottery::Lottery, @@ -573,7 +574,14 @@ impl Site { } // Size is 0..1 - pub fn generate_city(land: &Land, rng: &mut impl Rng, origin: Vec2, size: f32) -> Self { + pub fn generate_city( + land: &Land, + index: IndexRef, + rng: &mut impl Rng, + origin: Vec2, + size: f32, + calendar: Option<&Calendar>, + ) -> Self { let mut rng = reseed(rng); let mut site = Site { @@ -593,6 +601,7 @@ impl Site { (5.0, 4), (5.0, 5), (15.0, 6), + (15.0, 7), ]); let mut castles = 0; @@ -600,6 +609,8 @@ impl Site { let mut workshops = 0; let mut airship_docks = 0; + + let mut taverns = 0; for _ in 0..(size * 200.0) as i32 { match *build_chance.choose_seeded(rng.gen()) { // Workshop @@ -655,6 +666,7 @@ impl Site { door_tile, door_dir, aabr, + calendar, ); let house_alt = house.alt; let plot = site.create_plot(Plot { @@ -917,6 +929,43 @@ impl Site { } } }, + 7 if (size > 0.125 && taverns < 2) => { + let size = (3.5 + rng.gen::().powf(5.0) * 2.0).round() as u32; + if let Some((aabr, door_tile, door_dir)) = attempt(32, || { + site.find_roadside_aabr( + &mut rng, + 7..(size + 1).pow(2), + Extent2::broadcast(size), + ) + }) { + let tavern = plot::Tavern::generate( + land, + index, + &mut reseed(&mut rng), + &site, + door_tile, + Dir::from_vec2(door_dir), + aabr, + ); + let tavern_alt = tavern.door_wpos.z; + let plot = site.create_plot(Plot { + kind: PlotKind::Tavern(tavern), + root_tile: aabr.center(), + tiles: aabr_tiles(aabr).collect(), + seed: rng.gen(), + }); + + site.blit_aabr(aabr, Tile { + kind: TileKind::Building, + plot: Some(plot), + hard_alt: Some(tavern_alt), + }); + + taverns += 1; + } else { + site.make_plaza(land, &mut rng); + } + }, _ => {}, } } @@ -1593,6 +1642,7 @@ impl Site { (-border..TILE_SIZE as i32 + border) .map(move |x| (twpos + Vec2::new(x, y), Vec2::new(x, y))) }); + let calendar = None; #[allow(clippy::single_match)] match &tile.kind { @@ -1647,7 +1697,7 @@ impl Site { .unwrap(); canvas.spawn( EntityInfo::at(Vec3::new(wpos2d.x, wpos2d.y, alt).as_()) - .with_asset_expect(spec, dynamic_rng) + .with_asset_expect(spec, dynamic_rng, calendar) .with_alignment(Alignment::Tame), ); } @@ -1824,6 +1874,7 @@ impl Site { let (prim_tree, fills, mut entities) = match &self.plots[plot].kind { PlotKind::House(house) => house.render_collect(self, canvas), PlotKind::AirshipDock(airship_dock) => airship_dock.render_collect(self, canvas), + PlotKind::Tavern(tavern) => tavern.render_collect(self, canvas), PlotKind::CoastalHouse(coastal_house) => coastal_house.render_collect(self, canvas), PlotKind::CoastalWorkshop(coastal_workshop) => { coastal_workshop.render_collect(self, canvas) @@ -1963,7 +2014,20 @@ impl Site { } pub fn test_site() -> Site { - Site::generate_city(&Land::empty(), &mut thread_rng(), Vec2::zero(), 0.5) + let index = crate::index::Index::new(0); + let index_ref = IndexRef { + colors: &index.colors(), + features: &index.features(), + index: &index, + }; + Site::generate_city( + &Land::empty(), + index_ref, + &mut thread_rng(), + Vec2::zero(), + 0.5, + None, + ) } fn wpos_is_hazard(land: &Land, wpos: Vec2) -> Option { diff --git a/world/src/site2/plot.rs b/world/src/site2/plot.rs index 15693441fc..ccb9118aff 100644 --- a/world/src/site2/plot.rs +++ b/world/src/site2/plot.rs @@ -22,6 +22,7 @@ mod savannah_hut; mod savannah_pit; mod savannah_workshop; mod sea_chapel; +pub mod tavern; mod troll_cave; mod workshop; @@ -34,7 +35,7 @@ pub use self::{ gnarling::GnarlingFortification, house::House, jungle_ruin::JungleRuin, pirate_hideout::PirateHideout, rock_circle::RockCircle, savannah_hut::SavannahHut, savannah_pit::SavannahPit, savannah_workshop::SavannahWorkshop, sea_chapel::SeaChapel, - troll_cave::TrollCave, workshop::Workshop, + tavern::Tavern, troll_cave::TrollCave, workshop::Workshop, }; use super::*; @@ -77,6 +78,7 @@ impl Plot { pub enum PlotKind { House(House), AirshipDock(AirshipDock), + Tavern(Tavern), CoastalHouse(CoastalHouse), CoastalWorkshop(CoastalWorkshop), Workshop(Workshop), diff --git a/world/src/site2/plot/adlet.rs b/world/src/site2/plot/adlet.rs index c333b6a756..94f15e24c0 100644 --- a/world/src/site2/plot/adlet.rs +++ b/world/src/site2/plot/adlet.rs @@ -129,7 +129,7 @@ impl AdletStronghold { let mut outer_structures = Vec::<(AdletStructure, Vec2, Dir)>::new(); - let entrance_dir = Dir::from_vector(entrance - cavern_center); + let entrance_dir = Dir::from_vec2(entrance - cavern_center); outer_structures.push((AdletStructure::TunnelEntrance, Vec2::zero(), entrance_dir)); let desired_structures = surface_radius.pow(2) / 100; @@ -176,7 +176,7 @@ impl AdletStronghold { Some((structure_center, structure_kind)) } }) { - let dir_to_wall = Dir::from_vector(rpos); + let dir_to_wall = Dir::from_vec2(rpos); let door_rng: u32 = rng.gen_range(0..9); let door_dir = match door_rng { 0..=3 => dir_to_wall, @@ -352,7 +352,7 @@ impl AdletStronghold { .then_some((structure, rpos)) }) { // Direction facing the central bonfire - let dir = Dir::from_vector(rpos).opposite(); + let dir = Dir::from_vec2(rpos).opposite(); cavern_structures.push((structure, rpos, dir)); } } @@ -493,7 +493,7 @@ impl Structure for AdletStronghold { // Tunnel let dist: f32 = self.cavern_center.as_().distance(self.entrance.as_()); - let dir = Dir::from_vector(self.entrance - self.cavern_center); + let dir = Dir::from_vec2(self.entrance - self.cavern_center); let tunnel_start: Vec3 = match dir { Dir::X => Vec2::new(self.entrance.x + 7, self.entrance.y), Dir::Y => Vec2::new(self.entrance.x, self.entrance.y + 7), @@ -2290,18 +2290,27 @@ impl RibCageGenerator { } fn adlet_hunter(pos: Vec3, rng: &mut R) -> EntityInfo { - EntityInfo::at(pos.map(|x| x as f32)) - .with_asset_expect("common.entity.dungeon.adlet.hunter", rng) + EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect( + "common.entity.dungeon.adlet.hunter", + rng, + None, + ) } fn adlet_icepicker(pos: Vec3, rng: &mut R) -> EntityInfo { - EntityInfo::at(pos.map(|x| x as f32)) - .with_asset_expect("common.entity.dungeon.adlet.icepicker", rng) + EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect( + "common.entity.dungeon.adlet.icepicker", + rng, + None, + ) } fn adlet_tracker(pos: Vec3, rng: &mut R) -> EntityInfo { - EntityInfo::at(pos.map(|x| x as f32)) - .with_asset_expect("common.entity.dungeon.adlet.tracker", rng) + EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect( + "common.entity.dungeon.adlet.tracker", + rng, + None, + ) } fn random_adlet(pos: Vec3, rng: &mut R) -> EntityInfo { @@ -2313,42 +2322,67 @@ fn random_adlet(pos: Vec3, rng: &mut R) -> EntityInfo { } fn adlet_elder(pos: Vec3, rng: &mut R) -> EntityInfo { - EntityInfo::at(pos.map(|x| x as f32)) - .with_asset_expect("common.entity.dungeon.adlet.elder", rng) + EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect( + "common.entity.dungeon.adlet.elder", + rng, + None, + ) } fn rat(pos: Vec3, rng: &mut R) -> EntityInfo { - EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect("common.entity.wild.peaceful.rat", rng) + EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect( + "common.entity.wild.peaceful.rat", + rng, + None, + ) } fn wolf(pos: Vec3, rng: &mut R) -> EntityInfo { - EntityInfo::at(pos.map(|x| x as f32)) - .with_asset_expect("common.entity.wild.aggressive.wolf", rng) + EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect( + "common.entity.wild.aggressive.wolf", + rng, + None, + ) } fn bear(pos: Vec3, rng: &mut R) -> EntityInfo { - EntityInfo::at(pos.map(|x| x as f32)) - .with_asset_expect("common.entity.wild.aggressive.bear", rng) + EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect( + "common.entity.wild.aggressive.bear", + rng, + None, + ) } fn frostfang(pos: Vec3, rng: &mut R) -> EntityInfo { - EntityInfo::at(pos.map(|x| x as f32)) - .with_asset_expect("common.entity.wild.aggressive.frostfang", rng) + EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect( + "common.entity.wild.aggressive.frostfang", + rng, + None, + ) } fn roshwalr(pos: Vec3, rng: &mut R) -> EntityInfo { - EntityInfo::at(pos.map(|x| x as f32)) - .with_asset_expect("common.entity.wild.aggressive.roshwalr", rng) + EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect( + "common.entity.wild.aggressive.roshwalr", + rng, + None, + ) } fn icedrake(pos: Vec3, rng: &mut R) -> EntityInfo { - EntityInfo::at(pos.map(|x| x as f32)) - .with_asset_expect("common.entity.wild.aggressive.icedrake", rng) + EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect( + "common.entity.wild.aggressive.icedrake", + rng, + None, + ) } fn tursus(pos: Vec3, rng: &mut R) -> EntityInfo { - EntityInfo::at(pos.map(|x| x as f32)) - .with_asset_expect("common.entity.wild.aggressive.tursus", rng) + EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect( + "common.entity.wild.aggressive.tursus", + rng, + None, + ) } fn random_yetipit_mob(pos: Vec3, rng: &mut R) -> EntityInfo { @@ -2361,7 +2395,11 @@ fn random_yetipit_mob(pos: Vec3, rng: &mut R) -> EntityInfo { } fn yeti(pos: Vec3, rng: &mut R) -> EntityInfo { - EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect("common.entity.dungeon.adlet.yeti", rng) + EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect( + "common.entity.dungeon.adlet.yeti", + rng, + None, + ) } #[cfg(test)] diff --git a/world/src/site2/plot/airship_dock.rs b/world/src/site2/plot/airship_dock.rs index 36ed15f3c7..5fa4e998f3 100644 --- a/world/src/site2/plot/airship_dock.rs +++ b/world/src/site2/plot/airship_dock.rs @@ -1,5 +1,9 @@ use super::*; -use crate::{site2::gen::PrimitiveTransform, Land}; +use crate::{ + site2::gen::PrimitiveTransform, + util::{RandomField, Sampler}, + Land, +}; use common::terrain::{Block, BlockKind, SpriteKind}; use rand::prelude::*; use std::f32::consts::PI; @@ -694,5 +698,31 @@ impl Structure for AirshipDock { }) .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base)) .fill(sprite_fill.clone()); + + // crate and barrel sprites + let mut sprite_positions = vec![]; + for a in 0..5 { + sprite_positions.push(Vec2::new(center.x + 1 + a, center.y + 2)); + } + for b in 0..=1 { + sprite_positions.push(Vec2::new(center.x, center.y + 3 + b)); + } + for sprite_pos in sprite_positions { + let rows = (RandomField::new(0).get(sprite_pos.with_z(base)) % 3) as i32; + for r in 0..rows { + painter + .aabb(Aabb { + min: sprite_pos.with_z(height + 10 + r), + max: (sprite_pos + 1).with_z(height + 11 + r), + }) + .rotate_about(Mat3::rotation_z(self.rotation).as_(), center.with_z(base)) + .fill(Fill::Block(Block::air( + match (RandomField::new(0).get(sprite_pos.with_z(base + r)) % 2) as i32 { + 0 => SpriteKind::Barrel, + _ => SpriteKind::CrateBlock, + }, + ))); + } + } } } diff --git a/world/src/site2/plot/bridge.rs b/world/src/site2/plot/bridge.rs index 44bda8eac1..4687706df8 100644 --- a/world/src/site2/plot/bridge.rs +++ b/world/src/site2/plot/bridge.rs @@ -227,7 +227,7 @@ fn render_flat(bridge: &Bridge, painter: &Painter) { } .made_valid(); - let [ramp_aabr, aabr] = bridge.dir.split_aabr(aabr, height); + let [ramp_aabr, aabr] = bridge.dir.split_aabr_offset(aabr, height); let ramp_prim = |ramp_aabr: Aabr, offset: i32| { painter @@ -254,7 +254,7 @@ fn render_flat(bridge: &Bridge, painter: &Painter) { let vault_offset = 5; let bridge_thickness = 4; - let [vault, _] = bridge.dir.split_aabr(aabr, vault_width); + let [vault, _] = bridge.dir.split_aabr_offset(aabr, vault_width); let len = bridge.dir.select(aabr.size()); let true_offset = vault_width + vault_offset; @@ -321,8 +321,11 @@ fn render_heightened_viaduct(bridge: &Bridge, painter: &Painter, data: &Heighten } .made_valid(); - let [_start_aabr, rest] = bridge.dir.split_aabr(aabr, bridge_start_z - bridge.start.z); - let [_end_aabr, bridge_aabr] = (-bridge.dir).split_aabr(rest, bridge_start_z - bridge.end.z); + let [_start_aabr, rest] = bridge + .dir + .split_aabr_offset(aabr, bridge_start_z - bridge.start.z); + let [_end_aabr, bridge_aabr] = + (-bridge.dir).split_aabr_offset(rest, bridge_start_z - bridge.end.z); let under = bridge.center.z - 15; let bridge_prim = |bridge_width: i32| { @@ -334,11 +337,14 @@ fn render_heightened_viaduct(bridge: &Bridge, painter: &Painter, data: &Heighten } .made_valid(); - let [start_aabr, rest] = bridge.dir.split_aabr(aabr, bridge_start_z - bridge.start.z); - let [end_aabr, bridge_aabr] = (-bridge.dir).split_aabr(rest, bridge_start_z - bridge.end.z); + let [start_aabr, rest] = bridge + .dir + .split_aabr_offset(aabr, bridge_start_z - bridge.start.z); + let [end_aabr, bridge_aabr] = + (-bridge.dir).split_aabr_offset(rest, bridge_start_z - bridge.end.z); let [bridge_start, bridge_end] = bridge .dir - .split_aabr(bridge_aabr, bridge.dir.select(bridge_aabr.size()) / 2); + .split_aabr_offset(bridge_aabr, bridge.dir.select(bridge_aabr.size()) / 2); let ramp_in_aabr = |aabr: Aabr, dir: Dir, zmin, zmax| { let inset = dir.select(aabr.size()); @@ -505,8 +511,11 @@ fn render_heightened_viaduct(bridge: &Bridge, painter: &Painter, data: &Heighten let mut rng = thread_rng(); if rng.gen_bool(0.1) { painter.spawn( - EntityInfo::at(c.with_z(bridge.center.z).as_()) - .with_asset_expect("common.entity.wild.aggressive.swamp_troll", &mut rng), + EntityInfo::at(c.with_z(bridge.center.z).as_()).with_asset_expect( + "common.entity.wild.aggressive.swamp_troll", + &mut rng, + None, + ), ); } } @@ -592,7 +601,7 @@ fn render_tower(bridge: &Bridge, painter: &Painter, roof_kind: &RoofKind) { let aabr = bridge .dir .rotated_cw() - .split_aabr(tower_aabr, stair_thickness + 1)[1]; + .split_aabr_offset(tower_aabr, stair_thickness + 1)[1]; painter .aabb(aabb( @@ -748,7 +757,7 @@ fn render_hang(bridge: &Bridge, painter: &Painter) { let top_offset = 4; let top = bridge.end.z + top_offset; - let [ramp_f, aabr] = bridge.dir.split_aabr(aabr, top - bridge.start.z + 1); + let [ramp_f, aabr] = bridge.dir.split_aabr_offset(aabr, top - bridge.start.z + 1); painter .aabb(aabb( @@ -764,7 +773,7 @@ fn render_hang(bridge: &Bridge, painter: &Painter) { ) .fill(rock.clone()); - let [ramp_b, aabr] = (-bridge.dir).split_aabr(aabr, top_offset + 1); + let [ramp_b, aabr] = (-bridge.dir).split_aabr_offset(aabr, top_offset + 1); painter .aabb(aabb( ramp_b.min.with_z(bridge.end.z - 10), @@ -878,7 +887,7 @@ impl Bridge { let min_water_dist = 5; let find_edge = |start: Vec2, end: Vec2| { let mut test_start = start; - let dir = Dir::from_vector(end - start).to_vec2(); + let dir = Dir::from_vec2(end - start).to_vec2(); let mut last_alt = if let Some(col) = land.column_sample(start, index) { col.alt as i32 } else { @@ -932,7 +941,7 @@ impl Bridge { start, end, center, - dir: Dir::from_vector(end.xy() - start.xy()), + dir: Dir::from_vec2(end.xy() - start.xy()), kind: bridge, biome: land .get_chunk_wpos(center.xy()) diff --git a/world/src/site2/plot/camp.rs b/world/src/site2/plot/camp.rs index b6babc6551..806e55a1f7 100644 --- a/world/src/site2/plot/camp.rs +++ b/world/src/site2/plot/camp.rs @@ -88,8 +88,11 @@ impl Structure for Camp { CampType::Pirate => { for p in 0..npc_rng { painter.spawn( - EntityInfo::at((center + p).with_z(base + 2).as_()) - .with_asset_expect("common.entity.spot.pirate", &mut thread_rng), + EntityInfo::at((center + p).with_z(base + 2).as_()).with_asset_expect( + "common.entity.spot.pirate", + &mut thread_rng, + None, + ), ) } let pet = if npc_rng < 3 { @@ -98,21 +101,30 @@ impl Structure for Camp { "common.entity.wild.peaceful.rat" }; painter.spawn( - EntityInfo::at(center.with_z(base + 2).as_()) - .with_asset_expect(pet, &mut thread_rng), + EntityInfo::at(center.with_z(base + 2).as_()).with_asset_expect( + pet, + &mut thread_rng, + None, + ), ) }, _ => { if npc_rng > 2 { painter.spawn( - EntityInfo::at((center - 1).with_z(base + 2).as_()) - .with_asset_expect("common.entity.village.bowman", &mut thread_rng), + EntityInfo::at((center - 1).with_z(base + 2).as_()).with_asset_expect( + "common.entity.village.bowman", + &mut thread_rng, + None, + ), ); } if npc_rng < 4 { painter.spawn( - EntityInfo::at((center + 1).with_z(base + 2).as_()) - .with_asset_expect("common.entity.village.skinner", &mut thread_rng), + EntityInfo::at((center + 1).with_z(base + 2).as_()).with_asset_expect( + "common.entity.village.skinner", + &mut thread_rng, + None, + ), ) } }, diff --git a/world/src/site2/plot/dungeon.rs b/world/src/site2/plot/dungeon.rs index 26b4602f10..49f04c8520 100644 --- a/world/src/site2/plot/dungeon.rs +++ b/world/src/site2/plot/dungeon.rs @@ -704,9 +704,19 @@ fn enemy_2(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3) -> Vec entity.with_asset_expect("common.entity.dungeon.sahagin.sniper", dynamic_rng), - 1 => entity.with_asset_expect("common.entity.dungeon.sahagin.sorcerer", dynamic_rng), - _ => entity.with_asset_expect("common.entity.dungeon.sahagin.spearman", dynamic_rng), + 0 => { + entity.with_asset_expect("common.entity.dungeon.sahagin.sniper", dynamic_rng, None) + }, + 1 => entity.with_asset_expect( + "common.entity.dungeon.sahagin.sorcerer", + dynamic_rng, + None, + ), + _ => entity.with_asset_expect( + "common.entity.dungeon.sahagin.spearman", + dynamic_rng, + None, + ), } }); @@ -720,9 +730,11 @@ fn enemy_3(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3) -> Vec entity.with_asset_expect("common.entity.dungeon.haniwa.archer", dynamic_rng), - 1 => entity.with_asset_expect("common.entity.dungeon.haniwa.soldier", dynamic_rng), - _ => entity.with_asset_expect("common.entity.dungeon.haniwa.guard", dynamic_rng), + 0 => entity.with_asset_expect("common.entity.dungeon.haniwa.archer", dynamic_rng, None), + 1 => { + entity.with_asset_expect("common.entity.dungeon.haniwa.soldier", dynamic_rng, None) + }, + _ => entity.with_asset_expect("common.entity.dungeon.haniwa.guard", dynamic_rng, None), } }); @@ -736,9 +748,21 @@ fn enemy_4(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3) -> Vec entity.with_asset_expect("common.entity.dungeon.myrmidon.marksman", dynamic_rng), - 1 => entity.with_asset_expect("common.entity.dungeon.myrmidon.strategian", dynamic_rng), - _ => entity.with_asset_expect("common.entity.dungeon.myrmidon.hoplite", dynamic_rng), + 0 => entity.with_asset_expect( + "common.entity.dungeon.myrmidon.marksman", + dynamic_rng, + None, + ), + 1 => entity.with_asset_expect( + "common.entity.dungeon.myrmidon.strategian", + dynamic_rng, + None, + ), + _ => entity.with_asset_expect( + "common.entity.dungeon.myrmidon.hoplite", + dynamic_rng, + None, + ), } }); @@ -752,9 +776,15 @@ fn enemy_5(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3) -> Vec entity.with_asset_expect("common.entity.dungeon.cultist.warlock", dynamic_rng), - 1 => entity.with_asset_expect("common.entity.dungeon.cultist.warlord", dynamic_rng), - _ => entity.with_asset_expect("common.entity.dungeon.cultist.cultist", dynamic_rng), + 0 => { + entity.with_asset_expect("common.entity.dungeon.cultist.warlock", dynamic_rng, None) + }, + 1 => { + entity.with_asset_expect("common.entity.dungeon.cultist.warlord", dynamic_rng, None) + }, + _ => { + entity.with_asset_expect("common.entity.dungeon.cultist.cultist", dynamic_rng, None) + }, } }); @@ -766,31 +796,37 @@ fn enemy_fallback(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3) -> Vec) -> EntityInfo { - EntityInfo::at(pos).with_asset_expect("common.entity.dungeon.haniwa.sentry", dynamic_rng) + EntityInfo::at(pos).with_asset_expect("common.entity.dungeon.haniwa.sentry", dynamic_rng, None) } fn turret_5(dynamic_rng: &mut impl Rng, pos: Vec3) -> EntityInfo { - EntityInfo::at(pos).with_asset_expect("common.entity.dungeon.cultist.turret", dynamic_rng) + EntityInfo::at(pos).with_asset_expect("common.entity.dungeon.cultist.turret", dynamic_rng, None) } fn boss_2(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3) -> Vec { vec![ - EntityInfo::at(tile_wcenter.map(|e| e as f32)) - .with_asset_expect("common.entity.dungeon.sahagin.tidalwarrior", dynamic_rng), + EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect( + "common.entity.dungeon.sahagin.tidalwarrior", + dynamic_rng, + None, + ), ] } fn boss_3(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3) -> Vec { let mut entities = Vec::new(); entities.resize_with(2, || { - EntityInfo::at(tile_wcenter.map(|e| e as f32)) - .with_asset_expect("common.entity.dungeon.haniwa.claygolem", dynamic_rng) + EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect( + "common.entity.dungeon.haniwa.claygolem", + dynamic_rng, + None, + ) }); entities @@ -798,30 +834,42 @@ fn boss_3(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3) -> Vec) -> Vec { vec![ - EntityInfo::at(tile_wcenter.map(|e| e as f32)) - .with_asset_expect("common.entity.dungeon.myrmidon.minotaur", dynamic_rng), + EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect( + "common.entity.dungeon.myrmidon.minotaur", + dynamic_rng, + None, + ), ] } fn boss_5(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3) -> Vec { vec![ - EntityInfo::at(tile_wcenter.map(|e| e as f32)) - .with_asset_expect("common.entity.dungeon.cultist.mindflayer", dynamic_rng), + EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect( + "common.entity.dungeon.cultist.mindflayer", + dynamic_rng, + None, + ), ] } fn boss_fallback(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3) -> Vec { vec![ - EntityInfo::at(tile_wcenter.map(|e| e as f32)) - .with_asset_expect("common.entity.dungeon.fallback.boss", dynamic_rng), + EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect( + "common.entity.dungeon.fallback.boss", + dynamic_rng, + None, + ), ] } fn mini_boss_2(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3) -> Vec { let mut entities = Vec::new(); entities.resize_with(6, || { - EntityInfo::at(tile_wcenter.map(|e| e as f32)) - .with_asset_expect("common.entity.dungeon.sahagin.hakulaq", dynamic_rng) + EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect( + "common.entity.dungeon.sahagin.hakulaq", + dynamic_rng, + None, + ) }); entities } @@ -829,16 +877,22 @@ fn mini_boss_2(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3) -> Vec) -> Vec { let mut entities = Vec::new(); entities.resize_with(3, || { - EntityInfo::at(tile_wcenter.map(|e| e as f32)) - .with_asset_expect("common.entity.dungeon.haniwa.bonerattler", dynamic_rng) + EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect( + "common.entity.dungeon.haniwa.bonerattler", + dynamic_rng, + None, + ) }); entities } fn mini_boss_4(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3) -> Vec { vec![ - EntityInfo::at(tile_wcenter.map(|e| e as f32)) - .with_asset_expect("common.entity.dungeon.myrmidon.cyclops", dynamic_rng), + EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect( + "common.entity.dungeon.myrmidon.cyclops", + dynamic_rng, + None, + ), ] } @@ -847,24 +901,36 @@ fn mini_boss_5(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3) -> Vec { entities.push( - EntityInfo::at(tile_wcenter.map(|e| e as f32)) - .with_asset_expect("common.entity.dungeon.cultist.beastmaster", dynamic_rng), + EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect( + "common.entity.dungeon.cultist.beastmaster", + dynamic_rng, + None, + ), ); entities.resize_with(entities.len() + 4, || { - EntityInfo::at(tile_wcenter.map(|e| e as f32)) - .with_asset_expect("common.entity.dungeon.cultist.hound", dynamic_rng) + EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect( + "common.entity.dungeon.cultist.hound", + dynamic_rng, + None, + ) }); }, 1 => { entities.resize_with(2, || { - EntityInfo::at(tile_wcenter.map(|e| e as f32)) - .with_asset_expect("common.entity.dungeon.cultist.husk_brute", dynamic_rng) + EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect( + "common.entity.dungeon.cultist.husk_brute", + dynamic_rng, + None, + ) }); }, _ => { entities.resize_with(10, || { - EntityInfo::at(tile_wcenter.map(|e| e as f32)) - .with_asset_expect("common.entity.dungeon.cultist.husk", dynamic_rng) + EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect( + "common.entity.dungeon.cultist.husk", + dynamic_rng, + None, + ) }); }, } @@ -873,8 +939,11 @@ fn mini_boss_5(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3) -> Vec) -> Vec { vec![ - EntityInfo::at(tile_wcenter.map(|e| e as f32)) - .with_asset_expect("common.entity.dungeon.fallback.miniboss", dynamic_rng), + EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect( + "common.entity.dungeon.fallback.miniboss", + dynamic_rng, + None, + ), ] } diff --git a/world/src/site2/plot/dwarven_mine.rs b/world/src/site2/plot/dwarven_mine.rs index bf09aa574a..505ea8b13e 100644 --- a/world/src/site2/plot/dwarven_mine.rs +++ b/world/src/site2/plot/dwarven_mine.rs @@ -637,7 +637,7 @@ fn spawn_entity(pos: Vec3, painter: &Painter, entity_path: &str) { let mut rng = thread_rng(); painter.spawn( EntityInfo::at(pos) - .with_asset_expect(entity_path, &mut rng) + .with_asset_expect(entity_path, &mut rng, None) .with_no_flee(), ); } @@ -668,7 +668,7 @@ fn spawn_entities( let spawn_pos = pos + Vec3::new(x_offset, y_offset, 0.0); - painter.spawn(EntityInfo::at(spawn_pos).with_asset_expect(entity_path, &mut rng)); + painter.spawn(EntityInfo::at(spawn_pos).with_asset_expect(entity_path, &mut rng, None)); } } diff --git a/world/src/site2/plot/giant_tree.rs b/world/src/site2/plot/giant_tree.rs index 96327fb862..3753ff5f57 100644 --- a/world/src/site2/plot/giant_tree.rs +++ b/world/src/site2/plot/giant_tree.rs @@ -49,27 +49,31 @@ impl GiantTree { if above_block.kind() == BlockKind::Leaves && dynamic_rng.gen_bool(0.001) { let entity = EntityInfo::at(pos.as_()); match dynamic_rng.gen_range(0..=4) { - 0 => { - Some(entity.with_asset_expect( - "common.entity.wild.aggressive.horn_beetle", - dynamic_rng, - )) - }, - 1 => { - Some(entity.with_asset_expect( - "common.entity.wild.aggressive.stag_beetle", - dynamic_rng, - )) - }, - 2 => Some( - entity.with_asset_expect("common.entity.wild.aggressive.deadwood", dynamic_rng), - ), - 3 => Some( - entity.with_asset_expect("common.entity.wild.aggressive.maneater", dynamic_rng), - ), - 4 => Some( - entity.with_asset_expect("common.entity.wild.peaceful.parrot", dynamic_rng), - ), + 0 => Some(entity.with_asset_expect( + "common.entity.wild.aggressive.horn_beetle", + dynamic_rng, + None, + )), + 1 => Some(entity.with_asset_expect( + "common.entity.wild.aggressive.stag_beetle", + dynamic_rng, + None, + )), + 2 => Some(entity.with_asset_expect( + "common.entity.wild.aggressive.deadwood", + dynamic_rng, + None, + )), + 3 => Some(entity.with_asset_expect( + "common.entity.wild.aggressive.maneater", + dynamic_rng, + None, + )), + 4 => Some(entity.with_asset_expect( + "common.entity.wild.peaceful.parrot", + dynamic_rng, + None, + )), _ => None, } } else { diff --git a/world/src/site2/plot/gnarling.rs b/world/src/site2/plot/gnarling.rs index ce25e7ad2a..2f75357d21 100644 --- a/world/src/site2/plot/gnarling.rs +++ b/world/src/site2/plot/gnarling.rs @@ -237,7 +237,7 @@ impl GnarlingFortification { )) } }) { - let dir_to_center = Dir::from_vector(hut_loc.xy()).opposite(); + let dir_to_center = Dir::from_vec2(hut_loc.xy()).opposite(); let door_rng: u32 = rng.gen_range(0..9); let door_dir = match door_rng { 0..=3 => dir_to_center, @@ -262,7 +262,7 @@ impl GnarlingFortification { let chieftain_hut_loc = ((inner_tower_locs[0] + inner_tower_locs[1]) + 2 * outer_wall_corners[chieftain_indices[1]]) / 4; - let chieftain_hut_ori = Dir::from_vector(chieftain_hut_loc).opposite(); + let chieftain_hut_ori = Dir::from_vec2(chieftain_hut_loc).opposite(); structure_locations.push(( GnarlingStructure::ChieftainHut, chieftain_hut_loc.with_z(rpos_height(chieftain_hut_loc)), @@ -1874,18 +1874,27 @@ impl Structure for GnarlingFortification { } fn gnarling_mugger(pos: Vec3, rng: &mut R) -> EntityInfo { - EntityInfo::at(pos.map(|x| x as f32)) - .with_asset_expect("common.entity.dungeon.gnarling.mugger", rng) + EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect( + "common.entity.dungeon.gnarling.mugger", + rng, + None, + ) } fn gnarling_stalker(pos: Vec3, rng: &mut R) -> EntityInfo { - EntityInfo::at(pos.map(|x| x as f32)) - .with_asset_expect("common.entity.dungeon.gnarling.stalker", rng) + EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect( + "common.entity.dungeon.gnarling.stalker", + rng, + None, + ) } fn gnarling_logger(pos: Vec3, rng: &mut R) -> EntityInfo { - EntityInfo::at(pos.map(|x| x as f32)) - .with_asset_expect("common.entity.dungeon.gnarling.logger", rng) + EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect( + "common.entity.dungeon.gnarling.logger", + rng, + None, + ) } fn random_gnarling(pos: Vec3, rng: &mut R) -> EntityInfo { @@ -1898,28 +1907,40 @@ fn random_gnarling(pos: Vec3, rng: &mut R) -> EntityInfo { fn gnarling_chieftain(pos: Vec3, rng: &mut R) -> EntityInfo { EntityInfo::at(pos.map(|x| x as f32)) - .with_asset_expect("common.entity.dungeon.gnarling.chieftain", rng) + .with_asset_expect("common.entity.dungeon.gnarling.chieftain", rng, None) .with_no_flee() } fn deadwood(pos: Vec3, rng: &mut R) -> EntityInfo { - EntityInfo::at(pos.map(|x| x as f32)) - .with_asset_expect("common.entity.wild.aggressive.deadwood", rng) + EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect( + "common.entity.wild.aggressive.deadwood", + rng, + None, + ) } fn mandragora(pos: Vec3, rng: &mut R) -> EntityInfo { - EntityInfo::at(pos.map(|x| x as f32)) - .with_asset_expect("common.entity.dungeon.gnarling.mandragora", rng) + EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect( + "common.entity.dungeon.gnarling.mandragora", + rng, + None, + ) } fn wood_golem(pos: Vec3, rng: &mut R) -> EntityInfo { - EntityInfo::at(pos.map(|x| x as f32)) - .with_asset_expect("common.entity.dungeon.gnarling.woodgolem", rng) + EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect( + "common.entity.dungeon.gnarling.woodgolem", + rng, + None, + ) } fn harvester_boss(pos: Vec3, rng: &mut R) -> EntityInfo { - EntityInfo::at(pos.map(|x| x as f32)) - .with_asset_expect("common.entity.dungeon.gnarling.harvester", rng) + EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect( + "common.entity.dungeon.gnarling.harvester", + rng, + None, + ) } #[derive(Default)] diff --git a/world/src/site2/plot/house.rs b/world/src/site2/plot/house.rs index 68da7d0386..4d126cad2f 100644 --- a/world/src/site2/plot/house.rs +++ b/world/src/site2/plot/house.rs @@ -4,7 +4,10 @@ use crate::{ util::{RandomField, Sampler, DIRS}, Land, }; -use common::terrain::{Block, BlockKind, SpriteKind}; +use common::{ + calendar::{Calendar, CalendarEvent}, + terrain::{Block, BlockKind, SpriteKind}, +}; use rand::prelude::*; use vek::*; @@ -25,6 +28,7 @@ pub struct House { /// Color of the roof roof_color: Rgb, front: u8, + christmas_decorations: bool, } impl House { @@ -35,6 +39,7 @@ impl House { door_tile: Vec2, door_dir: Vec2, tile_aabr: Aabr, + calendar: Option<&Calendar>, ) -> Self { let levels = rng.gen_range(1..2 + (tile_aabr.max - tile_aabr.min).product() / 6) as u32; let door_tile_pos = site.tile_center_wpos(door_tile); @@ -52,6 +57,8 @@ impl House { } else { 1 }; + let christmas_decorations = + calendar.map_or(false, |c| c.is_event(CalendarEvent::Christmas)); Self { door_tile: door_tile_pos, @@ -83,6 +90,7 @@ impl House { *colors.choose(rng).unwrap_or(&Rgb::new(21, 43, 48)) }, front, + christmas_decorations, } } @@ -2041,6 +2049,52 @@ impl Structure for House { painter.prim(Primitive::Aabb(fire_embers)), Fill::Block(Block::air(SpriteKind::Ember)), ); + if self.christmas_decorations { + let (wreath_pos, wreath_ori) = match self.front { + 0 => ( + Aabb { + min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 3) + .with_z(alt + 2), + max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 4) + .with_z(alt + 3), + }, + 4, + ), + 1 => ( + Aabb { + min: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 1) + .with_z(alt + 2), + max: Vec2::new(fireplace_origin.x + 4, fireplace_origin.y + 2) + .with_z(alt + 3), + }, + 2, + ), + 2 => ( + Aabb { + min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y - 1) + .with_z(alt + 2), + max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y).with_z(alt + 3), + }, + 0, + ), + _ => ( + Aabb { + min: Vec2::new(fireplace_origin.x - 1, fireplace_origin.y + 1) + .with_z(alt + 2), + max: Vec2::new(fireplace_origin.x, fireplace_origin.y + 2).with_z(alt + 3), + }, + 6, + ), + }; + painter.fill( + painter.prim(Primitive::Aabb(wreath_pos)), + Fill::Block( + Block::air(SpriteKind::ChristmasWreath) + .with_ori(wreath_ori) + .unwrap(), + ), + ); + } // Door // Fill around the door with wall @@ -2170,5 +2224,56 @@ impl Structure for House { painter.prim(Primitive::Aabb(door2)), Fill::Block(Block::air(SpriteKind::Door).with_ori(door2_ori).unwrap()), ); + if self.christmas_decorations { + // we need to randomize position to see both variants + let rng = RandomField::new(0).get(self.door_tile.with_z(alt + 3)); + let right = (rng % 2) as i32; + let (door_light_pos, door_light_ori) = match self.front { + 0 => ( + Aabb { + min: Vec2::new(self.door_tile.x + right, self.bounds.max.y + 1) + .with_z(alt + 3), + max: Vec2::new(self.door_tile.x + 1 + right, self.bounds.max.y + 2) + .with_z(alt + 4), + }, + 4, + ), + 1 => ( + Aabb { + min: Vec2::new(self.bounds.max.x + 1, self.door_tile.y + right) + .with_z(alt + 3), + max: Vec2::new(self.bounds.max.x + 2, self.door_tile.y + 1 + right) + .with_z(alt + 4), + }, + 2, + ), + 2 => ( + Aabb { + min: Vec2::new(self.door_tile.x + right, self.bounds.min.y - 1) + .with_z(alt + 3), + max: Vec2::new(self.door_tile.x + 1 + right, self.bounds.min.y) + .with_z(alt + 4), + }, + 0, + ), + _ => ( + Aabb { + min: Vec2::new(self.bounds.min.x - 1, self.door_tile.y + right) + .with_z(alt + 3), + max: Vec2::new(self.bounds.min.x, self.door_tile.y + 1 + right) + .with_z(alt + 4), + }, + 6, + ), + }; + painter.fill( + painter.prim(Primitive::Aabb(door_light_pos)), + Fill::Block( + Block::air(SpriteKind::ChristmasOrnament) + .with_ori(door_light_ori) + .unwrap(), + ), + ); + } } } diff --git a/world/src/site2/plot/jungle_ruin.rs b/world/src/site2/plot/jungle_ruin.rs index 158d20a130..c0f69da6df 100644 --- a/world/src/site2/plot/jungle_ruin.rs +++ b/world/src/site2/plot/jungle_ruin.rs @@ -240,17 +240,24 @@ impl Structure for JungleRuin { EntityInfo::at(npc_pos.with_z(plot_base + 5).as_()).with_asset_expect( "common.entity.spot.dwarf_grave_robber", &mut thread_rng, + None, ), ), // sauroks 1 => painter.spawn( - EntityInfo::at(npc_pos.with_z(plot_base + 5).as_()) - .with_asset_expect("common.entity.spot.saurok", &mut thread_rng), + EntityInfo::at(npc_pos.with_z(plot_base + 5).as_()).with_asset_expect( + "common.entity.spot.saurok", + &mut thread_rng, + None, + ), ), // grim salvager 2 => painter.spawn( - EntityInfo::at(npc_pos.with_z(plot_base + 5).as_()) - .with_asset_expect("common.entity.spot.grim_salvager", &mut thread_rng), + EntityInfo::at(npc_pos.with_z(plot_base + 5).as_()).with_asset_expect( + "common.entity.spot.grim_salvager", + &mut thread_rng, + None, + ), ), _ => {}, } diff --git a/world/src/site2/plot/pirate_hideout.rs b/world/src/site2/plot/pirate_hideout.rs index f361707962..0a4c19d80b 100644 --- a/world/src/site2/plot/pirate_hideout.rs +++ b/world/src/site2/plot/pirate_hideout.rs @@ -68,18 +68,27 @@ impl Structure for PirateHideout { match RandomField::new(0).get(npc_pos.with_z(base)) % 10 { // rat 0 => painter.spawn( - EntityInfo::at(npc_pos.with_z(base).as_()) - .with_asset_expect("common.entity.wild.peaceful.rat", &mut thread_rng), + EntityInfo::at(npc_pos.with_z(base).as_()).with_asset_expect( + "common.entity.wild.peaceful.rat", + &mut thread_rng, + None, + ), ), // parrot 1 => painter.spawn( - EntityInfo::at(npc_pos.with_z(base).as_()) - .with_asset_expect("common.entity.wild.peaceful.parrot", &mut thread_rng), + EntityInfo::at(npc_pos.with_z(base).as_()).with_asset_expect( + "common.entity.wild.peaceful.parrot", + &mut thread_rng, + None, + ), ), // pirates _ => painter.spawn( - EntityInfo::at(npc_pos.with_z(base).as_()) - .with_asset_expect("common.entity.spot.pirate", &mut thread_rng), + EntityInfo::at(npc_pos.with_z(base).as_()).with_asset_expect( + "common.entity.spot.pirate", + &mut thread_rng, + None, + ), ), } } diff --git a/world/src/site2/plot/rock_circle.rs b/world/src/site2/plot/rock_circle.rs index dfcb022f2a..37c3637265 100644 --- a/world/src/site2/plot/rock_circle.rs +++ b/world/src/site2/plot/rock_circle.rs @@ -57,8 +57,11 @@ impl Structure for RockCircle { if thread_rng.gen_range(0..=8) < 1 { // dullahan painter.spawn( - EntityInfo::at(center.with_z(base + 2).as_()) - .with_asset_expect("common.entity.wild.aggressive.dullahan", &mut thread_rng), + EntityInfo::at(center.with_z(base + 2).as_()).with_asset_expect( + "common.entity.wild.aggressive.dullahan", + &mut thread_rng, + None, + ), ) } } diff --git a/world/src/site2/plot/sea_chapel.rs b/world/src/site2/plot/sea_chapel.rs index a7d25d0583..4f6e6f0416 100644 --- a/world/src/site2/plot/sea_chapel.rs +++ b/world/src/site2/plot/sea_chapel.rs @@ -611,10 +611,11 @@ impl Structure for SeaChapel { // cellar sea crocodiles let cellar_sea_croc_pos = (center - (diameter / 4)).with_z(base - (diameter / 2)); for _ in 0..(3 + ((RandomField::new(0).get((cellar_sea_croc_pos).with_z(base))) % 5)) { - painter.spawn( - EntityInfo::at(cellar_sea_croc_pos.as_()) - .with_asset_expect("common.entity.wild.aggressive.sea_crocodile", &mut rng), - ) + painter.spawn(EntityInfo::at(cellar_sea_croc_pos.as_()).with_asset_expect( + "common.entity.wild.aggressive.sea_crocodile", + &mut rng, + None, + )) } // clear chapel main room painter @@ -681,20 +682,29 @@ impl Structure for SeaChapel { // organ on chapel top floor organ podium let first_floor_organ_pos = center_o2.with_z(base - (diameter / 8) + diameter - 4); painter.spawn( - EntityInfo::at(first_floor_organ_pos.as_()) - .with_asset_expect("common.entity.dungeon.sea_chapel.organ", &mut rng), + EntityInfo::at(first_floor_organ_pos.as_()).with_asset_expect( + "common.entity.dungeon.sea_chapel.organ", + &mut rng, + None, + ), ); // sea clerics, bishop on top floor let first_floor_spawn_pos = (center_o2 - 2).with_z(base - (diameter / 8) + diameter - 4); for _ in 0..(2 + ((RandomField::new(0).get((first_floor_spawn_pos).with_z(base))) % 2)) { painter.spawn( - EntityInfo::at(first_floor_spawn_pos.as_()) - .with_asset_expect("common.entity.dungeon.sea_chapel.sea_cleric", &mut rng), + EntityInfo::at(first_floor_spawn_pos.as_()).with_asset_expect( + "common.entity.dungeon.sea_chapel.sea_cleric", + &mut rng, + None, + ), ) } painter.spawn( - EntityInfo::at(first_floor_spawn_pos.as_()) - .with_asset_expect("common.entity.dungeon.sea_chapel.sea_bishop", &mut rng), + EntityInfo::at(first_floor_spawn_pos.as_()).with_asset_expect( + "common.entity.dungeon.sea_chapel.sea_bishop", + &mut rng, + None, + ), ); // chapel main room gold decor ring and floor painter @@ -739,26 +749,38 @@ impl Structure for SeaChapel { // organ on chapel main room organ podium let first_floor_organ_pos = center_o1.with_z(base + 2); painter.spawn( - EntityInfo::at(first_floor_organ_pos.as_()) - .with_asset_expect("common.entity.dungeon.sea_chapel.organ", &mut rng), + EntityInfo::at(first_floor_organ_pos.as_()).with_asset_expect( + "common.entity.dungeon.sea_chapel.organ", + &mut rng, + None, + ), ); // sea clerics on main floor let main_room_sea_clerics_pos = (center_o1 - 2).with_z(base + 2); for _ in 0..(3 + ((RandomField::new(0).get((main_room_sea_clerics_pos).with_z(base))) % 3)) { painter.spawn( - EntityInfo::at(main_room_sea_clerics_pos.as_()) - .with_asset_expect("common.entity.dungeon.sea_chapel.sea_cleric", &mut rng), + EntityInfo::at(main_room_sea_clerics_pos.as_()).with_asset_expect( + "common.entity.dungeon.sea_chapel.sea_cleric", + &mut rng, + None, + ), ) } // coral golem on main floor painter.spawn( - EntityInfo::at((first_floor_organ_pos + 2).as_()) - .with_asset_expect("common.entity.dungeon.sea_chapel.coralgolem", &mut rng), + EntityInfo::at((first_floor_organ_pos + 2).as_()).with_asset_expect( + "common.entity.dungeon.sea_chapel.coralgolem", + &mut rng, + None, + ), ); painter.spawn( - EntityInfo::at((first_floor_organ_pos + 4).as_()) - .with_asset_expect("common.entity.dungeon.sea_chapel.sea_bishop", &mut rng), + EntityInfo::at((first_floor_organ_pos + 4).as_()).with_asset_expect( + "common.entity.dungeon.sea_chapel.sea_bishop", + &mut rng, + None, + ), ); // chapel main room glassbarrier to cellar let center_g = center - diameter / 7; @@ -833,17 +855,19 @@ impl Structure for SeaChapel { // cardinals room sea clerics let cr_sea_clerics_pos = (center - (diameter / 5)).with_z(base - (diameter / 4) - 3); for _ in 0..(2 + ((RandomField::new(0).get((cr_sea_clerics_pos).with_z(base))) % 3)) { - painter.spawn( - EntityInfo::at(cr_sea_clerics_pos.as_()) - .with_asset_expect("common.entity.dungeon.sea_chapel.sea_cleric", &mut rng), - ) + painter.spawn(EntityInfo::at(cr_sea_clerics_pos.as_()).with_asset_expect( + "common.entity.dungeon.sea_chapel.sea_cleric", + &mut rng, + None, + )) } // Cardinal let cr_cardinal_pos = (center - (diameter / 6)).with_z(base - (diameter / 4) - 3); - painter.spawn( - EntityInfo::at(cr_cardinal_pos.as_()) - .with_asset_expect("common.entity.dungeon.sea_chapel.cardinal", &mut rng), - ); + painter.spawn(EntityInfo::at(cr_cardinal_pos.as_()).with_asset_expect( + "common.entity.dungeon.sea_chapel.cardinal", + &mut rng, + None, + )); // glassbarrier to water basin painter .cylinder(Aabb { @@ -1394,6 +1418,7 @@ impl Structure for SeaChapel { painter.spawn(EntityInfo::at(room_clerics_pos.as_()).with_asset_expect( "common.entity.dungeon.sea_chapel.sea_cleric", &mut rng, + None, )); }; // decor for top rooms @@ -1668,8 +1693,11 @@ impl Structure for SeaChapel { let underwater_organ_pos = (center - (diameter / 4)).with_z(base - (3 * diameter) + (diameter / 2) + 1); painter.spawn( - EntityInfo::at(underwater_organ_pos.as_()) - .with_asset_expect("common.entity.dungeon.sea_chapel.organ", &mut rng), + EntityInfo::at(underwater_organ_pos.as_()).with_asset_expect( + "common.entity.dungeon.sea_chapel.organ", + &mut rng, + None, + ), ); // underwater chamber decor ring painter @@ -1724,10 +1752,11 @@ impl Structure for SeaChapel { .fill(gold_chain); // underwater chamber dagon let cellar_miniboss_pos = (center + 6).with_z(base - (3 * diameter) + (diameter / 2) + 1); - painter.spawn( - EntityInfo::at(cellar_miniboss_pos.as_()) - .with_asset_expect("common.entity.dungeon.sea_chapel.dagon", &mut rng), - ); + painter.spawn(EntityInfo::at(cellar_miniboss_pos.as_()).with_asset_expect( + "common.entity.dungeon.sea_chapel.dagon", + &mut rng, + None, + )); // underwater chamber floor entry painter .cylinder_with_radius( @@ -2764,8 +2793,11 @@ impl Structure for SeaChapel { 0..(2 + ((RandomField::new(0).get((bldg_cellar_sea_croc_pos).with_z(base))) % 2)) { painter.spawn( - EntityInfo::at(bldg_cellar_sea_croc_pos.as_()) - .with_asset_expect("common.entity.wild.aggressive.sea_crocodile", &mut rng), + EntityInfo::at(bldg_cellar_sea_croc_pos.as_()).with_asset_expect( + "common.entity.wild.aggressive.sea_crocodile", + &mut rng, + None, + ), ) } match bldg_variant { @@ -2821,6 +2853,7 @@ impl Structure for SeaChapel { EntityInfo::at(bldg_floor_sea_cleric_pos.as_()).with_asset_expect( "common.entity.dungeon.sea_chapel.sea_cleric", &mut rng, + None, ), ) } @@ -2962,6 +2995,7 @@ impl Structure for SeaChapel { EntityInfo::at(bldg_floor_sea_cleric_pos.as_()).with_asset_expect( "common.entity.dungeon.sea_chapel.sea_cleric", &mut rng, + None, ), ) } @@ -2974,6 +3008,7 @@ impl Structure for SeaChapel { EntityInfo::at(bldg_floor3_sea_cleric_pos.as_()).with_asset_expect( "common.entity.dungeon.sea_chapel.sea_cleric", &mut rng, + None, ), ) } @@ -3319,6 +3354,7 @@ impl Structure for SeaChapel { EntityInfo::at(prisoner_pos.as_()).with_asset_expect( "common.entity.dungeon.sea_chapel.prisoner", &mut rng, + None, ), ) } diff --git a/world/src/site2/plot/tavern.rs b/world/src/site2/plot/tavern.rs new file mode 100644 index 0000000000..672c0f846b --- /dev/null +++ b/world/src/site2/plot/tavern.rs @@ -0,0 +1,1588 @@ +use std::{mem::swap, ops::RangeInclusive}; + +use common::{ + comp::Content, + lottery::Lottery, + store::{Id, Store}, + terrain::{BlockKind, SpriteCfg, SpriteKind}, +}; +use enum_map::EnumMap; +use enumset::EnumSet; +use hashbrown::HashSet; +use rand::{seq::IteratorRandom, Rng}; +use strum::{EnumIter, IntoEnumIterator}; +use vek::*; + +use crate::{ + site::namegen, + site2::{gen::PrimitiveTransform, Dir, Fill, Site, Structure}, + util::RandomField, + IndexRef, Land, +}; + +type Neighbor = Option>; + +pub struct Wall { + start: Vec2, + end: Vec2, + base_alt: i32, + top_alt: i32, + from: Neighbor, + to: Neighbor, + to_dir: Dir, + door: Option<(i32, i32)>, +} + +impl Wall { + pub fn door_pos(&self) -> Option> { + let wall_dir = Dir::from_vec2(self.end - self.start); + + self.door.map(|(door_min, door_max)| { + (self.start.as_() + wall_dir.to_vec2().as_() * (door_min + door_max) as f32 / 2.0 + 0.5) + .with_z(self.base_alt as f32) + }) + } + + pub fn door_bounds(&self) -> Option> { + let wall_dir = Dir::from_vec2(self.end - self.start); + + self.door.map(|(door_min, door_max)| { + Aabr { + min: self.start + wall_dir.to_vec2() * door_min, + max: self.start + wall_dir.to_vec2() * door_max, + } + .made_valid() + }) + } +} + +#[derive(Copy, Clone)] +enum RoofStyle { + Flat, + FlatBars { dir: Dir }, + LeanTo { dir: Dir, max_z: i32 }, + Gable { dir: Dir, max_z: i32 }, + Hip { max_z: i32 }, +} + +struct Roof { + bounds: Aabr, + min_z: i32, + style: RoofStyle, +} + +#[derive(Clone, Copy, EnumIter, enum_map::Enum)] +enum RoomKind { + Garden, + StageRoom, + BarRoom, + EntranceRoom, +} + +impl RoomKind { + /// Returns the (side length size range, area size range) + fn size_range(&self) -> (RangeInclusive, RangeInclusive) { + match self { + RoomKind::Garden => (4..=20, 25..=250), + RoomKind::StageRoom => (10..=20, 130..=400), + RoomKind::BarRoom => (7..=14, 56..=196), + RoomKind::EntranceRoom => (3..=10, 9..=50), + } + } +} + +#[derive(Clone, Copy)] +pub enum Detail { + Bar { + aabr: Aabr, + }, + Table { + pos: Vec2, + chairs: EnumSet, + }, + Stage { + aabr: Aabr, + }, +} + +pub struct Room { + /// Inclusive + pub bounds: Aabb, + kind: RoomKind, + // stairs: Option>, + walls: EnumMap>>, + roofs: Vec>, + detail_areas: Vec>, + pub details: Vec, +} + +impl Room { + fn new(bounds: Aabb, kind: RoomKind) -> Self { + Self { + bounds, + kind, + roofs: Default::default(), + walls: Default::default(), + detail_areas: Default::default(), + details: Default::default(), + } + } + + /// Are any of this rooms roofs fully covering it? + fn is_covered_by_roof(&self, roofs: &Store) -> bool { + let aabr = Aabr { + min: self.bounds.min.xy(), + max: self.bounds.max.xy(), + }; + for roof in self.roofs.iter() { + if roofs[*roof].bounds.contains_aabr(aabr) { + return true; + } + } + false + } +} + +pub struct Tavern { + name: String, + pub rooms: Store, + walls: Store, + roofs: Store, + /// Tile position of the door tile + pub door_tile: Vec2, + pub door_wpos: Vec3, + /// Axis aligned bounding region for the house + pub bounds: Aabr, +} + +impl Tavern { + pub fn generate( + land: &Land, + _index: IndexRef, + rng: &mut impl Rng, + site: &Site, + door_tile: Vec2, + door_dir: Dir, + tile_aabr: Aabr, + ) -> Self { + let name = namegen::NameGen::location(rng).generate_tavern(); + + let mut rooms = Store::default(); + let mut walls = Store::default(); + let mut roofs = Store::default(); + let mut room_counts = EnumMap::::default(); + + let bounds = Aabr { + min: site.tile_wpos(tile_aabr.min), + max: site.tile_wpos(tile_aabr.max), + }; + + let ibounds = Aabr { + min: bounds.min + 1, + max: bounds.max - 2, + }; + + let door_tile_center = site.tile_center_wpos(door_tile); + let door_wpos = door_dir.select_aabr_with(ibounds, door_tile_center); + + let door_alt = land.get_alt_approx(door_wpos); + let door_wpos = door_wpos.with_z(door_alt.ceil() as i32); + + /// Place room in bounds. + fn place_room_in( + room: RoomKind, + max_bounds: Aabr, + in_dir: Dir, + in_pos: Vec2, + rng: &mut impl Rng, + ) -> Option> { + let (size_range, area_range) = room.size_range(); + + let mut gen_range = |min, max, snap_max| { + let res = rng.gen_range(min..=max); + if snap_max <= max && snap_max - res <= 2 { + snap_max + } else { + res + } + }; + let min = *size_range.start(); + let snap_max = in_dir.select(max_bounds.size()); + let max = snap_max.min(*size_range.end()); + if max < min { + return None; + } + let size_x = gen_range(min, max, snap_max); + + let min = ((*area_range.start() + size_x - 1) / size_x).max(*size_range.start()); + let snap_max = in_dir.orthogonal().select(max_bounds.size()); + let max = snap_max + .min(*size_range.end()) + .min(*area_range.end() / size_x); + + if max < min { + return None; + } + let size_y = gen_range(min, max, snap_max); + + // calculate a valid aabr + let half_size_y = size_y / 2 + (size_y % 2) * rng.gen_range(0..=1); + let min = in_pos + in_dir.to_vec2() + in_dir.rotated_cw().to_vec2() * half_size_y; + let min = max_bounds.projected_point(min); + let max = min + in_dir.to_vec2() * size_x + in_dir.rotated_ccw().to_vec2() * size_y; + let max = max_bounds.projected_point(max); + let min = max - in_dir.to_vec2() * size_x + in_dir.rotated_cw().to_vec2() * size_y; + + let bounds = Aabr { min, max }.made_valid(); + Some(bounds) + } + struct RoomMeta { + id: Id, + walls: EnumSet, + } + + let mut room_metas = Vec::new(); + + { + let entrance_rooms = + Lottery::from(vec![(1.0, RoomKind::Garden), (2.0, RoomKind::EntranceRoom)]); + + let entrance_room = *entrance_rooms.choose_seeded(rng.gen()); + let entrance_room_hgt = rng.gen_range(3..=4); + let entrance_room_aabr = + place_room_in(entrance_room, ibounds, -door_dir, door_wpos.xy(), rng) + .expect("Not enough room in plot for a tavern"); + let entrance_room_aabb = Aabb { + min: entrance_room_aabr.min.with_z(door_wpos.z), + max: entrance_room_aabr + .max + .with_z(door_wpos.z + entrance_room_hgt), + } + .made_valid(); + + let entrance_id = rooms.insert(Room::new(entrance_room_aabb, entrance_room)); + + let start = door_dir.select_aabr_with( + entrance_room_aabr, + Vec2::broadcast(door_dir.rotated_cw().select_aabr(entrance_room_aabr)), + ) + door_dir.rotated_cw().to_vec2() + + door_dir.to_vec2(); + let door_center = door_dir.rotated_cw().select(door_wpos.xy() - start).abs(); + let wall_id = walls.insert(Wall { + start, + end: door_dir.select_aabr_with( + entrance_room_aabr, + Vec2::broadcast(door_dir.rotated_ccw().select_aabr(entrance_room_aabr)), + ) + door_dir.rotated_ccw().to_vec2() + + door_dir.to_vec2(), + base_alt: entrance_room_aabb.min.z, + top_alt: entrance_room_aabb.max.z, + from: None, + to: Some(entrance_id), + to_dir: -door_dir, + door: Some((door_center - 1, door_center + 1)), + }); + rooms[entrance_id].walls[door_dir].push(wall_id); + + room_metas.push(RoomMeta { + id: entrance_id, + walls: Dir::iter().filter(|d| *d != door_dir).collect(), + }); + + room_counts[entrance_room] += 1; + } + + let to_aabr = |aabb: Aabb| Aabr { + min: aabb.min.xy(), + max: aabb.max.xy(), + }; + // Extend a valid aabr + let extend_aabr = |aabr: Aabr, amount: i32| Aabr { + min: aabr.min - amount, + max: aabr.max + amount, + }; + 'room_gen: while !room_metas.is_empty() { + // Continue extending from a random existing room + let mut room_meta = room_metas.swap_remove(rng.gen_range(0..room_metas.len())); + if room_meta.walls.is_empty() { + continue 'room_gen; + } + + // Pick a direction to choose from + let Some(in_dir) = room_meta.walls.into_iter().choose(rng) else { + continue 'room_gen; + }; + room_meta.walls.remove(in_dir); + + let right = in_dir.orthogonal(); + let left = -right; + + let from_id = room_meta.id; + let from_room = &rooms[from_id]; + + // If there are more directions to continue from, push this room again. + if !room_meta.walls.is_empty() { + room_metas.push(room_meta); + } + + let from_bounds = to_aabr(from_room.bounds); + + // The maximum bounds, limited by the plot bounds and other rooms. + let mut max_bounds = Aabr { + min: in_dir.select_aabr_with(from_bounds, ibounds.min) + in_dir.to_vec2() * 2, + max: in_dir.select_aabr_with(ibounds, ibounds.max), + } + .made_valid(); + // Pick a height of the new room + let room_hgt = rng.gen_range(3..=5); + let wanted_alt = land.get_alt_approx(max_bounds.center()) as i32 + 1; + let max_stair_length = (in_dir.select(if wanted_alt < from_room.bounds.min.z { + from_bounds.size() + } else { + max_bounds.size() + }) / 2) + .min(5); + let alt = wanted_alt.clamp( + from_room.bounds.min.z - max_stair_length, + from_room.bounds.min.z + max_stair_length, + ); + let min_z = from_room.bounds.min.z.min(alt); + let max_z = from_room.bounds.max.z.max(alt + room_hgt); + + // Take other rooms into account when calculating `max_bounds`. We don't care + // about this room if it's the originating room or at another + // height. + for (_, room) in rooms.iter().filter(|(room_id, room)| { + *room_id != from_id + && room.bounds.min.z - 1 <= max_z + && room.bounds.max.z + 1 >= min_z + }) { + let bounds = to_aabr(room.bounds); + let bounds = extend_aabr(bounds, 2); + let intersection = bounds.intersection(max_bounds); + if intersection.is_valid() { + // Find the direction to shrink in that yields the highest area. + let Some(bounds) = Dir::iter() + .filter(|dir| { + *dir != in_dir + && dir.select_aabr(intersection) * dir.signum() + < dir.select_aabr(max_bounds) * dir.signum() + }) + .map(|min_dir| { + Aabr { + min: min_dir.select_aabr_with( + max_bounds, + Vec2::broadcast(min_dir.rotated_ccw().select_aabr(max_bounds)), + ), + max: min_dir.select_aabr_with( + intersection, + Vec2::broadcast(min_dir.rotated_cw().select_aabr(max_bounds)), + ), + } + .made_valid() + }) + .filter(|bounds| { + left.select_aabr(*bounds) < right.select_aabr(from_bounds) + && right.select_aabr(*bounds) > left.select_aabr(from_bounds) + }) + .max_by_key(|bounds| bounds.size().product()) + else { + continue 'room_gen; + }; + + max_bounds = bounds; + } + } + + // the smallest side on the maximum bounds + let max_min_size = max_bounds.size().reduce_min(); + // max bounds area + let max_area = max_bounds.size().product(); + + let room_lottery = RoomKind::iter() + // Filter out rooms that won't fit here. + .filter(|room_kind| { + let (size_range, area_range) = room_kind.size_range(); + *size_range.start() <= max_min_size && *area_range.start() <= max_area + }) + // Calculate chance for each room. + .map(|room_kind| { + ( + match room_kind { + RoomKind::Garden => { + 0.5 / (1.0 + room_counts[RoomKind::Garden] as f32 * 0.8) + }, + RoomKind::StageRoom => { + 2.0 / (1.0 + room_counts[RoomKind::StageRoom] as f32).powi(2) + }, + RoomKind::BarRoom => { + 2.0 / (1.0 + room_counts[RoomKind::BarRoom] as f32).powi(2) + }, + RoomKind::EntranceRoom => { + 0.05 / (1.0 + room_counts[RoomKind::EntranceRoom] as f32) + }, + }, + room_kind, + ) + }) + .collect::>(); + // We have no rooms to pick from. + if room_lottery.is_empty() { + continue 'room_gen; + } + + // Pick a room. + let room_lottery = Lottery::from(room_lottery); + let room_kind = *room_lottery.choose_seeded(rng.gen()); + + // Select a door position + let mut min = left + .select_aabr(from_bounds) + .max(left.select_aabr(max_bounds)); + let mut max = right + .select_aabr(from_bounds) + .min(right.select_aabr(max_bounds)); + if max < min { + swap(&mut min, &mut max); + } + if min + 2 > max { + continue 'room_gen; + } + let in_pos = rng.gen_range(min + 1..=max - 1); + let in_pos = + in_dir.select_aabr_with(from_bounds, Vec2::broadcast(in_pos)) + in_dir.to_vec2(); + + // Place the room in the given max bounds + let Some(bounds) = place_room_in(room_kind, max_bounds, in_dir, in_pos, rng) else { + continue 'room_gen; + }; + + let bounds3 = Aabb { + min: bounds.min.with_z(alt), + max: bounds.max.with_z(alt + room_hgt), + }; + let id = rooms.insert(Room::new(bounds3, room_kind)); + + let start = in_dir.select_aabr_with( + from_bounds, + Vec2::broadcast(left.select_aabr(from_bounds).max(left.select_aabr(bounds))), + ) + in_dir.to_vec2() + + left.to_vec2(); + + let end = in_dir.select_aabr_with( + from_bounds, + Vec2::broadcast( + right + .select_aabr(from_bounds) + .min(right.select_aabr(bounds)), + ), + ) + in_dir.to_vec2() + + right.to_vec2(); + + let door_center = right.select(in_pos - start); + let b = rng.gen_bool(0.5); + let door_min = door_center - b as i32; + let door_max = door_center - (!b) as i32; + let wall_id = walls.insert(Wall { + start, + end, + base_alt: min_z, + top_alt: max_z, + from: Some(from_id), + to: Some(id), + to_dir: in_dir, + door: Some((door_min, door_max)), + }); + + rooms[id].walls[-in_dir].push(wall_id); + rooms[from_id].walls[in_dir].push(wall_id); + + room_metas.push(RoomMeta { + id, + walls: Dir::iter().filter(|d| *d != -in_dir).collect(), + }); + room_counts[room_kind] += 1; + } + + // Place walls where needed. + for from_id in rooms.ids() { + let room_bounds = to_aabr(rooms[from_id].bounds); + let mut skip = HashSet::new(); + skip.insert(from_id); + let mut wall_ranges = EnumMap::>::default(); + for dir in Dir::iter() { + let orth = dir.orthogonal(); + let range = (orth.select(room_bounds.min), orth.select(room_bounds.max)); + wall_ranges[dir].push(range); + } + // Split the wall into parts. + let mut split_range = |dir: Dir, min: i32, max: i32| { + debug_assert!(min <= max); + let mut new_ranges = Vec::new(); + wall_ranges[dir].retain_mut(|(r_min, r_max)| { + if *r_min <= max && *r_max >= min { + match (*r_min >= min, *r_max <= max) { + (true, true) => false, + (true, false) => { + *r_min = max + 1; + true + }, + (false, true) => { + *r_max = min - 1; + true + }, + (false, false) => { + new_ranges.push((max + 1, *r_max)); + *r_max = min - 1; + true + }, + } + } else { + true + } + }); + wall_ranges[dir].extend(new_ranges); + }; + for dir in Dir::iter() { + let connected_walls = &mut rooms[from_id].walls[dir]; + skip.extend( + connected_walls + .iter() + .flat_map(|wall| walls[*wall].from.into_iter().chain(walls[*wall].to)), + ); + let orth = dir.orthogonal(); + // Divide wall ranges by existing walls. + for wall in connected_walls.iter() { + let wall = &walls[*wall]; + let mut min = orth.select(wall.start); + let mut max = orth.select(wall.end); + if min > max { + swap(&mut min, &mut max); + } + min += 1; + max -= 1; + split_range(dir, min, max); + } + } + + // Divide wall ranges by neighbouring rooms + for to_id in rooms.ids().filter(|id| !skip.contains(id)) { + let a_min_z = rooms[from_id].bounds.min.z; + let a_max_z = rooms[from_id].bounds.max.z; + let b_min_z = rooms[to_id].bounds.min.z; + let b_max_z = rooms[to_id].bounds.max.z; + if a_min_z >= b_max_z || a_max_z <= b_min_z { + // We are not at the same altitude. + continue; + } + let min_z = a_min_z.min(b_min_z); + let max_z = a_max_z.max(b_max_z); + let n_room_bounds = to_aabr(rooms[to_id].bounds); + + let p1 = n_room_bounds.projected_point(room_bounds.center()); + let p0 = room_bounds.projected_point(p1); + + let to_dir = Dir::from_vec2(p1 - p0); + + let intersection = to_dir + .extend_aabr(room_bounds, 1) + .intersection(to_dir.opposite().extend_aabr(n_room_bounds, 1)); + + if intersection.is_valid() { + let start = intersection.min; + let end = intersection.max; + + let orth = to_dir.orthogonal(); + + let min = orth.select(start); + let max = orth.select(end); + split_range(to_dir, min, max); + let door = if max - min > 2 && max_z - min_z > 3 && rng.gen_bool(0.8) { + let door_center = rng.gen_range(1..=max - min - 2); + Some((door_center, door_center + 1)) + } else { + None + }; + + let id = walls.insert(Wall { + start: start - orth.to_vec2(), + end: end + orth.to_vec2(), + base_alt: min_z, + top_alt: max_z, + from: Some(from_id), + to: Some(to_id), + to_dir, + door, + }); + + rooms[from_id].walls[to_dir].push(id); + rooms[to_id].walls[-to_dir].push(id); + } + } + // Place remaining walls. + for (dir, ranges) in wall_ranges { + for (min, max) in ranges { + let start = + dir.select_aabr_with(room_bounds, Vec2::broadcast(min - 1)) + dir.to_vec2(); + let end = + dir.select_aabr_with(room_bounds, Vec2::broadcast(max + 1)) + dir.to_vec2(); + + let wall_id = walls.insert(Wall { + start, + end, + base_alt: rooms[from_id].bounds.min.z, + top_alt: rooms[from_id].bounds.max.z, + from: Some(from_id), + to: None, + to_dir: dir, + door: None, + }); + + rooms[from_id].walls[dir].push(wall_id); + } + } + } + + // Compute detail areas + for room in rooms.values_mut() { + let bounds = to_aabr(room.bounds); + let walls = &walls; + let mut avoid = room + .walls + .iter() + .flat_map(|(dir, dir_walls)| { + dir_walls.iter().filter_map(move |wall_id| { + let wall = &walls[*wall_id]; + + let door_bounds = wall.door_bounds()?; + + Some( + Aabr { + min: dir.select_aabr_with(bounds, door_bounds.min), + max: dir.select_with(bounds.center(), door_bounds.max), + } + .made_valid(), + ) + }) + }) + .collect::>(); + + let mut x = bounds.min.x; + // Basically greedy meshing, but for aabrs + while x <= bounds.max.x { + let mut y = bounds.min.y; + 'y_loop: while y <= bounds.max.y { + let min = Vec2::new(x, y); + let mut max_y = bounds.max.y; + for area in avoid.iter() { + let contains_x = area.min.x <= min.x && min.x <= area.max.x; + let contains_y = area.min.y <= min.y && min.y <= area.max.y; + if contains_x && contains_y { + y = area.max.y + 1; + continue 'y_loop; + } + + if contains_x && min.y < area.min.y && area.min.y - 1 < max_y { + max_y = area.min.y - 1; + } + } + + let max_x = avoid + .iter() + .filter_map(|area| { + if area.min.x > x && area.min.y <= max_y && area.max.y >= min.y { + Some(area.min.x - 1) + } else { + None + } + }) + .min() + .unwrap_or(bounds.max.x); + + let area = Aabr { + min, + max: Vec2::new(max_x, max_y), + }; + avoid.push(area); + room.detail_areas.push(area); + y = max_y + 1; + } + x += 1; + } + } + + // Place details in detail areas. + for room in rooms.values_mut() { + let room_aabr = to_aabr(room.bounds); + let table = |pos: Vec2, aabr: Aabr| Detail::Table { + pos, + chairs: Dir::iter() + .filter(|dir| aabr.contains_point(pos + dir.to_vec2())) + .collect(), + }; + match room.kind { + RoomKind::Garden => room.detail_areas.retain(|&aabr| { + if aabr.size().reduce_max() > 1 && rng.gen_bool(0.7) { + room.details.push(table(aabr.center(), aabr)); + false + } else { + true + } + }), + RoomKind::StageRoom => { + let mut best = None; + let mut best_score = 0; + for (i, aabr) in room.detail_areas.iter().enumerate() { + let edges = Dir::iter() + .filter(|dir| dir.select_aabr(*aabr) == dir.select_aabr(room_aabr)) + .count() as i32; + let test_score = edges * aabr.size().product(); + if best_score < test_score { + best_score = test_score; + best = Some(i); + } + } + if let Some(aabr) = best.map(|i| room.detail_areas.swap_remove(i)) { + room.details.push(Detail::Stage { aabr }) + } + room.detail_areas.retain(|&aabr| { + if aabr.size().reduce_max() > 1 && rng.gen_bool(0.8) { + room.details.push(table(aabr.center(), aabr)); + false + } else { + true + } + }); + }, + RoomKind::BarRoom => { + let mut best = None; + let mut best_score = 0; + for (i, aabr) in room.detail_areas.iter().enumerate() { + let test_score = Dir::iter() + .any(|dir| dir.select_aabr(*aabr) == dir.select_aabr(room_aabr)) + as i32 + * aabr.size().product(); + if best_score < test_score { + best_score = test_score; + best = Some(i); + } + } + if let Some(aabr) = best.map(|i| room.detail_areas.swap_remove(i)) { + room.details.push(Detail::Bar { aabr }) + } + room.detail_areas.retain(|&aabr| { + if aabr.size().reduce_max() > 1 && rng.gen_bool(0.1) { + room.details.push(table(aabr.center(), aabr)); + false + } else { + true + } + }); + }, + RoomKind::EntranceRoom => {}, + } + } + + for room_id in rooms.ids() { + let room = &rooms[room_id]; + // If a room is already fully covered by a roof, we skip it. + if room.is_covered_by_roof(&roofs) { + continue; + } + let roof_min_z = room.bounds.max.z + 1; + let mut roof_bounds = to_aabr(room.bounds); + roof_bounds.min -= 2; + roof_bounds.max += 2; + let mut dirs = Vec::from(Dir::ALL); + + let mut over_rooms = vec![room_id]; + // Extend roof over adjecent rooms. + while !dirs.is_empty() { + let dir = dirs.swap_remove(rng.gen_range(0..dirs.len())); + let orth = dir.orthogonal(); + // Check for room intersections in this direction. + for (room_id, room) in rooms.iter() { + let room_aabr = to_aabr(room.bounds); + if room.bounds.max.z == roof_min_z + && dir.select_aabr(roof_bounds) + dir.signum() + == (-dir).select_aabr(room_aabr) + && orth.select_aabr(roof_bounds) <= orth.select_aabr(room_aabr) + 2 + && (-orth).select_aabr(roof_bounds) >= (-orth).select_aabr(room_aabr) - 2 + { + // If the room we found is fully covered by a roof already, we don't go in + // this direction. + if room.is_covered_by_roof(&roofs) { + break; + } + roof_bounds = dir.extend_aabr(roof_bounds, dir.select(room_aabr.size())); + dirs.push(dir); + over_rooms.push(room_id); + break; + } + } + } + + // Build a lottery of valid roofs to pick from + let mut valid_styles = vec![(0.5, RoofStyle::Flat)]; + + let gardens = over_rooms + .iter() + .filter(|id| matches!(rooms[**id].kind, RoomKind::Garden)) + .count(); + + // If we just have gardens, we can use FlatBars style. + if gardens == over_rooms.len() { + let ratio = Dir::X.select(roof_bounds.size()) as f32 + / Dir::Y.select(roof_bounds.size()) as f32; + valid_styles.extend([ + (5.0 * ratio, RoofStyle::FlatBars { dir: Dir::X }), + (5.0 / ratio, RoofStyle::FlatBars { dir: Dir::Y }), + ]); + } + + // Find heights of possible adjecent rooms. + let mut dir_zs = EnumMap::default(); + for dir in Dir::iter() { + let orth = dir.orthogonal(); + for room in rooms.values() { + let room_aabr = to_aabr(room.bounds); + if room.bounds.max.z > roof_min_z + && dir.select_aabr(roof_bounds) == (-dir).select_aabr(room_aabr) + && orth.select_aabr(roof_bounds) <= orth.select_aabr(room_aabr) + 2 + && (-orth).select_aabr(roof_bounds) >= (-orth).select_aabr(room_aabr) - 2 + { + dir_zs[dir] = Some(room.bounds.max.z); + break; + } + } + } + + for dir in [Dir::X, Dir::Y] { + if dir_zs[dir.orthogonal()].is_none() && dir_zs[-dir.orthogonal()].is_none() { + let max_z = + roof_min_z + (dir.orthogonal().select(roof_bounds.size()) / 2 - 1).min(7); + let max_z = match (dir_zs[dir], dir_zs[-dir]) { + (Some(a), Some(b)) => { + if a.min(b) >= roof_min_z + 3 { + max_z.min(a.min(b)) + } else { + max_z + } + }, + (None, None) => max_z, + _ => continue, + }; + + for max_z in roof_min_z + 3..=max_z { + valid_styles.push((1.0, RoofStyle::Gable { dir, max_z })) + } + } + } + + for dir in Dir::iter() { + if let (Some(h), None) = (dir_zs[dir], dir_zs[-dir]) { + for max_z in roof_min_z + 2..=h { + valid_styles.push((1.0, RoofStyle::LeanTo { dir, max_z })) + } + } + } + + if Dir::iter().all(|d| dir_zs[d].is_none()) { + for max_z in roof_min_z + 3..=roof_min_z + 7 { + valid_styles.push((0.8, RoofStyle::Hip { max_z })) + } + } + + let style_lottery = Lottery::from(valid_styles); + + debug_assert!( + roof_bounds.is_valid(), + "Roof bounds aren't valid: {:?}", + roof_bounds + ); + let roof_id = roofs.insert(Roof { + bounds: roof_bounds, + min_z: roof_min_z, + style: *style_lottery.choose_seeded(rng.gen()), + }); + + for room_id in over_rooms { + rooms[room_id].roofs.push(roof_id); + } + } + + Self { + name, + rooms, + walls, + roofs, + door_tile, + door_wpos, + bounds, + } + } +} + +fn aabb(mut aabb: Aabb) -> Aabb { + aabb.make_valid(); + aabb.max += 1; + aabb +} + +impl Structure for Tavern { + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"render_tavern\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "render_tavern")] + fn render_inner(&self, _site: &Site, _land: &Land, painter: &crate::site2::Painter) { + let field = RandomField::new(740384); + + const DOWN: i32 = 6; + + let mut offset = 0; + let mut choose = |slice: &[Rgb]| -> Rgb { + offset += 1; + *field + .choose(self.door_wpos + offset, slice) + .expect("Color slice should not be empty.") + }; + + let detail_fill = Fill::Brick( + BlockKind::Rock, + choose(&[ + Rgb::new(55, 65, 64), + Rgb::new(46, 62, 100), + Rgb::new(46, 100, 62), + Rgb::new(100, 100, 105), + ]), + 15, + ); + let wall_fill = Fill::Brick( + BlockKind::Wood, + choose(&[ + Rgb::new(160, 53, 34), + Rgb::new(147, 51, 29), + Rgb::new(147, 101, 69), + Rgb::new(90, 90, 95), + Rgb::new(170, 140, 52), + ]), + 20, + ); + let wall_detail_fill = Fill::Brick( + BlockKind::Wood, + choose(&[Rgb::new(108, 100, 79), Rgb::new(150, 150, 150)]), + 25, + ); + let floor_fill = Fill::Brick( + BlockKind::Wood, + choose(&[Rgb::new(42, 44, 43), Rgb::new(56, 18, 10)]), + 10, + ); + let roof_fill = Fill::Brick( + BlockKind::Wood, + choose(&[ + Rgb::new(21, 43, 48), + Rgb::new(11, 23, 38), + Rgb::new(45, 28, 21), + Rgb::new(10, 55, 40), + Rgb::new(5, 35, 15), + Rgb::new(40, 5, 11), + Rgb::new(55, 45, 11), + ]), + 20, + ); + let simple_roof_fill = Fill::Brick( + BlockKind::Wood, + choose(&[Rgb::new(106, 73, 64), Rgb::new(85, 52, 43)]), + 20, + ); + + let get_kind = |room| self.rooms.get(room).kind; + let get_door_stair = |wall: &Wall, door: Aabr| { + let filter = |room: &Id| self.rooms[*room].bounds.min.z > wall.base_alt; + wall.to + .filter(filter) + .zip(Some(wall.to_dir)) + .or(wall.from.filter(filter).zip(Some(-wall.to_dir))) + .map(|(room, to_dir)| { + let room = &self.rooms[room]; + + let max = door.max + to_dir.to_vec2() * (room.bounds.min.z - wall.base_alt + 1); + (door.min, max, room, to_dir) + }) + }; + + for roof in self.roofs.values() { + match roof.style { + RoofStyle::Flat => { + painter + .aabb(aabb(Aabb { + min: roof.bounds.min.with_z(roof.min_z), + max: roof.bounds.max.with_z(roof.min_z), + })) + .fill(roof_fill.clone()); + }, + RoofStyle::FlatBars { dir } => painter + .aabb(aabb(Aabb { + min: dir + .select_aabr_with(roof.bounds, roof.bounds.min) + .with_z(roof.min_z), + max: dir + .select_aabr_with(roof.bounds, roof.bounds.max) + .with_z(roof.min_z), + })) + .repeat( + -dir.to_vec3() * 2, + (dir.select(roof.bounds.size()) as u32 + 3) / 2, + ) + .fill(simple_roof_fill.clone()), + RoofStyle::LeanTo { dir, max_z } => { + painter + .aabb(aabb(Aabb { + min: roof.bounds.min.with_z(roof.min_z), + max: roof.bounds.max.with_z(roof.min_z), + })) + .fill(roof_fill.clone()); + painter + .ramp( + aabb(Aabb { + min: roof.bounds.min.with_z(roof.min_z), + max: roof.bounds.max.with_z(max_z), + }), + dir, + ) + .fill(roof_fill.clone()); + for d in [dir.orthogonal(), -dir.orthogonal()] { + painter + .ramp( + aabb(Aabb { + min: (d.select_aabr_with(roof.bounds, roof.bounds.min) + - d.to_vec2()) + .with_z(roof.min_z - 1), + max: (d.select_aabr_with(roof.bounds, roof.bounds.max) + - d.to_vec2()) + .with_z(max_z - 1), + }), + dir, + ) + .fill(wall_fill.clone()); + painter + .ramp( + aabb(Aabb { + min: d + .select_aabr_with(roof.bounds, roof.bounds.min) + .with_z(roof.min_z - 1), + max: d + .select_aabr_with(roof.bounds, roof.bounds.max) + .with_z(max_z - 1), + }), + dir, + ) + .clear(); + } + }, + RoofStyle::Gable { dir, max_z } => { + painter + .gable( + aabb(Aabb { + min: roof.bounds.min.with_z(roof.min_z), + max: roof.bounds.max.with_z(max_z), + }), + max_z - roof.min_z + 1, + dir, + ) + .fill(roof_fill.clone()); + for dir in [dir, -dir] { + painter + .gable( + aabb(Aabb { + min: (dir.select_aabr_with(roof.bounds, roof.bounds.min + 1) + - dir.to_vec2()) + .with_z(roof.min_z), + max: (dir.select_aabr_with(roof.bounds, roof.bounds.max - 1) + - dir.to_vec2()) + .with_z(max_z - 1), + }), + max_z - roof.min_z, + dir, + ) + .fill(wall_fill.clone()); + painter + .aabb(aabb(Aabb { + min: (dir.select_aabr_with(roof.bounds, roof.bounds.min + 1) + - dir.to_vec2()) + .with_z(roof.min_z), + max: (dir.select_aabr_with(roof.bounds, roof.bounds.max - 1) + - dir.to_vec2()) + .with_z(roof.min_z), + })) + .fill(wall_detail_fill.clone()); + let center_bounds = Aabr { + min: (dir.select_aabr_with(roof.bounds, roof.bounds.center()) + - dir.to_vec2()), + max: (dir.select_aabr_with( + roof.bounds, + (roof.bounds.min + roof.bounds.max + 1) / 2, + ) - dir.to_vec2()), + }; + painter + .aabb(aabb(Aabb { + min: center_bounds.min.with_z(roof.min_z), + max: center_bounds.max.with_z(max_z - 1), + })) + .fill(wall_detail_fill.clone()); + for d in [dir.orthogonal(), -dir.orthogonal()] { + let hgt = max_z - roof.min_z; + let half_size = d.select(roof.bounds.size() + 1) / 2; + let e = half_size - hgt + 1; + let e = e - e % 2; + let f = half_size - e; + let hgt = (hgt - 1).min(e - f % 2) - (d.signum() - 1) / 2; + let mut aabr = Aabr { + min: d.select_aabr_with(center_bounds, center_bounds.min), + max: d.select_aabr_with(center_bounds, center_bounds.max) + + d.to_vec2() * hgt, + } + .made_valid(); + aabr.max += 1; + painter + .plane( + aabr, + aabr.min + .with_z(if d.signum() < 0 { + roof.min_z + hgt + } else { + roof.min_z + }) + .as_(), + d.to_vec2().as_(), + ) + .fill(wall_detail_fill.clone()); + } + painter + .gable( + aabb(Aabb { + min: dir + .select_aabr_with(roof.bounds, roof.bounds.min + 1) + .with_z(roof.min_z), + max: dir + .select_aabr_with(roof.bounds, roof.bounds.max - 1) + .with_z(max_z - 1), + }), + max_z - roof.min_z, + dir, + ) + .clear(); + } + }, + RoofStyle::Hip { max_z } => { + painter + .pyramid(aabb(Aabb { + min: roof.bounds.min.with_z(roof.min_z), + max: roof.bounds.max.with_z(max_z), + })) + .fill(roof_fill.clone()); + }, + } + } + + for room in self.rooms.values() { + painter + .aabb(aabb(Aabb { + min: room.bounds.min.with_z(room.bounds.min.z - DOWN), + max: room.bounds.max.with_z(room.bounds.min.z - 1), + })) + .fill(floor_fill.clone()); + } + for wall in self.walls.values() { + let wall_aabb = Aabb { + min: wall.start.with_z(wall.base_alt), + max: wall.end.with_z(wall.top_alt), + }; + let wall_dir = Dir::from_vec2(wall.end - wall.start); + match (wall.from.map(get_kind), wall.to.map(get_kind)) { + (Some(RoomKind::Garden), None) | (None, Some(RoomKind::Garden)) => { + let hgt = wall_aabb.min.z..=wall_aabb.max.z; + painter + .column(wall_aabb.min.xy(), hgt.clone()) + .fill(wall_detail_fill.clone()); + painter + .column(wall_aabb.max.xy(), hgt) + .fill(wall_detail_fill.clone()); + let z = (wall.base_alt + wall.top_alt) / 2; + + painter + .aabb(aabb(Aabb { + min: (wall_aabb.min + wall_dir.to_vec2()).with_z(wall_aabb.min.z + 1), + max: (wall_aabb.max - wall_dir.to_vec2()).with_z(wall_aabb.max.z - 1), + })) + .clear(); + + painter.rotated_sprite( + wall_aabb.min.with_z(z) + wall_dir.to_vec2(), + SpriteKind::WallSconce, + wall_dir.sprite_ori(), + ); + painter.rotated_sprite( + wall_aabb.max.with_z(z) - wall_dir.to_vec2(), + SpriteKind::WallSconce, + wall_dir.opposite().sprite_ori(), + ); + painter + .aabb(aabb(Aabb { + min: wall_aabb.min.with_z(wall_aabb.min.z - DOWN), + max: wall_aabb.max.with_z(wall_aabb.min.z), + })) + .fill(wall_detail_fill.clone()); + painter + .aabb(aabb(Aabb { + min: wall_aabb.min.with_z(wall_aabb.max.z), + max: wall_aabb.max, + })) + .fill(wall_detail_fill.clone()); + }, + (Some(RoomKind::Garden), Some(RoomKind::Garden)) => { + painter + .aabb(aabb(Aabb { + min: wall_aabb.min.with_z(wall_aabb.min.z - DOWN), + max: wall_aabb.max.with_z(wall_aabb.min.z - 1), + })) + .fill(floor_fill.clone()); + painter.aabb(aabb(wall_aabb)).clear(); + }, + (None, None) => {}, + _ => { + painter + .aabb(aabb(Aabb { + min: wall_aabb.min.with_z(wall_aabb.min.z - DOWN), + max: wall_aabb.max, + })) + .fill(wall_fill.clone()); + painter + .column(wall.start, wall.base_alt - DOWN..=wall.top_alt) + .fill(wall_detail_fill.clone()); + painter + .column(wall.end, wall.base_alt - DOWN..=wall.top_alt) + .fill(wall_detail_fill.clone()); + }, + } + if let Some(door) = wall.door_bounds() { + let orth = wall.to_dir.orthogonal(); + if let Some((min, max, room, to_dir)) = get_door_stair(wall, door) { + painter + .aabb(aabb(Aabb { + min: (min + to_dir.to_vec2() - orth.to_vec2()) + .with_z(wall.base_alt - 1), + max: (max + orth.to_vec2()).with_z(room.bounds.min.z - 1), + })) + .fill(floor_fill.clone()); + } + } + } + for room in self.rooms.values() { + painter.aabb(aabb(room.bounds)).clear(); + + let room_aabr = Aabr { + min: room.bounds.min.xy(), + max: room.bounds.max.xy(), + }; + match room.kind { + RoomKind::Garden => {}, + RoomKind::StageRoom => { + for aabr in room.detail_areas.iter().copied() { + for dir in Dir::iter().filter(|dir| { + dir.select_aabr(aabr) == dir.select_aabr(room_aabr) + && dir.rotated_cw().select_aabr(aabr) + == dir.rotated_cw().select_aabr(room_aabr) + }) { + let pos = dir.select_aabr_with( + aabr, + Vec2::broadcast(dir.rotated_cw().select_aabr(aabr)), + ); + painter.sprite(pos.with_z(room.bounds.min.z), SpriteKind::StreetLamp); + } + } + }, + RoomKind::BarRoom => { + for aabr in room.detail_areas.iter().copied() { + for dir in Dir::iter() + .filter(|dir| dir.select_aabr(aabr) == dir.select_aabr(room_aabr)) + { + let pos = dir + .select_aabr_with(aabr, aabr.center()) + .with_z(room.bounds.center().z); + + painter.rotated_sprite( + pos, + SpriteKind::WallLampSmall, + dir.opposite().sprite_ori(), + ); + } + } + }, + RoomKind::EntranceRoom => { + for aabr in room.detail_areas.iter() { + let edges = Dir::iter() + .filter(|dir| dir.select_aabr(*aabr) == dir.select_aabr(room_aabr)) + .count(); + let hanger_pos = if edges == 2 { + let pos = aabr.center().with_z(room.bounds.min.z); + painter.sprite(pos, SpriteKind::CoatRack); + Some(pos) + } else { + None + }; + + for dir in Dir::iter() + .filter(|dir| dir.select_aabr(*aabr) == dir.select_aabr(room_aabr)) + { + let pos = dir + .select_aabr_with(*aabr, aabr.center()) + .with_z(room.bounds.center().z + 1); + if hanger_pos.map_or(false, |p| p.xy() != pos.xy()) { + painter.rotated_sprite( + pos, + SpriteKind::WallLampSmall, + dir.opposite().sprite_ori(), + ); + } + } + } + }, + } + for detail in room.details.iter() { + match *detail { + Detail::Bar { aabr } => { + for dir in Dir::iter() { + let edge = dir.select_aabr(aabr); + let rot_dir = if field.chance(aabr.center().with_z(0), 0.5) { + dir.rotated_cw() + } else { + dir.rotated_ccw() + }; + let rot_edge = rot_dir.select_aabr(aabr); + match ( + edge == dir.select_aabr(room_aabr), + rot_edge == rot_dir.select_aabr(room_aabr), + ) { + (false, _) => { + let (min, max) = ( + dir.select_aabr_with( + aabr, + Vec2::broadcast(rot_dir.select_aabr(aabr)), + ), + dir.select_aabr_with( + aabr, + Vec2::broadcast(rot_dir.opposite().select_aabr(aabr)), + ), + ); + painter + .aabb(aabb(Aabb { + min: (min - rot_dir.to_vec2()) + .with_z(room.bounds.min.z), + max: max.with_z(room.bounds.min.z), + })) + .fill(wall_detail_fill.clone()); + painter + .aabb(aabb(Aabb { + min: min.with_z(room.bounds.min.z + 3), + max: max.with_z(room.bounds.max.z), + })) + .fill(wall_detail_fill.clone()); + }, + (true, true) => { + painter.sprite( + dir.abs().vec2(edge, rot_edge).with_z(room.bounds.min.z), + SpriteKind::CookingPot, + ); + }, + (true, false) => {}, + } + } + }, + Detail::Stage { aabr } => { + painter + .aabb(aabb(Aabb { + min: aabr.min.with_z(room.bounds.min.z), + max: aabr.max.with_z(room.bounds.min.z), + })) + .fill(detail_fill.clone()); + painter + .aabb(aabb(Aabb { + min: (aabr.min + 1).with_z(room.bounds.min.z), + max: (aabr.max - 1).with_z(room.bounds.min.z), + })) + .fill(wall_fill.clone()); + for dir in Dir::iter().filter(|dir| { + dir.select_aabr(aabr) != dir.select_aabr(room_aabr) + && dir.rotated_cw().select_aabr(aabr) + != dir.rotated_cw().select_aabr(room_aabr) + }) { + let pos = dir.select_aabr_with( + aabr, + Vec2::broadcast(dir.rotated_cw().select_aabr(aabr)), + ); + painter + .column(pos, room.bounds.min.z..=room.bounds.max.z) + .fill(wall_detail_fill.clone()); + + for dir in Dir::iter() { + painter.rotated_sprite( + pos.with_z(room.bounds.center().z + 1) + dir.to_vec2(), + SpriteKind::WallSconce, + dir.sprite_ori(), + ); + } + } + }, + Detail::Table { pos, chairs } => { + let pos = pos.with_z(room.bounds.min.z); + painter.sprite(pos, SpriteKind::TableDining); + for dir in chairs.into_iter() { + painter.rotated_sprite( + pos + dir.to_vec2(), + SpriteKind::ChairSingle, + dir.opposite().sprite_ori(), + ); + } + }, + } + } + } + + for wall in self.walls.values() { + let kinds = (wall.from.map(get_kind), wall.to.map(get_kind)); + let in_dir_room = if let (Some(room), to @ None) | (None, to @ Some(room)) = kinds { + let in_dir = if to.is_none() { + -wall.to_dir + } else { + wall.to_dir + }; + + Some((in_dir, room)) + } else { + None + }; + if let Some((in_dir, room)) = in_dir_room { + let width = in_dir.orthogonal().select(wall.end - wall.start).abs(); + let wall_center = (wall.start + wall.end) / 2; + let door_dist = wall.door_bounds().map_or(i32::MAX, |door| { + (door.min - wall_center) + .map(|x| x.abs()) + .reduce_max() + .max((door.max - wall_center).map(|x| x.abs()).reduce_max()) + }); + match room { + RoomKind::Garden => { + if door_dist >= 2 { + painter.rotated_sprite( + wall_center.with_z(wall.base_alt + 1), + SpriteKind::Planter, + in_dir.sprite_ori(), + ); + } + }, + _ => { + if width >= 5 && door_dist > 3 { + painter + .aabb(aabb(Aabb { + min: (wall_center + in_dir.rotated_ccw().to_vec2()) + .with_z(wall.base_alt + 1), + max: (wall_center + in_dir.rotated_cw().to_vec2()) + .with_z(wall.base_alt + 2), + })) + .fill(Fill::RotatedSprite( + SpriteKind::Window1, + in_dir.sprite_ori(), + )); + } + }, + } + } + if let Some(door) = wall.door_bounds() && !matches!(kinds, (Some(RoomKind::Garden), Some(RoomKind::Garden))) { + let orth = wall.to_dir.orthogonal(); + painter + .aabb(aabb(Aabb { + min: (door.min - orth.to_vec2()).with_z(wall.base_alt), + max: (door.max + orth.to_vec2()).with_z(wall.base_alt + 3), + })) + .fill(detail_fill.clone()); + painter + .aabb(aabb(Aabb { + min: (door.min - orth.to_vec2()).with_z(wall.base_alt - 1), + max: (door.max + orth.to_vec2()).with_z(wall.base_alt - 1), + })) + .fill(floor_fill.clone()); + painter + .aabb(aabb(Aabb { + min: (door.min + wall.to_dir.to_vec2()).with_z(wall.base_alt), + max: (door.max - wall.to_dir.to_vec2()).with_z(wall.base_alt + 2), + })) + .clear(); + if let Some((min, max, room, to_dir)) = get_door_stair(wall, door) { + // Place a ramp if the door is lower than the room alt. + painter + .ramp( + aabb(Aabb { + min: (min - to_dir.to_vec2() * 3).with_z(wall.base_alt), + max: max.with_z(room.bounds.min.z + 2), + }), + to_dir, + ) + // TOOD: For zoomy worldgen, this a sheared aabb. + .without( + painter + .ramp( + aabb(Aabb { + min: (min + to_dir.to_vec2() * 2).with_z(wall.base_alt), + max: max.with_z(room.bounds.min.z - 1), + }), + to_dir, + ) + ) + .clear(); + } + if let Some((in_dir, _room)) = in_dir_room { + let sprite = match in_dir.rotated_cw().select(door.size()) { + 2.. => SpriteKind::DoorWide, + _ => SpriteKind::Door, + }; + painter.rotated_sprite( + in_dir + .rotated_cw() + .select_aabr_with(door, door.min) + .with_z(wall.base_alt), + sprite, + in_dir.sprite_ori(), + ); + painter.rotated_sprite( + in_dir + .rotated_ccw() + .select_aabr_with(door, door.min) + .with_z(wall.base_alt), + sprite, + in_dir.opposite().sprite_ori(), + ); + + let dir = match field.chance(door.min.with_z(wall.base_alt), 0.5) { + true => in_dir.rotated_cw(), + false => in_dir.rotated_ccw(), + }; + + let pos = + dir.select_aabr_with(door, door.min) + dir.to_vec2() - in_dir.to_vec2(); + + painter.rotated_sprite_with_cfg( + pos.with_z(wall.base_alt + 2), + SpriteKind::HangingSign, + in_dir.opposite().sprite_ori(), + SpriteCfg { + unlock: None, + content: Some(Content::Plain(self.name.clone())), + }, + ); + } + } + } + } +} diff --git a/world/src/site2/plot/troll_cave.rs b/world/src/site2/plot/troll_cave.rs index 903ff7016a..ce7df799b3 100644 --- a/world/src/site2/plot/troll_cave.rs +++ b/world/src/site2/plot/troll_cave.rs @@ -73,13 +73,19 @@ impl Structure for TrollCave { // troll painter.spawn( - EntityInfo::at(center.with_z(base - 15).as_()) - .with_asset_expect(troll, &mut thread_rng), + EntityInfo::at(center.with_z(base - 15).as_()).with_asset_expect( + troll, + &mut thread_rng, + None, + ), ); // bat painter.spawn( - EntityInfo::at((center - 2).with_z(base + 5).as_()) - .with_asset_expect("common.entity.wild.aggressive.bat", &mut thread_rng), + EntityInfo::at((center - 2).with_z(base + 5).as_()).with_asset_expect( + "common.entity.wild.aggressive.bat", + &mut thread_rng, + None, + ), ) } } diff --git a/world/src/site2/util/mod.rs b/world/src/site2/util/mod.rs index b43266c8d6..a57542c931 100644 --- a/world/src/site2/util/mod.rs +++ b/world/src/site2/util/mod.rs @@ -6,7 +6,7 @@ use rand::Rng; use vek::*; /// A 2d direction. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Debug, enum_map::Enum, strum::EnumIter, enumset::EnumSetType)] pub enum Dir { X, Y, @@ -26,7 +26,7 @@ impl Dir { } } - pub fn from_vector(vec: Vec2) -> Dir { + pub fn from_vec2(vec: Vec2) -> Dir { if vec.x.abs() > vec.y.abs() { if vec.x > 0 { Dir::X } else { Dir::NegX } } else if vec.y > 0 { @@ -110,6 +110,17 @@ impl Dir { } } + /// Create a vec2 where x is in the direction of `self`, and y is anti + /// clockwise of `self`. + pub fn vec2(self, x: i32, y: i32) -> Vec2 { + match self { + Dir::X => Vec2::new(x, y), + Dir::NegX => Vec2::new(-x, -y), + Dir::Y => Vec2::new(y, x), + Dir::NegY => Vec2::new(-y, -x), + } + } + /// Returns a 3x3 matrix that rotates Vec3(1, 0, 0) to the direction you get /// in to_vec3. Inteded to be used with Primitive::Rotate. /// @@ -223,7 +234,7 @@ impl Dir { } } - pub fn split_aabr(self, aabr: Aabr, offset: T) -> [Aabr; 2] + pub fn split_aabr_offset(self, aabr: Aabr, offset: T) -> [Aabr; 2] where T: Copy + PartialOrd + Add + Sub, { @@ -241,6 +252,29 @@ impl Dir { } } + /// Try to split an aabr in a certain direction + pub fn try_split_aabr(self, aabr: Aabr, sp: T) -> Option<[Aabr; 2]> + where + T: Copy + PartialOrd + Add + Sub, + { + match self { + Dir::NegX | Dir::X => { + if aabr.min.x <= sp && sp <= aabr.max.x { + Some(aabr.split_at_x(sp)) + } else { + None + } + }, + Dir::NegY | Dir::Y => { + if aabr.min.y <= sp && sp <= aabr.max.y { + Some(aabr.split_at_y(sp)) + } else { + None + } + }, + } + } + pub fn trim_aabr(self, aabr: Aabr, offset: i32) -> Aabr { Aabr { min: aabr.min + self.abs().to_vec2() * offset, diff --git a/world/src/util/random.rs b/world/src/util/random.rs index 54aacf42ee..ceee42c7ab 100644 --- a/world/src/util/random.rs +++ b/world/src/util/random.rs @@ -15,6 +15,15 @@ impl RandomField { pub fn get_f32(&self, pos: Vec3) -> f32 { (self.get(pos) % (1 << 16)) as f32 / ((1 << 16) as f32) } + + pub fn choose<'a, T>(&self, pos: Vec3, slice: &'a [T]) -> Option<&'a T> { + if slice.is_empty() { + return None; + } + + let i = self.get(pos) as usize; + slice.get(i % slice.len()) + } } impl Sampler<'static> for RandomField {