summaryrefslogtreecommitdiff
path: root/revert-24_fix-repair-nanobots-not-working-at-all-on-broken-lim.patch
blob: c1de272d9d2108cca78752be60f4d08d7192f9a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
From 5da2793a2a464a997b19c9b156cdb6baaaacb081 Mon Sep 17 00:00:00 2001
From: scarf <greenscarf005@gmail.com>
Date: Wed, 6 Dec 2023 11:35:40 +0900
Subject: [PATCH 213/318] fix: repair nanobots not working at all on broken
 limbs (#3787)

fix: make nanobot work regardless of splint
---
 data/json/bionics.json       |  2 +-
 data/json/items/bionics.json |  2 +-
 src/bionics.cpp              | 47 ++++++++++++++++++++----------------
 src/character.cpp            | 11 +++------
 src/regen.cpp                | 35 +++++++++++++++++++++++++++
 src/regen.h                  | 18 ++++++++++++++
 6 files changed, 85 insertions(+), 30 deletions(-)
 create mode 100644 src/regen.cpp
 create mode 100644 src/regen.h

diff --git a/data/json/bionics.json b/data/json/bionics.json
index 2e4b121ce7f..824be5bad23 100644
--- a/data/json/bionics.json
+++ b/data/json/bionics.json
@@ -661,7 +661,7 @@
     "id": "bio_nanobots",
     "type": "bionic",
     "name": { "str": "Repair Nanobots" },
-    "description": "Inside your body is a fleet of tiny dormant robots.  While activated they will reduce the intensity of one bleed effect every 30 seconds, and heal all injured body parts by 1 HP (or broken limbs by 1%) every 2 minutes if you have 3 kJ bionic power and 5 kcal per body part.  Broken limbs must still be splinted (unless you have specific mutations) to benefit.  If you don't have enough, they will prioritize based on the resources you have.",
+    "description": "Inside your body is a fleet of tiny dormant robots.  While activated they will reduce the intensity of one bleed effect every 30 seconds, and heal all injured body parts by 1 HP (or broken limbs by 1%) every 2 minutes if you have 3 kJ bionic power and 5 kcal per body part.  If you don't have enough, they will prioritize based on the resources you have.",
     "occupied_bodyparts": [ [ "torso", 10 ] ],
     "flags": [ "BIONIC_TOGGLED", "BIONIC_NPC_USABLE", "BIONIC_SLEEP_FRIENDLY" ],
     "act_cost": "300 J",
diff --git a/data/json/items/bionics.json b/data/json/items/bionics.json
index 8e06717899b..5a5c9e5a037 100644
--- a/data/json/items/bionics.json
+++ b/data/json/items/bionics.json
@@ -610,7 +610,7 @@
     "type": "BIONIC_ITEM",
     "name": { "str": "Repair Nanobots CBM" },
     "looks_like": "bio_int_enhancer",
-    "description": "A fleet of tiny dormant robots.  While activated they will reduce the intensity of one bleed effect every 30 seconds, and heal all injured body parts by 1 HP (or broken limbs by 1%) every 2 minutes if you have 3 kJ bionic power and 5 kcal per body part.  Broken limbs must still be splinted (unless you have specific mutations) to benefit.  If you don't have enough, they will prioritize based on the resources you have.",
+    "description": "A fleet of tiny dormant robots.  While activated they will reduce the intensity of one bleed effect every 30 seconds, and heal all injured body parts by 1 HP (or broken limbs by 1%) every 2 minutes if you have 3 kJ bionic power and 5 kcal per body part.  If you don't have enough, they will prioritize based on the resources you have.",
     "price": "9500 USD",
     "weight": "200 g",
     "difficulty": 6
diff --git a/src/bionics.cpp b/src/bionics.cpp
index 63d72584731..28e79490d37 100644
--- a/src/bionics.cpp
+++ b/src/bionics.cpp
@@ -68,6 +68,7 @@
 #include "point.h"
 #include "projectile.h"
 #include "requirements.h"
+#include "regen.h"
 #include "rng.h"
 #include "sounds.h"
 #include "string_formatter.h"
@@ -1662,28 +1663,32 @@ void Character::process_bionic( bionic &bio )
                 }
             }
             if( calendar::once_every( 2_minutes ) ) {
-                std::vector<bodypart_id> damaged_hp_parts;
-                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 );
-                    }
-                }
-                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.
-                    std::sort( damaged_hp_parts.begin(), damaged_hp_parts.end(),
-                    [this]( const bodypart_id & a, const bodypart_id & b ) {
-                        return ( get_part_hp_cur( a ) - a->essential * 10 ) < ( get_part_hp_cur( b ) - b->essential * 10 );
-                    } );
-                    for( bodypart_id &bpid : damaged_hp_parts ) {
-                        if( !can_use_bionic() ) {
-                            return;
-                        }
-                        heal( bpid, 1 );
-                        mod_power_level( -bio.info().power_trigger );
-                        mod_stored_kcal( -bio.info().kcal_trigger );
+                // 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.
+                const auto effective_hp = [this]( const bodypart_id & bp ) -> int {
+                    return get_part_hp_cur( bp ) - bp->essential * 10;
+                };
+                const auto should_heal = [this]( const bodypart_id & bp ) -> bool {
+                    return get_part_hp_cur( bp ) < get_part_hp_max( bp );
+                };
+                const auto sort_by = [effective_hp]( const bodypart_id & a, const bodypart_id & b ) -> bool {
+                    return effective_hp( a ) < effective_hp( b );
+                };
+                const auto damaged_parts = [this, should_heal, sort_by]() {
+                    const auto xs = get_all_body_parts( true );
+                    auto ys = std::vector<bodypart_id> {};
+                    std::copy_if( xs.begin(), xs.end(), std::back_inserter( ys ), should_heal );
+                    std::sort( ys.begin(), ys.end(), sort_by );
+                    return ys;
+                };
+
+                for( bodypart_id &bp : damaged_parts() ) {
+                    if( !can_use_bionic() ) {
+                        return;
                     }
+                    heal_adjusted( *this, bp, 1 );
+                    mod_power_level( -bio.info().power_trigger );
+                    mod_stored_kcal( -bio.info().kcal_trigger );
                 }
             }
         }
diff --git a/src/character.cpp b/src/character.cpp
index 9b6c15ce40c..25be749aa56 100644
--- a/src/character.cpp
+++ b/src/character.cpp
@@ -1,5 +1,4 @@
 #include "character.h"
-#include "bodypart.h"
 #include "character_encumbrance.h"
 
 #include <algorithm>
@@ -82,6 +81,7 @@
 #include "profession.h"
 #include "recipe_dictionary.h"
 #include "ret_val.h"
+#include "regen.h"
 #include "rng.h"
 #include "scent_map.h"
 #include "skill.h"
@@ -5068,14 +5068,11 @@ void Character::regen( int rate_multiplier )
     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 ) {
-        const int base_heal = roll_remainder( rate_multiplier * heal_rate );
-        const int broken_heal = roll_remainder( base_heal * broken_regen_mod );
+        const int heal = roll_remainder( rate_multiplier * heal_rate );
 
         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 );
+            const int actually_healed = heal_adjusted( *this, bp, heal );
+            mod_part_healed_total( bp, actually_healed );
         }
     } else if( heal_rate < 0.0f ) {
         int rot_rate = roll_remainder( rate_multiplier * -heal_rate );
diff --git a/src/regen.cpp b/src/regen.cpp
new file mode 100644
index 00000000000..f8446c4243d
--- /dev/null
+++ b/src/regen.cpp
@@ -0,0 +1,35 @@
+#include "regen.h"
+#include "character.h"
+#include "rng.h"
+
+const flag_id flag_SPLINT( "SPLINT" );
+
+namespace
+{
+
+/// Limb is broken without splint
+auto has_broken_limb_penalty( const Character &c, const bodypart_id &bp ) -> bool
+{
+    return c.is_limb_broken( bp )
+           && !c.worn_with_flag( flag_SPLINT, bp );
+}
+
+/// Broken limbs without splint heal slower up to 25%
+auto mending_modifier( const Character &c ) -> float
+{
+    return clamp( c.mutation_value( "mending_modifier" ), 0.25f, 1.0f );
+}
+
+} // namespace
+
+auto heal_adjusted( Character &c, const bodypart_id &bp, const int heal ) -> int
+{
+    const float broken_regen_mod = mending_modifier( c );
+    const int broken_heal = roll_remainder( heal * broken_regen_mod );
+    const bool is_broken = has_broken_limb_penalty( c, bp );
+    const int actual_heal = is_broken ? broken_heal : heal;
+
+    c.heal( bp, actual_heal );
+
+    return actual_heal;
+}
diff --git a/src/regen.h b/src/regen.h
new file mode 100644
index 00000000000..671a8a0e75d
--- /dev/null
+++ b/src/regen.h
@@ -0,0 +1,18 @@
+#pragma once
+#ifndef CATA_SRC_REGEN_H
+#define CATA_SRC_REGEN_H
+
+#include "type_id.h"
+
+class Character;
+
+/// like heal, but actually takes account of
+/// - whether limb suffers from being broken without splint
+/// - `mending_modifier`
+///
+/// @return actually healed amount. used for `mod_part_healed_total`
+///
+/// TODO: merge into `Character::heal`?
+auto heal_adjusted( Character &c, const bodypart_id &bp, const int heal ) -> int;
+
+#endif // CATA_SRC_REGEN_H
-- 
2.42.0