summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjc_gargma <jc_gargma@iserlohn-fortress.net>2023-10-02 19:19:40 -0700
committerjc_gargma <jc_gargma@iserlohn-fortress.net>2023-10-02 19:19:40 -0700
commit8847061d07ba161a1a768f991fc64f9058ce3902 (patch)
tree45c4709bb979c653b01c55008d2b5ab0becbd656
parentPort out 8x40mm ammo to my ammo rebalance mod. (diff)
downloadcataclysm-bn-8847061d07ba161a1a768f991fc64f9058ce3902.tar.xz
Updated to 2023-09-23-0420
Port out shotpaper to my ammo rebalance mod. Revert the easy mode limb repair commit. Remove obsolete doc install.
-rw-r--r--PKGBUILD25
-rw-r--r--revert-08_undo-rifle-balance-pass.patch2
-rw-r--r--revert-09_undo-yet-more-ammo-balancing.patch37
-rw-r--r--revert-18-Simplify-broken-limb-mending-3054.patch830
4 files changed, 844 insertions, 50 deletions
diff --git a/PKGBUILD b/PKGBUILD
index 619234e..05df54c 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -17,9 +17,9 @@ pkgbase=cataclysm-bn
pkgname=(cataclysm-bn cataclysm-bn-tiles)
pkgname=cataclysm-bn
_pkgname=Cataclysm-BN-cbn-experimental
-pkgver=202309171522
-_pkgver=2023-09-17-1522
-pkgrel=2
+pkgver=202309230420
+_pkgver=2023-09-23-0420
+pkgrel=1
pkgdesc="A post-apocalyptic roguelike."
#url="http://cataclysmrl.blogspot.com/"
#url="http://www.cataclysm.glyphgryph.com/"
@@ -51,6 +51,7 @@ source=("$pkgname-$_pkgver.tar.gz::https://github.com/cataclysmbnteam/Cataclysm-
"revert-14_Removed-unrelated-references-2738.patch"
"revert-15_Fix-mutant-scenarios-adding-an-obsoleted-trait-2929.patch"
"revert-17_Rivtech-mainline-3092.patch"
+ "revert-18-Simplify-broken-limb-mending-3054.patch"
"ammo-01_inconsistent-ammo-names.patch"
"ammo-03_fix-reloaded-50bmg.patch"
@@ -155,7 +156,7 @@ source=("$pkgname-$_pkgver.tar.gz::https://github.com/cataclysmbnteam/Cataclysm-
"cataclysm-dda-soundpack_jcsoundpack.tar.xz::https://library.iserlohn-fortress.net/cataclysm-dda-soundpack_jcsoundpack.git/snapshot/cataclysm-dda-soundpack_jcsoundpack-master.tar.xz"
"cataclysm-dda-musicpack_coag-musicpack.tar.xz::https://library.iserlohn-fortress.net/cataclysm-dda-musicpack_coag-musicpack.git/snapshot/cataclysm-dda-musicpack_coag-musicpack-master.tar.xz"
)
-b2sums=('b3ec5268da460d8a1bfcbf24b52109dad611db181eba6759566bf532e3e2502f32db5d6d492408872c7a6d081e74d686338f0cee48a5a949cf30e50576150811'
+b2sums=('6ecc687444378aa0ea4775b2efba1f2945d78220756261a1a67f2f2dc017ed47bcb2601ceb5be6e5e2d6c49110a26d60bd6b8f384824b04cbc2821112eae3ef4'
'069ecde58859b3d44cd687c4b6e718610cefb693ff86e66f199ebfb1b3072023ad2b6f0c28e27ef9c1ce4997f6a5b2ca0d45046996b3ff35a4aeaeb1a7cf9421'
'ad88bc6c1e3c8183a313b5eec42f98d6956afea349feff34a86e4536c9921fa99d2594282caf27de8ebb7ffb56376ed2e76d572227bfd6d8173c7bb1f01e23b8'
'6f70e90359a14e4839d9a2683debb88850e5dd387add911ad68fd87e5512cfcdd435da63e1e370358153673fd5a72a9b1e9c94f1979edb7948b4da8c82407bad'
@@ -166,8 +167,8 @@ b2sums=('b3ec5268da460d8a1bfcbf24b52109dad611db181eba6759566bf532e3e2502f32db5d6
'2d197903715263628e767e867e9b20b9ebd3d85f8983ac8f1e2b534f2b6f8c0470886c79a409f117ad43348aa6aef2a6298925ae27faa32814183ad7677528ac'
'fe11304ee87f08f6691a77e5e814073fdb577d60a83df614c98cb05577375b03c979df1f1fa048c5d54798d0054cfc4f3f512d45009a85b6be228792482d5cd6'
'e6f0c25863074990ac54ec0a8fd05a3458c05bf41b7ebf9ec8e7ca302694b5a2fc89289d1a8818c44f0b879c61c2ecbd9d1defc9fc4a5a5fa0c98910859c8543'
- '43d89f815f7c7d7e57463174ad3bfa304a21c93dd34659dfa95824582f482fb97ef70f6d4c83be29b2b10b22c27ff1d19ce4ea1e2a0653fce35d53cdb30fb897'
- '0cc87fa8cb54b3001cc24f9c19a19bdc3933475cbe68a120099ecba3efdea5f1af777976cbe35ab7dfea0e51ed60ba0e3e1d9ff56702531f08ce0c0779c2555e'
+ 'cebd24bd72ace004972900eac56fc2b4d43d22d0fb7dbac014b55848f80067ba9c09e721543784bb9db19f28af3803288bd2be5821cbb97ebfac7a94868191a5'
+ 'c04a8b3df0d356d2a47eb9174af0851bf8687717d1240f3771f9cfacf08d5dc49900fe10ded6365fba87bc62b6de5d93810aa102693a1f3956382fae0d452d44'
'7311e7cfaf4c47ac2cc62ec2590c7f5b09b86615400f87f47bc62418d0028dc78ef88380022a70cbdb5e542becee9ad443cbf03e2793443d0e11656e91c0abc5'
'5df4497d779d6980a540f0f1dd54959ca403e8b00a9f4bd1a91fee3c41d351e216abb08f1ae6729ca0fcb04efda789804b5df5c86e0003d25998e988254712f7'
'68cc05b6224d873a2a5728e0120ce09e5c45f53f8c7bc03148a0ede00582975d740e42ddad1aa02c58fabf6d25aa649ddf73e3af2b7c98090e840c808e0742c8'
@@ -175,6 +176,7 @@ b2sums=('b3ec5268da460d8a1bfcbf24b52109dad611db181eba6759566bf532e3e2502f32db5d6
'3999499f63c50ab9fb38edab7592bcba4f8ab9a51b63d96445a9a6af843d5c5a36f36838735528fc42e5eec5c9e375e704fab1aa55df03f5a804e54d247edaa5'
'2de96509a572c1eca36d63f1a049a27583cd0f2df53605b927c9b5112d4e2385bccc82ba1a37af06fe756f96cc1e8c9d4b6cd081ad70651ec09ac57b93cee84f'
'664d6d2d4427040b25d9971fa07b32d3c1343dd60a9702835568ba1e287422ab2659a4a4e324e422755b6c655e324ca203933b6815c7b2e512beb4f15c4a27d8'
+ 'ee3722ba1367d993605c0cee12e67b8e10dcda0401c4480d8915bd3ac587c8a3b84379ef6f98d6e93cf433b1dae7a0db35937271787bc6b893b373dc1d44ae7d'
'ea9e227eff0a9470a06effc35d8e991c0e21d5521e0325317ab36760b5bb3256676fee29dd948fcc7f4b09ce9235c2d859cd22d6839ebf14deb369cdf97b20f0'
'124893f23b7d865709fa87a9fade8fb01e596c1f31b0811ab32d5e730e1101c62af672eaf5fe9cdefa338fc25164407023f4c7dcc7cacdb0c86b4713180d345d'
'67cdb7e097bbb46da5cf04708bc2858b080d1a85742afc4c088da3e4e3fdeb6e4c51240fc5a6b9a1c7d927b30b3d251236e025ee4e5496142a7716d4ba51b82c'
@@ -216,7 +218,7 @@ b2sums=('b3ec5268da460d8a1bfcbf24b52109dad611db181eba6759566bf532e3e2502f32db5d6
'9fbf8cf2aaa18c5cccca24783f40503cf7b7c66731f65450cc312e8b29145c56c23d31d19063dccdf3790ec06480d773d7d64de1672f38b7a4740a8aa0fd4f7d'
'abafa39e57cf04396b841833215aca427655dd3b56ebc260b8a57d6376360b31a4b1d4493da76ec4dc0129939ab9e23cada70dd6f49e647f02bce12c81f6451a'
'e6eda6cf4831df11facb124ab80972ddffabc8e2a61f8180275c7a95a8f00917301e9b8912f2418138c9dabd91c979d5d5b5d0b2b4b8eae3891f9c1880a4c526'
- 'de272d4124994e707946255a2bb0c15de912f2d049e777487be962080f2e27463e61c6cd7f3d6d0b4b82002ef18baafdf4e64c8c42de82aff380c53d6eddba9c'
+ '8eba2f66280defcc930424d695baff297cff32e91e73f01210bb3f26389ea9e93b4b4d9e2c5a5a048756eff219d51c3fbf3f05690c3c984afcc32c3928df91aa'
'80da2c341d8564a47bc460fcdaf9196ac3bb77f0f2ba56bd71089e80e7481728a3ccbdcfcbc3bf70a9c9e5d9d9b01f2ca6615b67c7ab61003808ce00f6545ba3'
'b8a64accada87ee5be989c5307805610c9b5c0327bc107aab237ac3225dd9e4c51b6c79a2a7de15fe187d3c32d7cbe1c462f9b0e9fb5d5a55a74236c7061e96e'
'85aeb5920ee5879848be4057324153a077fe907bed527ed8f9b80a3c5ee1ef64786f63ee2999f5ba74e80a43e99ded3280ce27759c1f7b73259a6e2b5e584aa8'
@@ -285,7 +287,7 @@ prepare() {
sed -i 's|cataclysm-dda|cataclysm-bn|' src/path_info.cpp
# Fix version
- sed -i 's|VERSION = unstable|VERSION = "0.2-experimental 2023-09-17-1522"|' Makefile
+ sed -i 's|VERSION = unstable|VERSION = "0.2-experimental 2023-09-23-0420"|' Makefile
# # # Hotfixes
@@ -294,8 +296,10 @@ prepare() {
# # # Reverts
echo "Applying revert patches"
+ # # Revert easy-mode limb mending
+ patch -NREp1 --no-backup-if-mismatch -i "$srcdir"/revert-18-Simplify-broken-limb-mending-3054.patch
+
# # Revert mainline craftable rivtech ammo
- #echo "Applying revert-17_Rivtech-mainline-3092.patch"
patch -NREp1 --no-backup-if-mismatch -i "$srcdir"/revert-17_Rivtech-mainline-3092.patch
# # More reverts for generic night vision
@@ -729,9 +733,6 @@ package_cataclysm-bn() {
# Docs
install -d "$pkgdir/usr/share/doc/cataclysm-bn"
cp --reflink -r doc/* "$pkgdir/usr/share/doc/cataclysm-bn"
- # undo symlink
- rm "$pkgdir/usr/share/doc/cataclysm-bn/JSON_LOADING_ORDER.md"
- cp --reflink 'data/json/LOADING_ORDER.md' "$pkgdir/usr/share/doc/cataclysm-bn/JSON_LOADING_ORDER.md"
# License
install -Dm644 LICENSE.txt "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
diff --git a/revert-08_undo-rifle-balance-pass.patch b/revert-08_undo-rifle-balance-pass.patch
index 45ca828..c93e339 100644
--- a/revert-08_undo-rifle-balance-pass.patch
+++ b/revert-08_undo-rifle-balance-pass.patch
@@ -11,7 +11,7 @@ Subject: [PATCH 074/177] Ammo rebalance project, part 6 (#1851)
* I knew I forgot one
-* Revert shotshell and flintlock changes for now
+* Revert shotshell changes for now
* Slight nudge to .233 and .308 per feedback
diff --git a/revert-09_undo-yet-more-ammo-balancing.patch b/revert-09_undo-yet-more-ammo-balancing.patch
index 596e33a..aa6efad 100644
--- a/revert-09_undo-yet-more-ammo-balancing.patch
+++ b/revert-09_undo-yet-more-ammo-balancing.patch
@@ -26,7 +26,6 @@ Doi
data/json/items/ammo/5x50.json | 8 ++-
data/json/items/ammo/8x40mm.json | 23 ++++----
data/json/items/ammo/flintlock.json | 5 +-
- data/json/items/ammo/shotpaper.json | 2 +-
data/json/items/generic/casing.json | 8 +--
data/json/items/handloaded_bullets.json | 8 ++-
data/json/items/migration.json | 15 +++++
@@ -326,42 +325,6 @@ index 25d9b16a37b..8ca62a1bfb3 100644
{
"id": "8mm_hvp",
"copy-from": "8mm_caseless",
-diff --git a/data/json/items/ammo/flintlock.json b/data/json/items/ammo/flintlock.json
-index f7fc54e73da..c51ab370e4a 100644
---- a/data/json/items/ammo/flintlock.json
-+++ b/data/json/items/ammo/flintlock.json
-@@ -15,7 +15,8 @@
- "stack_size": 10,
- "ammo_type": "flintlock",
- "range": 12,
-- "damage": { "damage_type": "bullet", "amount": 50 },
-+ "//": "Balanced as FMJ",
-+ "damage": { "damage_type": "bullet", "amount": 50, "armor_penetration": 22 },
- "dispersion": 90,
- "recoil": 1500,
- "loudness": 70,
-@@ -37,7 +38,7 @@
- "stack_size": 10,
- "ammo_type": "flintlock",
- "range": 8,
-- "damage": { "damage_type": "bullet", "amount": 45 },
-+ "damage": { "damage_type": "bullet", "amount": 63 },
- "dispersion": 20,
- "recoil": 1500,
- "loudness": 90,
-diff --git a/data/json/items/ammo/shotpaper.json b/data/json/items/ammo/shotpaper.json
-index f9915b9cf2e..40ec4081298 100644
---- a/data/json/items/ammo/shotpaper.json
-+++ b/data/json/items/ammo/shotpaper.json
-@@ -44,7 +44,7 @@
- "type": "AMMO",
- "name": { "str": ".62 paper cartridge" },
- "description": "A paper cartridge containing a premeasured amount of black powder and a .605 inch lead ball.",
-- "relative": { "range": 12, "damage": { "damage_type": "bullet", "armor_penetration": 4 } },
-+ "relative": { "range": 12, "damage": { "damage_type": "bullet", "amount": -8, "armor_penetration": 14 } },
- "delete": { "effects": [ "SHOT" ] },
- "dispersion": 100
- }
diff --git a/data/json/items/generic/casing.json b/data/json/items/generic/casing.json
index 510b4ba9c1f..f486ad3126a 100644
--- a/data/json/items/generic/casing.json
diff --git a/revert-18-Simplify-broken-limb-mending-3054.patch b/revert-18-Simplify-broken-limb-mending-3054.patch
new file mode 100644
index 0000000..dd3aa52
--- /dev/null
+++ b/revert-18-Simplify-broken-limb-mending-3054.patch
@@ -0,0 +1,830 @@
+From d8aa6d9696fbce4339edfccf96df85ae438a8fad Mon Sep 17 00:00:00 2001
+From: Coolthulhu <Coolthulhu@gmail.com>
+Date: Thu, 21 Sep 2023 15:58:59 +0200
+Subject: [PATCH] Simplify broken limb mending (#3054)
+
+* Rework broken limbs and mending
+
+* Redesign mending_modifier: 1.0 is same as splint
+
+* Update comments
+
+* Update disabled effect description
+
+---------
+
+Co-authored-by: Olanti <olanti-p@yandex.ru>
+---
+ data/json/effects.json | 14 +---
+ data/json/mutations/mutations.json | 33 ++++-----
+ data/json/obsoletion/effects.json | 4 +
+ src/bionics.cpp | 24 ------
+ src/character.cpp | 66 +++++++++--------
+ src/character.h | 6 +-
+ src/creature.cpp | 4 +-
+ src/iexamine.cpp | 15 ++--
+ src/iuse_actor.cpp | 12 ---
+ src/mutation.h | 6 +-
+ src/mutation_data.cpp | 2 +-
+ src/npc.cpp | 3 +-
+ src/panels.cpp | 45 ++++++-----
+ src/player_hardcoded_effects.cpp | 7 +-
+ src/suffer.cpp | 115 -----------------------------
+ tests/player_helpers.cpp | 3 +
+ 16 files changed, 96 insertions(+), 263 deletions(-)
+
+diff --git a/data/json/effects.json b/data/json/effects.json
+index 394bfb1a915..969cafe5046 100644
+--- a/data/json/effects.json
++++ b/data/json/effects.json
+@@ -1802,23 +1802,11 @@
+ "max_duration": "1 s",
+ "rating": "bad"
+ },
+- {
+- "type": "effect_type",
+- "id": "mending",
+- "name": [ "Started recovery", "Recovering", "Mostly recovered" ],
+- "desc": [ "This damaged limb is slowly regaining its functions." ],
+- "//": "Duration is 10 days, but the actual time taken is probabilistic.",
+- "max_duration": "10 d",
+- "int_dur_factor": "60 h",
+- "max_intensity": 3,
+- "rating": "good",
+- "permanent": true
+- },
+ {
+ "type": "effect_type",
+ "id": "disabled",
+ "name": [ { "ctxt": "physically", "str": "Disabled" } ],
+- "desc": [ "This limb is damaged beyond use and may require a splint to recover." ],
++ "desc": [ "This limb is damaged beyond use and must fully heal to recover. Using a splint may speed up the process." ],
+ "//": "This sounds weird. We need <bp_affected> tag or something",
+ "apply_message": "Your limb breaks!",
+ "remove_message": "The broken limb has mended.",
+diff --git a/data/json/mutations/mutations.json b/data/json/mutations/mutations.json
+index 1fe217b8559..333a471d30e 100644
+--- a/data/json/mutations/mutations.json
++++ b/data/json/mutations/mutations.json
+@@ -155,7 +155,7 @@
+ "category": [ "MEDICAL" ],
+ "healing_awake": 0.2,
+ "healing_resting": 0.5,
+- "mending_modifier": 2.0
++ "mending_modifier": 0.5
+ },
+ {
+ "type": "mutation",
+@@ -722,37 +722,34 @@
+ "id": "SLOWHEALER",
+ "name": { "str": "Slow Healer" },
+ "points": -2,
+- "description": "Your wounds heal a little slower than most. Your HP whilst asleep, as well as your broken limbs, heal at 75% of the regular rate.",
++ "description": "Your wounds heal a little slower than most. Your HP whilst asleep heals at 75% of the regular rate.",
+ "starting_trait": true,
+ "types": [ "HEALING" ],
+- "healing_resting": -0.25,
+- "mending_modifier": 0.5
++ "healing_resting": -0.25
+ },
+ {
+ "type": "mutation",
+ "id": "SLOWHEALER2",
+ "name": { "str": "Poor Healer" },
+ "points": -4,
+- "description": "Your health recovery is severely impaired. Your HP whilst asleep, as well as your broken limbs, heal at 33% of the regular rate.",
++ "description": "Your health recovery is severely impaired. Your HP whilst asleep heals at 33% of the regular rate.",
+ "starting_trait": true,
+ "valid": false,
+ "purifiable": false,
+ "types": [ "HEALING" ],
+- "healing_resting": -0.66,
+- "mending_modifier": 0.33
++ "healing_resting": -0.66
+ },
+ {
+ "type": "mutation",
+ "id": "SLOWHEALER3",
+ "name": { "str": "Imperceptive Healer" },
+ "points": -8,
+- "description": "Wounds are incredibly dangerous to you, as they barely heal at all. Your HP whilst asleep, as well as your broken limbs, heal at 10% of the regular rate.",
++ "description": "Wounds are incredibly dangerous to you, as they barely heal at all. Your HP whilst asleep heals at 10% of the regular rate.",
+ "starting_trait": true,
+ "valid": false,
+ "purifiable": false,
+ "types": [ "HEALING" ],
+- "healing_resting": -0.9,
+- "mending_modifier": 0.1
++ "healing_resting": -0.9
+ },
+ {
+ "type": "mutation",
+@@ -1377,34 +1374,34 @@
+ "category": [ "PLANT", "LIZARD" ],
+ "healing_awake": 0.66,
+ "healing_resting": 0.5,
+- "mending_modifier": 4.0
++ "mending_modifier": 0.5
+ },
+ {
+ "type": "mutation",
+ "id": "REGEN",
+ "name": { "str": "Regeneration" },
+ "points": 6,
+- "description": "Your flesh regenerates from wounds incredibly quickly. You heal 150% faster whilst asleep and 200% faster whilst awake. Your broken limbs also heal 16 times faster than usual.",
++ "description": "Your flesh regenerates from wounds incredibly quickly. You heal 150% faster whilst asleep and 200% faster whilst awake. You do not require splints to heal broken limbs.",
+ "types": [ "HEALING" ],
+ "prereqs": [ "FASTHEALER2" ],
+ "category": [ "SLIME", "TROGLOBITE" ],
+ "healing_awake": 2.0,
+ "healing_resting": 1.5,
+- "mending_modifier": 16.0
++ "mending_modifier": 1.0
+ },
+ {
+ "type": "mutation",
+ "id": "REGEN_LIZ",
+ "name": { "str": "Reptilian Healing" },
+- "points": 5,
++ "//": "Not worth a point, barely more than flavor.",
++ "points": 0,
+ "valid": false,
+ "purifiable": false,
+- "description": "Your broken limbs mend themselves without significant difficulty. You do not require splints and broken limbs heal 20 times faster than usual.",
+- "cancels": [ "ROT1", "ROT2", "ROT3" ],
+- "prereqs": [ "FASTHEALER2" ],
++ "description": "Your broken limbs mend themselves without significant difficulty. You do not require splints.",
++ "prereqs": [ "FASTHEALER" ],
+ "threshreq": [ "THRESH_LIZARD" ],
+ "category": [ "LIZARD" ],
+- "mending_modifier": 20.0
++ "mending_modifier": 1.0
+ },
+ {
+ "type": "mutation",
+diff --git a/data/json/obsoletion/effects.json b/data/json/obsoletion/effects.json
+index 38c218728cd..bb666566f6b 100644
+--- a/data/json/obsoletion/effects.json
++++ b/data/json/obsoletion/effects.json
+@@ -60,5 +60,9 @@
+ {
+ "type": "effect_type",
+ "id": "took_anticonvulsant_visible"
++ },
++ {
++ "type": "effect_type",
++ "id": "mending"
+ }
+ ]
+diff --git a/src/bionics.cpp b/src/bionics.cpp
+index 78827e780d7..bb2b2bd73e7 100644
+--- a/src/bionics.cpp
++++ b/src/bionics.cpp
+@@ -101,7 +101,6 @@ static const efftype_id effect_fungus( "fungus" );
+ static const efftype_id effect_hallu( "hallu" );
+ static const efftype_id effect_heating_bionic( "heating_bionic" );
+ static const efftype_id effect_iodine( "iodine" );
+-static const efftype_id effect_mending( "mending" );
+ static const efftype_id effect_meth( "meth" );
+ static const efftype_id effect_narcosis( "narcosis" );
+ static const efftype_id effect_operating( "operating" );
+@@ -190,7 +189,6 @@ static const trait_id trait_MASOCHIST_MED( "MASOCHIST_MED" );
+ static const trait_id trait_NOPAIN( "NOPAIN" );
+ static const trait_id trait_PROF_AUTODOC( "PROF_AUTODOC" );
+ static const trait_id trait_PROF_MED( "PROF_MED" );
+-static const trait_id trait_REGEN_LIZ( "REGEN_LIZ" );
+ static const trait_id trait_THRESH_MEDICAL( "THRESH_MEDICAL" );
+
+ static const std::string flag_ALLOWS_NATURAL_ATTACKS( "ALLOWS_NATURAL_ATTACKS" );
+@@ -1675,18 +1673,6 @@ void Character::process_bionic( bionic &bio )
+ }
+ if( calendar::once_every( 2_minutes ) ) {
+ std::vector<bodypart_id> damaged_hp_parts;
+- std::vector<effect *> mending_list;
+-
+- for( const bodypart_id &bp : get_all_body_parts( true ) ) {
+- const int hp_cur = get_part_hp_cur( bp );
+- if( !is_limb_broken( bp ) && hp_cur < get_part_hp_max( bp ) ) {
+- damaged_hp_parts.push_back( bp );
+- } else if( has_effect( effect_mending, bp.id() ) &&
+- ( has_trait( trait_REGEN_LIZ ) || worn_with_flag( flag_SPLINT, bp ) ) ) {
+- effect *e = &get_effect( effect_mending, bp->token );
+- mending_list.push_back( e );
+- }
+- }
+ if( !damaged_hp_parts.empty() ) {
+ // Essential parts are considered 10 HP lower than non-essential parts for the purpose of determining priority.
+ // I'd use the essential_value, but it's tied up in the heal_actor class of iuse_actor.
+@@ -1703,16 +1689,6 @@ void Character::process_bionic( bionic &bio )
+ mod_stored_kcal( -bio.info().kcal_trigger );
+ }
+ }
+- if( !mending_list.empty() ) {
+- for( effect *e : mending_list ) {
+- if( !can_use_bionic() ) {
+- return;
+- }
+- e->mod_duration( e->get_max_duration() / 100 );
+- mod_power_level( -bio.info().power_trigger );
+- mod_stored_kcal( -bio.info().kcal_trigger );
+- }
+- }
+ }
+ }
+ } else if( bio.id == bio_painkiller ) {
+diff --git a/src/character.cpp b/src/character.cpp
+index 6cb10461791..761e0785f44 100644
+--- a/src/character.cpp
++++ b/src/character.cpp
+@@ -140,6 +140,7 @@ static const efftype_id effect_cough_suppress( "cough_suppress" );
+ static const efftype_id effect_crushed( "crushed" );
+ static const efftype_id effect_darkness( "darkness" );
+ static const efftype_id effect_deaf( "deaf" );
++static const efftype_id effect_disabled( "disabled" );
+ static const efftype_id effect_disinfected( "disinfected" );
+ static const efftype_id effect_downed( "downed" );
+ static const efftype_id effect_drunk( "drunk" );
+@@ -167,7 +168,6 @@ static const efftype_id effect_lying_down( "lying_down" );
+ static const efftype_id effect_melatonin_supplements( "melatonin" );
+ static const efftype_id effect_meth( "meth" );
+ static const efftype_id effect_masked_scent( "masked_scent" );
+-static const efftype_id effect_mending( "mending" );
+ static const efftype_id effect_narcosis( "narcosis" );
+ static const efftype_id effect_nausea( "nausea" );
+ static const efftype_id effect_no_sight( "no_sight" );
+@@ -287,7 +287,6 @@ static const trait_id trait_INFRARED( "INFRARED" );
+ static const trait_id trait_LEG_TENT_BRACE( "LEG_TENT_BRACE" );
+ static const trait_id trait_LIGHT_BONES( "LIGHT_BONES" );
+ static const trait_id trait_LIZ_IR( "LIZ_IR" );
+-static const trait_id trait_REGEN_LIZ( "REGEN_LIZ" );
+ static const trait_id trait_M_DEPENDENT( "M_DEPENDENT" );
+ static const trait_id trait_M_IMMUNE( "M_IMMUNE" );
+ static const trait_id trait_M_SKIN2( "M_SKIN2" );
+@@ -1257,14 +1256,15 @@ int Character::get_working_leg_count() const
+
+ bool Character::is_limb_disabled( const bodypart_id &limb ) const
+ {
+- return get_part_hp_cur( limb ) <= get_part_hp_max( limb ) * .125;
++ return is_limb_broken( limb ) ||
++ ( get_part_hp_cur( limb ) <= get_part_hp_max( limb ) * 0.125 );
+ }
+
+ // this is the source of truth on if a limb is broken so all code to determine
+ // if a limb is broken should point here to make any future changes to breaking easier
+ bool Character::is_limb_broken( const bodypart_id &limb ) const
+ {
+- return get_part_hp_cur( limb ) <= 0;
++ return has_effect( effect_disabled, limb.id() );
+ }
+
+ bool Character::can_run()
+@@ -4580,8 +4580,17 @@ void Character::regen( int rate_multiplier )
+
+ float rest = rest_quality();
+ float heal_rate = healing_rate( rest ) * to_turns<int>( 5_minutes );
++ const float broken_regen_mod = clamp( mutation_value( "mending_modifier" ), 0.25f, 1.0f );
+ if( heal_rate > 0.0f ) {
+- healall( roll_remainder( rate_multiplier * heal_rate ) );
++ const int base_heal = roll_remainder( rate_multiplier * heal_rate );
++ const int broken_heal = roll_remainder( base_heal * broken_regen_mod );
++
++ for( const bodypart_id &bp : get_all_body_parts() ) {
++ const bool is_broken = is_limb_broken( bp ) &&
++ !worn_with_flag( flag_SPLINT, bp );
++ heal( bp, is_broken ? broken_heal : base_heal );
++ mod_part_healed_total( bp, is_broken ? broken_heal : base_heal );
++ }
+ } else if( heal_rate < 0.0f ) {
+ int rot_rate = roll_remainder( rate_multiplier * -heal_rate );
+ // Has to be in loop because some effects depend on rounding
+@@ -4595,9 +4604,13 @@ void Character::regen( int rate_multiplier )
+ const bodypart_id &bp = convert_bp( hp_to_bp( static_cast<hp_part>( i ) ) ).id();
+ float healing = healing_rate_medicine( rest, bp ) * to_turns<int>( 5_minutes );
+
+- int healing_apply = roll_remainder( healing );
++ const bool is_broken = is_limb_broken( bp ) &&
++ !worn_with_flag( flag_SPLINT, bp );
++ const int healing_apply = roll_remainder( is_broken ? healing *broken_regen_mod : healing );
++
+ healed_bp( i, healing_apply );
+ heal( bp, healing_apply );
++
+ if( damage_bandaged[i] > 0 ) {
+ damage_bandaged[i] -= healing_apply;
+ if( damage_bandaged[i] <= 0 ) {
+@@ -4707,9 +4720,6 @@ void Character::update_body( const time_point &from, const time_point &to )
+ check_needs_extremes();
+ update_needs( five_mins );
+ regen( five_mins );
+- // Note: mend ticks once per 5 minutes, but wants rate in TURNS, not 5 minute intervals
+- // TODO: change @ref med to take time_duration
+- mend( five_mins * to_turns<int>( 5_minutes ) );
+ }
+ if( ticks_between( from, to, 24_hours ) > 0 ) {
+ enforce_minimum_healing();
+@@ -5800,15 +5810,11 @@ hp_part Character::body_window( const std::string &menu_header,
+ const nc_color all_state_col = limb_color( bp, true, true, true );
+ // Broken means no HP can be restored, it requires surgical attention.
+ const bool limb_is_broken = is_limb_broken( bp );
+- const bool limb_is_mending = limb_is_broken &&
+- ( worn_with_flag( flag_SPLINT, bp ) || has_trait( trait_REGEN_LIZ ) );
+
+ if( show_all ) {
+ e.allowed = true;
+ } else if( has_curable_effect ) {
+ e.allowed = true;
+- } else if( limb_is_broken ) {
+- e.allowed = false;
+ } else if( current_hp < maximal_hp && ( e.bonus != 0 || bandage_power > 0.0f ||
+ disinfectant_power > 0.0f ) ) {
+ e.allowed = true;
+@@ -5837,21 +5843,21 @@ hp_part Character::body_window( const std::string &menu_header,
+
+ const auto &aligned_name = std::string( max_bp_name_len - utf8_width( e.name ), ' ' ) + e.name;
+ std::string hp_str;
+- if( limb_is_mending ) {
+- desc += colorize( _( "It is broken but has been set and just needs time to heal." ),
++ if( limb_is_broken ) {
++ const nc_color color = worn_with_flag( flag_SPLINT, bp ) ||
++ ( mutation_value( "mending_modifier" ) >= 1.0f ) ?
++ c_blue :
++ c_light_red;
++ desc += colorize( _( "It is broken and must heal fully before it becomes functional again." ),
+ c_blue ) + "\n";
+- const auto &eff = get_effect( effect_mending, bp_token );
+- const int mend_perc = eff.is_null() ? 0.0 : 100 * eff.get_duration() / eff.get_max_duration();
++ const int mend_perc = 100 * current_hp / maximal_hp;
+
+ if( precise ) {
+- hp_str = colorize( string_format( "=%2d%%=", mend_perc ), c_blue );
++ hp_str = colorize( string_format( "=%2d%%=", mend_perc ), color );
+ } else {
+ const int num = mend_perc / 20;
+- hp_str = colorize( std::string( num, '#' ) + std::string( 5 - num, '=' ), c_blue );
++ hp_str = colorize( std::string( num, '#' ) + std::string( 5 - num, '=' ), color );
+ }
+- } else if( limb_is_broken ) {
+- desc += colorize( _( "It is broken. It needs a splint or surgical attention." ), c_red ) + "\n";
+- hp_str = "==%==";
+ } else if( precise ) {
+ hp_str = string_format( "%d", current_hp );
+ } else {
+@@ -8431,11 +8437,6 @@ void Character::apply_damage( Creature *source, bodypart_id hurt, int dam,
+ put_into_vehicle_or_drop( *this, item_drop_reason::tumbling, { weapon } );
+ i_rem( &weapon );
+ }
+- if( has_effect( effect_mending, part_to_damage->token ) ) {
+- effect &e = get_effect( effect_mending, part_to_damage->token );
+- float remove_mend = dam / 20.0f;
+- e.mod_duration( -e.get_max_duration() * remove_mend );
+- }
+
+ if( dam > get_painkiller() ) {
+ on_hurt( source );
+@@ -8646,10 +8647,13 @@ int Character::reduce_healing_effect( const efftype_id &eff_id, int remove_med,
+
+ void Character::heal( const bodypart_id &healed, int dam )
+ {
+- if( !is_limb_broken( healed ) ) {
+- int effective_heal = std::min( dam, get_part_hp_max( healed ) - get_part_hp_cur( healed ) );
+- mod_part_hp_cur( healed, effective_heal );
+- g->events().send<event_type::character_heals_damage>( getID(), effective_heal );
++ const int max_hp = get_part_hp_max( healed );
++ const int cur_hp = get_part_hp_cur( healed );
++ const int effective_heal = std::min( dam, max_hp - cur_hp );
++ mod_part_hp_cur( healed, effective_heal );
++ g->events().send<event_type::character_heals_damage>( getID(), effective_heal );
++ if( cur_hp + dam >= max_hp ) {
++ remove_effect( effect_disabled, healed.id() );
+ }
+ }
+
+diff --git a/src/character.h b/src/character.h
+index c3ff9d3f7eb..a84bf824865 100644
+--- a/src/character.h
++++ b/src/character.h
+@@ -742,10 +742,8 @@ class Character : public Creature, public visitable<Character>
+ int get_working_arm_count() const;
+ /** Returns the number of functioning legs */
+ int get_working_leg_count() const;
+- /** Returns true if the limb is disabled(12.5% or less hp)*/
++ /** Returns true if the limb is disabled (12.5% or less hp, or broken)*/
+ bool is_limb_disabled( const bodypart_id &limb ) const;
+- /** Returns true if the limb is hindered(40% or less hp) */
+- bool is_limb_hindered( hp_part limb ) const;
+ /** Returns true if the limb is broken */
+ bool is_limb_broken( const bodypart_id &limb ) const;
+ /** source of truth of whether a Character can run */
+@@ -2063,8 +2061,6 @@ class Character : public Creature, public visitable<Character>
+ void suffer();
+ /** Handles mitigation and application of radiation */
+ bool irradiate( float rads, bool bypass = false );
+- /** Handles the chance for broken limbs to spontaneously heal to 1 HP */
+- void mend( int rate_multiplier );
+
+ /** Creates an auditory hallucination */
+ void sound_hallu();
+diff --git a/src/creature.cpp b/src/creature.cpp
+index 0d69db54329..d1c48950682 100644
+--- a/src/creature.cpp
++++ b/src/creature.cpp
+@@ -1652,14 +1652,14 @@ void Creature::mod_part_healed_total( const bodypart_id &id, int mod )
+ void Creature::set_all_parts_hp_cur( const int set )
+ {
+ for( std::pair<const bodypart_str_id, bodypart> &elem : body ) {
+- elem.second.set_hp_cur( set );
++ set_part_hp_cur( elem.first, set );
+ }
+ }
+
+ void Creature::set_all_parts_hp_to_max()
+ {
+ for( std::pair<const bodypart_str_id, bodypart> &elem : body ) {
+- elem.second.set_hp_to_max();
++ set_part_hp_cur( elem.first, get_part_hp_max( elem.first ) );
+ }
+ }
+
+diff --git a/src/iexamine.cpp b/src/iexamine.cpp
+index cb1af8fb5a7..5295e4bf0ca 100644
+--- a/src/iexamine.cpp
++++ b/src/iexamine.cpp
+@@ -123,7 +123,6 @@ static const efftype_id effect_bleed( "bleed" );
+ static const efftype_id effect_disinfected( "disinfected" );
+ static const efftype_id effect_earphones( "earphones" );
+ static const efftype_id effect_infected( "infected" );
+-static const efftype_id effect_mending( "mending" );
+ static const efftype_id effect_pblue( "pblue" );
+ static const efftype_id effect_pkill2( "pkill2" );
+ static const efftype_id effect_sleep( "sleep" );
+@@ -5081,11 +5080,7 @@ void iexamine::autodoc( player &p, const tripoint &examp )
+ for( int i = 0; i < num_hp_parts; i++ ) {
+ const bodypart_id &part = convert_bp( player::hp_to_bp( static_cast<hp_part>( i ) ) ).id();
+ const bool broken = patient.is_limb_broken( part );
+- effect &existing_effect = patient.get_effect( effect_mending, part->token );
+- // Skip part if not broken or already healed 50%
+- if( !broken || ( !existing_effect.is_null() &&
+- existing_effect.get_duration() >
+- existing_effect.get_max_duration() - 5_days - 1_turns ) ) {
++ if( !broken ) {
+ continue;
+ }
+ broken_limbs_count++;
+@@ -5116,9 +5111,11 @@ void iexamine::autodoc( player &p, const tripoint &examp )
+ patient.add_msg_player_or_npc( m_good, _( "The machine rapidly sets and splints your broken %s." ),
+ _( "The machine rapidly sets and splints <npcname>'s broken %s." ),
+ body_part_name( part ) );
+- patient.add_effect( effect_mending, 0_turns, part->token );
+- effect &mending_effect = patient.get_effect( effect_mending, part->token );
+- mending_effect.set_duration( mending_effect.get_max_duration() - 5_days );
++ // TODO: Prevent exploits with hp draining stuff?
++ int heal_amt = patient.get_part_hp_max( part ) / 2 - patient.get_part_hp_cur( part );
++ if( heal_amt > 0 ) {
++ patient.heal( part, heal_amt );
++ }
+ }
+ }
+ if( broken_limbs_count == 0 ) {
+diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp
+index a0d6e66b7dc..4a0eb9befdb 100644
+--- a/src/iuse_actor.cpp
++++ b/src/iuse_actor.cpp
+@@ -3903,18 +3903,6 @@ static hp_part pick_part_to_heal(
+ return healed_part;
+ }
+
+- if( patient.is_limb_broken( bp ) ) {
+- if( healed_part == hp_arm_l || healed_part == hp_arm_r ) {
+- add_msg( m_info, _( "That arm is broken. It needs surgical attention or a splint." ) );
+- } else if( healed_part == hp_leg_l || healed_part == hp_leg_r ) {
+- add_msg( m_info, _( "That leg is broken. It needs surgical attention or a splint." ) );
+- } else {
+- add_msg( m_info, "That body part is bugged. It needs developer's attention." );
+- }
+-
+- continue;
+- }
+-
+ if( force || patient.get_part_hp_cur( bp ) < patient.get_part_hp_max( bp ) ) {
+ return healed_part;
+ }
+diff --git a/src/mutation.h b/src/mutation.h
+index 8e82983e2d7..8fe226d47b5 100644
+--- a/src/mutation.h
++++ b/src/mutation.h
+@@ -115,8 +115,10 @@ struct mutation_branch {
+ // Healing per turn
+ float healing_awake = 0.0f;
+ float healing_resting = 0.0f;
+- // Limb mending bonus
+- float mending_modifier = 1.0f;
++ // Multiplier on regen of broken limbs.
++ // Base regen of broken limbs is 25% and 25% the low cap.
++ // Capped at 1.0, which makes broken limbs regen at same rate as unbroken.
++ float mending_modifier = 0.0f;
+ // Bonus HP multiplier. That is, 1.0 doubles hp, -0.5 halves it.
+ float hp_modifier = 0.0f;
+ // Second HP modifier that stacks with first but is otherwise identical.
+diff --git a/src/mutation_data.cpp b/src/mutation_data.cpp
+index 9c95b97873e..a070de723d8 100644
+--- a/src/mutation_data.cpp
++++ b/src/mutation_data.cpp
+@@ -377,7 +377,7 @@ void mutation_branch::load( const JsonObject &jo, const std::string & )
+ optional( jo, was_loaded, "pain_recovery", pain_recovery, 0.0f );
+ optional( jo, was_loaded, "healing_awake", healing_awake, 0.0f );
+ optional( jo, was_loaded, "healing_resting", healing_resting, 0.0f );
+- optional( jo, was_loaded, "mending_modifier", mending_modifier, 1.0f );
++ optional( jo, was_loaded, "mending_modifier", mending_modifier, 0.0f );
+ optional( jo, was_loaded, "hp_modifier", hp_modifier, 0.0f );
+ optional( jo, was_loaded, "hp_modifier_secondary", hp_modifier_secondary, 0.0f );
+ optional( jo, was_loaded, "hp_adjustment", hp_adjustment, 0.0f );
+diff --git a/src/npc.cpp b/src/npc.cpp
+index 36b63dd2bb4..9c31869540d 100644
+--- a/src/npc.cpp
++++ b/src/npc.cpp
+@@ -84,7 +84,6 @@ static const efftype_id effect_contacts( "contacts" );
+ static const efftype_id effect_drunk( "drunk" );
+ static const efftype_id effect_feral_killed_recently( "feral_killed_recently" );
+ static const efftype_id effect_infection( "infection" );
+-static const efftype_id effect_mending( "mending" );
+ static const efftype_id effect_npc_flee_player( "npc_flee_player" );
+ static const efftype_id effect_npc_suspend( "npc_suspend" );
+ static const efftype_id effect_pkill_l( "pkill_l" );
+@@ -1073,7 +1072,7 @@ bool npc::wear_if_wanted( const item &it, std::string &reason )
+ for( int i = 0; i < num_hp_parts; i++ ) {
+ hp_part hpp = static_cast<hp_part>( i );
+ body_part bp = player::hp_to_bp( hpp );
+- if( is_limb_broken( convert_bp( bp ) ) && !has_effect( effect_mending, bp ) &&
++ if( is_limb_broken( convert_bp( bp ) ) && !worn_with_flag( flag_SPLINT, convert_bp( bp ).id() ) &&
+ it.covers( convert_bp( bp ).id() ) ) {
+ reason = _( "Thanks, I'll wear that now." );
+ return !!wear_item( it, false );
+diff --git a/src/panels.cpp b/src/panels.cpp
+index 41983b82ae5..9c8ae1701bc 100644
+--- a/src/panels.cpp
++++ b/src/panels.cpp
+@@ -61,7 +61,6 @@
+ #include "vpart_position.h"
+ #include "weather.h"
+
+-static const trait_id trait_REGEN_LIZ( "REGEN_LIZ" );
+ static const trait_id trait_SELFAWARE( "SELFAWARE" );
+ static const trait_id trait_THRESH_FELINE( "THRESH_FELINE" );
+ static const trait_id trait_THRESH_BIRD( "THRESH_BIRD" );
+@@ -69,7 +68,7 @@ static const trait_id trait_THRESH_URSINE( "THRESH_URSINE" );
+
+ static const efftype_id effect_got_checked( "got_checked" );
+
+-static const std::string flag_SPLINT( "SPLINT" );
++static const flag_str_id flag_SPLINT( "SPLINT" );
+
+ // constructor
+ window_panel::window_panel( std::function<void( avatar &, const catacurses::window & )>
+@@ -771,36 +770,36 @@ static void draw_limb_health( avatar &u, const catacurses::window &w, int limb_i
+ wprintz( w, color, sym );
+ }
+ };
++
+ const bodypart_id bp = convert_bp( avatar::hp_to_bp( static_cast<hp_part>( limb_index ) ) ).id();
++ const int hp_cur = u.get_part_hp_cur( bp );
++ const int hp_max = u.get_part_hp_max( bp );
++
++ std::optional<nc_color> color_override;
++
+ if( u.is_limb_broken( bp.id() ) && ( limb_index >= hp_arm_l &&
+ limb_index <= hp_leg_r ) ) {
+ //Limb is broken
+- std::string limb = "~~%~~";
+- nc_color color = c_light_red;
+-
+- if( u.worn_with_flag( flag_SPLINT, bp ) || u.has_trait( trait_REGEN_LIZ ) ) {
+- static const efftype_id effect_mending( "mending" );
+- const auto &eff = u.get_effect( effect_mending, bp->token );
+- const int mend_perc = eff.is_null() ? 0.0 : 100 * eff.get_duration() / eff.get_max_duration();
++ const int mend_perc = 100 * hp_cur / hp_max;
++ bool splinted = u.worn_with_flag( flag_SPLINT.str(), bp ) ||
++ ( u.mutation_value( "mending_modifier" ) >= 1.0f );
++ nc_color color = splinted ? c_blue : c_dark_gray;
+
+- if( is_self_aware || u.has_effect( effect_got_checked ) ) {
+- limb = string_format( "=%2d%%=", mend_perc );
+- color = c_blue;
+- } else {
+- const int num = mend_perc / 20;
+- print_symbol_num( w, num, "#", c_blue );
+- print_symbol_num( w, 5 - num, "=", c_blue );
+- return;
+- }
++ if( is_self_aware || u.has_effect( effect_got_checked ) ) {
++ color_override = color;
++ } else {
++ const int num = mend_perc / 20;
++ print_symbol_num( w, num, "#", color );
++ print_symbol_num( w, 5 - num, "=", color );
++ return;
+ }
+-
+- wprintz( w, color, limb );
+- return;
+ }
+
+- const int hp_cur = u.get_part_hp_cur( bp );
+- const int hp_max = u.get_part_hp_max( bp );
++
+ std::pair<std::string, nc_color> hp = get_hp_bar( hp_cur, hp_max );
++ if( color_override ) {
++ hp.second = *color_override;
++ }
+
+ if( is_self_aware || u.has_effect( effect_got_checked ) ) {
+ wprintz( w, hp.second, "%3d ", hp_cur );
+diff --git a/src/player_hardcoded_effects.cpp b/src/player_hardcoded_effects.cpp
+index 2f74c64ccf4..88d7f83de8e 100644
+--- a/src/player_hardcoded_effects.cpp
++++ b/src/player_hardcoded_effects.cpp
+@@ -73,7 +73,6 @@ static const efftype_id effect_hallu( "hallu" );
+ static const efftype_id effect_hot( "hot" );
+ static const efftype_id effect_infected( "infected" );
+ static const efftype_id effect_lying_down( "lying_down" );
+-static const efftype_id effect_mending( "mending" );
+ static const efftype_id effect_mutating( "mutating" );
+ static const efftype_id effect_nausea( "nausea" );
+ static const efftype_id effect_narcosis( "narcosis" );
+@@ -1292,12 +1291,8 @@ void Character::hardcoded_effects( effect &it )
+ }
+ }
+ }
+- } else if( id == effect_mending ) {
+- if( !is_limb_broken( convert_bp( bp ) ) ) {
+- it.set_duration( 0_turns );
+- }
+ } else if( id == effect_disabled ) {
+- if( !is_limb_broken( convert_bp( bp ) ) ) {
++ if( get_part_hp_cur( convert_bp( bp ) ) >= get_part_hp_max( convert_bp( bp ) ) ) {
+ remove_effect( effect_disabled );
+ }
+ } else if( id == effect_panacea ) {
+diff --git a/src/suffer.cpp b/src/suffer.cpp
+index f752944f22b..acc6a8dc50e 100644
+--- a/src/suffer.cpp
++++ b/src/suffer.cpp
+@@ -95,7 +95,6 @@ static const efftype_id effect_glowy_led( "glowy_led" );
+ static const efftype_id effect_hallu( "hallu" );
+ static const efftype_id effect_iodine( "iodine" );
+ static const efftype_id effect_masked_scent( "masked_scent" );
+-static const efftype_id effect_mending( "mending" );
+ static const efftype_id effect_meth( "meth" );
+ static const efftype_id effect_narcosis( "narcosis" );
+ static const efftype_id effect_nausea( "nausea" );
+@@ -143,7 +142,6 @@ static const trait_id trait_RADIOACTIVE1( "RADIOACTIVE1" );
+ static const trait_id trait_RADIOACTIVE2( "RADIOACTIVE2" );
+ static const trait_id trait_RADIOACTIVE3( "RADIOACTIVE3" );
+ static const trait_id trait_RADIOGENIC( "RADIOGENIC" );
+-static const trait_id trait_REGEN_LIZ( "REGEN_LIZ" );
+ static const trait_id trait_ROOTS3( "ROOTS3" );
+ static const trait_id trait_SCHIZOPHRENIC( "SCHIZOPHRENIC" );
+ static const trait_id trait_SHARKTEETH( "SHARKTEETH" );
+@@ -174,16 +172,6 @@ static const std::string flag_RAD_RESIST( "RAD_RESIST" );
+ static const std::string flag_SPLINT( "SPLINT" );
+ static const std::string flag_SUN_GLASSES( "SUN_GLASSES" );
+
+-static float addiction_scaling( float at_min, float at_max, float add_lvl )
+-{
+- // Not addicted
+- if( add_lvl < MIN_ADDICTION_LEVEL ) {
+- return 1.0f;
+- }
+-
+- return lerp( at_min, at_max, ( add_lvl - MIN_ADDICTION_LEVEL ) / MAX_ADDICTION_LEVEL );
+-}
+-
+ void Character::suffer_water_damage( const mutation_branch &mdata )
+ {
+ for( const std::pair<const bodypart_str_id, bodypart> &elem : get_body() ) {
+@@ -1669,109 +1657,6 @@ bool Character::irradiate( float rads, bool bypass )
+ return false;
+ }
+
+-void Character::mend( int rate_multiplier )
+-{
+- // Wearing splints can slowly mend a broken limb back to 1 hp.
+- bool any_broken = false;
+- for( const bodypart_id &bp : get_all_body_parts() ) {
+- if( is_limb_broken( bp ) ) {
+- any_broken = true;
+- break;
+- }
+- }
+-
+- if( !any_broken ) {
+- return;
+- }
+-
+- double healing_factor = 1.0;
+- // Studies have shown that alcohol and tobacco use delay fracture healing time
+- // Being under effect is 50% slowdown
+- // Being addicted but not under effect scales from 25% slowdown to 75% slowdown
+- // The improvement from being intoxicated over withdrawal is intended
+- if( has_effect( effect_cig ) ) {
+- healing_factor *= 0.5;
+- } else {
+- healing_factor *= addiction_scaling( 0.25f, 0.75f, addiction_level( add_type::CIG ) );
+- }
+-
+- if( has_effect( effect_drunk ) ) {
+- healing_factor *= 0.5;
+- } else {
+- healing_factor *= addiction_scaling( 0.25f, 0.75f, addiction_level( add_type::ALCOHOL ) );
+- }
+-
+- if( get_rad() > 0 && !has_trait( trait_RADIOGENIC ) ) {
+- healing_factor *= clamp( ( 1000.0f - get_rad() ) / 1000.0f, 0.0f, 1.0f );
+- }
+-
+- // Bed rest speeds up mending
+- if( has_effect( effect_sleep ) ) {
+- healing_factor *= 4.0;
+- } else if( get_fatigue() > fatigue_levels::dead_tired ) {
+- // but being dead tired does not...
+- healing_factor *= 0.75;
+- } else {
+- // If not dead tired, resting without sleep also helps
+- healing_factor *= 1.0f + rest_quality();
+- }
+-
+- // Being healthy helps.
+- healing_factor *= 1.0f + get_healthy() / 200.0f;
+-
+- // Very hungry starts lowering the chance
+- // square rooting the value makes the numbers drop off faster when below 1
+- healing_factor *= std::sqrt( static_cast<float>( get_stored_kcal() ) / static_cast<float>
+- ( max_stored_kcal() ) );
+- // Similar for thirst - starts at very thirsty, drops to 0 at parched
+- healing_factor *= 1.0f - clamp( 1.0f * ( get_thirst() - thirst_levels::very_thirsty ) /
+- +thirst_levels::parched, 0.0f, 1.0f );
+-
+- // Mutagenic healing factor!
+- bool needs_splint = true;
+-
+- healing_factor *= mutation_value( "mending_modifier" );
+-
+- if( has_trait( trait_REGEN_LIZ ) ) {
+- needs_splint = false;
+- }
+-
+- add_msg( m_debug, "Limb mend healing factor: %.2f", healing_factor );
+- if( healing_factor <= 0.0f ) {
+- // The section below assumes positive healing rate
+- return;
+- }
+-
+- for( const bodypart_id &bp : get_all_body_parts() ) {
+- const bool broken = is_limb_broken( bp );
+- if( !broken ) {
+- continue;
+- }
+-
+- if( needs_splint && !worn_with_flag( flag_SPLINT, bp ) ) {
+- continue;
+- }
+-
+- const time_duration dur_inc = 1_turns * roll_remainder( rate_multiplier * healing_factor );
+- auto &eff = get_effect( effect_mending, bp->token );
+- if( eff.is_null() ) {
+- add_effect( effect_mending, dur_inc, bp->token );
+- continue;
+- }
+-
+- eff.set_duration( eff.get_duration() + dur_inc );
+-
+- if( eff.get_duration() >= eff.get_max_duration() ) {
+- set_part_hp_cur( bp, 1 );
+- remove_effect( effect_mending, bp->token );
+- g->events().send<event_type::broken_bone_mends>( getID(), bp->token );
+- //~ %s is bodypart
+- add_msg_if_player( m_good, _( "Your %s has started to mend!" ),
+- body_part_name( bp ) );
+- }
+- }
+-}
+-
+ void Character::sound_hallu()
+ {
+ // Random 'dangerous' sound from a random direction
+diff --git a/tests/player_helpers.cpp b/tests/player_helpers.cpp
+index fc95f1696d8..307b9a8834f 100644
+--- a/tests/player_helpers.cpp
++++ b/tests/player_helpers.cpp
+@@ -98,6 +98,9 @@ void clear_character( player &dummy, bool debug_storage )
+ dummy.set_stamina( dummy.get_stamina_max() );
+ dummy.set_movement_mode( CMM_WALK );
+
++ // Set HP to max here and also later, for disabled/broken limbs
++ dummy.set_all_parts_hp_to_max();
++
+ // Make sure we don't carry around weird effects.
+ dummy.clear_effects(); // mark effects for removal
+ dummy.process_effects(); // actually remove them
+--
+2.42.0
+