diff --git a/data/json/item_actions.json b/data/json/item_actions.json index fa31cb5f4e4e..659716fbc86d 100644 --- a/data/json/item_actions.json +++ b/data/json/item_actions.json @@ -164,16 +164,6 @@ "id": "enzlave", "name": { "str": "Create a zombie slave" } }, - { - "type": "item_action", - "id": "fireweapon_off", - "name": { "str": "Turn on" } - }, - { - "type": "item_action", - "id": "fireweapon_on", - "name": { "str": "Turn off" } - }, { "type": "item_action", "id": "transform", @@ -409,21 +399,11 @@ "id": "FILL_PIT", "name": { "str": "Fill pit / tamp ground" } }, - { - "type": "item_action", - "id": "FIRECRACKER", - "name": { "str": "Light up" } - }, { "type": "item_action", "id": "FIRECRACKER_ACT", "name": { "str": "Light up" } }, - { - "type": "item_action", - "id": "FIRECRACKER_PACK", - "name": { "str": "Light up" } - }, { "type": "item_action", "id": "FIRECRACKER_PACK_ACT", diff --git a/data/json/items/armor/power_armor.json b/data/json/items/armor/power_armor.json index a65fa8c64cd8..3c74a5460092 100644 --- a/data/json/items/armor/power_armor.json +++ b/data/json/items/armor/power_armor.json @@ -573,8 +573,7 @@ "warmth": 20, "material_thickness": 6, "environmental_protection": 3, - "max_charges": 500, - "ammo": "battery", + "max_power": "500 kJ", "relic_data": { "passive_effects": [ { "has": "WORN", "condition": "ACTIVE", "values": [ { "value": "STRENGTH", "add": 2 } ] } ] }, "use_action": { "type": "transform", @@ -620,8 +619,7 @@ "storage": "7 L", "warmth": 10, "material_thickness": 8, - "max_charges": 500, - "ammo": "battery", + "max_power": "500 kJ", "relic_data": { "passive_effects": [ { @@ -689,8 +687,7 @@ "storage": "15 L", "warmth": 10, "material_thickness": 8, - "max_charges": 500, - "ammo": "battery", + "max_power": "500 kJ", "relic_data": { "passive_effects": [ { diff --git a/data/json/items/battery.json b/data/json/items/battery.json index 4aa30f293ccb..0371df534558 100644 --- a/data/json/items/battery.json +++ b/data/json/items/battery.json @@ -1,24 +1,7 @@ [ - { - "id": "battery_test", - "type": "BATTERY", - "category": "battery", - "name": { "str": "test battery", "str_pl": "test batteries" }, - "description": "This is a testing item for the BATTERY item type. If you found one in game, it's a bug.", - "weight": "200 g", - "volume": "250 ml", - "price": "15 USD", - "price_postapoc": "0 cent", - "material": [ "iron", "plastic" ], - "symbol": "=", - "color": "yellow", - "max_capacity": "30 kJ", - "looks_like": "battery", - "flags": [ "NO_SALVAGE", "NO_UNLOAD", "RECHARGE" ] - }, { "id": "light_minus_battery_cell", - "type": "MAGAZINE", + "type": "BATTERY", "category": "battery", "name": { "str": "ultra-light battery", "str_pl": "ultra-light batteries" }, "description": "This is a light battery cell designed for small size over everything else. It retains its universal compatibility, though.", @@ -30,14 +13,13 @@ "material": [ "iron", "plastic" ], "symbol": "=", "color": "yellow", - "ammo_type": "battery", - "capacity": 50, + "max_power": "50 kJ", "looks_like": "battery", "flags": [ "NO_SALVAGE", "NO_UNLOAD", "RECHARGE" ] }, { "id": "light_minus_atomic_battery_cell", - "type": "MAGAZINE", + "type": "BATTERY", "category": "battery", "name": { "str": "ultra-light plutonium battery", "str_pl": "ultra-light plutonium batteries" }, "description": "This battery uses a thin plutonium-244 rod to stabilize an exotic nanocompound, manufactured from repurposed plutonium fission cells. It is universally compatible with small devices. Although it stores a huge amount of power, it cannot be recharged.", @@ -49,15 +31,13 @@ "material": [ "iron", "plastic" ], "symbol": "=", "color": "green", - "ammo_type": "battery", - "count": 500, - "capacity": 500, + "max_power": "500 kJ", "looks_like": "battery", "flags": [ "NO_SALVAGE", "NO_UNLOAD", "LEAK_DAM", "RADIOACTIVE" ] }, { "id": "light_minus_disposable_cell", - "type": "MAGAZINE", + "type": "BATTERY", "category": "battery", "name": { "str": "ultra-light disposable battery", "str_pl": "ultra-light disposable batteries" }, "description": "This is a light battery cell designed for small size over everything else. It retains its universal compatibility, though. The battery's chemistry means that it has a very high capacity, but cannot be recharged.", @@ -68,15 +48,13 @@ "material": [ "iron", "plastic" ], "symbol": "=", "color": "yellow", - "ammo_type": "battery", - "count": 150, - "capacity": 150, + "max_power": "150 kJ", "looks_like": "battery", "flags": [ "NO_SALVAGE", "NO_UNLOAD" ] }, { "id": "light_battery_cell", - "type": "MAGAZINE", + "type": "BATTERY", "category": "battery", "name": { "str": "light battery", "str_pl": "light batteries" }, "description": "This is a light battery cell, universally compatible with all kinds of small devices.", @@ -88,14 +66,13 @@ "material": [ "iron", "plastic" ], "symbol": "=", "color": "yellow", - "ammo_type": "battery", - "capacity": 100, + "max_power": "100 kJ", "looks_like": "battery", "flags": [ "NO_SALVAGE", "NO_UNLOAD", "RECHARGE", "MAG_COMPACT" ] }, { "id": "light_plus_battery_cell", - "type": "MAGAZINE", + "type": "BATTERY", "category": "battery", "name": { "str": "light battery (high-capacity)", "str_pl": "light batteries (high-capacity)" }, "description": "This is a high-capacity light battery cell, universally compatible with all kinds of small devices.", @@ -106,14 +83,13 @@ "material": [ "iron", "plastic" ], "symbol": "=", "color": "yellow", - "ammo_type": "battery", - "capacity": 150, + "max_power": "150 kJ", "looks_like": "battery", "flags": [ "NO_SALVAGE", "NO_UNLOAD", "RECHARGE", "MAG_COMPACT" ] }, { "id": "light_atomic_battery_cell", - "type": "MAGAZINE", + "type": "BATTERY", "category": "battery", "name": { "str": "light plutonium battery", "str_pl": "light plutonium batteries" }, "description": "This battery uses a thin plutonium-244 rod to stabilize an exotic nanocompound, manufactured from repurposed plutonium fission cells. It is universally compatible with all kinds of personal electronic devices. Although it stores a huge amount of power, it cannot be recharged.", @@ -125,15 +101,13 @@ "material": [ "iron", "plastic" ], "symbol": "=", "color": "green", - "ammo_type": "battery", - "count": 1000, - "capacity": 1000, + "max_power": "1000 kJ", "looks_like": "battery", "flags": [ "NO_SALVAGE", "NO_UNLOAD", "LEAK_DAM", "RADIOACTIVE", "MAG_COMPACT" ] }, { "id": "light_disposable_cell", - "type": "MAGAZINE", + "type": "BATTERY", "category": "battery", "name": { "str": "light disposable battery", "str_pl": "light disposable batteries" }, "description": "This is a light battery cell, universally compatible with all kinds of small devices. The battery's chemistry means that it has a very high capacity, but cannot be recharged.", @@ -144,15 +118,13 @@ "material": [ "iron", "plastic" ], "symbol": "=", "color": "yellow", - "ammo_type": "battery", - "count": 300, - "capacity": 300, + "max_power": "300 kJ", "looks_like": "battery", "flags": [ "NO_SALVAGE", "NO_UNLOAD", "MAG_COMPACT" ] }, { "id": "medium_battery_cell", - "type": "MAGAZINE", + "type": "BATTERY", "category": "battery", "name": { "str": "medium battery", "str_pl": "medium batteries" }, "description": "This is a medium battery cell, universally compatible with all kinds of appliances and power tools.", @@ -164,14 +136,13 @@ "material": [ "iron", "plastic" ], "symbol": "=", "color": "yellow", - "ammo_type": "battery", - "capacity": 500, + "max_power": "500 kJ", "looks_like": "battery", "flags": [ "NO_SALVAGE", "NO_UNLOAD", "RECHARGE", "MAG_COMPACT" ] }, { "id": "medium_plus_battery_cell", - "type": "MAGAZINE", + "type": "BATTERY", "category": "battery", "name": { "str": "medium battery (high-capacity)", "str_pl": "medium batteries (high-capacity)" }, "description": "This is a high-capacity medium battery cell, universally compatible with all kinds of appliances and power tools.", @@ -182,14 +153,13 @@ "material": [ "iron", "plastic" ], "symbol": "=", "color": "yellow", - "ammo_type": "battery", - "capacity": 750, + "max_power": "750 kJ", "looks_like": "battery", "flags": [ "NO_SALVAGE", "NO_UNLOAD", "RECHARGE", "MAG_COMPACT" ] }, { "id": "medium_atomic_battery_cell", - "type": "MAGAZINE", + "type": "BATTERY", "category": "battery", "name": { "str": "medium plutonium battery", "str_pl": "medium plutonium batteries" }, "description": "This battery uses a thin plutonium-244 rod to stabilize an exotic nanocompound, manufactured from repurposed plutonium fission cells. It is universally compatible with all kinds of appliances and power tools. Although it stores a huge amount of power, it cannot be recharged.", @@ -201,15 +171,13 @@ "material": [ "iron", "plastic" ], "symbol": "=", "color": "green", - "ammo_type": "battery", - "count": 5000, - "capacity": 5000, + "max_power": "5000 kJ", "looks_like": "battery", "flags": [ "NO_SALVAGE", "NO_UNLOAD", "LEAK_DAM", "RADIOACTIVE", "MAG_COMPACT" ] }, { "id": "medium_disposable_cell", - "type": "MAGAZINE", + "type": "BATTERY", "category": "battery", "name": { "str": "medium disposable battery", "str_pl": "medium disposable batteries" }, "description": "This is a medium battery cell, universally compatible with all kinds of appliances and power tools. The battery's chemistry means that it has a very high capacity, but cannot be recharged.", @@ -220,15 +188,13 @@ "material": [ "iron", "plastic" ], "symbol": "=", "color": "yellow", - "ammo_type": "battery", - "count": 1500, - "capacity": 1500, + "max_power": "1500 kJ", "looks_like": "battery", "flags": [ "NO_SALVAGE", "NO_UNLOAD", "MAG_COMPACT" ] }, { "id": "heavy_battery_cell", - "type": "MAGAZINE", + "type": "BATTERY", "category": "battery", "name": { "str": "heavy battery", "str_pl": "heavy batteries" }, "description": "This is a heavy battery cell, universally compatible with all kinds of industrial-grade equipment and large tools.", @@ -240,14 +206,13 @@ "material": [ "iron", "plastic" ], "symbol": "=", "color": "yellow", - "ammo_type": "battery", - "capacity": 1000, + "max_power": "1000 kJ", "looks_like": "battery", "flags": [ "NO_SALVAGE", "NO_UNLOAD", "RECHARGE", "MAG_BULKY" ] }, { "id": "heavy_plus_battery_cell", - "type": "MAGAZINE", + "type": "BATTERY", "category": "battery", "name": { "str": "heavy battery (high-capacity)", "str_pl": "heavy batteries (high-capacity)" }, "description": "This is a high-capacity heavy battery cell, universally compatible with all kinds of industrial-grade equipment and large tools.", @@ -258,14 +223,13 @@ "material": [ "iron", "plastic" ], "symbol": "=", "color": "yellow", - "ammo_type": "battery", - "capacity": 1500, + "max_power": "1500 kJ", "looks_like": "battery", "flags": [ "NO_SALVAGE", "NO_UNLOAD", "RECHARGE", "MAG_BULKY" ] }, { "id": "heavy_atomic_battery_cell", - "type": "MAGAZINE", + "type": "BATTERY", "category": "battery", "name": { "str": "heavy plutonium battery", "str_pl": "heavy plutonium batteries" }, "description": "This battery uses a thin plutonium-244 rod to stabilize an exotic nanocompound, manufactured from repurposed plutonium fission cells. It is universally compatible with all kinds of industrial-grade equipment and large tools. Although it stores a huge amount of power, it cannot be recharged.", @@ -277,15 +241,13 @@ "material": [ "iron", "plastic" ], "symbol": "=", "color": "green", - "ammo_type": "battery", - "count": 10000, - "capacity": 10000, + "max_power": "10000 kJ", "looks_like": "battery", "flags": [ "NO_SALVAGE", "NO_UNLOAD", "LEAK_DAM", "RADIOACTIVE", "MAG_BULKY" ] }, { "id": "huge_atomic_battery_cell", - "type": "MAGAZINE", + "type": "BATTERY", "category": "battery", "name": { "str": "military plutonium fuel cell" }, "description": "This battery uses a huge plutonium-244 rod to stabilize an exotic nanocompound, manufactured from repurposed plutonium fission cells. It was used in military mech-suits, was highly experimental, and had no civilian applications. Although it stores a stupendous amount of power, it cannot be recharged.", @@ -296,15 +258,13 @@ "material": [ "superalloy", "plastic" ], "symbol": "=", "color": "red", - "ammo_type": "battery", - "count": 100000, - "capacity": 100000, + "max_power": "100000 kJ", "looks_like": "battery", "flags": [ "NO_SALVAGE", "NO_UNLOAD", "MECH_BAT", "LEAK_DAM", "RADIOACTIVE" ] }, { "id": "heavy_disposable_cell", - "type": "MAGAZINE", + "type": "BATTERY", "category": "battery", "name": { "str": "heavy disposable battery", "str_pl": "heavy disposable batteries" }, "description": "This is a heavy battery cell, universally compatible with all kinds of industrial-grade equipment and large tools. The battery's chemistry means that it has a very high capacity, but cannot be recharged.", @@ -315,9 +275,7 @@ "material": [ "iron", "plastic" ], "symbol": "=", "color": "yellow", - "ammo_type": "battery", - "count": 3000, - "capacity": 3000, + "max_power": "3000 kJ", "looks_like": "battery", "flags": [ "NO_SALVAGE", "NO_UNLOAD", "MAG_BULKY" ] } diff --git a/data/json/items/biosignatures.json b/data/json/items/biosignatures.json index 8f21221705b4..293512388e67 100644 --- a/data/json/items/biosignatures.json +++ b/data/json/items/biosignatures.json @@ -67,7 +67,7 @@ "scent_typeid": "sc_fetid", "moves": 200, "duration": "1 h", - "charges_to_use": 1, + "cost": 1, "effects": [ { "id": "fetid_goop", "duration": 3600 } ] } } diff --git a/data/json/items/generic.json b/data/json/items/generic.json index bf4082af0171..eee0e602ee77 100644 --- a/data/json/items/generic.json +++ b/data/json/items/generic.json @@ -2597,46 +2597,6 @@ "volume": "5 ml", "to_hit": -3, "max_charges": 200000000, - "rand_charges": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 50, - 100, - 200, - 300, - 500, - 800, - 1000, - 1200, - 1400, - 1600, - 1800, - 2000, - 3000, - 4000, - 5000, - 6000, - 7000, - 8000, - 9000, - 10000, - 12000, - 14000, - 16000, - 18000, - 20000, - 50000, - 100000 - ], "ammo": "money" }, { diff --git a/data/json/items/generic/toys_and_sports.json b/data/json/items/generic/toys_and_sports.json index 1d2b387d04d0..8b2db09e4b18 100644 --- a/data/json/items/generic/toys_and_sports.json +++ b/data/json/items/generic/toys_and_sports.json @@ -12,22 +12,16 @@ "material": "plastic", "symbol": "|", "color": "pink", - "ammo": "battery", - "charges_per_use": 1, + "power_draw": "1 kJ", "use_action": "DOLLCHAT", - "magazines": [ - [ - "battery", - [ - "light_minus_disposable_cell", - "light_disposable_cell", - "light_minus_battery_cell", - "light_battery_cell", - "light_plus_battery_cell", - "light_atomic_battery_cell", - "light_minus_atomic_battery_cell" - ] - ] + "batteries": [ + "light_minus_disposable_cell", + "light_disposable_cell", + "light_minus_battery_cell", + "light_battery_cell", + "light_plus_battery_cell", + "light_atomic_battery_cell", + "light_minus_atomic_battery_cell" ], "magazine_well": "250 ml" }, @@ -44,22 +38,16 @@ "material": "plastic", "symbol": "|", "color": "pink", - "ammo": "battery", - "charges_per_use": 1, + "power_draw": "1 kJ", "use_action": "DOLLCHAT", - "magazines": [ - [ - "battery", - [ - "light_minus_disposable_cell", - "light_disposable_cell", - "light_minus_battery_cell", - "light_battery_cell", - "light_plus_battery_cell", - "light_atomic_battery_cell", - "light_minus_atomic_battery_cell" - ] - ] + "batteries": [ + "light_minus_disposable_cell", + "light_disposable_cell", + "light_minus_battery_cell", + "light_battery_cell", + "light_plus_battery_cell", + "light_atomic_battery_cell", + "light_minus_atomic_battery_cell" ], "magazine_well": "250 ml" } diff --git a/data/json/items/gun/12mm.json b/data/json/items/gun/12mm.json index c6f2d82baf24..ef73ba139ce2 100644 --- a/data/json/items/gun/12mm.json +++ b/data/json/items/gun/12mm.json @@ -13,7 +13,7 @@ "ammo": "12mm", "range": 60, "dispersion": 45, - "ups_charges": 5, + "power_draw": 5, "loudness": 50, "magazines": [ [ "12mm", [ "hk_g80mag" ] ] ] } diff --git a/data/json/items/gun/308.json b/data/json/items/gun/308.json index 87677a5128a2..26189ca00fb9 100644 --- a/data/json/items/gun/308.json +++ b/data/json/items/gun/308.json @@ -53,7 +53,7 @@ "material": "hardsteel", "color": "dark_gray", "ammo": "308", - "ups_charges": 1, + "power_draw": 1, "ranged_damage": { "damage_type": "bullet", "amount": -1 }, "durability": 9, "blackpowder_tolerance": 96, diff --git a/data/json/items/gun/metal_rail.json b/data/json/items/gun/metal_rail.json index f9093b92a2e5..b9944d50a40f 100644 --- a/data/json/items/gun/metal_rail.json +++ b/data/json/items/gun/metal_rail.json @@ -18,7 +18,7 @@ "dispersion": 200, "durability": 7, "clip_size": 20, - "ups_charges": 80, + "power_draw": 80, "reload": 200, "loudness": 200, "ammo_effects": [ "INCENDIARY" ], @@ -44,7 +44,7 @@ "dispersion": 100, "durability": 6, "clip_size": 12, - "ups_charges": 40, + "power_draw": 40, "loudness": 150, "ammo_effects": [ "INCENDIARY" ], "extend": { "flags": [ "RELOAD_ONE" ] } @@ -69,7 +69,7 @@ "dispersion": 50, "durability": 6, "clip_size": 20, - "ups_charges": 20, + "power_draw": 20, "loudness": 100, "modes": [ [ "DEFAULT", "semi", 1 ], [ "BURST", "burst", 2 ] ], "ammo_effects": [ "INCENDIARY" ] diff --git a/data/json/items/gun/nail.json b/data/json/items/gun/nail.json index 4b677dbc2b47..5dd8e73ebd98 100644 --- a/data/json/items/gun/nail.json +++ b/data/json/items/gun/nail.json @@ -44,7 +44,7 @@ "dispersion": 180, "loudness": 5, "durability": 5, - "ups_charges": 20, + "power_draw": 20, "valid_mod_locations": [ [ "accessories", 4 ], [ "grip", 1 ], diff --git a/data/json/items/gun/plasma.json b/data/json/items/gun/plasma.json index dbed0b9cf12b..52b56d56903f 100644 --- a/data/json/items/gun/plasma.json +++ b/data/json/items/gun/plasma.json @@ -10,7 +10,7 @@ "material": [ "steel", "plastic" ], "ammo_effects": [ "PLASMA", "FLAME", "EMP", "EXPLOSIVE_SMALL" ], "extend": { "flags": [ "PYROMANIAC_WEAPON" ] }, - "ups_charges": 100, + "power_draw": 100, "ammo": "plasma", "weight": "10500 g", "volume": "4 L", @@ -33,7 +33,7 @@ "material": "steel", "extend": { "flags": [ "PYROMANIAC_WEAPON" ] }, "delete": { "flags": [ "NO_UNLOAD" ] }, - "ups_charges": 5, + "power_draw": 5, "ammo_effects": [ "PLASMA", "EXPLOSIVE_SMALL", "FLAME" ], "ammo": "plasma", "weight": "4535 g", diff --git a/data/json/items/gun/shot.json b/data/json/items/gun/shot.json index 9e35aa6ad78e..868e809707b1 100644 --- a/data/json/items/gun/shot.json +++ b/data/json/items/gun/shot.json @@ -45,7 +45,7 @@ "price_postapoc": "1750 cent", "material": [ "steel" ], "ammo": "shot", - "ups_charges": 1, + "power_draw": 1, "dispersion": 855, "modes": [ [ "DEFAULT", "semi", 1 ], [ "AUTO", "auto", 6 ] ], "reload": 200, diff --git a/data/json/items/gun/ups.json b/data/json/items/gun/ups.json index ac5d49260b8b..1b3016d4fa16 100644 --- a/data/json/items/gun/ups.json +++ b/data/json/items/gun/ups.json @@ -17,7 +17,7 @@ "durability": 10, "modes": [ [ "DEFAULT", "semi", 1 ], [ "AUTO", "auto", 3 ] ], "loudness": 23, - "ups_charges": 60, + "power_draw": 60, "valid_mod_locations": [ [ "accessories", 4 ], [ "emitter", 1 ], @@ -47,7 +47,7 @@ "ranged_damage": { "damage_type": "heat", "amount": 40, "armor_penetration": 5 }, "dispersion": 100, "loudness": 12, - "ups_charges": 50, + "power_draw": 50, "modes": [ [ "DEFAULT", "semi", 1 ], [ "BURST", "burst", 5 ], [ "AUTO", "auto", 10 ] ], "ammo_effects": [ "LASER", "PLASMA_BUBBLE", "INCENDIARY" ], "extend": { "flags": [ "NO_UNWIELD", "NO_SALVAGE", "NO_REPAIR", "UNBREAKABLE_MELEE" ] } @@ -60,7 +60,7 @@ "description": "A rapid-fire weapon system stripped from a combat mech, modified for handheld use. While less efficient and too bulky to fire without proper support, its rotating-barrel laser system can still spray death downrange with ease.", "weight": "40 kg", "dispersion": 200, - "ups_charges": 80, + "power_draw": 80, "extend": { "flags": [ "MOUNTED_GUN" ] }, "delete": { "flags": [ "NO_UNWIELD", "NO_SALVAGE", "NO_REPAIR", "UNBREAKABLE_MELEE" ] } }, @@ -83,7 +83,7 @@ "ranged_damage": { "damage_type": "heat", "amount": 80, "armor_penetration": 10 }, "dispersion": 15, "loudness": 1, - "ups_charges": 100, + "power_draw": 100, "ammo_effects": [ "LASER", "PLASMA_BUBBLE", "INCENDIARY" ], "extend": { "flags": [ "NO_UNWIELD", "NO_REPAIR", "NO_SALVAGE", "UNBREAKABLE_MELEE" ] } }, @@ -95,7 +95,7 @@ "description": "A long-range weapon system stripped from a recon mech, modified for handheld use. While less efficient and too bulky to fire without proper support, it's still a quiet and relatively accurate marksman laser rifle.", "weight": "13 kg", "dispersion": 30, - "ups_charges": 160, + "power_draw": 160, "extend": { "flags": [ "MOUNTED_GUN" ] }, "delete": { "flags": [ "NO_UNWIELD", "NO_REPAIR", "NO_SALVAGE", "UNBREAKABLE_MELEE" ] } }, @@ -117,7 +117,7 @@ "dispersion": 90, "durability": 7, "loudness": 8, - "ups_charges": 25, + "power_draw": 25, "valid_mod_locations": [ [ "emitter", 1 ], [ "lens", 1 ], @@ -154,7 +154,7 @@ "dispersion": 10, "modes": [ [ "DEFAULT", "semi", 1 ], [ "AUTO", "auto", 4 ] ], "loudness": 12, - "ups_charges": 40, + "power_draw": 40, "ammo_effects": [ "LASER", "INCENDIARY" ] }, { @@ -173,7 +173,7 @@ "ranged_damage": { "damage_type": "heat", "amount": 10, "armor_penetration": 4 }, "dispersion": 180, "loudness": 7, - "ups_charges": 10, + "power_draw": 10, "ammo_effects": [ "LASER", "INCENDIARY" ] }, { @@ -194,7 +194,7 @@ "dispersion": 150, "durability": 6, "loudness": 14, - "ups_charges": 30, + "power_draw": 30, "ammo_effects": [ "LASER", "INCENDIARY" ] }, { diff --git a/data/json/items/items_holiday.json b/data/json/items/items_holiday.json index 3adb618859a1..3fae6d518195 100644 --- a/data/json/items/items_holiday.json +++ b/data/json/items/items_holiday.json @@ -13,14 +13,11 @@ "symbol": "0", "color": "yellow", "looks_like": "pumpkin", - "initial_charges": 100, - "max_charges": 100, - "ammo": [ "battery" ], + "max_power": "100 kJ", "use_action": { "target": "plastic_jack_o_lantern_lit", "msg": "You light the candle in the jack o'lantern.", "active": true, - "transform_charges": 1, "menu_text": "Light", "type": "transform" } @@ -39,8 +36,7 @@ "symbol": "0", "looks_like": "pumpkin", "color": "yellow", - "initial_charges": 100, - "max_charges": 100, + "max_power": "100 kJ", "charges_per_use": 1, "turns_per_charge": 1350, "use_action": { diff --git a/data/json/items/melee/bludgeons.json b/data/json/items/melee/bludgeons.json index 86411899bfdb..1ad9442d67c6 100644 --- a/data/json/items/melee/bludgeons.json +++ b/data/json/items/melee/bludgeons.json @@ -427,8 +427,7 @@ "material": [ "superalloy", "steel" ], "symbol": "/", "color": "light_gray", - "ammo": "battery", - "charges_per_use": 1, + "power_draw": "1 kJ", "techniques": [ "WBLOCK_1", "RAPID" ], "use_action": { "target": "l-stick_on", @@ -439,13 +438,8 @@ "type": "transform" }, "flags": [ "DURABLE_MELEE", "SHEATH_SPEAR" ], - "magazines": [ - [ - "battery", - [ "medium_plus_battery_cell", "medium_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_plus_battery_cell", "medium_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "l-stick_on", @@ -458,7 +452,7 @@ "power_draw": 10000, "use_action": { "target": "l-stick", "msg": "The l-stick(tm)'s light fades away.", "menu_text": "Turn off", "type": "transform" }, "flags": [ "LIGHT_300", "DURABLE_MELEE", "TRADER_AVOID", "SHEATH_SPEAR" ], - "magazine_well": "500 ml" + "battery_well": "500 ml" }, { "id": "lucern_hammer", @@ -752,7 +746,6 @@ "volume": "1750 ml", "price": "80 USD", "price_postapoc": "45 USD", - "ammo": "battery", "use_action": { "type": "transform", "msg": "You press a button and the staff crackles with electricity.", @@ -761,13 +754,8 @@ "need_charges_msg": "The %s's batteries are dead.", "target": "shock_staff_on" }, - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "shock_staff_on", @@ -779,8 +767,8 @@ "revert_msg": "The %s's batteries run dry.", "use_action": { "type": "transform", "msg": "You press a button and the staff turns off.", "target": "shock_staff" }, "extend": { "flags": [ "TRADER_AVOID", "SHOCKING" ] }, - "power_draw": 5000000, - "magazine_well": "500 ml" + "power_draw": "5 kJ", + "battery_well": "500 ml" }, { "id": "rock_sock", @@ -887,7 +875,6 @@ "price": "170 USD", "price_postapoc": "25 USD", "material": [ "plastic", "steel" ], - "ammo": "battery", "use_action": { "type": "transform", "msg": "You press a button and the tonfa crackles with electricity.", @@ -897,13 +884,8 @@ "target": "shocktonfa_on" }, "flags": [ "DURABLE_MELEE", "NONCONDUCTIVE", "BELT_CLIP" ], - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "shocktonfa_on", @@ -915,8 +897,8 @@ "revert_msg": "The %s's batteries run dry.", "use_action": { "type": "transform", "msg": "You press a button and the tonfa turns off.", "target": "shocktonfa_off" }, "extend": { "flags": [ "TRADER_AVOID", "SHOCKING" ] }, - "power_draw": 5000000, - "magazine_well": "500 ml" + "power_draw": "5 kJ", + "battery_well": "500 ml" }, { "id": "warhammer", diff --git a/data/json/items/melee/misc.json b/data/json/items/melee/misc.json index 10614d916705..462b833e69a3 100644 --- a/data/json/items/melee/misc.json +++ b/data/json/items/melee/misc.json @@ -106,16 +106,10 @@ "material": [ "plastic", "aluminum" ], "symbol": ";", "color": "dark_gray", - "ammo": "battery", - "charges_per_use": 100, + "power_draw": "100 kJ", "use_action": "TAZER", - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml", + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml", "flags": [ "BELT_CLIP" ] } ] diff --git a/data/json/items/melee/swords_and_blades.json b/data/json/items/melee/swords_and_blades.json index 8bd00880e74b..36961d6f3014 100644 --- a/data/json/items/melee/swords_and_blades.json +++ b/data/json/items/melee/swords_and_blades.json @@ -1140,13 +1140,8 @@ }, "extend": { "flags": [ "NONCONDUCTIVE" ] }, "relative": { "volume": "250 ml", "weight": "151 g" }, - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "shock_foil_on", @@ -1199,13 +1194,8 @@ }, "extend": { "flags": [ "NONCONDUCTIVE" ] }, "relative": { "volume": "250 ml", "weight": "151 g" }, - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "shock_epee_on", @@ -1257,13 +1247,8 @@ }, "extend": { "flags": [ "NONCONDUCTIVE" ] }, "relative": { "volume": "250 ml", "weight": "151 g" }, - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "shock_sabre_on", @@ -1386,13 +1371,8 @@ }, "extend": { "flags": [ "NONCONDUCTIVE" ] }, "relative": { "volume": "250 ml", "weight": "151 g" }, - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "shock_rapier_on", @@ -1574,10 +1554,8 @@ "need_dry": true }, "flags": [ "NONCONDUCTIVE", "POWERED", "ALWAYS_TWOHAND" ], - "magazines": [ - [ "battery", [ "heavy_battery_cell", "heavy_plus_battery_cell", "heavy_atomic_battery_cell", "heavy_disposable_cell" ] ] - ], - "magazine_well": "1000 ml" + "batteries": [ "heavy_battery_cell", "heavy_plus_battery_cell", "heavy_atomic_battery_cell", "heavy_disposable_cell" ], + "battery_well": "1000 ml" }, { "id": "ecs_lajatang_on", @@ -1595,7 +1573,7 @@ "use_action": { "type": "transform", "target": "ecs_lajatang_off", "msg": "You turn off the chainsaw lajatang." }, "qualities": [ [ "BUTCHER", -250 ] ], "flags": [ "MESSY", "DURABLE_MELEE", "TRADER_AVOID", "NONCONDUCTIVE", "ALWAYS_TWOHAND", "WATER_DISABLE" ], - "magazine_well": "1000 ml" + "battery_well": "1000 ml" }, { "id": "cutlass", @@ -1779,12 +1757,7 @@ }, "techniques": [ "WBLOCK_1", "SWEEP" ], "flags": [ "ALWAYS_TWOHAND", "POWERED" ], - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], "magazine_well": "500 ml" }, { @@ -1802,7 +1775,7 @@ "revert_msg": "Your combat chainsaw goes quiet", "use_action": { "type": "transform", "target": "e_combatsaw_off", "msg": "You turn off the combat chainsaw." }, "flags": [ "MESSY", "DURABLE_MELEE", "TRADER_AVOID", "ALWAYS_TWOHAND", "WATER_DISABLE" ], - "magazine_well": "500 ml" + "battery_well": "500 ml" }, { "id": "dagger_medieval", diff --git a/data/json/items/tool/cooking.json b/data/json/items/tool/cooking.json index ff0681c1a9a3..6a0dd75ed9ee 100644 --- a/data/json/items/tool/cooking.json +++ b/data/json/items/tool/cooking.json @@ -93,12 +93,7 @@ "need_dry": true }, "flags": [ "SHEATH_SWORD", "NONCONDUCTIVE" ], - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], "magazine_well": "500 ml" }, { @@ -251,12 +246,7 @@ "charges_per_use": 10, "qualities": [ [ "BOIL", 1 ] ], "use_action": "HOTPLATE", - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], "magazine_well": "500 ml" }, { @@ -276,13 +266,8 @@ "color": "blue", "ammo": "battery", "flags": [ "ALLOWS_REMOTE_USE" ], - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "eggs_ferment", @@ -475,13 +460,8 @@ "color": "white", "ammo": "battery", "flags": [ "ALLOWS_REMOTE_USE" ], - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "gasoline_cooker", @@ -541,13 +521,8 @@ "ammo": "battery", "charges_per_use": 5, "use_action": "HOTPLATE", - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "jar_eggs_pickled", @@ -638,12 +613,7 @@ "color": "white", "ammo": "battery", "flags": [ "ALLOWS_REMOTE_USE" ], - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ] + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] }, { "id": "mess_kit", @@ -665,13 +635,8 @@ "charges_per_use": 5, "qualities": [ [ "COOK", 2 ], [ "BOIL", 2 ], [ "CONTAIN", 1 ] ], "use_action": [ "HOTPLATE", "HEAT_FOOD" ], - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "mess_tin", @@ -711,13 +676,8 @@ "charges_per_use": 5, "qualities": [ [ "COOK", 2 ], [ "BOIL", 2 ], [ "CONTAIN", 1 ] ], "use_action": [ "HOTPLATE", "HEAT_FOOD" ], - "magazines": [ - [ - "battery", - [ "medium_plus_battery_cell", "medium_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_plus_battery_cell", "medium_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "mortar_pestle", @@ -751,16 +711,11 @@ "symbol": ";", "color": "red", "ammo": "battery", - "power_draw": 1500000, + "power_draw": "1J", "qualities": [ [ "CONTAIN", 1 ] ], "use_action": "MULTICOOKER", - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "multi_cooker_filled", @@ -1020,13 +975,8 @@ "color": "white", "ammo": "battery", "flags": [ "ALLOWS_REMOTE_USE" ], - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "waffleiron", @@ -1064,10 +1014,7 @@ "charges_per_use": 1, "use_action": "WATER_PURIFIER", "flags": [ "ALLOWS_REMOTE_USE" ], - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -1075,10 +1022,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] - ], - "magazine_well": "250 ml" + ], + "battery_well": "250 ml" }, { "type": "GENERIC", diff --git a/data/json/items/tool/electronics.json b/data/json/items/tool/electronics.json index 6f340e8fd747..4f852a0dc78e 100644 --- a/data/json/items/tool/electronics.json +++ b/data/json/items/tool/electronics.json @@ -35,10 +35,7 @@ "ammo": "battery", "charges_per_use": 5, "use_action": "CAMERA", - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_plus_battery_cell", "light_minus_battery_cell", "light_battery_cell", @@ -46,10 +43,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] - ], - "magazine_well": "250 ml" + ], + "battery_well": "250 ml" }, { "id": "camera_pro", @@ -97,10 +92,7 @@ "type": "transform" }, "flags": [ "WATCH", "ALARMCLOCK" ], - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_plus_battery_cell", "light_minus_battery_cell", "light_minus_disposable_cell", @@ -108,10 +100,8 @@ "light_disposable_cell", "light_atomic_battery_cell", "light_minus_atomic_battery_cell" - ] - ] ], - "magazine_well": "100 ml" + "battery_well": "100 ml" }, { "id": "cell_phone_flashlight", @@ -212,10 +202,7 @@ "symbol": ",", "color": "green", "ammo": "battery", - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -223,10 +210,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "geiger_off", @@ -245,10 +230,7 @@ "ammo": "battery", "charges_per_use": 1, "use_action": "GEIGER", - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -256,10 +238,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "geiger_on", @@ -288,10 +268,7 @@ "color": "light_gray", "ammo": "battery", "use_action": "HAND_CRANK", - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -299,8 +276,6 @@ "medium_plus_battery_cell", "heavy_battery_cell", "heavy_plus_battery_cell" - ] - ] ] }, { @@ -397,10 +372,7 @@ "charges_per_use": 1, "use_action": "NOISE_EMITTER_OFF", "flags": [ "RADIO_MODABLE" ], - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -408,8 +380,6 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ] }, { @@ -520,10 +490,8 @@ "symbol": ";", "color": "light_gray", "ammo": "battery", - "magazines": [ - [ "battery", [ "heavy_plus_battery_cell", "heavy_battery_cell", "heavy_atomic_battery_cell", "heavy_disposable_cell" ] ] - ], - "magazine_well": "2000 ml", + "batteries": [ "heavy_plus_battery_cell", "heavy_battery_cell", "heavy_atomic_battery_cell", "heavy_disposable_cell" ], + "battery_well": "2000 ml", "flags": [ "IS_UPS" ] }, { @@ -542,10 +510,7 @@ "ammo": "battery", "charges_per_use": 10, "use_action": "VIBE", - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -553,10 +518,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "bionic_scanner", @@ -576,14 +539,10 @@ "target": "bionic_scanner_on", "msg": "You start scanning for bionics.", "active": true, - "need_charges": 1, "need_charges_msg": "The scanner doesn't have enough power.", "type": "transform" }, - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_plus_battery_cell", "light_minus_battery_cell", "light_minus_disposable_cell", @@ -591,8 +550,6 @@ "light_disposable_cell", "light_atomic_battery_cell", "light_minus_atomic_battery_cell" - ] - ] ] }, { @@ -610,7 +567,7 @@ "color": "magenta", "use_action": "NOTE_BIONICS", "revert_to": "bionic_scanner", - "power_draw": 10000, + "power_draw": "100 J", "revert_msg": "The %s shuts down." } ] diff --git a/data/json/items/tool/explosives.json b/data/json/items/tool/explosives.json index a873bf35b0ee..8f96a9902418 100644 --- a/data/json/items/tool/explosives.json +++ b/data/json/items/tool/explosives.json @@ -378,7 +378,16 @@ "material": "paper", "symbol": ";", "color": "red", - "use_action": "FIRECRACKER", + "use_action": { + "target": "firecracker_act", + "msg": "You light the firecracker.", + "target_charges": 1, + "active": true, + "menu_text": "Light up", + "need_dry": true, + "need_fire": 1, + "type": "transform" + }, "flags": [ "GRENADE" ] }, { @@ -416,7 +425,16 @@ "initial_charges": 25, "max_charges": 25, "charges_per_use": 1, - "use_action": "FIRECRACKER_PACK", + "use_action": { + "target": "firecracker_pack_act", + "msg": "You light the pack of firecrackers.", + "target_charges": 25, + "active": true, + "menu_text": "Light up", + "need_dry": true, + "need_fire": 1, + "type": "transform" + }, "flags": [ "GRENADE" ] }, { diff --git a/data/json/items/tool/fire.json b/data/json/items/tool/fire.json index 3f67971ff016..747550ae2206 100644 --- a/data/json/items/tool/fire.json +++ b/data/json/items/tool/fire.json @@ -15,10 +15,7 @@ "ammo": "battery", "charges_per_use": 5, "use_action": { "type": "firestarter", "moves": 50 }, - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_minus_battery_cell", "light_plus_battery_cell", @@ -26,8 +23,6 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], "flags": [ "FIRESTARTER" ] }, @@ -102,7 +97,6 @@ "material": [ "plastic", "aluminum" ], "symbol": ",", "color": "blue", - "rand_charges": [ 1, 10, 12, 15, 16, 22, 44, 50, 67, 75, 82, 100 ], "max_charges": 100, "charges_per_use": 1, "use_action": { "type": "firestarter", "moves": 50 }, @@ -274,6 +268,6 @@ "charges_per_use": 1, "use_action": { "type": "firestarter", "moves": 50 }, "magazine_well": "50 ml", - "magazines": [ [ "battery", [ "light_minus_battery_cell", "light_minus_atomic_battery_cell", "light_minus_disposable_cell" ] ] ] + "batteries": [ "light_minus_battery_cell", "light_minus_atomic_battery_cell", "light_minus_disposable_cell" ] } ] diff --git a/data/json/items/tool/lighting.json b/data/json/items/tool/lighting.json index a6c0b64f1595..d71d7f561c30 100644 --- a/data/json/items/tool/lighting.json +++ b/data/json/items/tool/lighting.json @@ -153,40 +153,33 @@ "material": [ "plastic" ], "symbol": ";", "color": "green", - "ammo": "battery", "use_action": { "type": "transform", "target": "electric_lantern_on", "active": true, - "transform_charges": 1, "msg": "You turn the lamp on.", - "need_charges": 1, "need_charges_msg": "The lantern has no batteries." }, "flags": [ "RADIO_MODABLE", "ALLOWS_REMOTE_USE" ], - "magazines": [ - [ - "battery", - [ - "light_minus_battery_cell", - "light_minus_disposable_cell", - "light_minus_atomic_battery_cell", - "light_battery_cell", - "light_disposable_cell", - "light_plus_battery_cell", - "light_atomic_battery_cell" - ] - ] + "batteries": [ + "light_minus_battery_cell", + "light_minus_disposable_cell", + "light_minus_atomic_battery_cell", + "light_battery_cell", + "light_disposable_cell", + "light_plus_battery_cell", + "light_atomic_battery_cell" ], - "magazine_well": "500 ml" + "battery_well": "500 ml" }, { "id": "electric_lantern_on", "copy-from": "electric_lantern", "type": "TOOL", "name": { "str": "electric lantern (on)", "str_pl": "electric lanterns (on)" }, - "power_draw": 3500, + "power_draw": "3 J", "revert_to": "electric_lantern", + "revert_msg": "The lamp runs out of power.", "use_action": { "menu_text": "Turn off", "type": "transform", "target": "electric_lantern", "msg": "You turn the lamp off." }, "flags": [ "RADIO_MODABLE", "LIGHT_20", "TRADER_AVOID", "ALLOWS_REMOTE_USE" ] }, @@ -214,10 +207,7 @@ "need_charges": 1, "need_charges_msg": "The flashlight's batteries are dead." }, - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_disposable_cell", "light_minus_disposable_cell", "light_battery_cell", @@ -225,10 +215,8 @@ "light_minus_battery_cell", "light_atomic_battery_cell", "light_minus_atomic_battery_cell" - ] - ] ], - "magazine_well": "100 ml" + "battery_well": "100 ml" }, { "id": "flashlight_on", @@ -404,10 +392,7 @@ "need_charges": 1, "need_charges_msg": "The heavy duty flashlight's batteries are dead." }, - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_disposable_cell", "light_minus_disposable_cell", "light_plus_battery_cell", @@ -415,10 +400,8 @@ "light_minus_battery_cell", "light_atomic_battery_cell", "light_minus_atomic_battery_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "heavy_flashlight_on", @@ -477,10 +460,7 @@ "need_charges": 1, "type": "transform" }, - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -488,8 +468,6 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ] }, { @@ -591,8 +569,8 @@ "need_charges_msg": "The reading light winks out.", "type": "transform" }, - "magazines": [ [ "battery", [ "light_minus_disposable_cell", "light_minus_battery_cell", "light_minus_atomic_battery_cell" ] ] ], - "magazine_well": "100 ml" + "batteries": [ "light_minus_disposable_cell", "light_minus_battery_cell", "light_minus_atomic_battery_cell" ], + "battery_well": "100 ml" }, { "id": "reading_light_on", @@ -631,10 +609,7 @@ "type": "transform" }, "flags": [ "RADIO_ACTIVATION", "RADIOSIGNAL_2" ], - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -642,10 +617,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "smart_lamp_on", diff --git a/data/json/items/tool/metalworking.json b/data/json/items/tool/metalworking.json index c5e443df4d15..29034d199564 100644 --- a/data/json/items/tool/metalworking.json +++ b/data/json/items/tool/metalworking.json @@ -216,10 +216,8 @@ } ], "flags": [ "ALLOWS_REMOTE_USE" ], - "magazines": [ - [ "battery", [ "heavy_battery_cell", "heavy_plus_battery_cell", "heavy_atomic_battery_cell", "heavy_disposable_cell" ] ] - ], - "magazine_well": "1000 ml" + "batteries": [ "heavy_battery_cell", "heavy_plus_battery_cell", "heavy_atomic_battery_cell", "heavy_disposable_cell" ], + "battery_well": "1000 ml" }, { "id": "kiln_done", diff --git a/data/json/items/tool/misc.json b/data/json/items/tool/misc.json index 25deb4b2844c..f894d80ac9fc 100644 --- a/data/json/items/tool/misc.json +++ b/data/json/items/tool/misc.json @@ -104,12 +104,7 @@ "price_postapoc": "1 USD", "material": "plastic", "ammo": "battery", - "magazines": [ - [ - "battery", - [ "light_minus_battery_cell", "light_minus_disposable_cell", "light_battery_cell", "light_disposable_cell" ] - ] - ], + "batteries": [ "light_minus_battery_cell", "light_minus_disposable_cell", "light_battery_cell", "light_disposable_cell" ], "charges_per_use": 1, "max_charges": 100, "use_action": { @@ -138,12 +133,7 @@ "ammo": "battery", "power_draw": 9000, "revert_to": "dab_pen", - "magazines": [ - [ - "battery", - [ "light_minus_battery_cell", "light_minus_disposable_cell", "light_battery_cell", "light_disposable_cell" ] - ] - ], + "batteries": [ "light_minus_battery_cell", "light_minus_disposable_cell", "light_battery_cell", "light_disposable_cell" ], "charges_per_use": 1, "max_charges": 100, "use_action": { @@ -176,10 +166,7 @@ "need_charges": 1, "need_charges_msg": "Batteries not included." }, - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_disposable_cell", "light_minus_disposable_cell", "light_battery_cell", @@ -187,10 +174,8 @@ "light_minus_battery_cell", "light_atomic_battery_cell", "light_minus_atomic_battery_cell" - ] - ] ], - "magazine_well": "250 ml", + "battery_well": "250 ml", "relic_data": { "passive_effects": [ { @@ -458,10 +443,8 @@ "menu_text": "Turn on", "type": "transform" }, - "magazines": [ - [ "battery", [ "heavy_battery_cell", "heavy_plus_battery_cell", "heavy_atomic_battery_cell", "heavy_disposable_cell" ] ] - ], - "magazine_well": "1000 ml" + "batteries": [ "heavy_battery_cell", "heavy_plus_battery_cell", "heavy_atomic_battery_cell", "heavy_disposable_cell" ], + "battery_well": "1000 ml" }, { "id": "large_space_heater_on", @@ -669,13 +652,8 @@ "menu_text": "Turn on", "type": "transform" }, - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "small_space_heater_on", diff --git a/data/json/items/tool/radio_tools.json b/data/json/items/tool/radio_tools.json index 9468c6e16c27..5842b13b2291 100644 --- a/data/json/items/tool/radio_tools.json +++ b/data/json/items/tool/radio_tools.json @@ -38,10 +38,7 @@ "turns_per_charge": 5, "proportional": { "weight": 0.21, "volume": 0.25, "price": 0.2 }, "use_action": "RADIOCONTROL", - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_disposable_cell", "light_minus_disposable_cell", "light_battery_cell", @@ -49,10 +46,8 @@ "light_minus_battery_cell", "light_atomic_battery_cell", "light_minus_atomic_battery_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "radio_car", @@ -66,7 +61,7 @@ "charges_per_use": 1, "proportional": { "weight": 0.73, "volume": 0.75, "price": 0.8 }, "use_action": "RADIOCAR", - "magazines": [ [ "battery", [ "light_minus_disposable_cell", "light_minus_battery_cell", "light_minus_atomic_battery_cell" ] ] ] + "batteries": [ "light_minus_disposable_cell", "light_minus_battery_cell", "light_minus_atomic_battery_cell" ] }, { "id": "radio_car_on", @@ -113,10 +108,7 @@ "charges_per_use": 1, "flags": [ "WEATHER_FORECAST" ], "use_action": [ "RADIO_OFF", "WEATHER_TOOL" ], - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_disposable_cell", "light_minus_disposable_cell", "light_battery_cell", @@ -124,10 +116,8 @@ "light_minus_battery_cell", "light_atomic_battery_cell", "light_minus_atomic_battery_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "radio_on", @@ -158,10 +148,7 @@ "ammo": "battery", "charges_per_use": 1, "flags": [ "TWO_WAY_RADIO" ], - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_disposable_cell", "light_minus_disposable_cell", "light_battery_cell", @@ -169,10 +156,8 @@ "light_minus_battery_cell", "light_atomic_battery_cell", "light_minus_atomic_battery_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "remotevehcontrol", @@ -192,10 +177,7 @@ "charges_per_use": 1, "turns_per_charge": 10, "use_action": "REMOTEVEH", - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -203,9 +185,7 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" } ] diff --git a/data/json/items/tool/science.json b/data/json/items/tool/science.json index cd116f49789f..3414f8a775b1 100644 --- a/data/json/items/tool/science.json +++ b/data/json/items/tool/science.json @@ -56,13 +56,8 @@ "charges_per_use": 1, "qualities": [ [ "DISTILL", 1 ], [ "CHEM", 3 ], [ "BOIL", 1 ] ], "use_action": "HOTPLATE", - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "chemistry_set_basic", @@ -300,10 +295,7 @@ "charges_per_use": 5, "use_action": "WEATHER_TOOL", "flags": [ "THERMOMETER", "HYGROMETER", "BAROMETER", "WINDMETER" ], - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_disposable_cell", @@ -311,10 +303,8 @@ "light_minus_battery_cell", "light_minus_disposable_cell", "light_minus_atomic_battery_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "analytical_set_basic", @@ -333,13 +323,8 @@ "symbol": ";", "color": "light_gray", "qualities": [ [ "ANALYSIS", 1 ] ], - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "balance_small", @@ -373,13 +358,8 @@ "material": [ "plastic", "steel" ], "symbol": ";", "color": "light_gray", - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "ph_meter", @@ -397,10 +377,7 @@ "material": [ "plastic", "glass" ], "symbol": ";", "color": "light_gray", - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -408,10 +385,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "voltmeter", @@ -431,10 +406,7 @@ "color": "light_gray", "use_action": [ "REPORT_GRID_CHARGE", "REPORT_GRID_CONNECTIONS", "MODIFY_GRID_CONNECTIONS" ], "flags": [ "BELT_CLIP" ], - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -442,10 +414,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "melting_point", @@ -463,10 +433,7 @@ "material": [ "plastic", "glass" ], "symbol": ";", "color": "light_gray", - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -474,10 +441,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "vortex", @@ -666,10 +631,7 @@ "color": "white", "ammo": "battery", "qualities": [ [ "CONCENTRATE", 1 ], [ "SEPARATE", 1 ] ], - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -677,10 +639,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "3d_printer_basic", @@ -710,13 +670,8 @@ }, { "flame": false, "type": "cauterize" } ], - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "3d_printer_advanced", diff --git a/data/json/items/tool/smoking.json b/data/json/items/tool/smoking.json index 19dec8ed9aab..69b2adc256bc 100644 --- a/data/json/items/tool/smoking.json +++ b/data/json/items/tool/smoking.json @@ -17,10 +17,7 @@ "charges_per_use": 1, "power_draw": 7500, "use_action": "ECIG", - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -28,10 +25,8 @@ "light_disposable_cell", "light_minus_disposable_cell", "light_minus_atomic_battery_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "crackpipe", diff --git a/data/json/items/tool/toiletries.json b/data/json/items/tool/toiletries.json index 56bce9be4705..82ffe0426b3c 100644 --- a/data/json/items/tool/toiletries.json +++ b/data/json/items/tool/toiletries.json @@ -52,7 +52,7 @@ "ammo": "battery", "charges_per_use": 10, "use_action": "HAIRKIT", - "magazines": [ [ "battery", [ "light_minus_battery_cell", "light_minus_atomic_battery_cell", "light_minus_disposable_cell" ] ] ], + "batteries": [ "light_minus_battery_cell", "light_minus_atomic_battery_cell", "light_minus_disposable_cell" ], "magazine_well": "250 ml" }, { diff --git a/data/json/items/tool/woodworking.json b/data/json/items/tool/woodworking.json index 7a89d6522983..5a57fecc5da7 100644 --- a/data/json/items/tool/woodworking.json +++ b/data/json/items/tool/woodworking.json @@ -101,13 +101,8 @@ "charges_per_use": 5, "use_action": { "target": "circsaw_on", "msg": "You turn on the circular saw.", "active": true, "type": "transform" }, "flags": [ "NONCONDUCTIVE" ], - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "circsaw_on", @@ -197,13 +192,8 @@ "need_dry": true }, "flags": [ "NONCONDUCTIVE", "POWERED" ], - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "elec_chainsaw_on", diff --git a/data/json/items/tool/workshop.json b/data/json/items/tool/workshop.json index 28572aced703..4b4f3db06bcd 100644 --- a/data/json/items/tool/workshop.json +++ b/data/json/items/tool/workshop.json @@ -122,13 +122,8 @@ "charges_per_use": 1, "power_draw": 800000, "flags": [ "NONCONDUCTIVE" ], - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "brick_kiln", @@ -240,13 +235,8 @@ "charges_per_use": 20, "qualities": [ [ "CONTAIN", 1 ] ], "use_action": "HOTPLATE", - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "cordless_drill", @@ -266,13 +256,8 @@ "color": "yellow", "ammo": "battery", "qualities": [ [ "DRILL", 3 ], [ "SCREW", 1 ] ], - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "distaff_spindle", @@ -541,10 +526,8 @@ "color": "dark_gray", "ammo": "battery", "flags": [ "ALLOWS_REMOTE_USE" ], - "magazines": [ - [ "battery", [ "heavy_battery_cell", "heavy_plus_battery_cell", "heavy_atomic_battery_cell", "heavy_disposable_cell" ] ] - ], - "magazine_well": "1000 ml" + "batteries": [ "heavy_battery_cell", "heavy_plus_battery_cell", "heavy_atomic_battery_cell", "heavy_disposable_cell" ], + "battery_well": "1000 ml" }, { "id": "large_repairkit", @@ -576,13 +559,8 @@ [ "CHISEL", 3 ] ], "use_action": [ "GUN_CLEAN", "GUN_REPAIR", "CROWBAR", "HAMMER" ], - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml", + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml", "flags": [ "ALLOWS_REMOTE_USE" ] }, { @@ -849,10 +827,7 @@ "color": "light_gray", "ammo": "battery", "flags": [ "TRADER_AVOID" ], - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -860,10 +835,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "primitive_hammer", @@ -955,13 +928,8 @@ [ "CHISEL", 3 ] ], "use_action": [ "GUN_CLEAN", "GUN_REPAIR", "CROWBAR", "HAMMER" ], - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml", + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml", "flags": [ "ALLOWS_REMOTE_USE" ] }, { @@ -994,10 +962,7 @@ { "flame": false, "type": "cauterize" } ], "flags": [ "STAB", "BELT_CLIP", "ALLOWS_REMOTE_USE" ], - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_minus_battery_cell", "light_battery_cell", "light_plus_battery_cell", @@ -1005,10 +970,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "soldering_ethanol", @@ -1298,13 +1261,8 @@ } ], "flags": [ "ALLOWS_REMOTE_USE" ], - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "wood_smoother", diff --git a/data/json/items/tool_armor.json b/data/json/items/tool_armor.json index 2316b0563f9d..c4714623d03a 100644 --- a/data/json/items/tool_armor.json +++ b/data/json/items/tool_armor.json @@ -167,10 +167,7 @@ "encumbrance": 15, "coverage": 80, "material_thickness": 4, - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -178,10 +175,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "miner_hat_on", @@ -415,10 +410,7 @@ "warmth": 10, "coverage": 100, "material_thickness": 1, - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -426,10 +418,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "thermal_socks_on", @@ -473,10 +463,7 @@ "warmth": 10, "coverage": 100, "material_thickness": 1, - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_plus_battery_cell", "light_battery_cell", "light_minus_battery_cell", @@ -484,10 +471,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "thermal_suit_on", @@ -531,10 +516,7 @@ "warmth": 10, "coverage": 100, "material_thickness": 1, - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -542,10 +524,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "thermal_gloves_on", @@ -589,10 +569,7 @@ "warmth": 10, "coverage": 100, "material_thickness": 1, - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -600,10 +577,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "thermal_mask_on", @@ -698,10 +673,7 @@ "covers": [ "head" ], "coverage": 15, "material_thickness": 1, - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_battery_cell", "light_plus_battery_cell", "light_minus_battery_cell", @@ -709,10 +681,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "wearable_light_on", @@ -757,10 +727,7 @@ "covers": [ "head" ], "coverage": 20, "material_thickness": 1, - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_plus_battery_cell", "light_battery_cell", "light_minus_battery_cell", @@ -768,10 +735,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "survivor_light_on", @@ -1419,10 +1384,7 @@ "encumbrance": 40, "coverage": 100, "material_thickness": 2, - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_plus_battery_cell", "light_battery_cell", "light_minus_battery_cell", @@ -1430,10 +1392,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "goggles_nv_on", @@ -1482,10 +1442,7 @@ "encumbrance": 40, "coverage": 100, "material_thickness": 2, - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_plus_battery_cell", "light_battery_cell", "light_minus_battery_cell", @@ -1493,10 +1450,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "goggles_ir_on", @@ -1700,7 +1655,7 @@ "coverage": 5, "material_thickness": 1, "flags": [ "BELTED", "COMPACT", "FRAGILE", "ALLOWS_NATURAL_ATTACKS", "WATER_FRIENDLY", "OVERSIZE" ], - "magazines": [ [ "battery", [ "light_minus_battery_cell", "light_minus_atomic_battery_cell" ] ] ] + "batteries": [ "light_minus_battery_cell", "light_minus_atomic_battery_cell" ] }, { "id": "hairpin", @@ -2232,13 +2187,8 @@ "warmth": 10, "coverage": 100, "material_thickness": 1, - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "thermal_outfit_on", @@ -2594,10 +2544,7 @@ "encumbrance": 5, "coverage": 10, "material_thickness": 2, - "magazines": [ - [ - "battery", - [ + "batteries": [ "light_plus_battery_cell", "light_battery_cell", "light_minus_battery_cell", @@ -2605,10 +2552,8 @@ "light_minus_atomic_battery_cell", "light_minus_disposable_cell", "light_disposable_cell" - ] - ] ], - "magazine_well": "250 ml" + "battery_well": "250 ml" }, { "id": "powered_earmuffs_on", @@ -2907,13 +2852,8 @@ "need_charges_msg": "The blanket's batteries are dead." }, "flags": [ "OVERSIZE", "OUTER", "ALLOWS_NATURAL_ATTACKS" ], - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml" + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml" }, { "id": "electric_blanket_on", @@ -2960,13 +2900,8 @@ "need_charges": 1, "need_charges_msg": "The mask's batteries are dead." }, - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ], - "magazine_well": "500 ml", + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ], + "battery_well": "500 ml", "valid_mods": [ "resized_large" ], "flags": [ "OUTER", "SUN_GLASSES" ] }, diff --git a/data/json/not_really_obsolete.json b/data/json/not_really_obsolete.json index 4f04a398c1cf..0e132a4a7487 100644 --- a/data/json/not_really_obsolete.json +++ b/data/json/not_really_obsolete.json @@ -140,7 +140,7 @@ "dispersion": 90, "durability": 6, "loudness": 15, - "ups_charges": 40, + "power_draw": 40, "reload": 600, "valid_mod_locations": [ [ "emitter", 1 ], @@ -164,7 +164,7 @@ "material": [ "steel", "plastic" ], "ammo_effects": [ "PLASMA", "EXPLOSIVE", "FLAME" ], "delete": { "flags": [ "NO_UNLOAD" ] }, - "ups_charges": 5, + "power_draw": 5, "ammo": "fusion", "weight": "2267 g", "volume": "3500 ml", diff --git a/data/json/obsoletion/items.json b/data/json/obsoletion/items.json index dc8bf0dcd91b..8fdfaeb8e149 100644 --- a/data/json/obsoletion/items.json +++ b/data/json/obsoletion/items.json @@ -43,7 +43,6 @@ "name": { "str": "active makeshift grenade" }, "description": "This is an active grenade, and will explode any second now. Better throw it!", "price": "0 cent", - "rand_charges": [ 2, 7 ], "max_charges": 7, "turns_per_charge": 1, "use_action": { @@ -420,7 +419,7 @@ "dispersion": 180, "durability": 4, "loudness": 7, - "ups_charges": 20, + "power_draw": "20 kJ", "reload": 300, "valid_mod_locations": [ [ "accessories", 2 ], @@ -1196,17 +1195,16 @@ "symbol": "/", "color": "light_gray", "ammo": "gasoline", - "charges_per_use": 1, "max_charges": 50, "use_action": { - "type": "fireweapon_off", - "target_id": "shishkebab_on", + "type": "transform", + "target": "shishkebab_on", "moves": 10, - "noise": 10, - "success_chance": 5, - "success_message": "Let's dance, Zeds!", - "failure_message": "Aw, dangit. It fails to start!", - "lacks_fuel_message": "This thing needs some fuel!" + "active": true, + "need_dry": true, + "transform_charges": 1, + "msg": "Let's dance, Zeds!", + "need_charges_msg": "This thing needs some fuel!" }, "qualities": [ [ "CUT", 1 ], [ "BUTCHER", -30 ] ], "techniques": [ "WBLOCK_1" ], @@ -1220,21 +1218,12 @@ "description": "This is a large blade with a fuel pipe on the side, and a small tank and igniter built into the insulated hilt. The blade is glowing brightly. Use to shut off the gas.", "turns_per_charge": 20, "revert_to": "shishkebab_off", + "revert_msg": "Bummer, man! Your shishkebab's flame flickers and dies out.", "use_action": [ - { - "type": "fireweapon_on", - "noise": 10, - "noise_chance": 25, - "noise_message": "Your shishkebab crackles!", - "auto_extinguish_chance": 75, - "auto_extinguish_message": "Bummer, man! Your shishkebab's flame flickers and dies out.", - "voluntary_extinguish_message": "Peace out. Your shishkebab's flame dies.", - "charges_extinguish_message": "Uncool, outta gas! Your shishkebab's flame goes out.", - "water_extinguish_message": "Your shishkebab hisses in the water and goes out." - }, + { "type": "transform", "target": "shishkebab_off", "msg": "Peace out. Your shishkebab's flame dies." }, { "type": "firestarter", "moves": 30 } ], - "flags": [ "FIRE", "LIGHT_240", "CHARGEDIM", "FLAMING", "TRADER_AVOID" ] + "flags": [ "FIRE", "LIGHT_240", "CHARGEDIM", "FLAMING", "TRADER_AVOID", "WATER_DISABLE" ] }, { "id": "firemachete_off", @@ -1252,18 +1241,17 @@ "symbol": "/", "color": "dark_gray", "ammo": "gasoline", - "charges_per_use": 1, "max_charges": 50, "techniques": [ "WBLOCK_2" ], "use_action": { - "type": "fireweapon_off", - "target_id": "firemachete_on", + "type": "transform", + "target": "firemachete_on", "moves": 10, - "noise": 0, - "success_chance": 2, - "success_message": "Your No. 9 glows!", - "failure_message": "Click.", - "lacks_fuel_message": "Click." + "active": true, + "need_dry": true, + "transform_charges": 1, + "msg": "Your No. 9 glows!", + "need_charges_msg": "Click." }, "qualities": [ [ "CUT", 1 ], [ "BUTCHER", 12 ] ], "flags": [ "FIRE", "DURABLE_MELEE", "SHEATH_SWORD" ] @@ -1287,19 +1275,10 @@ "max_charges": 50, "turns_per_charge": 30, "revert_to": "firemachete_off", + "revert_msg": "Your No. 9 cuts out!", "techniques": [ "WBLOCK_2" ], "use_action": [ - { - "type": "fireweapon_on", - "noise": 5, - "noise_chance": 25, - "noise_message": "Your No. 9 hisses.", - "auto_extinguish_chance": 100, - "auto_extinguish_message": "Your No. 9 cuts out!", - "voluntary_extinguish_message": "Your No. 9 goes dark.", - "charges_extinguish_message": "Out of ammo!", - "water_extinguish_message": "Your No. 9 hisses in the water and goes out." - }, + { "type": "transform", "target": "firemachete_off", "msg": "Your No. 9 goes dark." }, { "type": "firestarter", "moves": 30 } ], "flags": [ "FIRE", "LIGHT_240", "CHARGEDIM", "FLAMING", "DURABLE_MELEE", "TRADER_AVOID", "WATER_EXTINGUISH" ] @@ -1319,16 +1298,17 @@ "symbol": "/", "color": "light_gray", "ammo": "gasoline", - "charges_per_use": 1, "max_charges": 50, "techniques": [ "RAPID", "WBLOCK_2" ], "use_action": { - "type": "fireweapon_off", - "target_id": "firekatana_on", + "type": "transform", + "target": "firekatana_on", "moves": 10, - "noise": 10, - "success_message": "The Sun rises.", - "lacks_fuel_message": "Time stands still." + "active": true, + "need_dry": true, + "transform_charges": 1, + "msg": "The Sun rises.", + "need_charges_msg": "Time stands still." }, "qualities": [ [ "CUT", 1 ], [ "BUTCHER", 6 ] ], "flags": [ "FIRE", "DURABLE_MELEE", "SHEATH_SWORD" ] @@ -1351,18 +1331,9 @@ "max_charges": 50, "turns_per_charge": 30, "revert_to": "firekatana_off", + "revert_msg": "The Light Fades.", "techniques": [ "RAPID", "WBLOCK_2" ], - "use_action": [ - { - "type": "fireweapon_on", - "noise_chance": 35, - "noise_message": "The Sun shines brightly.", - "voluntary_extinguish_message": "The Sun sets.", - "charges_extinguish_message": "The Light Fades.", - "water_extinguish_message": "Your sword hisses in the water and goes out." - }, - { "type": "firestarter", "moves": 30 } - ], + "use_action": [ { "type": "transform", "target": "firekatana_off", "msg": "The Sun sets." }, { "type": "firestarter", "moves": 30 } ], "flags": [ "FIRE", "LIGHT_240", "CHARGEDIM", "FLAMING", "DURABLE_MELEE", "TRADER_AVOID", "WATER_EXTINGUISH" ] }, { @@ -1381,16 +1352,17 @@ "symbol": "/", "color": "light_gray", "ammo": "gasoline", - "charges_per_use": 1, "max_charges": 50, "techniques": [ "WBLOCK_2" ], "use_action": { - "type": "fireweapon_off", - "target_id": "broadfire_on", + "type": "transform", + "target": "broadfire_on", "moves": 10, - "noise": 10, - "success_message": "Charge!", - "lacks_fuel_message": "No strength to fight!" + "active": true, + "need_dry": true, + "transform_charges": 1, + "msg": "Charge!", + "need_charges_msg": "No strength to fight!" }, "qualities": [ [ "CUT", 1 ], [ "BUTCHER", 6 ] ], "flags": [ "DURABLE_MELEE", "SHEATH_SWORD" ] @@ -1403,18 +1375,9 @@ "description": "This is a combination of two Dark Age conflict-resolution classics, the broadsword and the torch. The blade is glowing with heat. Excalibur can eat its heart out. Use to shut it off.", "turns_per_charge": 30, "revert_to": "broadfire_off", - "use_action": [ - { - "type": "fireweapon_on", - "noise_chance": 35, - "noise_message": "Your blade burns for combat!", - "voluntary_extinguish_message": "Run away!", - "charges_extinguish_message": "Thy strength fades!", - "water_extinguish_message": "Your sword hisses in the water and goes out." - }, - { "type": "firestarter", "moves": 30 } - ], - "flags": [ "FIRE", "LIGHT_240", "CHARGEDIM", "FLAMING", "DURABLE_MELEE", "TRADER_AVOID" ] + "revert_msg": "Thy strength fades!", + "use_action": [ { "type": "transform", "target": "broadfire_off", "msg": "Run away!" }, { "type": "firestarter", "moves": 30 } ], + "flags": [ "FIRE", "LIGHT_240", "CHARGEDIM", "FLAMING", "DURABLE_MELEE", "TRADER_AVOID", "WATER_DISABLE" ] }, { "id": "zweifire_off", @@ -1432,16 +1395,17 @@ "symbol": "/", "color": "light_gray", "ammo": "gasoline", - "charges_per_use": 1, "max_charges": 50, "techniques": [ "WBLOCK_1", "WIDE", "BRUTAL", "SWEEP" ], "use_action": { - "type": "fireweapon_off", - "target_id": "zweifire_on", + "type": "transform", + "target": "zweifire_on", "moves": 10, - "noise": 10, - "success_message": "Die Klinge deines Schwertes brennt!", - "lacks_fuel_message": "Dein Flammenschwert hat keinen Brennstoff mehr." + "active": true, + "need_dry": true, + "transform_charges": 1, + "msg": "Die Klinge deines Schwertes brennt!", + "need_charges_msg": "Dein Flammenschwert hat keinen Brennstoff mehr." }, "qualities": [ [ "CUT", 1 ], [ "BUTCHER", 1 ] ], "flags": [ "DURABLE_MELEE", "SHEATH_SWORD", "ALWAYS_TWOHAND" ] @@ -1465,16 +1429,10 @@ "max_charges": 50, "turns_per_charge": 30, "revert_to": "zweifire_off", + "revert_msg": "Dein Schwert zischt und erlischt.", "techniques": [ "WBLOCK_1", "WIDE", "BRUTAL", "SWEEP" ], "use_action": [ - { - "type": "fireweapon_on", - "noise_chance": 35, - "noise_message": "Das Feuer um deine Schwertklinge leuchtet hell!", - "voluntary_extinguish_message": "Die Flamme deines Schwertes erlischt.", - "charges_extinguish_message": "Deinem Flammenschwert ist der Brennstoff ausgegangen!", - "water_extinguish_message": "Dein Schwert zischt und erlischt." - }, + { "type": "transform", "target": "zweifire_off", "msg": "Die Flamme deines Schwertes erlischt." }, { "type": "firestarter", "moves": 30 } ], "flags": [ "FIRE", "LIGHT_240", "CHARGEDIM", "FLAMING", "DURABLE_MELEE", "TRADER_AVOID", "WATER_EXTINGUISH", "ALWAYS_TWOHAND" ] @@ -4158,7 +4116,7 @@ "weight": "40860 g", "ammo": "battery", "charges_per_use": 1, - "magazines": [ [ "battery", [ "large_storage_battery", "storage_battery" ] ] ], + "batteries": [ "large_storage_battery", "storage_battery" ], "volume": "27 L", "price": "1 kUSD", "to_hit": -10, @@ -4183,7 +4141,7 @@ "material": "steel", "ammo": "battery", "charges_per_use": 1, - "magazines": [ [ "battery", [ "large_storage_battery", "storage_battery" ] ] ], + "batteries": [ "large_storage_battery", "storage_battery" ], "symbol": "E", "color": "dark_gray", "use_action": { @@ -4212,7 +4170,7 @@ "power_draw": 120000, "revert_to": "vac_oven_small_full", "charges_per_use": 1, - "magazines": [ [ "battery", [ "large_storage_battery", "storage_battery" ] ] ], + "batteries": [ "large_storage_battery", "storage_battery" ], "material": "steel", "symbol": "E", "color": "dark_gray", @@ -4241,7 +4199,7 @@ "bashing": 10, "ammo": "battery", "charges_per_use": 1, - "magazines": [ [ "battery", [ "large_storage_battery", "storage_battery" ] ] ], + "batteries": [ "large_storage_battery", "storage_battery" ], "material": "steel", "symbol": "E", "color": "dark_gray", @@ -4274,10 +4232,7 @@ "need_charges_msg": "The vacuum pump's batteries need more charge.", "type": "transform" }, - "magazines": [ - [ - "battery", - [ + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_disposable_cell", @@ -4290,8 +4245,6 @@ "medium_storage_battery", "large_storage_battery", "storage_battery" - ] - ] ] }, { @@ -4323,10 +4276,7 @@ "need_charges_msg": "The vacuum pump's batteries need more charge.", "type": "transform" }, - "magazines": [ - [ - "battery", - [ + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_disposable_cell", @@ -4339,8 +4289,6 @@ "medium_storage_battery", "large_storage_battery", "storage_battery" - ] - ] ] }, { @@ -4371,10 +4319,7 @@ "need_charges_msg": "The small closed loop extractor's batteries need more charge.", "type": "transform" }, - "magazines": [ - [ - "battery", - [ + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_disposable_cell", @@ -4387,8 +4332,6 @@ "medium_storage_battery", "large_storage_battery", "storage_battery" - ] - ] ], "qualities": [ [ "EXTRACT", 2 ] ] }, @@ -4420,10 +4363,7 @@ "need_charges_msg": "The small closed loop extractor's batteries need more charge.", "type": "transform" }, - "magazines": [ - [ - "battery", - [ + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_disposable_cell", @@ -4436,8 +4376,6 @@ "medium_storage_battery", "large_storage_battery", "storage_battery" - ] - ] ], "qualities": [ [ "EXTRACT", 2 ] ] }, @@ -4459,10 +4397,7 @@ "flags": [ "ALLOWS_REMOTE_USE", "TRADER_AVOID" ], "ammo": "battery", "charges_per_use": 1, - "magazines": [ - [ - "battery", - [ + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_disposable_cell", @@ -4475,8 +4410,6 @@ "medium_storage_battery", "large_storage_battery", "storage_battery" - ] - ] ], "use_action": { "target": "closed_loop_extractor_large_on", @@ -4509,10 +4442,7 @@ "power_draw": 1500000, "revert_to": "closed_loop_extractor_large", "charges_per_use": 1, - "magazines": [ - [ - "battery", - [ + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_disposable_cell", @@ -4525,8 +4455,6 @@ "medium_storage_battery", "large_storage_battery", "storage_battery" - ] - ] ], "use_action": { "target": "closed_loop_extractor_large", @@ -4681,12 +4609,7 @@ } ], "flags": [ "ALLOWS_REMOTE_USE" ], - "magazines": [ - [ - "battery", - [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] - ] - ] + "batteries": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] }, { "id": "lobster", diff --git a/data/mods/Aftershock/items/gun/laser.json b/data/mods/Aftershock/items/gun/laser.json index 35f03f095094..7198de07e717 100644 --- a/data/mods/Aftershock/items/gun/laser.json +++ b/data/mods/Aftershock/items/gun/laser.json @@ -13,7 +13,7 @@ "range": 10, "ranged_damage": { "damage_type": "stab", "amount": 5, "armor_penetration": 15 }, "dispersion": 500, - "ups_charges": 25, + "power_draw": 25, "ammo_effects": [ "LASER", "BEANBAG" ], "flags": [ "NEVER_JAMS", "NO_UNLOAD", "NON_FOULING", "NEEDS_NO_LUBE" ] }, @@ -26,7 +26,7 @@ "color": "red", "range": 10, "ranged_damage": { "damage_type": "heat", "amount": 25, "armor_penetration": 4 }, - "ups_charges": 30, + "power_draw": 30, "modes": [ [ "MULTI", "trilaser", 3 ] ], "ammo_effects": [ "LASER" ], "flags": [ "NEVER_JAMS", "NO_UNLOAD", "NON_FOULING", "NEEDS_NO_LUBE" ] @@ -36,7 +36,7 @@ "type": "GUN", "copy-from": "afs_sentinel_laser", "name": { "str": "wrist-trilaser" }, - "ups_charges": 0, + "power_draw": 0, "flags": [ "NEVER_JAMS", "NO_UNLOAD", "NON_FOULING", "NEEDS_NO_LUBE" ] } ] diff --git a/data/mods/Aftershock/items/obsolete.json b/data/mods/Aftershock/items/obsolete.json index 1f74b84c090e..ec552c773832 100644 --- a/data/mods/Aftershock/items/obsolete.json +++ b/data/mods/Aftershock/items/obsolete.json @@ -297,7 +297,7 @@ "skill": "rifle", "dispersion": 90, "durability": 6, - "ups_charges": 40, + "power_draw": 40, "clip_size": 1, "reload": 1200, "valid_mod_locations": [ diff --git a/data/mods/Aftershock/items/weapons.json b/data/mods/Aftershock/items/weapons.json index 8ba97a588885..e6d6c0f0a6cd 100644 --- a/data/mods/Aftershock/items/weapons.json +++ b/data/mods/Aftershock/items/weapons.json @@ -94,7 +94,7 @@ "dispersion": 80, "durability": 6, "reload": 50, - "ups_charges": 20, + "power_draw": 20, "valid_mod_locations": [ [ "underbarrel", 1 ], [ "sights", 1 ], [ "accessories", 2 ], [ "stabilizer", 1 ] ] }, { @@ -244,7 +244,7 @@ "dispersion": 90, "durability": 7, "loudness": 8, - "ups_charges": 25, + "power_draw": 25, "reload": 200, "valid_mod_locations": [ [ "emitter", 1 ], diff --git a/data/mods/CRT_EXPANSION/items/crt_gun.json b/data/mods/CRT_EXPANSION/items/crt_gun.json index 131813643662..3bfa828927a4 100644 --- a/data/mods/CRT_EXPANSION/items/crt_gun.json +++ b/data/mods/CRT_EXPANSION/items/crt_gun.json @@ -19,7 +19,7 @@ "dispersion": 150, "durability": 9, "loudness": 14, - "ups_charges": 8, + "power_draw": 8, "reload": 220, "modes": [ [ "DEFAULT", "double", 2 ] ], "valid_mod_locations": [ @@ -55,7 +55,7 @@ "dispersion": 45, "durability": 9, "loudness": 28, - "ups_charges": 10, + "power_draw": 10, "reload": 220, "modes": [ [ "DEFAULT", "burst", 12 ] ], "valid_mod_locations": [ [ "accessories", 1 ], [ "emitter", 1 ], [ "grip", 1 ], [ "lens", 1 ], [ "rail", 1 ], [ "sights", 1 ], [ "stock", 1 ] ], @@ -83,7 +83,7 @@ "durability": 8, "modes": [ [ "DEFAULT", "semi-auto", 1 ] ], "loudness": 12, - "ups_charges": 20, + "power_draw": 20, "reload": 0, "valid_mod_locations": [ [ "accessories", 4 ], @@ -119,7 +119,7 @@ "durability": 8, "modes": [ [ "DEFAULT", "semi-auto", 1 ] ], "loudness": 20, - "ups_charges": 30, + "power_draw": 30, "reload": 0, "valid_mod_locations": [ [ "accessories", 4 ], @@ -182,7 +182,7 @@ "dispersion": 500, "durability": 9, "loudness": 10, - "ups_charges": 5, + "power_draw": 5, "modes": [ [ "DEFAULT", "blast", 1 ] ], "valid_mod_locations": [ [ "accessories", 1 ], @@ -246,7 +246,7 @@ "dispersion": 100, "durability": 10, "loudness": -150, - "ups_charges": 40, + "power_draw": 40, "ammo": "plasma", "clip_size": 12, "reload": 170, @@ -301,7 +301,7 @@ "dispersion": 100, "durability": 10, "loudness": -55, - "ups_charges": 100, + "power_draw": 100, "ammo": "plasma", "clip_size": 5, "reload": 320, @@ -358,7 +358,7 @@ "dispersion": 150, "durability": 10, "loudness": 10, - "ups_charges": 10, + "power_draw": 10, "ammo": "pulsesb", "clip_size": 8, "reload": 450, diff --git a/data/mods/CrazyCataclysm/crazy_items.json b/data/mods/CrazyCataclysm/crazy_items.json index c7b32fa979d5..91fc3ab3ce61 100644 --- a/data/mods/CrazyCataclysm/crazy_items.json +++ b/data/mods/CrazyCataclysm/crazy_items.json @@ -117,12 +117,14 @@ "max_charges": 50, "techniques": [ "RAPID", "WBLOCK_2" ], "use_action": { - "type": "fireweapon_off", - "target_id": "firekatana_on", + "type": "transform", + "target": "firekatana_on", "moves": 10, - "noise": 10, - "success_message": "The Sun rises.", - "lacks_fuel_message": "Time stands still." + "active": true, + "need_dry": true, + "transform_charges": 1, + "msg": "The Sun rises.", + "need_charges_msg": "Time stands still." }, "qualities": [ [ "CUT", 1 ], [ "BUTCHER", 6 ] ], "flags": [ "FIRE", "DURABLE_MELEE", "SHEATH_SWORD" ] @@ -136,17 +138,8 @@ "color": "red", "turns_per_charge": 30, "revert_to": "firekatana_off", - "use_action": [ - { - "type": "fireweapon_on", - "noise_chance": 35, - "noise_message": "The Sun shines brightly.", - "voluntary_extinguish_message": "The Sun sets.", - "charges_extinguish_message": "The Light Fades.", - "water_extinguish_message": "Your sword hisses in the water and goes out." - }, - { "type": "firestarter", "moves": 30 } - ], + "revert_msg": "The Light Fades.", + "use_action": [ { "type": "transform", "target": "firekatana_off", "msg": "The Sun sets." }, { "type": "firestarter", "moves": 30 } ], "flags": [ "FIRE", "LIGHT_240", "CHARGEDIM", "FLAMING", "DURABLE_MELEE", "TRADER_AVOID", "WATER_EXTINGUISH" ] }, { @@ -170,12 +163,14 @@ "max_charges": 50, "techniques": [ "WBLOCK_1", "WIDE", "BRUTAL", "SWEEP" ], "use_action": { - "type": "fireweapon_off", - "target_id": "zweifire_on", + "type": "transform", + "target": "zweifire_on", "moves": 10, - "noise": 10, - "success_message": "Die Klinge deines Schwertes brennt!", - "lacks_fuel_message": "Dein Flammenschwert hat keinen Brennstoff mehr." + "active": true, + "need_dry": true, + "transform_charges": 1, + "msg": "Die Klinge deines Schwertes brennt!", + "need_charges_msg": "Dein Flammenschwert hat keinen Brennstoff mehr." }, "qualities": [ [ "CUT", 1 ], [ "BUTCHER", 1 ] ], "flags": [ "DURABLE_MELEE", "SHEATH_SWORD", "ALWAYS_TWOHAND" ] @@ -190,15 +185,9 @@ "color": "red", "turns_per_charge": 30, "revert_to": "zweifire_off", + "revert_msg": "Dein Schwert zischt und erlischt.", "use_action": [ - { - "type": "fireweapon_on", - "noise_chance": 35, - "noise_message": "Das Feuer um deine Schwertklinge leuchtet hell!", - "voluntary_extinguish_message": "Die Flamme deines Schwertes erlischt.", - "charges_extinguish_message": "Deinem Flammenschwert ist der Brennstoff ausgegangen!", - "water_extinguish_message": "Dein Schwert zischt und erlischt." - }, + { "type": "transform", "target": "zweifire_off", "msg": "Die Flamme deines Schwertes erlischt." }, { "type": "firestarter", "moves": 30 } ], "flags": [ "FIRE", "LIGHT_240", "CHARGEDIM", "FLAMING", "DURABLE_MELEE", "TRADER_AVOID", "WATER_EXTINGUISH", "ALWAYS_TWOHAND" ] diff --git a/data/mods/No_Hope/Items/guns.json b/data/mods/No_Hope/Items/guns.json index f4188a09c0f5..7d6f0e47e18e 100644 --- a/data/mods/No_Hope/Items/guns.json +++ b/data/mods/No_Hope/Items/guns.json @@ -20,7 +20,7 @@ "dispersion": 90, "durability": 6, "loudness": 15, - "ups_charges": 40, + "power_draw": 40, "reload": 600, "valid_mod_locations": [ [ "emitter", 1 ], diff --git a/data/mods/No_Hope/Items/tools.json b/data/mods/No_Hope/Items/tools.json index 2b5687cd0cce..0a83ec2b3151 100644 --- a/data/mods/No_Hope/Items/tools.json +++ b/data/mods/No_Hope/Items/tools.json @@ -206,14 +206,14 @@ "max_charges": 50, "techniques": [ "WBLOCK_2" ], "use_action": { - "type": "fireweapon_off", - "target_id": "firemachete_on", + "type": "transform", + "target": "firemachete_on", "moves": 10, - "noise": 0, - "success_chance": 2, - "success_message": "Your No. 9 glows!", - "failure_message": "Click.", - "lacks_fuel_message": "Click." + "active": true, + "need_dry": true, + "transform_charges": 1, + "msg": "Your No. 9 glows!", + "need_charges_msg": "Click." }, "qualities": [ [ "CUT", 1 ], [ "BUTCHER", 12 ] ], "flags": [ "FIRE", "DURABLE_MELEE", "SHEATH_SWORD" ] @@ -237,19 +237,10 @@ "max_charges": 50, "turns_per_charge": 180, "revert_to": "firemachete_off", + "revert_msg": "Your No. 9 cuts out!", "techniques": [ "WBLOCK_2" ], "use_action": [ - { - "type": "fireweapon_on", - "noise": 5, - "noise_chance": 25, - "noise_message": "Your No. 9 hisses.", - "auto_extinguish_chance": 100, - "auto_extinguish_message": "Your No. 9 cuts out!", - "voluntary_extinguish_message": "Your No. 9 goes dark.", - "charges_extinguish_message": "Out of ammo!", - "water_extinguish_message": "Your No. 9 hisses in the water and goes out." - }, + { "type": "transform", "target": "firemachete_off", "msg": "Your No. 9 goes dark." }, { "type": "firestarter", "moves": 30 } ], "flags": [ "FIRE", "LIGHT_240", "CHARGEDIM", "FLAMING", "DURABLE_MELEE", "TRADER_AVOID", "WATER_EXTINGUISH" ] @@ -274,12 +265,14 @@ "max_charges": 50, "techniques": [ "WBLOCK_1", "WIDE", "BRUTAL", "SWEEP" ], "use_action": { - "type": "fireweapon_off", - "target_id": "zweifire_on", + "type": "transform", + "target": "zweifire_on", "moves": 10, - "noise": 10, - "success_message": "Die Klinge deines Schwertes brennt!", - "lacks_fuel_message": "Dein Flammenschwert hat keinen Brennstoff mehr." + "active": true, + "need_dry": true, + "transform_charges": 1, + "msg": "Die Klinge deines Schwertes brennt!", + "need_charges_msg": "Dein Flammenschwert hat keinen Brennstoff mehr." }, "qualities": [ [ "CUT", 1 ], [ "BUTCHER", 1 ] ], "flags": [ "DURABLE_MELEE", "SHEATH_SWORD", "ALWAYS_TWOHAND" ] @@ -303,16 +296,10 @@ "max_charges": 50, "turns_per_charge": 180, "revert_to": "zweifire_off", + "revert_msg": "Dein Schwert zischt und erlischt.", "techniques": [ "WBLOCK_1", "WIDE", "BRUTAL", "SWEEP" ], "use_action": [ - { - "type": "fireweapon_on", - "noise_chance": 35, - "noise_message": "Das Feuer um deine Schwertklinge leuchtet hell!", - "voluntary_extinguish_message": "Die Flamme deines Schwertes erlischt.", - "charges_extinguish_message": "Deinem Flammenschwert ist der Brennstoff ausgegangen!", - "water_extinguish_message": "Dein Schwert zischt und erlischt." - }, + { "type": "transform", "target": "zweifire_off", "msg": "Die Flamme deines Schwertes erlischt." }, { "type": "firestarter", "moves": 30 } ], "flags": [ "FIRE", "LIGHT_240", "CHARGEDIM", "FLAMING", "DURABLE_MELEE", "TRADER_AVOID", "WATER_EXTINGUISH", "ALWAYS_TWOHAND" ] @@ -337,12 +324,14 @@ "max_charges": 50, "techniques": [ "WBLOCK_2" ], "use_action": { - "type": "fireweapon_off", - "target_id": "broadfire_on", + "type": "transform", + "target": "broadfire_on", "moves": 10, - "noise": 10, - "success_message": "Charge!", - "lacks_fuel_message": "No strength to fight!" + "active": true, + "need_dry": true, + "transform_charges": 1, + "msg": "Charge!", + "need_charges_msg": "No strength to fight!" }, "qualities": [ [ "CUT", 1 ], [ "BUTCHER", 6 ] ], "flags": [ "DURABLE_MELEE", "SHEATH_SWORD" ] @@ -355,17 +344,8 @@ "description": "This is a combination of two Dark Age conflict-resolution classics, the broadsword and the torch. The blade is glowing with heat. Excalibur can eat its heart out. Use to shut it off.", "turns_per_charge": 180, "revert_to": "broadfire_off", - "use_action": [ - { - "type": "fireweapon_on", - "noise_chance": 35, - "noise_message": "Your blade burns for combat!", - "voluntary_extinguish_message": "Run away!", - "charges_extinguish_message": "Thy strength fades!", - "water_extinguish_message": "Your sword hisses in the water and goes out." - }, - { "type": "firestarter", "moves": 30 } - ], + "revert_msg": "Thy strength fades!", + "use_action": [ { "type": "transform", "target": "broadfire_off", "msg": "Run away!" }, { "type": "firestarter", "moves": 30 } ], "flags": [ "FIRE", "LIGHT_240", "CHARGEDIM", "FLAMING", "DURABLE_MELEE", "TRADER_AVOID" ] }, { @@ -387,12 +367,14 @@ "max_charges": 50, "techniques": [ "RAPID", "WBLOCK_2" ], "use_action": { - "type": "fireweapon_off", - "target_id": "firekatana_on", + "type": "transform", + "target": "firekatana_on", "moves": 10, - "noise": 10, - "success_message": "The Sun rises.", - "lacks_fuel_message": "Time stands still." + "active": true, + "need_dry": true, + "transform_charges": 1, + "msg": "The Sun rises.", + "need_charges_msg": "Time stands still." }, "qualities": [ [ "CUT", 1 ], [ "BUTCHER", 6 ] ], "flags": [ "FIRE", "DURABLE_MELEE", "SHEATH_SWORD" ] @@ -415,18 +397,9 @@ "max_charges": 50, "turns_per_charge": 180, "revert_to": "firekatana_off", + "revert_msg": "The Light Fades.", "techniques": [ "RAPID", "WBLOCK_2" ], - "use_action": [ - { - "type": "fireweapon_on", - "noise_chance": 35, - "noise_message": "The Sun shines brightly.", - "voluntary_extinguish_message": "The Sun sets.", - "charges_extinguish_message": "The Light Fades.", - "water_extinguish_message": "Your sword hisses in the water and goes out." - }, - { "type": "firestarter", "moves": 30 } - ], + "use_action": [ { "type": "transform", "target": "firekatana_off", "msg": "The Sun sets." }, { "type": "firestarter", "moves": 30 } ], "flags": [ "FIRE", "LIGHT_240", "CHARGEDIM", "FLAMING", "DURABLE_MELEE", "TRADER_AVOID", "WATER_EXTINGUISH" ] }, { @@ -447,14 +420,14 @@ "charges_per_use": 1, "max_charges": 50, "use_action": { - "type": "fireweapon_off", - "target_id": "shishkebab_on", + "type": "transform", + "target": "shishkebab_on", "moves": 10, - "noise": 10, - "success_chance": 5, - "success_message": "Let's dance, Zeds!", - "failure_message": "Aw, dangit. It fails to start!", - "lacks_fuel_message": "This thing needs some fuel!" + "active": true, + "need_dry": true, + "transform_charges": 1, + "msg": "Let's dance, Zeds!", + "need_charges_msg": "This thing needs some fuel!" }, "qualities": [ [ "CUT", 1 ], [ "BUTCHER", -30 ] ], "techniques": [ "WBLOCK_1" ], @@ -468,18 +441,9 @@ "description": "This is a large blade with a fuel pipe on the side, and a small tank and igniter built into the insulated hilt. The blade is glowing brightly. Use to shut off the gas.", "turns_per_charge": 120, "revert_to": "shishkebab_off", + "revert_msg": "Bummer, man! Your shishkebab's flame flickers and dies out.", "use_action": [ - { - "type": "fireweapon_on", - "noise": 10, - "noise_chance": 25, - "noise_message": "Your shishkebab crackles!", - "auto_extinguish_chance": 75, - "auto_extinguish_message": "Bummer, man! Your shishkebab's flame flickers and dies out.", - "voluntary_extinguish_message": "Peace out. Your shishkebab's flame dies.", - "charges_extinguish_message": "Uncool, outta gas! Your shishkebab's flame goes out.", - "water_extinguish_message": "Your shishkebab hisses in the water and goes out." - }, + { "type": "transform", "target": "shishkebab_off", "msg": "Peace out. Your shishkebab's flame dies." }, { "type": "firestarter", "moves": 30 } ], "flags": [ "FIRE", "LIGHT_240", "CHARGEDIM", "FLAMING", "TRADER_AVOID" ] diff --git a/src/active_tile_data.cpp b/src/active_tile_data.cpp index 97e11527b5e5..ff5025077bf2 100644 --- a/src/active_tile_data.cpp +++ b/src/active_tile_data.cpp @@ -188,24 +188,23 @@ void battery_tile::load( JsonObject &jo ) jo.read( "max_stored", max_stored ); } -int battery_tile::get_resource() const +units::energy battery_tile::get_resource() const { return stored; } -int battery_tile::mod_resource( int amt ) +units::energy battery_tile::mod_resource( units::energy amt ) { - // TODO: Avoid int64 math if possible - std::int64_t sum = static_cast( stored ) + amt; + units::energy sum = stored + amt; if( sum >= max_stored ) { stored = max_stored; return sum - max_stored; - } else if( sum <= 0 ) { - stored = 0; + } else if( sum <= 0_J ) { + stored = 0_J; return sum - stored; } else { stored = sum; - return 0; + return 0_J; } } @@ -261,16 +260,11 @@ void charger_tile::update_internal( time_point to, const tripoint_abs_ms &p, if( !n.has_flag( flag_RECHARGE ) && !n.has_flag( flag_USE_UPS ) ) { return VisitResponse::NEXT; } - if( n.ammo_capacity() > n.ammo_remaining() || - ( n.type->battery && n.type->battery->max_capacity > n.energy_remaining() ) ) { + if( n.is_battery() && n.energy_capacity() > n.energy_remaining() ) { while( power >= 1000 || x_in_y( power, 1000 ) ) { const int missing = grid.mod_resource( -1 ); if( missing == 0 ) { - if( n.is_battery() ) { - n.mod_energy( 1_kJ ); - } else { - n.ammo_set( itype_battery, n.ammo_remaining() + 1 ); - } + n.mod_energy( 1_kJ ); } power -= 1000; } diff --git a/src/active_tile_data_def.h b/src/active_tile_data_def.h index aa3cd6cf6e65..8ceddf66768b 100644 --- a/src/active_tile_data_def.h +++ b/src/active_tile_data_def.h @@ -21,8 +21,8 @@ class battery_tile : public active_tile_data { public: /* In J */ - int stored; - int max_stored; + units::energy stored; + units::energy max_stored; void update_internal( time_point to, const tripoint_abs_ms &p, distribution_grid &grid ) override; active_tile_data *clone() const override; @@ -30,8 +30,8 @@ class battery_tile : public active_tile_data void store( JsonOut &jsout ) const override; void load( JsonObject &jo ) override; - int get_resource() const; - int mod_resource( int amt ); + units::energy get_resource() const; + units::energy mod_resource( int amt ); }; class charge_watcher_tile : public active_tile_data diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 80ef07a576b7..b16e996b2b4b 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -2721,7 +2721,7 @@ void activity_handlers::repair_item_finish( player_activity *act, player *p ) // TODO: Allow setting this in the actor // TODO: Don't use charges_to_use: welder has 50 charges per use, soldering iron has 1 - if( !used_tool->units_sufficient( *p ) ) { + if( !used_tool->units_sufficient() ) { p->add_msg_if_player( _( "Your %s ran out of charges" ), used_tool->tname() ); act->set_to_null(); return; diff --git a/src/avatar_functions.cpp b/src/avatar_functions.cpp index a7bac69a8623..9c8421b05832 100644 --- a/src/avatar_functions.cpp +++ b/src/avatar_functions.cpp @@ -645,6 +645,13 @@ static detached_ptr add_or_drop_with_msg( avatar &you, detached_ptr return detached_ptr(); } +enum unload_type { + UNLOAD_MAGAZINE, + UNLOAD_BATTERY, + UNLOAD_BOTH, + UNLOAD_NONE, +}; + bool unload_item( avatar &you, item &loc ) { item &it = loc; @@ -717,11 +724,14 @@ bool unload_item( avatar &you, item &loc ) } // Next check for any reasons why the item cannot be unloaded - if( target->ammo_types().empty() || target->ammo_capacity() <= 0 ) { + // First: It has no ammo type, cannot contain ammo or has no suitable batteries. + if( ( target->ammo_types().empty() || target->ammo_capacity() <= 0 ) && + target->type->batteries.empty() ) { add_msg( m_info, _( "You can't unload a %s!" ), target->tname() ); return false; } + // Second: It has the NO_UNLOAD FLAG if( target->has_flag( flag_NO_UNLOAD ) ) { if( target->has_flag( flag_RECHARGE ) || target->has_flag( flag_USE_UPS ) ) { add_msg( m_info, _( "You can't unload a rechargeable %s!" ), target->tname() ); @@ -731,12 +741,10 @@ bool unload_item( avatar &you, item &loc ) return false; } - if( !target->magazine_current() && target->ammo_remaining() <= 0 && target->casings_count() <= 0 ) { - if( target->is_tool() ) { - add_msg( m_info, _( "Your %s isn't charged." ), target->tname() ); - } else { - add_msg( m_info, _( "Your %s isn't loaded." ), target->tname() ); - } + // Last: It has no current magazine, ammo, casings or batteries inside. + if( !target->magazine_current() && !target->battery_current() && target->ammo_remaining() <= 0 && + target->casings_count() <= 0 ) { + add_msg( m_info, _( "Your %s is empty!" ), target->tname() ); return false; } @@ -745,96 +753,146 @@ bool unload_item( avatar &you, item &loc ) return detached_ptr(); } ); - if( target->is_magazine() ) { - // Calculate the time to remove the contained ammo (consuming half as much time as required to load the magazine) - int mv = 0; - int qty = 0; - it.contents.remove_top_items_with( [&]( detached_ptr &&contained ) { - mv += you.item_reload_cost( it, *contained, contained->charges ) / 2; - qty += contained->charges; - return add_or_drop_with_msg( you, std::move( contained ), true ); - } ); + int unload_func = UNLOAD_NONE; - // remove the belt linkage - if( it.is_ammo_belt() ) { - if( it.type->magazine->linkage ) { - detached_ptr link = item::spawn( *it.type->magazine->linkage, calendar::turn, qty ); - add_or_drop_with_msg( you, std::move( link ), true ); + // No battery, so unload only magazine/itself. + if( !target->battery_current() ) { + unload_func = UNLOAD_MAGAZINE; + // No mag/internal ammo, so unload only battery. + } else if( !target->magazine_current() || target->ammo_remaining() <= 0 ) { + unload_func = UNLOAD_BATTERY; + // Both available, query player. + } else { + uilist umenu; + umenu.text = "Unload what?"; + + umenu.addentry( UNLOAD_MAGAZINE, true, '1', _( "Ammo/Magazine" ) ); + umenu.addentry( UNLOAD_BATTERY, true, '2', _( "Battery" ) ); + umenu.addentry( UNLOAD_BOTH, true, '3', _( "Both" ) ); + umenu.addentry( UNLOAD_NONE, true, '4', _( "None" ) ); + + umenu.selected = 1; + umenu.query(); + unload_func = umenu.ret; + } + + if( unload_func == UNLOAD_NONE ) { + return false; + } + + if( unload_func == UNLOAD_MAGAZINE || unload_func == UNLOAD_BOTH ) { + if( target->is_magazine() ) { + // Calculate the time to remove the contained ammo (consuming half as much time as required to load the magazine) + int mv = 0; + int qty = 0; + it.contents.remove_top_items_with( [&]( detached_ptr &&contained ) { + if( contained->typeId() != it.ammo_current() ) { + return contained; + } + mv += you.item_reload_cost( it, *contained, contained->charges ) / 2; + qty += contained->charges; + return add_or_drop_with_msg( you, std::move( contained ), true ); + } ); + + // remove the belt linkage + if( it.is_ammo_belt() ) { + if( it.type->magazine->linkage ) { + detached_ptr link = item::spawn( *it.type->magazine->linkage, calendar::turn, qty ); + add_or_drop_with_msg( you, std::move( link ), true ); + } + add_msg( _( "You disassemble your %s." ), it.tname() ); + } else { + add_msg( _( "You unload your %s." ), it.tname() ); } - add_msg( _( "You disassemble your %s." ), it.tname() ); - } else { - add_msg( _( "You unload your %s." ), it.tname() ); - } - you.mod_moves( -std::min( 200, mv ) ); - if( loc.has_flag( flag_MAG_DESTROY ) && loc.ammo_remaining() == 0 ) { - loc.detach(); - } - return true; - } else if( item *mag = target->magazine_current() ) { - bool unloaded = false; - target->contents.remove_top_items_with( [&]( detached_ptr &&it ) { - if( &*it == mag ) { - it = add_or_drop_with_msg( you, std::move( it ), true ); - if( !it ) { - unloaded = true; + you.mod_moves( -std::min( 200, mv ) ); + if( loc.has_flag( flag_MAG_DESTROY ) && loc.ammo_remaining() == 0 ) { + loc.detach(); + } + return true; + } else if( item *mag = target->magazine_current() ) { + bool unloaded = false; + target->contents.remove_top_items_with( [&]( detached_ptr &&it ) { + if( &*it == mag ) { + it = add_or_drop_with_msg( you, std::move( it ), true ); + if( !it ) { + unloaded = true; + } } + return std::move( it ); + } ); + if( unloaded ) { + // Eject magazine consuming half as much time as required to insert it + you.moves -= you.item_reload_cost( *target, *mag, -1 ) / 2; } - return std::move( it ); - } ); - if( unloaded ) { - // Eject magazine consuming half as much time as required to insert it - you.moves -= you.item_reload_cost( *target, *mag, -1 ) / 2; - } - } else if( target->ammo_remaining() ) { - int qty = target->ammo_remaining(); + } else if( target->ammo_remaining() ) { + int qty = target->ammo_remaining(); - if( target->ammo_current() == itype_plut_cell ) { - qty = target->ammo_remaining() / PLUTONIUM_CHARGES; - if( qty > 0 ) { - add_msg( _( "You recover %i unused plutonium." ), qty ); - } else { - add_msg( m_info, _( "You can't remove partially depleted plutonium!" ) ); - return false; + if( target->ammo_current() == itype_plut_cell ) { + qty = target->ammo_remaining() / PLUTONIUM_CHARGES; + if( qty > 0 ) { + add_msg( _( "You recover %i unused plutonium." ), qty ); + } else { + add_msg( m_info, _( "You can't remove partially depleted plutonium!" ) ); + return false; + } } - } - // Construct a new ammo item and try to drop it - detached_ptr ammo = item::spawn( target->ammo_current(), calendar::turn, qty ); - if( target->is_filthy() ) { - ammo->set_flag( flag_FILTHY ); - } + // Construct a new ammo item and try to drop it + detached_ptr ammo = item::spawn( target->ammo_current(), calendar::turn, qty ); + if( target->is_filthy() ) { + ammo->set_flag( flag_FILTHY ); + } - item &ammo_ref = *ammo; + item &ammo_ref = *ammo; - if( ammo->made_of( LIQUID ) ) { + if( ammo->made_of( LIQUID ) ) { - ammo = add_or_drop_with_msg( you, std::move( ammo ), false ); + ammo = add_or_drop_with_msg( you, std::move( ammo ), false ); - if( ammo ) { - qty -= ammo->charges; // only handled part (or none) of the liquid - } - if( qty <= 0 ) { - return false; // no liquid was moved - } + if( ammo ) { + qty -= ammo->charges; // only handled part (or none) of the liquid + } + if( qty <= 0 ) { + return false; // no liquid was moved + } - } else { - ammo = add_or_drop_with_msg( you, std::move( ammo ), qty > 1 ); - if( ammo ) { - return false; + } else { + ammo = add_or_drop_with_msg( you, std::move( ammo ), qty > 1 ); + if( ammo ) { + return false; + } } - } - // If successful remove appropriate qty of ammo consuming half as much time as required to load it - you.moves -= you.item_reload_cost( *target, ammo_ref, qty ) / 2; + // If successful remove appropriate qty of ammo consuming half as much time as required to load it + you.moves -= you.item_reload_cost( *target, ammo_ref, qty ) / 2; - if( target->ammo_current() == itype_plut_cell ) { - qty *= PLUTONIUM_CHARGES; + if( target->ammo_current() == itype_plut_cell ) { + qty *= PLUTONIUM_CHARGES; + } + + target->ammo_set( target->ammo_current(), target->ammo_remaining() - qty ); } + } - target->ammo_set( target->ammo_current(), target->ammo_remaining() - qty ); + if( unload_func == UNLOAD_BATTERY || unload_func == UNLOAD_BOTH ) { + item *bat = target->battery_current(); + bool unloaded = false; + target->contents.remove_top_items_with( [&]( detached_ptr &&it ) { + if( &*it == bat ) { + it = add_or_drop_with_msg( you, std::move( it ), true ); + if( !it ) { + unloaded = true; + } + } + return std::move( it ); + } ); + if( unloaded ) { + // Eject battery consuming half as much time as required to insert it + you.moves -= you.item_reload_cost( *target, *bat, -1 ) / 2; + } } // Turn off any active tools diff --git a/src/bionics.cpp b/src/bionics.cpp index 2859e0f4bbba..458ca76d796c 100644 --- a/src/bionics.cpp +++ b/src/bionics.cpp @@ -1482,11 +1482,9 @@ int Character::consume_remote_fuel( int amount ) static const item_filter used_ups = [&]( const item & itm ) { return itm.get_var( "cable" ) == "plugged_in"; }; - if( has_charges( itype_UPS_off, unconsumed_amount, used_ups ) ) { - use_charges( itype_UPS_off, unconsumed_amount, used_ups ); + if( use_charges_if_avail( itype_UPS_off, unconsumed_amount, used_ups ) ) { unconsumed_amount -= 1; - } else if( has_charges( itype_adv_UPS_off, unconsumed_amount, used_ups ) ) { - use_charges( itype_adv_UPS_off, roll_remainder( unconsumed_amount * 0.5 ), used_ups ); + } else if( use_charges_if_avail( itype_adv_UPS_off, unconsumed_amount, used_ups ) ) { unconsumed_amount -= 1; } } diff --git a/src/bionics_ui.cpp b/src/bionics_ui.cpp index 9b5f6c5889a8..2f12f9e518c2 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -225,24 +225,10 @@ static void draw_bionics_titlebar( const catacurses::window &window, Character * if( !found_fuel ) { fuel_string.clear(); } - std::string power_string; - const int curr_power = units::to_joule( p->get_power_level() ); - const int kilo = curr_power / units::to_joule( 1_kJ ); - const int joule = ( curr_power % units::to_joule( 1_kJ ) ) / units::to_joule( 1_J ); - if( kilo > 0 ) { - power_string = std::to_string( kilo ); - if( joule > 0 ) { - power_string += pgettext( "decimal separator", "." ) + std::to_string( joule ); - } - power_string += pgettext( "energy unit: kilojoule", "kJ" ); - } else { - power_string = std::to_string( joule ); - power_string += pgettext( "energy unit: joule", "J" ); - } const int pwr_str_pos = right_print( window, 1, 1, c_white, string_format( _( "Bionic Power: %s/%ikJ" ), - power_string, units::to_kilojoule( p->get_max_power_level() ) ) ); + units::display( p->get_power_level() ), units::display( p->get_max_power_level() ) ) ); mvwputch( window, point( pwr_str_pos - 1, 1 ), BORDER_COLOR, LINE_XOXO ); // | mvwputch( window, point( pwr_str_pos - 1, 2 ), BORDER_COLOR, LINE_XXOO ); // |_ diff --git a/src/catalua_iuse_actor.cpp b/src/catalua_iuse_actor.cpp index a4dc8ae3ad07..d14bc5dd9fbb 100644 --- a/src/catalua_iuse_actor.cpp +++ b/src/catalua_iuse_actor.cpp @@ -15,13 +15,14 @@ void lua_iuse_actor::load( const JsonObject & ) // TODO: custom data } -int lua_iuse_actor::use( player &who, item &itm, bool tick, const tripoint &pos ) const +std::pair lua_iuse_actor::use( player &who, item &itm, bool tick, + const tripoint &pos ) const { if( !tick ) { try { sol::protected_function_result res = luafunc( who.as_character(), itm, pos ); check_func_result( res ); - int ret = res; + std::pair ret = res; return ret; } catch( std::runtime_error &e ) { debugmsg( "Failed to run iuse_function k='%s': %s", type, e.what() ); @@ -29,7 +30,7 @@ int lua_iuse_actor::use( player &who, item &itm, bool tick, const tripoint &pos } else { // TODO: ticking use } - return 1; + return std::make_pair( 1, 0_J ); } ret_val lua_iuse_actor::can_use( const Character &, const item &, bool, diff --git a/src/catalua_iuse_actor.h b/src/catalua_iuse_actor.h index b9ae0fbdabc7..a65785c7a7af 100644 --- a/src/catalua_iuse_actor.h +++ b/src/catalua_iuse_actor.h @@ -16,7 +16,8 @@ class lua_iuse_actor : public iuse_actor lua_iuse_actor( const std::string &type, sol::protected_function &&luafunc ); ~lua_iuse_actor() override; void load( const JsonObject &obj ) override; - int use( player &who, item &itm, bool tick, const tripoint &pos ) const override; + std::pair use( player &who, item &itm, bool tick, + const tripoint &pos ) const override; ret_val can_use( const Character &, const item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; diff --git a/src/character.cpp b/src/character.cpp index 3cf091b1f8ca..2f0896634123 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -7610,23 +7610,19 @@ bool Character::invoke_item( item *used, const std::string &method, const tripoi return false; } - int charges_used = actually_used->type->invoke( *this->as_player(), *actually_used, pt, method ); - if( charges_used == 0 ) { + auto[chrg, enrg] = actually_used->type->invoke( *this->as_player(), *actually_used, pt, method ); + if( chrg == 0 && enrg == 0_J ) { return false; } // Prevent accessing the item as it may have been deleted by the invoked iuse function. - if( used->is_tool() || used->is_medication() || used->get_contained().is_medication() ) { - return consume_charges( *actually_used, charges_used ); + if( used->is_tool() || used->count_by_charges() || used->is_comestible() || + used->get_contained().is_comestible() ) { + used->energy_consume( enrg, pt ) == enrg; + return( consume_charges( *actually_used, chrg ) ); } else if( used->is_bionic() || used->is_deployable() || method == "place_trap" ) { used->detach(); return true; - } else if( used->count_by_charges() ) { - used->charges -= charges_used; - if( used->charges <= 0 ) { - used->detach(); - } - return true; } return false; @@ -7732,15 +7728,30 @@ bool Character::dispose_item( item &obj, const std::string &prompt ) } bool Character::has_enough_charges( const item &it, bool show_msg ) const +{ + if( !it.is_tool() || !it.ammo_required() ) { + return true; + } + if( !it.ammo_sufficient() ) { + if( show_msg ) { + add_msg_if_player( m_info, + vgettext( "Your %s has %d charge but needs %d.", + "Your %s has %d charges but needs %d.", + it.ammo_remaining() ), + it.tname(), it.ammo_remaining(), it.ammo_required() ); + } + return false; + } + return true; +} + +bool Character::has_enough_power( const item &it, bool show_msg ) const { if( !it.is_tool() || !it.ammo_required() ) { return true; } if( it.is_power_armor() ) { - if( ( character_funcs::can_interface_armor( *this ) && - has_charges( itype_bio_armor, it.ammo_required() ) ) || - ( it.has_flag( flag_USE_UPS ) && has_charges( itype_UPS, it.ammo_required() ) ) || - it.ammo_sufficient() ) { + if( it.energy_sufficient( *this ) ) { return true; } @@ -7812,27 +7823,7 @@ bool Character::consume_charges( item &used, int qty ) return false; } - if( used.is_power_armor() ) { - if( used.charges >= qty ) { - used.ammo_consume( qty, pos() ); - } else if( character_funcs::can_interface_armor( *this ) && has_charges( itype_bio_armor, qty ) ) { - use_charges( itype_bio_armor, qty ); - } else { - use_charges( itype_UPS, qty ); - } - } - - // USE_UPS may occur on base items and is added by the UPS tool mod - // If an item has the flag, then it should not be consumed on use. - if( used.has_flag( flag_USE_UPS ) ) { - // With the new UPS system, we'll want to use any charges built up in the tool before pulling from the UPS - // The usage of the item was already approved, so drain item if possible, otherwise use UPS - if( used.charges >= qty ) { - used.ammo_consume( qty, pos() ); - } else { - use_charges( itype_UPS, qty ); - } - } else if( used.is_tool() && used.units_remaining( *this ) == 0 && !used.ammo_required() ) { + if( used.is_tool() && used.units_remaining() == 0 && !used.ammo_required() ) { // Tools which don't require ammo are instead destroyed. // Put here cause tools may have use actions that require charges without charges_per_use used.detach(); @@ -10040,13 +10031,34 @@ bool Character::has_charges( const itype_id &it, int quantity, if( it == itype_fire || it == itype_apparatus ) { return has_fire( quantity ); } - if( it == itype_UPS && is_mounted() && - mounted_creature.get()->has_flag( MF_RIDEABLE_MECH ) ) { - auto mons = mounted_creature.get(); - return quantity <= mons->get_battery_item()->ammo_remaining(); + return charges_of( it, quantity, filter ) == quantity; +} + +bool Character::has_energy( const itype_id &it, units::energy amount, + const std::function &filter ) const +{ + if( it == itype_UPS ) { + units::energy UPS_needed = amount; + if( is_mounted() && mounted_creature.get()->has_flag( MF_RIDEABLE_MECH ) ) { + auto mons = mounted_creature.get(); + UPS_needed -= std::min( mons->get_battery_item()->energy_remaining(), UPS_needed ); + if( UPS_needed == 0_J ) { + return true; + } + } + if( has_power() && has_active_bionic( bio_ups ) ) { + UPS_needed -= std::min( get_power_level(), UPS_needed ); + if( UPS_needed == 0_J ) { + return true; + } + } + static const item_filter is_ups = [&]( const item & itm ) { + return itm.has_flag( flag_IS_UPS ); + }; + return energy_of( itype_id( "any" ), UPS_needed, is_ups ) == UPS_needed; } if( it == itype_bio_armor ) { - int mod_qty = 0; + units::energy mod_power = 0_J; float efficiency = 1; for( const bionic &bio : *my_bionics ) { if( bio.powered && bio.info().has_flag( flag_BIONIC_ARMOR_INTERFACE ) ) { @@ -10056,10 +10068,10 @@ bool Character::has_charges( const itype_id &it, int quantity, if( efficiency == 1 ) { debugmsg( "Player lacks a bionic armor interface with fuel efficiency field." ); } - mod_qty = quantity / efficiency; - return ( has_power() && get_power_level() >= units::from_kilojoule( mod_qty ) ); + mod_power = amount / efficiency; + return ( has_power() && get_power_level() >= mod_power ); } - return charges_of( it, quantity, filter ) == quantity; + return false; } std::vector> Character::use_amount( itype_id it, int quantity, @@ -10079,10 +10091,21 @@ std::vector> Character::use_amount( itype_id it, int quantity return ret; } -bool Character::use_charges_if_avail( const itype_id &it, int quantity ) +bool Character::use_charges_if_avail( const itype_id &it, int quantity, + const std::function &filter ) { - if( has_charges( it, quantity ) ) { - use_charges( it, quantity ); + if( has_charges( it, quantity, filter ) ) { + use_charges( it, quantity, filter ); + return true; + } + return false; +} + +bool Character::use_energy_if_avail( const itype_id &it, units::energy amount, + const std::function &filter ) +{ + if( has_energy( it, amount, filter ) ) { + use_energy( it, amount, filter ); return true; } return false; @@ -10094,7 +10117,6 @@ std::vector> Character::use_charges( const itype_id &what, in std::vector> res; if( qty <= 0 ) { return res; - } else if( what == itype_voltmeter_bionic ) { mod_power_level( units::from_kilojoule( -qty ) ); return res; @@ -10102,13 +10124,29 @@ std::vector> Character::use_charges( const itype_id &what, in } else if( what == itype_toolset ) { mod_power_level( units::from_kilojoule( -qty ) ); return res; - } else if( what == itype_fire ) { use_fire( qty ); return res; + } + + return res; +} + +std::vector> Character::use_energy( const itype_id &what, + const units::energy amount, + const std::function &filter ) +{ + std::vector> res; + if( amount <= 0_J ) { + return res; + + } else if( what == itype_toolset ) { + mod_power_level( amount ); + return res; + } else if( what == itype_bio_armor ) { - float mod_qty = 0; + units::energy mod_amount = 0_J; float efficiency = 1; for( const bionic &bio : *my_bionics ) { if( bio.powered && bio.info().has_flag( flag_BIONIC_ARMOR_INTERFACE ) ) { @@ -10118,93 +10156,69 @@ std::vector> Character::use_charges( const itype_id &what, in if( efficiency == 1 ) { debugmsg( "Player lacks a bionic armor interface with fuel efficiency field." ); } - mod_qty = qty / efficiency; - mod_power_level( units::from_kilojoule( -mod_qty ) ); + mod_amount = amount / efficiency; + mod_power_level( mod_amount ); return res; } else if( what == itype_UPS ) { + units::energy power_needed = amount; if( is_mounted() && mounted_creature.get()->has_flag( MF_RIDEABLE_MECH ) && mounted_creature.get()->get_battery_item() ) { auto mons = mounted_creature.get(); - int power_drain = std::min( mons->get_battery_item()->ammo_remaining(), qty ); + units::energy power_drain = std::min( mons->get_battery_item()->energy_remaining(), amount ); mons->use_mech_power( -power_drain ); - qty -= std::min( qty, power_drain ); - return res; + power_needed -= power_drain; + if( power_needed == 0_J ) { + return res; + } } if( has_power() && has_active_bionic( bio_ups ) ) { - int bio = std::min( units::to_kilojoule( get_power_level() ), qty ); - mod_power_level( units::from_kilojoule( -bio ) ); - qty -= std::min( qty, bio ); + units::energy bio = std::min( get_power_level(), amount ); + mod_power_level( -bio ); + power_needed -= bio; + if( power_needed == 0_J ) { + return res; + } } - int adv = charges_of( itype_adv_UPS_off, static_cast( std::ceil( qty * 0.5 ) ) ); - if( adv > 0 ) { - int adv_odd = x_in_y( qty % 2, 2 ); - // qty % 2 returns 1 if odd and 0 if even, giving a 50% chance of consuming one less charge if odd, 0 otherwise. - // (eg: if 5, consumes either 2 or 3) - std::vector> found = use_charges( itype_adv_UPS_off, adv - adv_odd ); - res.insert( res.end(), std::make_move_iterator( found.begin() ), - std::make_move_iterator( found.end() ) ); - qty -= std::min( qty, static_cast( adv / 0.5 ) ); - } + tripoint p = pos(); + remove_items_with( [&power_needed, filter, &res, &p]( detached_ptr &&e ) { + if( power_needed == 0_J ) { + // found sufficient power + return VisitResponse::ABORT; + } + if( !filter( *e ) ) { + return VisitResponse::NEXT; + } + if( e->has_flag( flag_IS_UPS ) ) { + power_needed -= e->energy_consume( power_needed, p ); + + return VisitResponse::SKIP; + } + + // recurse through any nested containers + return VisitResponse::NEXT; + } ); - int ups = charges_of( itype_UPS_off, qty ); - if( ups > 0 ) { - std::vector> found = use_charges( itype_UPS_off, ups ); - res.insert( res.end(), std::make_move_iterator( found.begin() ), - std::make_move_iterator( found.end() ) ); - qty -= std::min( qty, ups ); - } return res; } - - bool has_tool_with_UPS = false; tripoint p = pos(); - remove_items_with( [&qty, filter, &has_tool_with_UPS, &what, &res, &p]( detached_ptr &&e ) { - if( qty == 0 ) { + units::energy power_needed = amount; + remove_items_with( [&power_needed, filter, &what, &res, &p]( detached_ptr &&e ) { + if( power_needed == 0_J ) { // found sufficient charges return VisitResponse::ABORT; } if( !filter( *e ) ) { return VisitResponse::NEXT; } - if( e->typeId() == what && e->has_flag( flag_USE_UPS ) ) { - has_tool_with_UPS = true; - } - if( e->is_tool() ) { - if( e->typeId() == what ) { - int n = std::min( e->ammo_remaining(), qty ); - qty -= n; + if( e->typeId() == what ) { + units::energy n = std::min( e->energy_remaining(), power_needed ); + power_needed -= n; + e->energy_consume( n, p ); - if( n == e->ammo_remaining() ) { - res.push_back( item::spawn( *e ) ); - e->ammo_consume( n, p ); - } else { - detached_ptr split = item::spawn( *e ); - split->ammo_set( e->ammo_current(), n ); - e->ammo_consume( n, p ); - res.push_back( std::move( split ) ); - } - } - return VisitResponse::SKIP; - - } else if( e->count_by_charges() ) { - if( e->typeId() == what ) { - if( e->charges > qty ) { - e->charges -= qty; - detached_ptr split = item::spawn( *e ); - split->charges = qty; - res.push_back( std::move( split ) ); - qty = 0; - return VisitResponse::ABORT; - } else { - qty -= e->charges; - res.push_back( std::move( e ) ); - } - } - // items counted by charges are not themselves expected to be containers return VisitResponse::SKIP; } @@ -10212,12 +10226,6 @@ std::vector> Character::use_charges( const itype_id &what, in return VisitResponse::NEXT; } ); - if( has_tool_with_UPS ) { - std::vector> found = use_charges( itype_UPS, qty ); - res.insert( res.end(), std::make_move_iterator( found.begin() ), - std::make_move_iterator( found.end() ) ); - } - return res; } @@ -10303,8 +10311,7 @@ void Character::use_fire( const int quantity ) } else if( has_item_with_flag( flag_FIRESTARTER ) ) { auto firestarters = all_items_with_flag( flag_FIRESTARTER ); for( auto &i : firestarters ) { - if( has_charges( i->typeId(), quantity ) ) { - use_charges( i->typeId(), quantity ); + if( use_charges_if_avail( i->typeId(), quantity ) ) { return; } } @@ -11546,7 +11553,7 @@ int Character::item_reload_cost( const item &it, item &ammo, int qty ) const qty = std::max( std::min( ammo.charges, qty ), 1 ); } else if( ammo.is_ammo_container() || ammo.is_container() ) { qty = clamp( qty, ammo.contents.front().charges, 1 ); - } else if( ammo.is_magazine() ) { + } else if( ammo.is_magazine() || ammo.is_battery() ) { qty = 1; } else { debugmsg( "cannot determine reload cost as %s is neither ammo or magazine", ammo.tname() ); diff --git a/src/character.h b/src/character.h index 257aa499f04a..b8a40324c6a2 100644 --- a/src/character.h +++ b/src/character.h @@ -1150,10 +1150,15 @@ class Character : public Creature, public location_visitable /** * Has the item enough charges to invoke its use function? - * Also checks if UPS from this player is used instead of item charges. */ bool has_enough_charges( const item &it, bool show_msg ) const; + /** + * Has the item enough charges to invoke its use function? + * Also checks if UPS from this player is used instead of item charges. + */ + bool has_enough_power( const item &it, bool show_msg ) const; + /** Consume charges of a tool or comestible item, potentially destroying it in the process * @param used item consuming the charges * @param qty number of charges to consume which must be non-zero @@ -1697,20 +1702,32 @@ class Character : public Creature, public location_visitable */ std::vector all_items_with_flag( const flag_id &flag ) const; + // has_charges works ONLY for charges. + // has_energy wokrs ONLY for energy + bool has_charges( const itype_id &it, int quantity, const std::function &filter = return_true ) const; + bool has_energy( const itype_id &it, units::energy amount, + const std::function &filter = return_true ) const; - // has_amount works ONLY for quantity. - // has_charges works ONLY for charges. std::vector> use_amount( itype_id it, int quantity, const std::function &filter = return_true ); // Uses up charges - bool use_charges_if_avail( const itype_id &it, int quantity ); + bool use_charges_if_avail( const itype_id &it, int quantity, + const std::function &filter = return_true ); // Uses up charges std::vector> use_charges( const itype_id &what, int qty, const std::function &filter = return_true ); + // Uses up energy if enough is found, if not, returns false and uses no energy + bool use_energy_if_avail( const itype_id &it, units::energy amount, + const std::function &filter = return_true ); + + // Uses up energy + std::vector> use_energy( const itype_id &what, const units::energy amount, + const std::function &filter = return_true ); + bool has_fire( int quantity ) const; void use_fire( int quantity ); void assign_stashed_activity(); diff --git a/src/character_functions.cpp b/src/character_functions.cpp index 33d1ab19b31c..6ddb1e204dde 100644 --- a/src/character_functions.cpp +++ b/src/character_functions.cpp @@ -1102,11 +1102,11 @@ std::vector get_ammo_items( const Character &who, const ammotype &at ) template void find_ammo_helper( T &src, const item &obj, bool empty, Output out, bool nested ) { - if( obj.is_watertight_container() ) { + if( obj.is_container() ) { if( !obj.is_container_empty() ) { auto contents_id = obj.contents.front().typeId(); - // Look for containers with the same type of liquid as that already in our container + // Look for containers with the same type of content as that already in our container src.visit_items( [&nested, &out, &contents_id, &obj]( item * node ) { if( node == &obj ) { // This stops containers and magazines counting *themselves* as ammo sources. @@ -1120,13 +1120,24 @@ void find_ammo_helper( T &src, const item &obj, bool empty, Output out, bool nes return nested ? VisitResponse::NEXT : VisitResponse::SKIP; } ); } else { - // Look for containers with any liquid - src.visit_items( [&nested, &out]( item * node ) { - if( node->is_container() && node->contents_made_of( LIQUID ) ) { - out = node; - } - return nested ? VisitResponse::NEXT : VisitResponse::SKIP; - } ); + if( obj.is_watertight_container() ) { + // Look for containers with any liquid + src.visit_items( [&nested, &out]( item * node ) { + if( node->is_container() && node->contents_made_of( LIQUID ) ) { + out = node; + } + return nested ? VisitResponse::NEXT : VisitResponse::SKIP; + } ); + } else { + // Look for non-liquid count by charges items and containers with such items + src.visit_items( [&nested, &out]( item * node ) { + if( ( node->is_container() && !node->contents_made_of( LIQUID ) ) || ( node->count_by_charges() && + !node->made_of( LIQUID ) ) ) { + out = node; + } + return nested ? VisitResponse::NEXT : VisitResponse::SKIP; + } ); + } } } if( obj.magazine_integral() ) { @@ -1165,17 +1176,19 @@ void find_ammo_helper( T &src, const item &obj, bool empty, Output out, bool nes } return nested ? VisitResponse::NEXT : VisitResponse::SKIP; } ); - } else { - // find compatible magazines excluding those already loaded in tools/guns - const auto mags = obj.magazine_compatible(); + } + if( !obj.magazine_compatible().empty() || !obj.type->batteries.empty() ) { const std::set &ammo = obj.ammo_types(); + const itype_id cur_battery = obj.battery_current() ? obj.battery_current()->typeId() : + itype_id::NULL_ID(); + const std::set mags = obj.magazine_compatible(); + const std::vector bats = obj.type->batteries; - src.visit_items( [&nested, &out, mags, empty, &ammo]( item * node ) { + src.visit_items( [&nested, &out, mags, bats, empty, &ammo, &cur_battery]( item * node ) { if( node->is_gun() || node->is_tool() ) { return VisitResponse::SKIP; } if( node->is_magazine() ) { - if( !node->contents.empty() ) { for( const ammotype &at : ammo ) { if( node->contents.front().ammo_type() != at ) { @@ -1188,6 +1201,15 @@ void find_ammo_helper( T &src, const item &obj, bool empty, Output out, bool nes out = node; } return VisitResponse::SKIP; + } else if( node->is_battery() ) { + if( cur_battery == node->typeId() ) { + VisitResponse::SKIP; + } + if( std::count( bats.begin(), bats.end(), node->typeId() ) && ( node->energy_remaining() > 0_J || + empty ) ) { + out = node; + } + return VisitResponse::SKIP; } return nested ? VisitResponse::NEXT : VisitResponse::SKIP; } ); @@ -1219,13 +1241,18 @@ std::vector find_reloadables( Character &who ) who.visit_items( [&]( item * node ) { bool reloadable = false; - if( node->is_gun() && !node->magazine_compatible().empty() ) { - reloadable = node->magazine_current() == nullptr || - node->ammo_remaining() < node->ammo_capacity(); - } else { - reloadable = ( node->is_magazine() || node->is_bandolier() || - ( node->is_gun() && node->magazine_integral() ) ) && - node->ammo_remaining() < node->ammo_capacity(); + if( node->is_gun() ) { + if( !node->magazine_compatible().empty() || !node->type->batteries.empty() ) { + reloadable = true; + } + if( ( node->ammo_remaining() < node->ammo_capacity() || + node->energy_remaining() < node->energy_capacity() ) ) { + if( node->magazine_integral() ) { + reloadable = true; + } + } + } else if( node->is_magazine() || node->is_bandolier() ) { + reloadable |= node->ammo_remaining() < node->ammo_capacity(); } if( node->is_holster() ) { const holster_actor *ptr = dynamic_cast @@ -1248,9 +1275,9 @@ int ammo_count_for( const Character &who, const item &gun ) return item::INFINITE_CHARGES; } int ammo_drain = gun.ammo_required(); - int energy_drain = gun.get_gun_ups_drain(); + units::energy energy_drain = gun.get_gun_ups_drain(); - units::energy power = units::from_kilojoule( who.charges_of( itype_UPS ) ); + units::energy power = who.energy_of( itype_UPS ); int total_ammo = gun.ammo_remaining(); const std::vector inv_ammo = find_ammo_items_or_mags( who, gun, true, -1 ); @@ -1266,12 +1293,12 @@ int ammo_count_for( const Character &who, const item &gun ) } } - if( ammo_drain > 0 && energy_drain > 0 ) { + if( ammo_drain > 0 && energy_drain > 0_J ) { // Both UPS and ammo, lower is limiting. - return std::min( total_ammo / ammo_drain, power / units::from_kilojoule( energy_drain ) ); - } else if( energy_drain > 0 ) { + return std::min( total_ammo / ammo_drain, power / energy_drain ); + } else if( energy_drain > 0_J ) { //Only one of the two, it is limiting. - return power / units::from_kilojoule( energy_drain ); + return power / energy_drain; } else if( ammo_drain > 0 ) { return total_ammo / ammo_drain; } else { diff --git a/src/character_turn.cpp b/src/character_turn.cpp index 90c9589b28ca..1a8a1183df4f 100644 --- a/src/character_turn.cpp +++ b/src/character_turn.cpp @@ -866,47 +866,33 @@ void Character::process_items() // Active item processing done, now we're recharging. std::vector active_worn_items; + for( item *&w : worn ) { + if( w->has_flag( flag_USE_UPS ) && + w->energy_remaining() < w->energy_capacity() ) { + active_worn_items.push_back( w ); + } + } bool weapon_active = primary_weapon().has_flag( flag_USE_UPS ) && primary_weapon().charges < primary_weapon().type->maximum_charges(); std::vector active_held_items; - int ch_UPS = 0; for( size_t index = 0; index < inv.size(); index++ ) { item &it = inv.find_item( index ); - itype_id identifier = it.type->get_id(); - if( identifier == itype_UPS_off ) { - ch_UPS += it.ammo_remaining(); - } else if( identifier == itype_adv_UPS_off ) { - ch_UPS += it.ammo_remaining() / 0.5; - } - if( it.has_flag( flag_USE_UPS ) && it.charges < it.type->maximum_charges() ) { + if( it.has_flag( flag_USE_UPS ) && it.energy_remaining() < it.energy_capacity() ) { active_held_items.push_back( index ); } } - bool update_required = get_check_encumbrance(); - for( item *&w : worn ) { - if( w->has_flag( flag_USE_UPS ) && - w->charges < w->type->maximum_charges() ) { - active_worn_items.push_back( w ); - } - // Necessary for UPS in Aftershock - check worn items for charge - const itype_id &identifier = w->typeId(); - if( identifier == itype_UPS_off ) { - ch_UPS += w->ammo_remaining(); - } else if( identifier == itype_adv_UPS_off ) { - ch_UPS += w->ammo_remaining() / 0.5; - } - if( !update_required && w->encumbrance_update_ ) { - update_required = true; - } - w->encumbrance_update_ = false; - } - if( update_required ) { - reset_encumbrance(); - } + + static const item_filter is_ups = [&]( const item & itm ) { + return itm.has_flag( flag_IS_UPS ); + }; + + units::energy ch_UPS = energy_of( itype_id( "any" ), units::energy_max, is_ups ); + if( has_active_bionic( bionic_id( "bio_ups" ) ) ) { - ch_UPS += units::to_kilojoule( get_power_level() ); + ch_UPS += get_power_level(); } - int ch_UPS_used = 0; + + units::energy ch_UPS_used = 0_J; // Load all items that use the UPS to their minimal functional charge, // The tool is not really useful if its charges are below charges_to_use @@ -915,22 +901,22 @@ void Character::process_items() break; } item &it = inv.find_item( index ); - ch_UPS_used++; - it.charges++; + ch_UPS_used += 1_kJ; + it.mod_energy( 1_kJ ); } if( weapon_active && ch_UPS_used < ch_UPS ) { - ch_UPS_used++; - primary_weapon().charges++; + ch_UPS_used += 1_kJ; + primary_weapon().mod_energy( 1_kJ ); } for( item *worn_item : active_worn_items ) { if( ch_UPS_used >= ch_UPS ) { break; } - ch_UPS_used++; - worn_item->charges++; + ch_UPS_used += 1_kJ; + worn_item->mod_energy( 1_kJ ); } - if( ch_UPS_used > 0 ) { - use_charges( itype_UPS, ch_UPS_used ); + if( ch_UPS_used > 0_J ) { + use_energy( itype_UPS, ch_UPS_used ); } } diff --git a/src/consumption.cpp b/src/consumption.cpp index df3e274cf3dd..95d90ba5a2ab 100644 --- a/src/consumption.cpp +++ b/src/consumption.cpp @@ -832,7 +832,7 @@ bool Character::eat( item &food, bool force ) int charges_used = 0; if( food.type->has_use() ) { if( !food.type->can_use( "PETFOOD" ) ) { - charges_used = food.type->invoke( *this->as_player(), food, pos() ); + charges_used = food.type->invoke( *this->as_player(), food, pos() ).first; if( charges_used <= 0 ) { return false; } @@ -1642,7 +1642,7 @@ bool Character::consume_med( item &target ) int amount_used = 1; if( target.type->has_use() ) { - amount_used = target.type->invoke( *this->as_player(), target, pos() ); + amount_used = target.type->invoke( *this->as_player(), target, pos() ).first; if( amount_used <= 0 ) { return false; } diff --git a/src/distribution_grid.cpp b/src/distribution_grid.cpp index 07a5c2400667..08c51f251882 100644 --- a/src/distribution_grid.cpp +++ b/src/distribution_grid.cpp @@ -70,20 +70,20 @@ void distribution_grid::update( time_point to ) #include "vehicle.h" #include "vehicle_part.h" static itype_id itype_battery( "battery" ); -int distribution_grid::mod_resource( int amt, bool recurse ) +units::energy distribution_grid::mod_resource( units::energy amt, bool recurse ) { std::vector connected_vehicles; for( const auto &c : contents ) { for( const tile_location &loc : c.second ) { battery_tile *battery = active_tiles::furn_at( loc.absolute ); if( battery != nullptr ) { - int amt_before_battery = amt; + units::energy amt_before_battery = amt; amt = battery->mod_resource( amt ); if( cached_amount_here ) { cached_amount_here = *cached_amount_here + amt_before_battery - amt; } - if( amt == 0 ) { - return 0; + if( amt == 0_J ) { + return 0_J; } continue; } @@ -109,7 +109,7 @@ int distribution_grid::mod_resource( int amt, bool recurse ) // TODO: Giga ugly. We only charge the first vehicle to get it to use its recursive graph traversal because it's inaccessible from here due to being a template method if( !connected_vehicles.empty() ) { - if( amt > 0 ) { + if( amt > 0_J ) { amt = connected_vehicles.front()->charge_battery( amt, true ); } else { amt = -connected_vehicles.front()->discharge_battery( -amt, true ); @@ -119,16 +119,16 @@ int distribution_grid::mod_resource( int amt, bool recurse ) return amt; } -int distribution_grid::get_resource( bool recurse ) const +units::energy distribution_grid::get_resource( bool recurse ) const { if( !recurse ) { if( cached_amount_here ) { return *cached_amount_here; } else { - cached_amount_here = 0; + cached_amount_here = 0_J; } } - int res = 0; + units::energy res = 0_J; std::vector connected_vehicles; for( const auto &c : contents ) { for( const tile_location &loc : c.second ) { diff --git a/src/distribution_grid.h b/src/distribution_grid.h index da77172da01f..656d9a9df5ff 100644 --- a/src/distribution_grid.h +++ b/src/distribution_grid.h @@ -46,7 +46,7 @@ class distribution_grid std::vector flat_contents; std::vector submap_coords; - mutable std::optional cached_amount_here; + mutable std::optional cached_amount_here; mapbuffer &mb; @@ -55,8 +55,8 @@ class distribution_grid bool empty() const; explicit operator bool() const; void update( time_point to ); - int mod_resource( int amt, bool recurse = true ); - int get_resource( bool recurse = true ) const; + units::energy mod_resource( units::energy amt, bool recurse = true ); + units::energy get_resource( bool recurse = true ) const; const std::vector &get_contents() const { return flat_contents; } diff --git a/src/game.cpp b/src/game.cpp index 4a67ed18ea62..d16340af8e1e 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -8947,11 +8947,11 @@ bool game::walk_move( const tripoint &dest_loc, const bool via_ramp ) const double encumb_moves = u.get_weight() / 4800.0_gram; u.moves -= static_cast( std::ceil( base_moves + encumb_moves ) ); if( u.movement_mode_is( CMM_WALK ) ) { - crit->use_mech_power( -2 ); + crit->use_mech_power( -2_kJ ); } else if( u.movement_mode_is( CMM_CROUCH ) ) { - crit->use_mech_power( -1 ); + crit->use_mech_power( -1_kJ ); } else if( u.movement_mode_is( CMM_RUN ) ) { - crit->use_mech_power( -3 ); + crit->use_mech_power( -3_kJ ); } } else { u.moves -= u.run_cost( mcost, diag ); @@ -10336,13 +10336,13 @@ void game::vertical_move( int movez, bool force, bool peeking ) if( u.is_mounted() ) { monster *crit = u.mounted_creature.get(); if( crit->has_flag( MF_RIDEABLE_MECH ) ) { - crit->use_mech_power( -1 ); + crit->use_mech_power( -1_kJ ); if( u.movement_mode_is( CMM_WALK ) ) { - crit->use_mech_power( -2 ); + crit->use_mech_power( -2_kJ ); } else if( u.movement_mode_is( CMM_CROUCH ) ) { - crit->use_mech_power( -1 ); + crit->use_mech_power( -1_kJ ); } else if( u.movement_mode_is( CMM_RUN ) ) { - crit->use_mech_power( -3 ); + crit->use_mech_power( -3_kJ ); } } } else { diff --git a/src/generic_readers.h b/src/generic_readers.h index ffc230809716..86fbe760c7df 100644 --- a/src/generic_readers.h +++ b/src/generic_readers.h @@ -368,6 +368,14 @@ class temperature_reader : public unit_reader {} }; +class energy_reader : public unit_reader +{ + public: + energy_reader() + : unit_reader( units::energy_units ) + {} +}; + /** * Uses a map (unordered or standard) to convert strings from JSON to some other type * (the mapped type of the map: `C::mapped_type`). It works for all mapped types, not just enums. diff --git a/src/handle_action.cpp b/src/handle_action.cpp index 8b4c94fb2565..4bffa21c8be2 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -728,7 +728,7 @@ static void smash() if( u.is_mounted() ) { monster *crit = u.mounted_creature.get(); if( crit->has_flag( MF_RIDEABLE_MECH ) ) { - crit->use_mech_power( -3 ); + crit->use_mech_power( -3_kJ ); } } for( std::pair &fd_to_smsh : here.field_at( smashp ) ) { @@ -1034,7 +1034,7 @@ static void sleep() std::vector active; for( auto &it : u.inv_dump() ) { if( it->has_flag( flag_LITCIG ) || - ( it->is_active() && ( it->charges > 0 || it->units_remaining( u ) > 0 ) && it->is_tool() && + ( it->is_active() && ( it->charges > 0 || it->units_remaining() > 0 ) && it->is_tool() && !it->has_flag( flag_SLEEP_IGNORE ) ) ) { active.push_back( it->tname() ); } diff --git a/src/iexamine.cpp b/src/iexamine.cpp index 783c85d4230c..b66eb486b76a 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -2951,8 +2951,9 @@ void iexamine::fireplace( player &p, const tripoint &examp ) p.add_msg_if_player( _( "You attempt to start a fire with your %s…" ), it->tname() ); const ret_val can_use = actor->can_use( p, *it, false, examp ); if( can_use.success() ) { - const int charges = actor->use( p, *it, false, examp ); - p.use_charges( it->typeId(), charges ); + const auto [chrg, enrg] = actor->use( p, *it, false, examp ); + it->energy_consume( enrg, examp ); + p.use_charges( it->typeId(), chrg ); return; } else { p.add_msg_if_player( m_bad, can_use.str() ); diff --git a/src/item.cpp b/src/item.cpp index 2ca4d822ce2e..beeaf3921118 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -277,22 +277,23 @@ item::item() : contents( this ), charges = 0; } -item::item( const itype *type, time_point turn, int qty ) : type( type ), - contents( this ), +item::item( const itype *type, time_point turn, const int charge, + const units::energy power ) : type( type ), contents( this ), components( new component_item_location( this ) ), bday( turn ) { corpse = has_flag( flag_CORPSE ) ? &mtype_id::NULL_ID().obj() : nullptr; item_counter = type->countdown_interval; - if( qty >= 0 ) { - charges = qty; + if( charge >= 0 ) { + charges = charge; } else { - if( type->tool && type->tool->rand_charges.size() > 1 ) { - const int charge_roll = rng( 1, type->tool->rand_charges.size() - 1 ); - charges = rng( type->tool->rand_charges[charge_roll - 1], type->tool->rand_charges[charge_roll] ); - } else { - charges = type->charges_default(); - } + charges = type->charges_default(); + } + + if( power >= 0_kJ ) { + energy = power; + } else if( is_battery() && type->battery->def_energy > 0_kJ ) { + energy = type->battery->def_energy; } if( has_flag( flag_NANOFAB_TEMPLATE ) ) { @@ -302,12 +303,12 @@ item::item( const itype *type, time_point turn, int qty ) : type( type ), if( type->gun ) { for( const itype_id &mod : type->gun->built_in_mods ) { - detached_ptr it = item::spawn( mod, turn, qty ); + detached_ptr it = item::spawn( mod, turn, charge ); it->set_flag( flag_IRREMOVABLE ); put_in( std::move( it ) ); } for( const itype_id &mod : type->gun->default_mods ) { - put_in( item::spawn( mod, turn, qty ) ); + put_in( item::spawn( mod, turn, charge ) ); } } else if( type->magazine ) { @@ -339,14 +340,8 @@ item::item( const itype *type, time_point turn, int qty ) : type( type ), } } -item::item( const itype_id &id, time_point turn, int qty ) - : item( & * id, turn, qty ) {} - -item::item( const itype *type, time_point turn, default_charges_tag ) - : item( type, turn, type->charges_default() ) {} - -item::item( const itype_id &id, time_point turn, default_charges_tag tag ) - : item( & * id, turn, tag ) {} +item::item( const itype_id &id, time_point turn, int charge, units::energy power ) + : item( & * id, turn, charge, power ) {} item::item( const itype *type, time_point turn, solitary_tag ) : item( type, turn, type->count_by_charges() ? 1 : -1 ) {} @@ -618,22 +613,36 @@ bool item::revert( const Character *ch, bool alert ) return true; } -units::energy item::mod_energy( const units::energy &qty ) +void item::set_energy( const units::energy &qty ) { - if( !is_battery() ) { - debugmsg( "Tried to set energy of non-battery item" ); - return 0_J; + if( !is_battery() && !is_gun() && !is_tool() ) { + debugmsg( "Tried to set energy of non-battery, non-gun, non-tool item" ); + return; + } + if( qty < 0_J ) { + debugmsg( "Tried to set energy of item to negative value" ); + return; + } + energy = qty; + return; +} + +void item::mod_energy( const units::energy &qty ) +{ + if( !is_battery() && !is_gun() && !is_tool() ) { + debugmsg( "Tried to set energy of non-battery, non-gun, non-tool item" ); + return; } units::energy val = energy_remaining() + qty; if( val < 0_J ) { - return val; - } else if( val > type->battery->max_capacity ) { - energy = type->battery->max_capacity; + energy = 0_J; + } else if( val > energy_capacity() ) { + energy = energy_capacity(); } else { energy = val; } - return 0_J; + return; } void item::ammo_set( const itype_id &ammo, int qty ) @@ -2515,12 +2524,10 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf mod->ammo_data()->nname( mod->ammo_remaining() ) ) ); } - if( mod->get_gun_ups_drain() && parts->test( iteminfo_parts::AMMO_UPSCOST ) ) { + if( mod->get_gun_ups_drain() > 0_J && parts->test( iteminfo_parts::AMMO_UPSCOST ) ) { info.emplace_back( "AMMO", - string_format( vgettext( "Uses %i charge of UPS per shot", - "Uses %i charges of UPS per shot", - mod->get_gun_ups_drain() ), - mod->get_gun_ups_drain() ) ); + string_format( "Uses %s of UPS per shot", + units::display( mod->get_gun_ups_drain() ) ) ); } if( skill.ident() == skill_throw ) { @@ -3163,23 +3170,22 @@ void item::container_info( std::vector &info, const iteminfo_query *pa info.emplace_back( "CONTAINER", container_str ); } -void item::battery_info( std::vector &info, const iteminfo_query * /*parts*/, +void item::battery_info( std::vector &info, const iteminfo_query *parts, int /*batch*/, bool /*debug*/ ) const { if( !is_battery() ) { return; } + insert_separation_line( info ); + + std::string battery_string; - std::string info_string; - if( type->battery->max_capacity < 1_kJ ) { - info_string = string_format( _( "Capacity: %dJ" ), - to_joule( type->battery->max_capacity ) ); - } else if( type->battery->max_capacity >= 1_kJ ) { - info_string = string_format( _( "Capacity: %dkJ" ), - to_kilojoule( type->battery->max_capacity ) ); + if( parts->test( iteminfo_parts::BATTERY_ENERGY ) ) { + battery_string = "Power: " + units::display( energy_remaining() ) + "/" + units::display( + energy_capacity() ); } - insert_separation_line( info ); - info.emplace_back( "BATTERY", info_string ); + + info.emplace_back( "BATTERY", battery_string ); } void item::tool_info( std::vector &info, const iteminfo_query *parts, int /*batch*/, @@ -3190,12 +3196,40 @@ void item::tool_info( std::vector &info, const iteminfo_query *parts, } insert_separation_line( info ); + + if( energy_required() > 0_J && parts->test( iteminfo_parts::TOOL_ENERGYDRAW ) ) { + info.emplace_back( "TOOL", string_format( "Power Draw: %s per turn", + units::display( energy_required() ) ) ); + } + + if( energy_capacity() != 0_J && parts->test( iteminfo_parts::TOOL_ENERGY ) ) { + info.emplace_back( "TOOL", string_format( _( "Power: %s/%s" ), + units::display( energy_remaining() ), units::display( energy_capacity() ) ) ); + } + + if( !type->batteries.empty() && parts->test( iteminfo_parts::TOOL_BATTERIES ) ) { + info.emplace_back( "TOOL", _( "Compatible batteries: " ), + enumerate_as_string( type->batteries.begin(), type->batteries.end(), []( const itype_id & id ) { + return item::nname( id ); + } ) ); + } + + if( ( ( type->tool->charges_per_use > 0 || type->tool->turns_per_charge > 0 ) && + parts->test( iteminfo_parts::TOOL_CHARGEUSAGE ) ) ) { + int charges_per_tick = type->tool->charges_per_use > 0 ? type->tool->charges_per_use : 1; + int tick_length = type->tool->turns_per_charge > 0 ? type->tool->turns_per_charge : 1; + std::string time_string = tick_length == 1 ? _( "turn" ) : string_format( _( "%d turns" ), + tick_length ); + info.emplace_back( "TOOL", string_format( + _( "Charge usage: %d charges every %s" ), charges_per_tick, time_string ) ); + } + if( ammo_capacity() != 0 && parts->test( iteminfo_parts::TOOL_CHARGES ) ) { info.emplace_back( "TOOL", string_format( _( "Charges: %d" ), ammo_remaining() ) ); } - if( !magazine_integral() ) { + if( !type->magazines.empty() ) { if( magazine_current() && parts->test( iteminfo_parts::TOOL_MAGAZINE_CURRENT ) ) { info.emplace_back( "TOOL", _( "Magazine: " ), string_format( "%s", magazine_current()->tname() ) ); @@ -5093,10 +5127,12 @@ std::string item::display_name( unsigned int quantity ) const // A chargeable item amount = charges; max_amount = ammo_capacity(); - } else if( is_battery() ) { - show_amt = true; - amount = to_joule( energy_remaining() ); - max_amount = to_joule( type->battery->max_capacity ); + } + + std::string powertext; + if( energy_capacity() > 0_J ) { + powertext = string_format( " (%s/%s)", units::display( energy_remaining() ), + units::display( energy_capacity() ) ); } std::string ammotext; @@ -5106,26 +5142,27 @@ std::string item::display_name( unsigned int quantity ) const } else { ammotext = ammotype( *ammo_types().begin() )->name(); } + if( !ammotext.empty() ) { + ammotext = " " + ammotext; + } } + std::string chargetext; if( amount || show_amt ) { if( is_money() ) { - amt = string_format( " $%.2f", amount / 100.0 ); + chargetext = string_format( " $%.2f", amount / 100.0 ); } else { - if( !ammotext.empty() ) { - ammotext = " " + ammotext; - } - if( max_amount != 0 ) { - amt = string_format( " (%i/%i%s)", amount, max_amount, ammotext ); + chargetext = string_format( " (%i/%i%s)", amount, max_amount, ammotext ); } else { - amt = string_format( " (%i%s)", amount, ammotext ); + chargetext = string_format( " (%i%s)", amount, ammotext ); } } - } else if( !ammotext.empty() ) { - amt = " (" + ammotext + ")"; } + amt = chargetext.empty() ? string_format( "%s%s", powertext, ammotext ) : string_format( "%s%s", + chargetext, powertext ); + // HACK: This is a hack to prevent possible crashing when displaying maps as items during character creation if( is_map() && calendar::turn != calendar::turn_zero ) { // TODO: fix point types @@ -5400,6 +5437,11 @@ units::volume item::volume( bool integral ) const ret += std::max( magazine_current()->volume() - type->magazine_well, 0_ml ); } + // Some batteries sit (partly) flush with the item so add less extra volume + if( battery_current() != nullptr ) { + ret += std::max( battery_current()->volume() - type->battery_well, 0_ml ); + } + if( is_gun() ) { for( const item *elem : gunmods() ) { ret += elem->volume( true ); @@ -7319,16 +7361,22 @@ bool item::is_reloadable_with( const itype_id &ammo ) const bool item::is_reloadable_helper( const itype_id &ammo, bool now ) const { // empty ammo is passed for listing possible ammo apparently, so it needs to return true. + if( ammo.is_empty() ) { + return true; + } if( !is_reloadable() ) { return false; - } else if( is_watertight_container() ) { - if( ammo.is_empty() ) { - return now ? !is_container_full() : true; - } else if( ammo->phase != LIQUID ) { + } + if( is_container() ) { + if( !ammo->count_by_charges() ) { + return false; + } else if( ammo->phase == LIQUID && !is_watertight_container() ) { return false; } else { return now ? ( is_container_empty() || contents.front().typeId() == ammo ) : true; } + } else if( !type->batteries.empty() ) { + return std::count( type->batteries.begin(), type->batteries.end(), ammo ); } else if( magazine_integral() ) { if( !ammo.is_empty() ) { if( now && ammo_data() ) { @@ -7345,7 +7393,7 @@ bool item::is_reloadable_helper( const itype_id &ammo, bool now ) const } return now ? ( ammo_remaining() < ammo_capacity() ) : true; } else { - return ammo.is_empty() ? true : magazine_compatible().count( ammo ); + return magazine_compatible().count( ammo ); } } @@ -7811,15 +7859,153 @@ int item::gun_range( const player *p ) const return std::max( 0, ret ); } +units::energy item::energy_available( const Character &ch, units::energy limit ) const +{ + units::energy res = energy_remaining(); + + if( limit > res ) { + if( is_power_armor() ) { + if( character_funcs::can_interface_armor( ch ) && has_flag( flag_USE_UPS ) ) { + res += std::max( ch.energy_of( itype_UPS, limit - res ), ch.energy_of( itype_bio_armor, + limit - res ) ); + } else if( character_funcs::can_interface_armor( ch ) ) { + res += ch.energy_of( itype_bio_armor, limit - res ); + } else { + res += ch.energy_of( itype_UPS, limit - res ); + } + } else if( res < limit && has_flag( flag_USE_UPS ) ) { + res += ch.energy_of( itype_UPS, limit - res ); + } + } + + return res; +} + units::energy item::energy_remaining() const { + const item *bat = battery_current(); + + if( bat ) { + return bat->energy_remaining(); + } + + return energy; +} + +units::energy item::energy_capacity() const +{ + const item *mag = battery_current(); + if( mag ) { + return mag->energy_capacity(); + } else if( is_battery() ) { + return type->battery->max_energy; + } else if( is_tool() ) { + units::energy res = type->tool->max_energy; + for( const item *e : toolmods() ) { + } + return res; + } else if( is_gun() ) { + units::energy res = type->gun->capacity; + for( const item *e : gunmods() ) { + } + return res; + } + return 0_J; +} + +units::energy item::energy_required() const +{ + if( is_tool() ) { + return type->tool->energy_draw; + } + if( is_gun() ) { + return type->gun->energy_draw; + } + return 0_J; +} + +bool item::energy_sufficient( const Character &ch, units::energy p_needed ) const +{ + if( p_needed == -1_J ) { + p_needed = energy_required(); + } + if( p_needed == 0_J ) { + return true; + } + return energy_available( ch, p_needed ) >= p_needed; +} + +units::energy item::energy_consume( const units::energy power, const tripoint &pos ) +{ + if( power < 0_J ) { + debugmsg( "Cannot consume negative power for %s", tname() ); + return 0_J; + } + + item *bat = battery_current(); + if( bat ) { + const units::energy res = bat->energy_consume( power, pos ); + if( res > 0_J && energy_remaining() == 0_J ) { + if( bat->has_flag( flag_MAG_DESTROY ) ) { + remove_item( *bat ); + } else if( bat->has_flag( flag_MAG_EJECT ) ) { + get_map().add_item( pos, remove_item( *bat ) ); + } + } + return res; + } + if( is_battery() ) { - return energy; + units::energy need = std::min( energy_remaining(), power ); + mod_energy( -need ); + return power - need; + } else if( is_tool() || is_gun() ) { + if( has_flag( flag_USES_BIONIC_POWER ) ) { + avatar &you = get_avatar(); + units::energy bio_power_used = std::min( power, you.get_power_level() ); + you.mod_power_level( bio_power_used ); + return bio_power_used; + } else if( battery_integral() ) { + units::energy need = std::min( energy_remaining(), power ); + mod_energy( -need ); + return need; + } + } + return 0_J; +} + +units::energy item::energy_recharge( const units::energy power ) +{ + if( power > 0_J ) { + debugmsg( "Cannot charge negative power for %s", tname() ); + return 0_J; + } + + item *bat = battery_current(); + if( bat ) { + const units::energy res = bat->energy_recharge( power ); + return res; } + if( is_battery() || ( ( is_tool() || is_gun() ) && battery_integral() ) ) { + units::energy to_charge = std::min( energy_capacity() - energy_remaining(), power ); + mod_energy( to_charge ); + return to_charge; + } return 0_J; } +bool item::battery_integral() const +{ + // We have an integral magazine if we're a gun or tool with capacity defined. + if( is_gun() && type->gun->capacity > 0_J ) { + return true; + } else if( is_tool() && type->tool->max_energy > 0_J ) { + return true; + } + return false; +} + int item::ammo_remaining() const { const item *mag = magazine_current(); @@ -8174,6 +8360,19 @@ const item *item::magazine_current() const return const_cast( this )->magazine_current(); } +item *item::battery_current() +{ + return contents.get_item_with( + []( const item & it ) { + return it.is_battery(); + } ); +} + +const item *item::battery_current() const +{ + return const_cast( this )->battery_current(); +} + std::vector item::gunmods() { return contents.gunmods(); @@ -8456,36 +8655,27 @@ item *item::get_usable_item( const std::string &use_name ) return const_cast( const_cast( this )->get_usable_item( use_name ) ); } -int item::units_remaining( const Character &ch, int limit ) const +int item::units_remaining( int limit ) const { if( count_by_charges() ) { return std::min( static_cast( charges ), limit ); } int res = ammo_remaining(); - if( res < limit && is_power_armor() ) { - if( character_funcs::can_interface_armor( ch ) && has_flag( flag_USE_UPS ) ) { - res += std::max( ch.charges_of( itype_UPS, limit - res ), ch.charges_of( itype_bio_armor, - limit - res ) ); - } else if( character_funcs::can_interface_armor( ch ) ) { - res += ch.charges_of( itype_bio_armor, limit - res ); - } else { - res += ch.charges_of( itype_UPS, limit - res ); - } - } else if( res < limit && has_flag( flag_USE_UPS ) ) { - res += ch.charges_of( itype_UPS, limit - res ); - } return std::min( res, limit ); } -bool item::units_sufficient( const Character &ch, int qty ) const +bool item::units_sufficient( int qty ) const { if( qty < 0 ) { qty = count_by_charges() ? 1 : ammo_required(); } + if( qty == 0 ) { + return true; + } - return units_remaining( ch, qty ) == qty; + return units_remaining( qty ) == qty; } item_reload_option::item_reload_option( const item_reload_option & ) = default; @@ -8652,7 +8842,7 @@ bool item::reload( player &u, item &loc, int qty ) } ); } else if( !magazine_integral() ) { // if we already have a magazine loaded prompt to eject it - if( magazine_current() ) { + if( ammo->is_magazine() && magazine_current() ) { //~ %1$s: magazine name, %2$s: weapon name std::string prompt = string_format( pgettext( "magazine", "Eject %1$s from %2$s?" ), magazine_current()->tname(), tname() ); @@ -8660,6 +8850,14 @@ bool item::reload( player &u, item &loc, int qty ) if( !u.dispose_item( *magazine_current(), prompt ) ) { return false; } + } else if( ammo->is_battery() && battery_current() ) { + //~ %1$s: magazine name, %2$s: weapon name + std::string prompt = string_format( pgettext( "magazine", "Eject %1$s from %2$s?" ), + battery_current()->tname(), tname() ); + + if( !u.dispose_item( *battery_current(), prompt ) ) { + return false; + } } put_in( ammo->detach() ); @@ -9994,47 +10192,50 @@ detached_ptr item::process_tool( detached_ptr &&self, player *carrie } } - int energy = 0; + int charges_to_use = 0; + bool charge_dependent = charges_to_use; + units::energy energy_to_use = self->energy_required(); + bool energy_dependent = energy_to_use > 0_J; + const bool uses_UPS = self->has_flag( flag_USE_UPS ); bool revert_destroy = false; if( self->type->tool->turns_per_charge > 0 ) { if( self->type->tool->turns_active >= self->type->tool->turns_per_charge ) { - energy = std::max( self->ammo_required(), 1 ); + charges_to_use = std::max( self->ammo_required(), 1 ); self->type->tool->turns_active = 0; } self->type->tool->turns_active += 1; - } else if( self->type->tool->power_draw > 0 ) { - // power_draw in mW / 1000000 to give kJ (battery unit) per second - energy = self->type->tool->power_draw / 1000000; - // energy_bat remainder results in chance at additional charge/discharge - energy += x_in_y( self->type->tool->power_draw % 1000000, 1000000 ) ? 1 : 0; } // If ammo_required is 0 we just skip over this and go to tick processing. - if( energy || self->ammo_required() > 0 ) { + // We check self->ammo_required to trigger revert/consumption code for items with turns_per_charge > 1 + if( charges_to_use || energy_to_use > 0_J || self->ammo_required() > 0 ) { // No need to look for charges if energy is 0 - if( energy ) { - energy -= self->ammo_consume( energy, pos ); - + if( charges_to_use ) { + charges_to_use -= self->ammo_consume( charges_to_use, pos ); + } + if( energy_to_use > 0_J ) { // for power armor pieces, try to use power armor interface first. if( carrier && self->is_power_armor() && character_funcs::can_interface_armor( *carrier ) ) { - if( carrier->use_charges_if_avail( itype_bio_armor, energy ) ) { - energy = 0; + if( carrier->use_energy_if_avail( itype_bio_armor, energy_to_use ) ) { + energy_to_use = 0_J; } } + energy_to_use -= self->energy_consume( energy_to_use, pos ); + // for items in player possession if insufficient charges within tool try UPS if( carrier && uses_UPS ) { - if( carrier->use_charges_if_avail( itype_UPS, energy ) ) { - energy = 0; + if( carrier->use_energy_if_avail( itype_UPS, energy_to_use ) ) { + energy_to_use = 0_J; } } } - // HACK: this means that UPS items will last one more check longer than they should since they don't trigger when - // their ammo_remaining is 0, since that doesn't check the UPS "stock" available (which is an expensive check) // It's done like this cause grenades must be destroyed when charge reaches 0, or it will linger an extra turn. - if( ( self->ammo_remaining() == 0 && !uses_UPS ) || energy > 0 ) { + if( ( charge_dependent && self->ammo_remaining() == 0 ) || + ( energy_dependent && self->energy_available( *carrier ) == 0_J ) || + energy_to_use > 0_J || charges_to_use > 0 ) { revert_destroy = true; if( carrier ) { if( self->is_power_armor() ) { @@ -10168,7 +10369,7 @@ detached_ptr item::process_internal( detached_ptr &&self, player *ca avatar &you = get_avatar(); if( activate ) { - if( self->type->invoke( carrier != nullptr ? *carrier : you, *self, pos ) > 0 ) { + if( self->type->invoke( carrier != nullptr ? *carrier : you, *self, pos ).first > 0 ) { return detached_ptr(); } return std::move( self ); @@ -10394,14 +10595,14 @@ bool item::is_reloadable() const } else if( is_container() ) { return true; - } else if( !is_gun() && !is_tool() && !is_magazine() ) { - return false; + } else if( is_magazine() && !ammo_types().empty() ) { + return true; - } else if( ammo_types().empty() ) { - return false; + } else if( ( is_gun() || is_tool() ) && ( !ammo_types().empty() || !type->batteries.empty() ) ) { + return true; } - return true; + return false; } std::string item::type_name( unsigned int quantity ) const @@ -10487,17 +10688,17 @@ bool item::count_by_charges( const itype_id &id ) return id->count_by_charges(); } -int item::get_gun_ups_drain() const +units::energy item::get_gun_ups_drain() const { - int draincount = 0; + units::energy draincount = 0_J; if( type->gun ) { - int modifier = 0; + units::energy modifier = 0_J; float multiplier = 1.0f; for( const item *mod : gunmods() ) { - modifier += mod->type->gunmod->ups_charges_modifier; + modifier += units::from_kilojoule( mod->type->gunmod->ups_charges_modifier ); multiplier *= mod->type->gunmod->ups_charges_multiplier; } - draincount = ( type->gun->ups_charges * multiplier ) + modifier; + draincount = type->gun->energy_draw * multiplier + modifier; } return draincount; } @@ -10557,7 +10758,7 @@ bool item::on_drop( const tripoint &pos, map &m ) } avatar &you = get_avatar(); you.flag_encumbrance(); - return type->drop_action && type->drop_action.call( you, *this, false, pos ); + return type->drop_action && type->drop_action.call( you, *this, false, pos ).first; } time_duration item::age() const diff --git a/src/item.h b/src/item.h index 67252694294a..1d0bdeeb2416 100644 --- a/src/item.h +++ b/src/item.h @@ -239,14 +239,10 @@ class item : public location_visitable, public game_object item( const item & ); item &operator=( const item & ); - explicit item( const itype_id &id, time_point turn = calendar::turn, int qty = -1 ); - explicit item( const itype *type, time_point turn = calendar::turn, int qty = -1 ); - - /** Suppress randomization and always start with default quantity of charges */ - - struct default_charges_tag {}; - item( const itype_id &id, time_point turn, default_charges_tag ); - item( const itype *type, time_point turn, default_charges_tag ); + explicit item( const itype_id &id, time_point turn = calendar::turn, int charge = -1, + units::energy power = -1_J ); + explicit item( const itype *type, time_point turn = calendar::turn, int charge = -1, + units::energy power = -1_J ); /** Default (or randomized) charges except if counted by charges then only one charge */ @@ -331,16 +327,21 @@ class item : public location_visitable, public game_object */ bool revert( const Character *ch, bool alert = true ); + /** + * Set energy of item. Cannot be negative + * @param qty energy quantity to set + */ + void set_energy( const units::energy &qty ); + /** * Add or remove energy from a battery. * If adding the specified energy quantity would go over the battery's capacity fill * the battery and ignore the remainder. * If adding the specified energy quantity would reduce the battery's charge level - * below 0 do nothing and return how far below 0 it would have gone. + * below 0 set it to 0. * @param qty energy quantity to add (can be negative) - * @return 0 valued energy quantity on success */ - units::energy mod_energy( const units::energy &qty ); + void mod_energy( const units::energy &qty ); /** * Sets the ammo for this instance @@ -1853,8 +1854,46 @@ class item : public location_visitable, public game_object */ bool is_gun() const; - /** Quantity of energy currently loaded in tool or battery */ + /** + * Amount of energy available to a tool including UPS + * if you want only the energy in the tool, use energy_remaining() + */ + units::energy energy_available( const Character &ch, + units::energy p_needed = units::from_joule( INT_MAX ) ) const; + /** + * Amount of energy currently loaded in tool, gun or battery + * For total including UPS use energy_available() + */ units::energy energy_remaining() const; + /** Maximum quantity of energy loadable for tool, gun or battery*/ + units::energy energy_capacity() const; + /** Amount of power consumed per usage of tool or with each shot of gun */ + units::energy energy_required() const; + + /** + * Check that item has sufficient energy + * @param ch Character to check (used if ammo is UPS charges) + * @param uses number of uses, if unspecified use 1x item default + */ + bool energy_sufficient( const Character &ch, units::energy p_needed = -1_J ) const; + + /** + * Consume power(if available) and return the amount of power that was consumed + * @param power maximum amount of power to be consumed. + * @param pos current location of item, not currently used by anything, but required for the overload + * @return amount of power consumed which will be between 0_J and power + */ + units::energy energy_consume( const units::energy power, const tripoint &pos ); + + /** + * Recharge power(if available) and return the amount of power that was recharged + * @param power maximum amount of power to be recharged. + * @return amount of power recharged which will be between 0_J and power + */ + units::energy energy_recharge( const units::energy power ); + + /** Does item have an integral battery (as opposed to allowing detachable batteries) */ + bool battery_integral() const; /** Quantity of ammunition currently loaded in tool, gun or auxiliary gunmod */ int ammo_remaining() const; @@ -1945,6 +1984,13 @@ class item : public location_visitable, public game_object item *magazine_current(); const item *magazine_current() const; + /** Currently loaded battery (if any) + * @return current battery or nullptr if either no battery loaded or item has internal battery + * @see item::battery_integral + */ + item *battery_current(); + const item *battery_current() const; + /** Returns all gunmods currently attached to this item (always empty if item not a gun) */ std::vector gunmods(); std::vector gunmods() const; @@ -2093,18 +2139,16 @@ class item : public location_visitable, public game_object /** * How many units (ammo or charges) are remaining? - * @param ch character responsible for invoking the item * @param limit stop searching after this many units found * @note also checks availability of UPS charges if applicable */ - int units_remaining( const Character &ch, int limit = INT_MAX ) const; + int units_remaining( int limit = INT_MAX ) const; /** * Check if item has sufficient units (ammo or charges) remaining - * @param ch Character to check (used if ammo is UPS charges) * @param qty units required, if unspecified use item default */ - bool units_sufficient( const Character &ch, int qty = -1 ) const; + bool units_sufficient( int qty = -1 ) const; /** * Returns name of deceased being if it had any or empty string if not **/ @@ -2142,7 +2186,7 @@ class item : public location_visitable, public game_object */ bool release_monster( const tripoint &target, int radius = 0 ); /* add the monster at target to this item, despawning it */ - int contain_monster( const tripoint &target ); + std::pair contain_monster( const tripoint &target ); time_duration age() const; void set_age( const time_duration &age ); @@ -2151,7 +2195,7 @@ class item : public location_visitable, public game_object time_point birthday() const; void set_birthday( const time_point &bday ); void handle_pickup_ownership( Character &c ); - int get_gun_ups_drain() const; + units::energy get_gun_ups_drain() const; void validate_ownership() const; inline void set_old_owner( const faction_id &temp_owner ) { old_owner = temp_owner; @@ -2385,7 +2429,7 @@ class item : public location_visitable, public game_object cata::value_ptr relic_data; public: int charges; - units::energy energy; // Amount of energy currently stored in a battery + units::energy energy; int recipe_charges = 1; // The number of charges a recipe creates. int burnt = 0; // How badly we're burnt diff --git a/src/item_factory.cpp b/src/item_factory.cpp index 02b9ca039b08..8a6e7713bd3b 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -363,6 +363,7 @@ void Item_factory::finalize_pre( itype &obj ) if( obj.magazine ) { // ensure default_ammo is set if( obj.magazine->default_ammo.is_null() ) { + std::string name = obj.get_id().c_str(); obj.magazine->default_ammo = ammotype( *obj.magazine->type.begin() )->default_ammotype(); } @@ -839,7 +840,8 @@ class iuse_function_wrapper : public iuse_actor : iuse_actor( type ), cpp_function( f ) { } ~iuse_function_wrapper() override = default; - int use( player &p, item &it, bool a, const tripoint &pos ) const override { + std::pair use( player &p, item &it, bool a, + const tripoint &pos ) const override { return ( *cpp_function )( &p, &it, a, pos ); } std::unique_ptr clone() const override { @@ -954,9 +956,7 @@ void Item_factory::init() add_iuse( "EXTINGUISHER", &iuse::extinguisher ); add_iuse( "EYEDROPS", &iuse::eyedrops ); add_iuse( "FILL_PIT", &iuse::fill_pit ); - add_iuse( "FIRECRACKER", &iuse::firecracker ); add_iuse( "FIRECRACKER_ACT", &iuse::firecracker_act ); - add_iuse( "FIRECRACKER_PACK", &iuse::firecracker_pack ); add_iuse( "FIRECRACKER_PACK_ACT", &iuse::firecracker_pack_act ); add_iuse( "FISH_ROD", &iuse::fishing_rod ); add_iuse( "FISH_TRAP", &iuse::fish_trap ); @@ -1049,7 +1049,6 @@ void Item_factory::init() add_iuse( "STIMPACK", &iuse::stimpack ); add_iuse( "STRONG_ANTIBIOTIC", &iuse::strong_antibiotic ); add_iuse( "TAZER", &iuse::tazer ); - add_iuse( "TAZER2", &iuse::tazer2 ); add_iuse( "TELEPORT", &iuse::teleport ); add_iuse( "THORAZINE", &iuse::thorazine ); add_iuse( "THROWABLE_EXTINGUISHER_ACT", &iuse::throwable_extinguisher_act ); @@ -1089,8 +1088,6 @@ void Item_factory::init() add_actor( std::make_unique() ); add_actor( std::make_unique() ); add_actor( std::make_unique() ); - add_actor( std::make_unique() ); - add_actor( std::make_unique() ); add_actor( std::make_unique() ); add_actor( std::make_unique() ); add_actor( std::make_unique() ); @@ -1329,8 +1326,8 @@ void Item_factory::check_definitions() const } } if( type->battery ) { - if( type->battery->max_capacity < 0_J ) { - msg += "battery cannot have negative maximum charge\n"; + if( type->battery->max_energy < 0_J ) { + msg += "battery cannot have negative maximum power\n"; } } if( type->gun ) { @@ -1881,7 +1878,7 @@ void Item_factory::load( islot_gun &slot, const JsonObject &jo, const std::strin assign( jo, "barrel_length", slot.barrel_length, strict, 0_ml ); assign( jo, "built_in_mods", slot.built_in_mods, strict ); assign( jo, "default_mods", slot.default_mods, strict ); - assign( jo, "ups_charges", slot.ups_charges, strict, 0 ); + assign( jo, "power_draw", slot.energy_draw, strict, 0_J ); assign( jo, "blackpowder_tolerance", slot.blackpowder_tolerance, strict, 0 ); assign( jo, "min_cycle_recoil", slot.min_cycle_recoil, strict, 0 ); assign( jo, "ammo_effects", slot.ammo_effects, strict ); @@ -2084,24 +2081,17 @@ void Item_factory::load( islot_tool &slot, const JsonObject &jo, const std::stri assign( jo, "charges_per_use", slot.charges_per_use, strict, 0 ); assign( jo, "charge_factor", slot.charge_factor, strict, 1 ); assign( jo, "turns_per_charge", slot.turns_per_charge, strict, 0 ); - assign( jo, "power_draw", slot.power_draw, strict, 0 ); + + assign( jo, "max_power", slot.max_energy, strict, 0_kJ ); + assign( jo, "initial_power", slot.def_energy, strict, 0_kJ ); + assign( jo, "power_draw", slot.energy_draw, strict, 0_kJ ); + assign( jo, "revert_to", slot.revert_to, strict ); assign( jo, "revert_msg", slot.revert_msg, strict ); assign( jo, "sub", slot.subtype, strict ); if( jo.has_array( "rand_charges" ) ) { - if( jo.has_member( "initial_charges" ) ) { - jo.throw_error( "You can have a fixed initial amount of charges, or randomized. Not both.", - "rand_charges" ); - } - for( const int charge : jo.get_array( "rand_charges" ) ) { - slot.rand_charges.push_back( charge ); - } - if( slot.rand_charges.size() == 1 ) { - // see item::item(...) for the use of this array - jo.throw_error( "a rand_charges array with only one entry will be ignored, it needs at least 2 entries!", - "rand_charges" ); - } + jo.throw_error( "rand_charges is deprecated, and should be handled directly at mapgen/profession." ); } } @@ -2452,17 +2442,33 @@ void Item_factory::load_magazine( const JsonObject &jo, const std::string &src ) } } -void Item_factory::load( islot_battery &slot, const JsonObject &jo, const std::string & ) +void islot_battery::load( const JsonObject &jo ) { - slot.max_capacity = read_from_json_string( *jo.get_raw( "max_capacity" ), - units::energy_units ); + mandatory( jo, was_loaded, "max_power", max_energy, energy_reader() ); + optional( jo, was_loaded, "initial_power", def_energy, energy_reader(), max_energy ); +} + +void islot_battery::deserialize( JsonIn &jsin ) +{ + const JsonObject jo = jsin.get_object(); + load( jo ); } void Item_factory::load_battery( const JsonObject &jo, const std::string &src ) { itype def; if( load_definition( jo, src, def ) ) { - load_slot( def.battery, jo, src ); + if( def.was_loaded ) { + if( def.battery ) { + def.battery->was_loaded = true; + } else { + def.battery = cata::make_value(); + def.battery->was_loaded = true; + } + } else { + def.battery = cata::make_value(); + } + def.battery->load( jo ); load_basic_info( jo, def, src ); } } @@ -2608,6 +2614,7 @@ void Item_factory::load_basic_info( const JsonObject &jo, itype &def, const std: assign( jo, "min_perception", def.min_per ); assign( jo, "emits", def.emits ); assign( jo, "magazine_well", def.magazine_well ); + assign( jo, "battery_well", def.battery_well ); assign( jo, "explode_in_fire", def.explode_in_fire ); assign( jo, "solar_efficiency", def.solar_efficiency ); assign( jo, "ascii_picture", def.picture_id ); @@ -2737,6 +2744,13 @@ void Item_factory::load_basic_info( const JsonObject &jo, itype &def, const std: } } + bool assigned_batteries = assign( jo, "batteries", def.batteries ); + if( assigned_batteries ) { + def.batteries.erase( std::unique( def.batteries.begin(), def.batteries.end() ), + def.batteries.end() ); + def.battery_default = def.batteries[0]; + } + JsonArray jarr = jo.get_array( "min_skills" ); if( !jarr.empty() ) { def.min_skills.clear(); diff --git a/src/item_functions.cpp b/src/item_functions.cpp index 80d6ce6a2a09..8d67a83fc19e 100644 --- a/src/item_functions.cpp +++ b/src/item_functions.cpp @@ -24,7 +24,7 @@ bool can_be_unloaded( const item &itm ) return false; } - if( itm.magazine_current() ) { + if( itm.magazine_current() || itm.battery_current() ) { return true; } @@ -49,13 +49,13 @@ int shots_remaining( const Character &who, const item &it ) } int ammo_drain = it.ammo_required(); - int energy_drain = it.get_gun_ups_drain(); - int power = who.charges_of( itype_UPS ); + units::energy energy_drain = it.get_gun_ups_drain(); + units::energy power = who.energy_of( itype_UPS ); - if( ammo_drain > 0 && energy_drain > 0 ) { + if( ammo_drain > 0 && energy_drain > 0_J ) { // Both UPS and ammo, lower is limiting. return std::min( it.ammo_remaining() / ammo_drain, power / energy_drain ); - } else if( energy_drain > 0 ) { + } else if( energy_drain > 0_J ) { //Only one of the two, it is limiting. return power / energy_drain; } else if( ammo_drain > 0 ) { diff --git a/src/item_group.cpp b/src/item_group.cpp index f35ea0a4c437..a8f847dbc32c 100644 --- a/src/item_group.cpp +++ b/src/item_group.cpp @@ -341,7 +341,7 @@ detached_ptr Item_modifier::modify( detached_ptr &&new_item ) const if( new_item->is_tool() || new_item->is_gun() || new_item->is_magazine() ) { bool spawn_ammo = rng( 0, 99 ) < with_ammo && new_item->ammo_remaining() == 0 && ch == -1 && - ( !new_item->is_tool() || new_item->type->tool->rand_charges.empty() ); + ( !new_item->is_tool() ); bool spawn_mag = rng( 0, 99 ) < with_magazine && !new_item->magazine_current() && new_item->magazine_default() != itype_id::NULL_ID(); diff --git a/src/iteminfo_query.h b/src/iteminfo_query.h index f21122359714..3ad91a17d70d 100644 --- a/src/iteminfo_query.h +++ b/src/iteminfo_query.h @@ -153,6 +153,12 @@ enum class iteminfo_parts : size_t { CONTAINER_DETAILS, + BATTERY_ENERGY, + + TOOL_ENERGYDRAW, + TOOL_ENERGY, + TOOL_BATTERIES, + TOOL_CHARGEUSAGE, TOOL_CHARGES, TOOL_MAGAZINE_CURRENT, TOOL_MAGAZINE_COMPATIBLE, diff --git a/src/itype.cpp b/src/itype.cpp index 9c7adc90522f..d7e739f03863 100644 --- a/src/itype.cpp +++ b/src/itype.cpp @@ -176,28 +176,29 @@ void itype::tick( player &p, item &it, const tripoint &pos ) const } } -int itype::invoke( player &p, item &it, const tripoint &pos ) const +std::pair itype::invoke( player &p, item &it, const tripoint &pos ) const { if( !has_use() ) { - return 0; + return std::make_pair( 0, 0_J ); } return invoke( p, it, pos, use_methods.begin()->first ); } -int itype::invoke( player &p, item &it, const tripoint &pos, const std::string &iuse_name ) const +std::pair itype::invoke( player &p, item &it, const tripoint &pos, + const std::string &iuse_name ) const { const use_function *use = get_use( iuse_name ); if( use == nullptr ) { debugmsg( "Tried to invoke %s on a %s, which doesn't have this use_function", iuse_name, nname( 1 ) ); - return 0; + return std::make_pair( 0, 0_J ); } const auto ret = use->can_call( p, it, false, pos ); if( !ret.success() ) { p.add_msg_if_player( m_info, ret.str() ); - return 0; + return std::make_pair( 0, 0_J ); } // used for grenades and such, to increase kill count // invoke is called a first time with transform, when the explosive item is activated diff --git a/src/itype.h b/src/itype.h index 5bd78050e944..c1ea0a284582 100644 --- a/src/itype.h +++ b/src/itype.h @@ -97,6 +97,7 @@ class gunmod_location }; struct islot_tool { + bool was_loaded; std::set ammo_id; std::optional revert_to; @@ -110,9 +111,10 @@ struct islot_tool { int charges_per_use = 0; int turns_per_charge = 0; int turns_active = 0; - int power_draw = 0; - std::vector rand_charges; + units::energy max_energy = 0_kJ; + units::energy def_energy = 0_kJ; + units::energy energy_draw = 0_kJ; }; struct islot_comestible { @@ -513,10 +515,13 @@ struct islot_gun : common_ranged_data { /** Modifies base loudness as provided by the currently loaded ammo */ int loudness = 0; + /** For guns with integral battery what is the capacity */ + units::energy capacity = 0_J; /** - * If this uses UPS charges, how many (per shoot), 0 for no UPS charges at all. + * If this uses energy, how much (per shot), 0_J for no UPS charges at all. */ - int ups_charges = 0; + units::energy energy_draw = 0_J; + /** * One in X chance for gun to require major cleanup after firing blackpowder shot. */ @@ -656,8 +661,13 @@ struct islot_magazine { }; struct islot_battery { - /** Maximum energy the battery can store */ - units::energy max_capacity; + bool was_loaded; + + units::energy max_energy = 0_kJ; + units::energy def_energy = 0_kJ; + + void load( const JsonObject &jo ); + void deserialize( JsonIn &jsin ); }; struct islot_ammo : common_ranged_data { @@ -1033,6 +1043,15 @@ struct itype { /** Volume above which the magazine starts to protrude from the item and add extra volume */ units::volume magazine_well = 0_ml; + /** Batteries (if any) that can be used to reload this item */ + std::vector batteries; + + /** Default battery that can be used to reload this item */ + itype_id battery_default; + + /** Volume above which the battery starts to protrude from the item and add extra volume */ + units::volume battery_well = 0_ml; + layer_level layer = layer_level::MAX_CLOTHING_LAYER; /** @@ -1080,8 +1099,10 @@ struct itype { const use_function *get_use( const std::string &iuse_name ) const; // Here "invoke" means "actively use". "Tick" means "active item working" - int invoke( player &p, item &it, const tripoint &pos ) const; // Picks first method or returns 0 - int invoke( player &p, item &it, const tripoint &pos, const std::string &iuse_name ) const; + // Picks first method or returns 0 + std::pair invoke( player &p, item &it, const tripoint &pos ) const; + std::pair invoke( player &p, item &it, const tripoint &pos, + const std::string &iuse_name ) const; void tick( player &p, item &it, const tripoint &pos ) const; bool is_fuel() const; diff --git a/src/iuse.cpp b/src/iuse.cpp index 43a210b89f25..44d5e391e89e 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -471,10 +471,11 @@ static bool check_litcig( player &u ) * Regardless, returning 0 indicates the item has not been used up, * though it may have been successfully activated. */ -int iuse::sewage( player *p, item *it, bool, const tripoint & ) +std::pair iuse::sewage( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( !p->query_yn( _( "Are you sure you want to drink… this?" ) ) ) { - return 0; + return std::make_pair( 0, 0_J ); } g->events().send(); @@ -482,20 +483,22 @@ int iuse::sewage( player *p, item *it, bool, const tripoint & ) if( one_in( 4 ) ) { p->mutate(); } - return it->type->charges_to_use(); + return res; } -int iuse::honeycomb( player *p, item *it, bool, const tripoint & ) +std::pair iuse::honeycomb( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); g->m.spawn_item( p->pos(), itype_wax, 2 ); - return it->type->charges_to_use(); + return res; } -int iuse::xanax( player *p, item *it, bool, const tripoint & ) +std::pair iuse::xanax( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); p->add_msg_if_player( _( "You take some %s." ), it->tname() ); p->add_effect( effect_took_xanax, 90_minutes ); - return it->type->charges_to_use(); + return res; } static constexpr time_duration alc_strength( const int strength, const time_duration &weak, @@ -527,19 +530,19 @@ static int alcohol( player &p, const item &it, const int strength ) return it.type->charges_to_use(); } -int iuse::alcohol_weak( player *p, item *it, bool, const tripoint & ) +std::pair iuse::alcohol_weak( player *p, item *it, bool, const tripoint & ) { - return alcohol( *p, *it, 0 ); + return std::make_pair( alcohol( *p, *it, 0 ), 0_J ); } -int iuse::alcohol_medium( player *p, item *it, bool, const tripoint & ) +std::pair iuse::alcohol_medium( player *p, item *it, bool, const tripoint & ) { - return alcohol( *p, *it, 1 ); + return std::make_pair( alcohol( *p, *it, 1 ), 0_J ); } -int iuse::alcohol_strong( player *p, item *it, bool, const tripoint & ) +std::pair iuse::alcohol_strong( player *p, item *it, bool, const tripoint & ) { - return alcohol( *p, *it, 2 ); + return std::make_pair( alcohol( *p, *it, 2 ), 0_J ); } /** @@ -550,18 +553,19 @@ int iuse::alcohol_strong( player *p, item *it, bool, const tripoint & ) * @param it the item to be smoked. * @return Charges used in item smoked */ -int iuse::smoking( player *p, item *it, bool, const tripoint & ) +std::pair iuse::smoking( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); bool hasFire = ( p->has_charges( itype_fire, 1 ) ); // make sure we're not already smoking something if( !check_litcig( *p ) ) { - return 0; + return std::make_pair( 0, 0_J ); } if( !hasFire ) { p->add_msg_if_player( m_info, _( "You don't have anything to light it with!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } detached_ptr cig; @@ -594,7 +598,7 @@ int iuse::smoking( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_bad, _( "Please let the devs know you should be able to smoke a %s but the smoking code does not know how." ), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } // If we're here, we better have a cig to light. p->use_charges_if_avail( itype_fire, 1 ); @@ -614,11 +618,12 @@ int iuse::smoking( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_bad, _( "Ugh, too much smoke… you feel nasty." ) ); } - return it->type->charges_to_use(); + return res; } -int iuse::ecig( player *p, item *it, bool, const tripoint & ) +std::pair iuse::ecig( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( it->typeId() == itype_ecig ) { p->add_msg_if_player( m_neutral, _( "You take a puff from your electronic cigarette." ) ); } else if( it->typeId() == itype_advanced_ecig ) { @@ -630,7 +635,7 @@ int iuse::ecig( player *p, item *it, bool, const tripoint & ) p->consume_effects( *dummy_ecig ); } else { p->add_msg_if_player( m_info, _( "You don't have any nicotine liquid!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } } @@ -641,11 +646,12 @@ int iuse::ecig( player *p, item *it, bool, const tripoint & ) add_type::CIG ) + 1 ) ) { p->add_msg_if_player( m_bad, _( "Ugh, too much nicotine… you feel nasty." ) ); } - return it->type->charges_to_use(); + return res; } -int iuse::antibiotic( player *p, item *it, bool, const tripoint & ) +std::pair iuse::antibiotic( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); p->add_msg_player_or_npc( m_neutral, _( "You take some antibiotics." ), _( " takes some antibiotics." ) ); @@ -654,18 +660,19 @@ int iuse::antibiotic( player *p, item *it, bool, const tripoint & ) _( "Maybe just placebo effect, but you feel a little better as the dose settles in." ) ); } p->add_effect( effect_antibiotic, 12_hours ); - return it->type->charges_to_use(); + return res; } -int iuse::eyedrops( player *p, item *it, bool, const tripoint & ) +std::pair iuse::eyedrops( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( it->charges < it->type->charges_to_use() ) { p->add_msg_if_player( _( "You're out of %s." ), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } p->add_msg_if_player( _( "You use your %s." ), it->tname() ); p->moves -= to_moves( 10_seconds ); @@ -673,21 +680,22 @@ int iuse::eyedrops( player *p, item *it, bool, const tripoint & ) p->remove_effect( effect_boomered ); p->add_msg_if_player( m_good, _( "You wash the slime from your eyes." ) ); } - return it->type->charges_to_use(); + return res; } -int iuse::fungicide( player *p, item *it, bool, const tripoint & ) +std::pair iuse::fungicide( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const bool has_fungus = p->has_effect( effect_fungus ); const bool has_spores = p->has_effect( effect_spores ); if( p->is_npc() && !has_fungus && !has_spores ) { - return 0; + return std::make_pair( 0, 0_J ); } p->add_msg_player_or_npc( _( "You use your fungicide." ), _( " uses some fungicide" ) ); @@ -728,14 +736,15 @@ int iuse::fungicide( player *p, item *it, bool, const tripoint & ) } } } - return it->type->charges_to_use(); + return res; } -int iuse::antifungal( player *p, item *it, bool, const tripoint & ) +std::pair iuse::antifungal( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } p->add_msg_if_player( _( "You take some antifungal medication." ) ); if( p->has_effect( effect_fungus ) ) { @@ -748,14 +757,15 @@ int iuse::antifungal( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_warning, _( "Your skin grows warm for a moment." ) ); } } - return it->type->charges_to_use(); + return res; } -int iuse::antiparasitic( player *p, item *it, bool, const tripoint & ) +std::pair iuse::antiparasitic( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } p->add_msg_if_player( _( "You take some antiparasitic medication." ) ); if( p->has_effect( effect_dermatik ) ) { @@ -793,11 +803,12 @@ int iuse::antiparasitic( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_good, _( "The pain in your joints goes away." ) ); } } - return it->type->charges_to_use(); + return res; } -int iuse::anticonvulsant( player *p, item *it, bool, const tripoint & ) +std::pair iuse::anticonvulsant( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); p->add_msg_if_player( _( "You take some anticonvulsant medication." ) ); /** @EFFECT_STR reduces duration of anticonvulsant medication */ time_duration duration = 8_hours - p->str_cur * rng( 0_turns, 10_minutes ); @@ -812,11 +823,12 @@ int iuse::anticonvulsant( player *p, item *it, bool, const tripoint & ) p->remove_effect( effect_shakes ); p->add_msg_if_player( m_good, _( "You stop shaking." ) ); } - return it->type->charges_to_use(); + return res; } -int iuse::weed_cake( player *p, item *it, bool, const tripoint & ) +std::pair iuse::weed_cake( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); p->add_msg_if_player( _( "You start scarfing down the delicious cake. It tastes a little funny though…" ) ); time_duration duration = 12_minutes; @@ -836,11 +848,12 @@ int iuse::weed_cake( player *p, item *it, bool, const tripoint & ) if( one_in( 5 ) ) { weed_msg( *p ); } - return it->type->charges_to_use(); + return res; } -int iuse::meth( player *p, item *it, bool, const tripoint & ) +std::pair iuse::meth( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); /** @EFFECT_STR reduces duration of meth */ time_duration duration = 1_minutes * ( 60 - p->str_cur ); if( p->has_amount( itype_apparatus, 1 ) && p->use_charges_if_avail( itype_fire, 1 ) ) { @@ -873,31 +886,34 @@ int iuse::meth( player *p, item *it, bool, const tripoint & ) } p->add_effect( effect_meth, duration ); } - return it->type->charges_to_use(); + return res; } -int iuse::vaccine( player *p, item *it, bool, const tripoint & ) +std::pair iuse::vaccine( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); p->add_msg_if_player( _( "You inject the vaccine." ) ); p->add_msg_if_player( m_good, _( "You feel tough." ) ); p->mod_healthy_mod( 200, 200 ); p->mod_pain( 3 ); p->i_add( item::spawn( "syringe", it->birthday() ) ); - return it->type->charges_to_use(); + return res; } -int iuse::antiasthmatic( player *p, item *it, bool, const tripoint & ) +std::pair iuse::antiasthmatic( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); p->add_msg_if_player( m_good, _( "You no longer need to worry about asthma attacks, at least for a while." ) ); p->add_effect( effect_took_antiasthmatic, 1_days, bodypart_str_id::NULL_ID() ); - return it->type->charges_to_use(); + return res; } -int iuse::poison( player *p, item *it, bool, const tripoint & ) +std::pair iuse::poison( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( ( p->has_trait( trait_EATDEAD ) ) ) { - return it->type->charges_to_use(); + return res; } // NPCs have a magical sense of what is inedible @@ -905,24 +921,25 @@ int iuse::poison( player *p, item *it, bool, const tripoint & ) if( !it->has_flag( flag_HIDDEN_POISON ) && ( p->is_npc() || !p->query_yn( _( "Are you sure you want to eat this? It looks poisonous…" ) ) ) ) { - return 0; + return std::make_pair( 0, 0_J ); } if( !p->has_trait( trait_POISRESIST ) ) { p->add_effect( effect_poison, 15_minutes ); } p->add_effect( effect_foodpoison, 3_hours ); - return it->type->charges_to_use(); + return res; } -int iuse::meditate( player *p, item *it, bool t, const tripoint & ) +std::pair iuse::meditate( player *p, item *it, bool t, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( !p || t ) { - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->has_trait( trait_SPIRITUAL ) ) { const int moves = to_moves( 20_minutes ); @@ -931,11 +948,12 @@ int iuse::meditate( player *p, item *it, bool t, const tripoint & ) p->add_msg_if_player( _( "This %s probably meant a lot to someone at one time." ), it->tname() ); } - return it->type->charges_to_use(); + return res; } -int iuse::thorazine( player *p, item *it, bool, const tripoint & ) +std::pair iuse::thorazine( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( p->has_effect( effect_took_thorazine ) ) { p->remove_effect( effect_took_thorazine ); p->mod_fatigue( 15 ); @@ -953,11 +971,12 @@ int iuse::thorazine( player *p, item *it, bool, const tripoint & ) } else { p->add_msg_if_player( m_warning, _( "You feel a bit wobbly." ) ); } - return it->type->charges_to_use(); + return res; } -int iuse::prozac( player *p, item *it, bool, const tripoint & ) +std::pair iuse::prozac( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( !p->has_effect( effect_took_prozac ) ) { p->add_effect( effect_took_prozac, 12_hours ); } else { @@ -967,19 +986,21 @@ int iuse::prozac( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_warning, _( "You suddenly feel hollow inside." ) ); p->add_effect( effect_took_prozac_bad, p->get_effect_dur( effect_took_prozac ) ); } - return it->type->charges_to_use(); + return res; } -int iuse::sleep( player *p, item *it, bool, const tripoint & ) +std::pair iuse::sleep( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); p->add_msg_if_player( m_warning, _( "You feel sleepy…" ) ); - return it->type->charges_to_use(); + return res; } -int iuse::datura( player *p, item *it, bool, const tripoint & ) +std::pair iuse::datura( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( p->is_npc() ) { - return 0; + return std::make_pair( 0, 0_J ); } p->add_effect( effect_datura, rng( 3_hours, 13_hours ) ); @@ -987,26 +1008,29 @@ int iuse::datura( player *p, item *it, bool, const tripoint & ) if( p->has_trait( trait_SPIRITUAL ) ) { p->add_morale( MORALE_FOOD_GOOD, 36, 72, 2_hours, 1_hours, false, it->type ); } - return it->type->charges_to_use(); + return res; } -int iuse::flumed( player *p, item *it, bool, const tripoint & ) +std::pair iuse::flumed( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); p->add_effect( effect_took_flumed, 10_hours ); p->add_msg_if_player( _( "You take some %s" ), it->tname() ); - return it->type->charges_to_use(); + return res; } -int iuse::flusleep( player *p, item *it, bool, const tripoint & ) +std::pair iuse::flusleep( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); p->add_effect( effect_took_flumed, 12_hours ); p->add_msg_if_player( _( "You take some %s" ), it->tname() ); p->add_msg_if_player( m_warning, _( "You feel sleepy…" ) ); - return it->type->charges_to_use(); + return res; } -int iuse::inhaler( player *p, item *it, bool, const tripoint & ) +std::pair iuse::inhaler( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); p->add_msg_player_or_npc( m_neutral, _( "You take a puff from your inhaler." ), _( " takes a puff from their inhaler." ) ); if( !p->remove_effect( effect_asthma ) ) { @@ -1017,11 +1041,12 @@ int iuse::inhaler( player *p, item *it, bool, const tripoint & ) } p->add_effect( effect_took_antiasthmatic, rng( 1_hours, 2_hours ) ); p->remove_effect( effect_smoke ); - return it->type->charges_to_use(); + return res; } -int iuse::oxygen_bottle( player *p, item *it, bool, const tripoint & ) +std::pair iuse::oxygen_bottle( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); p->moves -= to_moves( 10_seconds ); p->add_msg_player_or_npc( m_neutral, string_format( _( "You breathe deeply from the %s" ), it->tname() ), @@ -1038,19 +1063,20 @@ int iuse::oxygen_bottle( player *p, item *it, bool, const tripoint & ) p->mod_painkiller( 2 ); } p->mod_painkiller( 2 ); - return it->type->charges_to_use(); + return res; } -int iuse::blech( player *p, item *it, bool, const tripoint & ) +std::pair iuse::blech( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); // TODO: Add more effects? if( it->made_of( LIQUID ) ) { if( !p->query_yn( _( "This looks unhealthy, sure you want to drink it?" ) ) ) { - return 0; + return std::make_pair( 0, 0_J ); } } else { //Assume that if a blech consumable isn't a drink, it will be eaten. if( !p->query_yn( _( "This looks unhealthy, sure you want to eat it?" ) ) ) { - return 0; + return std::make_pair( 0, 0_J ); } } @@ -1072,27 +1098,30 @@ int iuse::blech( player *p, item *it, bool, const tripoint & ) p->apply_damage( nullptr, bodypart_id( "torso" ), rng( 4, 12 ) ); p->vomit(); } - return it->type->charges_to_use(); + return res; } -int iuse::blech_because_unclean( player *p, item *it, bool, const tripoint & ) +std::pair iuse::blech_because_unclean( player *p, item *it, bool, + const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( !p->is_npc() ) { if( it->made_of( LIQUID ) ) { if( !p->query_yn( _( "This looks unclean, sure you want to drink it?" ) ) ) { - return 0; + return std::make_pair( 0, 0_J ); } } else { //Assume that if a blech consumable isn't a drink, it will be eaten. if( !p->query_yn( _( "This looks unclean, sure you want to eat it?" ) ) ) { - return 0; + return std::make_pair( 0, 0_J ); } } } - return it->type->charges_to_use(); + return res; } -int iuse::plantblech( player *p, item *it, bool, const tripoint &pos ) +std::pair iuse::plantblech( player *p, item *it, bool, const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( p->has_trait( trait_THRESH_PLANT ) ) { double multiplier = -1; if( p->has_trait( trait_CHLOROMORPH ) ) { @@ -1108,17 +1137,18 @@ int iuse::plantblech( player *p, item *it, bool, const tripoint &pos ) p->mod_healthy_mod( it->get_comestible()->healthy * multiplier, it->get_comestible()->healthy * multiplier ); p->add_morale( MORALE_FOOD_GOOD, -10 * multiplier, 60, 1_hours, 30_minutes, false, it->type ); - return it->type->charges_to_use(); + return res; } else { return blech( p, it, true, pos ); } } -int iuse::chew( player *p, item *it, bool, const tripoint & ) +std::pair iuse::chew( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); // TODO: Add more effects? p->add_msg_if_player( _( "You chew your %s." ), it->tname() ); - return it->type->charges_to_use(); + return res; } // Helper to handle the logic of removing some random mutations. @@ -1147,24 +1177,26 @@ static void do_purify( player &p ) } } -int iuse::purifier( player *p, item *it, bool, const tripoint & ) +std::pair iuse::purifier( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); mutagen_attempt checks = mutagen_common_checks( *p, *it, false, mutagen_technique::consumed_purifier ); if( !checks.allowed ) { - return checks.charges_used; + return std::make_pair( checks.charges_used, 0_J ); } do_purify( *p ); - return it->type->charges_to_use(); + return res; } -int iuse::purify_iv( player *p, item *it, bool, const tripoint & ) +std::pair iuse::purify_iv( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); mutagen_attempt checks = mutagen_common_checks( *p, *it, false, mutagen_technique::injected_purifier ); if( !checks.allowed ) { - return checks.charges_used; + return std::make_pair( checks.charges_used, 0_J ); } std::vector valid; // Which flags the player has @@ -1176,7 +1208,7 @@ int iuse::purify_iv( player *p, item *it, bool, const tripoint & ) } if( valid.empty() ) { p->add_msg_if_player( _( "You feel cleansed." ) ); - return it->type->charges_to_use(); + return res; } int num_cured = rng( 4, valid.size() ); //Essentially a double-strength purifier, but guaranteed at least 4. Double-edged and all @@ -1198,15 +1230,16 @@ int iuse::purify_iv( player *p, item *it, bool, const tripoint & ) p->mod_thirst( 2 * num_cured ); p->mod_fatigue( 2 * num_cured ); } - return it->type->charges_to_use(); + return res; } -int iuse::purify_smart( player *p, item *it, bool, const tripoint & ) +std::pair iuse::purify_smart( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); mutagen_attempt checks = mutagen_common_checks( *p, *it, false, mutagen_technique::injected_smart_purifier ); if( !checks.allowed ) { - return checks.charges_used; + return std::make_pair( checks.charges_used, 0_J ); } std::vector valid; // Which flags the player has @@ -1222,12 +1255,12 @@ int iuse::purify_smart( player *p, item *it, bool, const tripoint & ) } if( valid.empty() ) { p->add_msg_if_player( _( "You don't have any mutations to purify." ) ); - return 0; + return std::make_pair( 0, 0_J ); } int mutation_index = uilist( _( "Choose a mutation to purify" ), valid_names ); if( mutation_index < 0 ) { - return 0; + return std::make_pair( 0, 0_J ); } p->add_msg_if_player( @@ -1239,7 +1272,7 @@ int iuse::purify_smart( player *p, item *it, bool, const tripoint & ) p->mod_pain( 3 ); p->i_add( item::spawn( "syringe", it->birthday() ) ); - return it->type->charges_to_use(); + return res; } static void spawn_spores( const player &p ) @@ -1401,51 +1434,55 @@ static bool marloss_prevented( const player &p ) return false; } -int iuse::marloss( player *p, item *it, bool, const tripoint & ) +std::pair iuse::marloss( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( marloss_prevented( *p ) ) { - return 0; + return std::make_pair( 0, 0_J ); } g->events().send( p->getID(), it->typeId() ); marloss_common( *p, *it, trait_MARLOSS ); - return it->type->charges_to_use(); + return res; } -int iuse::marloss_seed( player *p, item *it, bool, const tripoint & ) +std::pair iuse::marloss_seed( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( !query_yn( _( "Sure you want to eat the %s? You could plant it in a mound of dirt." ), colorize( it->tname(), it->color_in_inventory() ) ) ) { - return 0; // Save the seed for later! + return std::make_pair( 0, 0_J ); // Save the seed for later! } if( marloss_prevented( *p ) ) { - return 0; + return std::make_pair( 0, 0_J ); } g->events().send( p->getID(), it->typeId() ); marloss_common( *p, *it, trait_MARLOSS_BLUE ); - return it->type->charges_to_use(); + return res; } -int iuse::marloss_gel( player *p, item *it, bool, const tripoint & ) +std::pair iuse::marloss_gel( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( marloss_prevented( *p ) ) { - return 0; + return std::make_pair( 0, 0_J ); } g->events().send( p->getID(), it->typeId() ); marloss_common( *p, *it, trait_MARLOSS_YELLOW ); - return it->type->charges_to_use(); + return res; } -int iuse::mycus( player *p, item *it, bool t, const tripoint &pos ) +std::pair iuse::mycus( player *p, item *it, bool t, const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( p->is_npc() ) { - return it->type->charges_to_use(); + return res; } // Welcome our guide. Welcome. To. The Mycus. if( p->has_trait( trait_THRESH_MARLOSS ) ) { @@ -1531,21 +1568,22 @@ int iuse::mycus( player *p, item *it, bool t, const tripoint &pos ) p->vomit(); // no hunger/quench benefit for you p->mod_healthy_mod( -8, -50 ); } - return it->type->charges_to_use(); + return res; } -int iuse::petfood( player *p, item *it, bool, const tripoint & ) +std::pair iuse::petfood( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( !it->is_comestible() ) { p->add_msg_if_player( _( "You doubt someone would want to eat % 1$s." ), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } const std::optional pnt_ = choose_adjacent( string_format( _( "Tame which animal with the %s?" ), it->tname() ) ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint pnt = *pnt_; p->moves -= to_moves( 1_seconds ); @@ -1561,16 +1599,16 @@ int iuse::petfood( player *p, item *it, bool, const tripoint & ) person.say( _( "Okay, but please, don't give me this again. I don't want to eat pet food in the cataclysm all day." ) ); p->consume_charges( *it, 1 ); - return 0; + return std::make_pair( 0, 0_J ); } else { p->add_msg_if_player( _( "%s knocks it out from your hand!" ), person.name ); person.make_angry(); p->consume_charges( *it, 1 ); - return 0; + return std::make_pair( 0, 0_J ); } } else { p->add_msg_if_player( _( "Never mind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } } @@ -1582,7 +1620,7 @@ int iuse::petfood( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( _( "You try to feed the %s some %s, but it vanishes!" ), mon.type->nname(), it->tname() ); mon.die( nullptr ); - return 0; + return std::make_pair( 0, 0_J ); } // Feral survivors don't get to tame normal critters. @@ -1591,7 +1629,7 @@ int iuse::petfood( player *p, item *it, bool, const tripoint & ) // can't tame them, and for flavor possibly only allow taming with meat-based items. p->add_msg_if_player( _( "You reach for the %s, but it recoils away from you!" ), mon.type->nname() ); - return 0; + return std::make_pair( 0, 0_J ); } //check to see if the item has a petfood data entry deterimine if the item can be fed to a bet @@ -1611,7 +1649,7 @@ int iuse::petfood( player *p, item *it, bool, const tripoint & ) if( !can_feed ) { p->add_msg_if_player( _( "The %s doesn't want that kind of food." ), mon.type->nname() ); - return 0; + return std::make_pair( 0, 0_J ); } if( mon.type->id == mon_dog_thing ) { @@ -1620,9 +1658,8 @@ int iuse::petfood( player *p, item *it, bool, const tripoint & ) if( one_in( 5 ) ) { p->add_msg_if_player( _( "Apparently it's more interested in your flesh than the pet food in your hand!" ) ); - p->consume_charges( *it, 1 ); - return 0; } + return res; } p->add_msg_if_player( _( "You feed your %1$s to the %2$s." ), it->tname(), mon.get_name() ); @@ -1634,20 +1671,19 @@ int iuse::petfood( player *p, item *it, bool, const tripoint & ) } mon.make_pet(); - p->consume_charges( *it, 1 ); - return 0; + return res; } p->add_msg_if_player( _( "There is nothing to be fed here." ) ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::radio_mod( player *p, item *, bool, const tripoint & ) +std::pair iuse::radio_mod( player *p, item *, bool, const tripoint & ) { if( p->is_npc() ) { // Now THAT would be kinda cruel - return 0; + return std::make_pair( 0, 0_J ); } auto filter = []( const item & itm ) { @@ -1660,7 +1696,7 @@ int iuse::radio_mod( player *p, item *, bool, const tripoint & ) if( !loc ) { p->add_msg_if_player( _( "You do not have that item!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } item &modded = *loc; @@ -1684,12 +1720,12 @@ int iuse::radio_mod( player *p, item *, bool, const tripoint & ) colorname = _( "\"Green\"" ); break; default: - return 0; + return std::make_pair( 0, 0_J ); } if( modded.has_flag( flag_RADIO_MOD ) && modded.has_flag( newtag ) ) { p->add_msg_if_player( _( "This item has been modified this way already." ) ); - return 0; + return std::make_pair( 0, 0_J ); } remove_radio_mod( modded, *p ); @@ -1701,13 +1737,13 @@ int iuse::radio_mod( player *p, item *, bool, const tripoint & ) modded.set_flag( flag_RADIOCARITEM ); modded.set_flag( flag_RADIO_MOD ); modded.set_flag( newtag ); - return 1; + return std::make_pair( 1, 0_J ); } -int iuse::remove_all_mods( player *p, item *, bool, const tripoint & ) +std::pair iuse::remove_all_mods( player *p, item *, bool, const tripoint & ) { if( !p ) { - return 0; + return std::make_pair( 0, 0_J ); } item *loc = g->inv_map_splice( []( const item & e ) { @@ -1723,7 +1759,7 @@ int iuse::remove_all_mods( player *p, item *, bool, const tripoint & ) if( !loc ) { add_msg( m_info, _( "Never mind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( !loc->ammo_remaining() || avatar_funcs::unload_item( *p->as_avatar(), *loc ) ) { @@ -1740,7 +1776,7 @@ int iuse::remove_all_mods( player *p, item *, bool, const tripoint & ) remove_radio_mod( *loc, *p ); } - return 0; + return std::make_pair( 0, 0_J ); } static bool good_fishing_spot( tripoint pos ) @@ -1761,15 +1797,15 @@ static bool good_fishing_spot( tripoint pos ) return true; } -int iuse::fishing_rod( player *p, item *it, bool, const tripoint & ) +std::pair iuse::fishing_rod( player *p, item *it, bool, const tripoint & ) { if( p->is_npc() ) { // Long actions - NPCs don't like those yet. - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } std::optional found; for( const tripoint &pnt : g->m.points_in_radius( p->pos(), 1 ) ) { @@ -1780,54 +1816,54 @@ int iuse::fishing_rod( player *p, item *it, bool, const tripoint & ) } if( !found ) { p->add_msg_if_player( m_info, _( "You can't fish there!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } p->add_msg_if_player( _( "You cast your line and wait to hook something…" ) ); p->assign_activity( ACT_FISH, to_moves( 5_hours ), 0, 0, it->tname() ); p->activity->targets.emplace_back( it ); p->activity->coord_set = g->get_fishable_locations( 60, *found ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::fish_trap( player *p, item *it, bool t, const tripoint &pos ) +std::pair iuse::fish_trap( player *p, item *it, bool t, const tripoint &pos ) { if( !t ) { // Handle deploying fish trap. if( it->is_active() ) { it->deactivate(); - return 0; + return std::make_pair( 0, 0_J ); } if( it->charges < 0 ) { it->charges = 0; - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( it->charges == 0 ) { p->add_msg_if_player( _( "Fish are not foolish enough to go in here without bait." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const std::optional pnt_ = choose_adjacent( _( "Put fish trap where?" ) ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint pnt = *pnt_; if( !g->m.has_flag( "FISHABLE", pnt ) ) { p->add_msg_if_player( m_info, _( "You can't fish there!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( !good_fishing_spot( pnt ) ) { - return 0; + return std::make_pair( 0, 0_J ); } it->activate(); it->set_age( 0_turns ); @@ -1835,19 +1871,19 @@ int iuse::fish_trap( player *p, item *it, bool t, const tripoint &pos ) p->add_msg_if_player( m_info, _( "You place the fish trap, in three hours or so you may catch some fish." ) ); - return 0; + return std::make_pair( 0, 0_J ); } else { // Handle processing fish trap over time. if( it->charges == 0 ) { it->deactivate(); - return 0; + return std::make_pair( 0, 0_J ); } if( it->age() > 3_hours ) { it->deactivate(); if( !g->m.has_flag( "FISHABLE", pos ) ) { - return 0; + return std::make_pair( 0, 0_J ); } int success = -50; @@ -1879,7 +1915,7 @@ int iuse::fish_trap( player *p, item *it, bool t, const tripoint &pos ) it->charges = 0; p->practice( skill_survival, rng( 5, 15 ) ); - return 0; + return std::make_pair( 0, 0_J ); } //get the fishables around the trap's spot @@ -1918,20 +1954,21 @@ int iuse::fish_trap( player *p, item *it, bool t, const tripoint &pos ) } } } - return 0; + return std::make_pair( 0, 0_J ); } } -int iuse::extinguisher( player *p, item *it, bool, const tripoint & ) +std::pair iuse::extinguisher( player *p, item *it, bool, const tripoint & ) { - if( !it->ammo_sufficient() ) { - return 0; + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( !it->ammo_sufficient() || !it->energy_sufficient( *p ) ) { + return std::make_pair( 0, 0_J ); } // If anyone other than the player wants to use one of these, // they're going to need to figure out how to aim it. const std::optional dest_ = choose_adjacent( _( "Spray where?" ) ); if( !dest_ ) { - return 0; + return std::make_pair( 0, 0_J ); } tripoint dest = *dest_; @@ -1979,37 +2016,37 @@ int iuse::extinguisher( player *p, item *it, bool, const tripoint & ) g->m.mod_field_intensity( dest, fd_fire, std::min( 0 - rng( 0, 1 ) + rng( 0, 1 ), 0 ) ); } - return it->type->charges_to_use(); + return res; } -int iuse::unpack_item( player *p, item *it, bool, const tripoint & ) +std::pair iuse::unpack_item( player *p, item *it, bool, const tripoint & ) { if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } std::string oname = it->typeId().str() + "_on"; p->moves -= to_moves( 10_seconds ); p->add_msg_if_player( _( "You unpack your %s for use." ), it->tname() ); it->convert( itype_id( oname ) ); it->deactivate(); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::pack_cbm( player *p, item *it, bool, const tripoint & ) +std::pair iuse::pack_cbm( player *p, item *it, bool, const tripoint & ) { item *bionic = g->inv_map_splice( []( const item & e ) { return e.is_bionic() && e.has_flag( flag_NO_PACKED ); }, _( "Choose CBM to pack" ), PICKUP_RANGE, _( "You don't have any CBMs." ) ); if( !bionic ) { - return 0; + return std::make_pair( 0, 0_J ); } if( !bionic->faults.empty() ) { if( p->query_yn( _( "This CBM is faulty. You should mend it first. Do you want to try?" ) ) ) { avatar_funcs::mend_item( *p->as_avatar(), *bionic ); } - return 0; + return std::make_pair( 0, 0_J ); } const int success = p->get_skill_level( skill_firstaid ) - rng( 0, 6 ); @@ -2024,44 +2061,46 @@ int iuse::pack_cbm( player *p, item *it, bool, const tripoint & ) comps.emplace_back( it->typeId(), 1 ); p->consume_items( comps, 1, is_crafting_component ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::pack_item( player *p, item *it, bool t, const tripoint & ) +std::pair iuse::pack_item( player *p, item *it, bool t, const tripoint & ) { if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( t ) { // Normal use // Numbers below -1 are reserved for worn items } else if( p->get_item_position( it ) < -1 ) { p->add_msg_if_player( m_info, _( "You can't pack your %s until you take it off." ), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } else { // Turning it off std::string oname = it->typeId().str(); if( oname.ends_with( "_on" ) ) { oname.erase( oname.length() - 3, 3 ); } else { debugmsg( "no item type to turn it into (%s)!", oname ); - return 0; + return std::make_pair( 0, 0_J ); } p->moves -= to_moves( 10_seconds ); p->add_msg_if_player( _( "You pack your %s for storage." ), it->tname() ); it->convert( itype_id( oname ) ); it->deactivate(); } - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::water_purifier( player *p, item *it, bool, const tripoint & ) +std::pair iuse::water_purifier( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + auto [chrg, enrg] = res; constexpr auto purification_efficiency = 8; // one tablet purifies 250ml x 8 = 2L if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } auto obj = g->inv_map_splice( []( const item & e ) { return !e.contents.empty() && e.contents.front().typeId() == itype_water; @@ -2069,37 +2108,42 @@ int iuse::water_purifier( player *p, item *it, bool, const tripoint & ) if( !obj ) { p->add_msg_if_player( m_info, _( "You do not have that item!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } item &liquid = obj->contents.front(); - const auto used_charges = std::max( liquid.charges / purification_efficiency, 1 ); - if( !it->units_sufficient( *p, used_charges ) ) { + const auto use_multiplier = std::max( liquid.charges / purification_efficiency, 1 ); + enrg *= use_multiplier; + chrg *= use_multiplier; + if( !( it->units_sufficient( chrg ) && it->energy_sufficient( *p, enrg ) ) ) { p->add_msg_if_player( m_info, _( "That volume of water is too large to purify." ) ); - return 0; + return std::make_pair( 0, 0_J ); } p->moves -= to_moves( 2_seconds ); liquid.convert( itype_water_clean ); liquid.poison = 0; - return used_charges; + return res; } -int iuse::radio_off( player *p, item *it, bool, const tripoint & ) +std::pair iuse::radio_off( player *p, item *it, bool, const tripoint & ) { - if( !it->units_sufficient( *p ) ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( !it->units_sufficient() ) { p->add_msg_if_player( _( "It's dead." ) ); } else { p->add_msg_if_player( _( "You turn the radio on." ) ); it->convert( itype_radio_on ); it->activate(); } - return it->type->charges_to_use(); + return res; } -int iuse::directional_antenna( player *p, item *it, bool, const tripoint & ) +std::pair iuse::directional_antenna( player *p, item *it, bool, + const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); // Find out if we have an active radio auto radios = p->items_with( []( const item & it ) { return it.typeId() == itype_radio_on; @@ -2115,25 +2159,26 @@ int iuse::directional_antenna( player *p, item *it, bool, const tripoint & ) } if( radios.empty() ) { add_msg( m_info, _( "Must have an active radio to check for signal direction." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const item &radio = *radios.front(); // Find the radio station its tuned to (if any) const auto tref = overmap_buffer.find_radio_station( radio.frequency ); if( !tref ) { p->add_msg_if_player( m_info, _( "You can't find the direction if your radio isn't tuned." ) ); - return 0; + return std::make_pair( 0, 0_J ); } // Report direction. // TODO: fix point types const tripoint_abs_sm player_pos( p->global_sm_location() ); direction angle = direction_from( player_pos.xy(), tref.abs_sm_pos ); add_msg( _( "The signal seems strongest to the %s." ), direction_name( angle ) ); - return it->type->charges_to_use(); + return res; } -int iuse::radio_on( player *p, item *it, bool t, const tripoint &pos ) +std::pair iuse::radio_on( player *p, item *it, bool t, const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( t ) { // Normal use std::string message = _( "Radio: Kssssssssssssh." ); @@ -2217,23 +2262,26 @@ int iuse::radio_on( player *p, item *it, bool t, const tripoint &pos ) break; } } - return it->type->charges_to_use(); + return res; } -int iuse::noise_emitter_off( player *p, item *it, bool, const tripoint & ) +std::pair iuse::noise_emitter_off( player *p, item *it, bool, const tripoint & ) { - if( !it->units_sufficient( *p ) ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( !it->units_sufficient() ) { p->add_msg_if_player( _( "It's dead." ) ); } else { p->add_msg_if_player( _( "You turn the noise emitter on." ) ); it->convert( itype_noise_emitter_on ); it->activate(); } - return it->type->charges_to_use(); + return res; } -int iuse::noise_emitter_on( player *p, item *it, bool t, const tripoint &pos ) +std::pair iuse::noise_emitter_on( player *p, item *it, bool t, + const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( t ) { // Normal use //~ the sound of a noise emitter when turned on sounds::sound( pos, 30, sounds::sound_t::alarm, _( "KXSHHHHRRCRKLKKK!" ), true, "tool", @@ -2243,27 +2291,29 @@ int iuse::noise_emitter_on( player *p, item *it, bool t, const tripoint &pos ) it->convert( itype_noise_emitter ); it->deactivate(); } - return it->type->charges_to_use(); + return res; } // Ugly and uses variables that shouldn't be public -int iuse::note_bionics( player *p, item *it, bool t, const tripoint &pos ) +std::pair iuse::note_bionics( player *p, item *it, bool t, const tripoint &pos ) { + const bool possess = p->has_item( *it ); + if( !t ) { it->revert( p, true ); it->deactivate(); - return 0; + return std::make_pair( 0, 0_J ); } if( !p->is_avatar() ) { // Not supported at the moment - return 0; + return std::make_pair( 0, 0_J ); } map &here = get_map(); if( !p->has_enough_charges( *it, false ) ) { it->revert( p, true ); it->deactivate(); - return 0; + return std::make_pair( 0, 0_J ); } for( const tripoint &pt : here.points_in_radius( pos, PICKUP_RANGE ) ) { if( !here.has_items( pt ) || !p->sees( pt ) ) { @@ -2282,6 +2332,14 @@ int iuse::note_bionics( player *p, item *it, bool t, const tripoint &pos ) } } + units::energy power_needed = units::from_kilojoule( static_cast( cbms.size() ) ); + power_needed -= it->energy_consume( power_needed, pos ); + if( power_needed > 0_J ) { + it->revert( p, true ); + it->deactivate(); + return std::make_pair( 0, 0_J ); + } + corpse->set_var( "bionics_scanned_by", p->getID().get_value() ); if( !cbms.empty() ) { corpse->set_flag( flag_CBM_SCANNED ); @@ -2300,30 +2358,32 @@ int iuse::note_bionics( player *p, item *it, bool t, const tripoint &pos ) } } - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::ma_manual( player *p, item *it, bool, const tripoint & ) +std::pair iuse::ma_manual( player *p, item *it, bool, const tripoint & ) { // [CR] - should NPCs just be allowed to learn this stuff? Just like that? + std::pair res( it->type->charges_to_use(), it->energy_required() ); const matype_id style_to_learn = martial_art_learned_from( *it->type ); if( !style_to_learn.is_valid() ) { debugmsg( "ERROR: Invalid martial art" ); - return 0; + return std::make_pair( 0, 0_J ); } p->martial_arts_data->learn_style( style_to_learn, p->is_avatar() ); - return 1; + return res; } -int iuse::hammer( player *p, item *it, bool, const tripoint & ) +std::pair iuse::hammer( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const std::set allowed_ter_id { t_fence, @@ -2352,7 +2412,7 @@ int iuse::hammer( player *p, item *it, bool, const tripoint & ) const std::optional pnt_ = choose_adjacent_highlight( _( "Pry where?" ), _( "There is nothing to pry nearby." ), f, false ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint &pnt = *pnt_; const ter_id type = g->m.ter( pnt ); @@ -2363,7 +2423,7 @@ int iuse::hammer( player *p, item *it, bool, const tripoint & ) } else { p->add_msg_if_player( m_info, _( "You can't pry that." ) ); } - return 0; + return std::make_pair( 0, 0_J ); } if( type == t_fence || type == t_window_boarded || type == t_window_boarded_noglass || @@ -2377,17 +2437,18 @@ int iuse::hammer( player *p, item *it, bool, const tripoint & ) -1 ); act->placement = pnt; p->assign_activity( std::move( act ) ); - return it->type->charges_to_use(); + return res; } else { - return 0; + return std::make_pair( 0, 0_J ); } } -int iuse::crowbar( player *p, item *it, bool, const tripoint &pos ) +std::pair iuse::crowbar( player *p, item *it, bool, const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const pry_result *pry = nullptr; bool pry_furn; @@ -2406,7 +2467,7 @@ int iuse::crowbar( player *p, item *it, bool, const tripoint &pos ) const std::optional pnt_ = ( pos != p->pos() ) ? pos : choose_adjacent_highlight( _( "Pry where?" ), _( "There is nothing to pry nearby." ), can_pry, false ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint &pnt = *pnt_; const ter_id ter = g->m.ter( pnt ); @@ -2423,7 +2484,7 @@ int iuse::crowbar( player *p, item *it, bool, const tripoint &pos ) p->add_msg_if_player( m_info, _( "You can't pry that." ) ); } - return 0; + return std::make_pair( 0, 0_J ); } if( furn->pry.pry_quality != -1 ) { @@ -2445,7 +2506,7 @@ int iuse::crowbar( player *p, item *it, bool, const tripoint &pos ) p->add_msg_if_player( _( "You can't get sufficient leverage to open that with your %s." ), it->tname() ); p->mod_moves( 10 ); // spend a few moves trying it. - return 0; + return std::make_pair( 0, 0_J ); } // For every level of PRY over the requirement, remove n from the difficulty. @@ -2506,43 +2567,44 @@ int iuse::crowbar( player *p, item *it, bool, const tripoint &pos ) p->global_sm_location() ); } } - return it->type->charges_to_use(); + return res; } } p->add_msg_if_player( pry->fail_message ); } - return it->type->charges_to_use(); + return res; } -int iuse::makemound( player *p, item *it, bool t, const tripoint & ) +std::pair iuse::makemound( player *p, item *it, bool t, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( !p || t ) { - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const std::optional pnt_ = choose_adjacent( _( "Till soil where?" ) ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint pnt = *pnt_; if( pnt == p->pos() ) { p->add_msg_if_player( m_info, _( "You think about jumping on a shovel, but then change up your mind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( g->m.has_flag( flag_PLOWABLE, pnt ) && !g->m.has_flag( flag_PLANT, pnt ) ) { p->add_msg_if_player( _( "You start churning up the earth here." ) ); p->assign_activity( ACT_CHURN, 18000, -1, p->get_item_position( it ) ); p->activity->placement = g->m.getabs( pnt ); - return it->type->charges_to_use(); + return res; } else { p->add_msg_if_player( _( "You can't churn up this ground." ) ); - return 0; + return std::make_pair( 0, 0_J ); } } @@ -2596,14 +2658,15 @@ static digging_moves_and_byproducts dig_pit_moves_and_byproducts( player *p, ite return { moves, ( dig_minutes / 60 ), g->m.ter( pos )->digging_result, result_terrain }; } -int iuse::dig( player *p, item *it, bool t, const tripoint & ) +std::pair iuse::dig( player *p, item *it, bool t, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( !p || t ) { - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const tripoint dig_point = p->pos(); @@ -2616,7 +2679,7 @@ int iuse::dig( player *p, item *it, bool t, const tripoint & ) if( !can_dig_here ) { p->add_msg_if_player( _( "You can't dig a pit in this location. Ensure it is clear diggable ground with no items or obstacles." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const bool can_deepen = g->m.has_flag( "DIGGABLE_CAN_DEEPEN", dig_point ); const bool grave = g->m.ter( dig_point ) == t_grave; @@ -2624,10 +2687,10 @@ int iuse::dig( player *p, item *it, bool t, const tripoint & ) if( !p->crafting_inventory().has_quality( qual_DIG, 2 ) ) { if( can_deepen ) { p->add_msg_if_player( _( "You can't deepen this pit without a proper shovel." ) ); - return 0; + return std::make_pair( 0, 0_J ); } else if( grave ) { p->add_msg_if_player( _( "You can't exhume a grave without a proper shovel." ) ); - return 0; + return std::make_pair( 0, 0_J ); } } @@ -2639,14 +2702,14 @@ int iuse::dig( player *p, item *it, bool t, const tripoint & ) _( "Deposit excavated materials where?" ), _( "There is nowhere to deposit the excavated materials." ), f, false ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint deposit_point = *pnt_; if( !f( deposit_point ) ) { p->add_msg_if_player( _( "You can't deposit the excavated materials onto an impassable location." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( grave ) { @@ -2689,17 +2752,19 @@ int iuse::dig( player *p, item *it, bool t, const tripoint & ) moves_and_byproducts.byproducts_item_group ) ) ); - return it->type->charges_to_use(); + return res; } -int iuse::dig_channel( player *p, item *it, bool t, const tripoint & ) +std::pair iuse::dig_channel( player *p, item *it, bool t, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( !p || t ) { - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const tripoint dig_point = p->pos(); @@ -2717,7 +2782,7 @@ int iuse::dig_channel( player *p, item *it, bool t, const tripoint & ) if( !can_dig_here ) { p->add_msg_if_player( _( "You can't dig a channel in this location. Ensure it is clear diggable ground with no items or obstacles, adjacent to flowing water." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const std::function f = []( const tripoint & pnt ) { @@ -2728,14 +2793,14 @@ int iuse::dig_channel( player *p, item *it, bool t, const tripoint & ) _( "Deposit excavated materials where?" ), _( "There is nowhere to deposit the excavated materials." ), f, false ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint deposit_point = *pnt_; if( !f( deposit_point ) ) { p->add_msg_if_player( _( "You can't deposit the excavated materials onto an impassable location." ) ); - return 0; + return std::make_pair( 0, 0_J ); } digging_moves_and_byproducts moves_and_byproducts = dig_pit_moves_and_byproducts( p, it, false, @@ -2755,17 +2820,19 @@ int iuse::dig_channel( player *p, item *it, bool t, const tripoint & ) moves_and_byproducts.spawn_count, moves_and_byproducts.byproducts_item_group ) ) ); - return it->type->charges_to_use(); + return res; } -int iuse::fill_pit( player *p, item *it, bool t, const tripoint & ) +std::pair iuse::fill_pit( player *p, item *it, bool t, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( !p || t ) { - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const std::set allowed_ter_id { t_pit, @@ -2787,7 +2854,7 @@ int iuse::fill_pit( player *p, item *it, bool t, const tripoint & ) const std::optional pnt_ = choose_adjacent_highlight( _( "Fill which pit or mound?" ), _( "There is no pit or mound to fill nearby." ), f, false ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint &pnt = *pnt_; const ter_id ter = g->m.ter( pnt ); @@ -2797,7 +2864,7 @@ int iuse::fill_pit( player *p, item *it, bool t, const tripoint & ) } else { p->add_msg_if_player( m_info, _( "There is nothing to fill." ) ); } - return 0; + return std::make_pair( 0, 0_J ); } int moves; @@ -2809,7 +2876,7 @@ int iuse::fill_pit( player *p, item *it, bool t, const tripoint & ) } else if( ter == t_dirtmound ) { moves = to_moves( time_duration::from_minutes( 5 ) ); } else { - return 0; + return std::make_pair( 0, 0_J ); } const std::vector helpers = character_funcs::get_crafting_helpers( *p, 3 ); @@ -2821,7 +2888,7 @@ int iuse::fill_pit( player *p, item *it, bool t, const tripoint & ) p->assign_activity( ACT_FILL_PIT, moves, -1, p->get_item_position( it ) ); p->activity->placement = pnt; - return it->type->charges_to_use(); + return res; } /** @@ -2831,11 +2898,13 @@ int iuse::fill_pit( player *p, item *it, bool t, const tripoint & ) * index: The bonus, for calculating hunger and thirst penalties. */ -int iuse::clear_rubble( player *p, item *it, bool, const tripoint & ) +std::pair iuse::clear_rubble( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const std::function f = []( const tripoint & pnt ) { return g->m.has_flag( "RUBBLE", pnt ); @@ -2844,12 +2913,12 @@ int iuse::clear_rubble( player *p, item *it, bool, const tripoint & ) const std::optional pnt_ = choose_adjacent_highlight( _( "Clear rubble where?" ), _( "There is no rubble to clear nearby." ), f, false ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint &pnt = *pnt_; if( !f( pnt ) ) { p->add_msg_if_player( m_bad, _( "There's no rubble to clear." ) ); - return 0; + return std::make_pair( 0, 0_J ); } int moves = to_moves( 30_seconds ); @@ -2864,16 +2933,18 @@ int iuse::clear_rubble( player *p, item *it, bool, const tripoint & ) player_activity act( ACT_CLEAR_RUBBLE, moves / bonus, bonus ); p->assign_activity( std::make_unique( ACT_CLEAR_RUBBLE, moves / bonus, bonus ) ); p->activity->placement = pnt; - return it->type->charges_to_use(); + return res; } void act_vehicle_siphon( vehicle * ); // veh_interact.cpp -int iuse::siphon( player *p, item *it, bool, const tripoint & ) +std::pair iuse::siphon( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const std::function f = []( const tripoint & pnt ) { const optional_vpart_position vp = g->m.veh_at( pnt ); @@ -2903,7 +2974,7 @@ int iuse::siphon( player *p, item *it, bool, const tripoint & ) std::optional pnt_ = choose_adjacent_highlight( _( "Siphon from where?" ), _( "There is nothing to siphon nearby." ), f, false ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const optional_vpart_position vp = g->m.veh_at( *pnt_ ); if( vp ) { @@ -2913,44 +2984,46 @@ int iuse::siphon( player *p, item *it, bool, const tripoint & ) if( v == nullptr ) { p->add_msg_if_player( m_info, _( "There's no vehicle there." ) ); - return 0; + return std::make_pair( 0, 0_J ); } act_vehicle_siphon( v ); - return it->type->charges_to_use(); + return res; } -int iuse::jackhammer( player *p, item *it, bool, const tripoint &pos ) +std::pair iuse::jackhammer( player *p, item *it, bool, const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + // use has_enough_charges to check for UPS availability // p is assumed to exist for iuse cases if( !p->has_enough_charges( *it, false ) ) { - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } tripoint pnt = pos; if( pos == p->pos() ) { const std::optional pnt_ = choose_adjacent( _( "Drill where?" ) ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } pnt = *pnt_; } if( !g->m.has_flag( "MINEABLE", pnt ) ) { p->add_msg_if_player( m_info, _( "You can't drill there." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( g->m.veh_at( pnt ) ) { p->add_msg_if_player( _( "There's a vehicle in the way!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } // Base time of 30 minutes at 8 strength @@ -2973,13 +3046,15 @@ int iuse::jackhammer( player *p, item *it, bool, const tripoint &pos ) p->add_msg_if_player( _( "You start drilling into the %1$s with your %2$s." ), g->m.tername( pnt ), it->tname() ); - return it->type->charges_to_use(); + return res; } -int iuse::pick_lock( player *p, item *it, bool, const tripoint &pos ) +std::pair iuse::pick_lock( player *p, item *it, bool, const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( p->is_npc() ) { - return 0; + return std::make_pair( 0, 0_J ); } avatar &you = dynamic_cast( *p ); @@ -2991,7 +3066,7 @@ int iuse::pick_lock( player *p, item *it, bool, const tripoint &pos ) target = pos; } if( !target.has_value() ) { - return 0; + return std::make_pair( 0, 0_J ); } int qual = it->get_quality( qual_LOCKPICK ); @@ -3009,40 +3084,40 @@ int iuse::pick_lock( player *p, item *it, bool, const tripoint &pos ) you.assign_activity( std::make_unique( lockpick_activity_actor::use_item( duration, *it, g->m.getabs( *target ) ) ) ); - return it->type->charges_to_use(); + return res; } -int iuse::pickaxe( player *p, item *it, bool, const tripoint &pos ) +std::pair iuse::pickaxe( player *p, item *it, bool, const tripoint &pos ) { if( p->is_npc() ) { // Long action - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } tripoint pnt = pos; if( pos == p->pos() ) { const std::optional pnt_ = choose_adjacent( _( "Mine where?" ) ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } pnt = *pnt_; } if( !g->m.has_flag( "MINEABLE", pnt ) ) { p->add_msg_if_player( m_info, _( "You can't mine there." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( g->m.veh_at( pnt ) ) { p->add_msg_if_player( _( "There's a vehicle in the way!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } // Base time of 90 minutes at 8 strength @@ -3064,40 +3139,40 @@ int iuse::pickaxe( player *p, item *it, bool, const tripoint &pos ) p->activity->placement = g->m.getabs( pnt ); p->add_msg_if_player( _( "You strike the %1$s with your %2$s." ), g->m.tername( pnt ), it->tname() ); - return 0; // handled when the activity finishes + return std::make_pair( 0, 0_J ); // handled when the activity finishes } -int iuse::burrow( player *p, item *it, bool, const tripoint &pos ) +std::pair iuse::burrow( player *p, item *it, bool, const tripoint &pos ) { if( p->is_npc() ) { // Long action - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } tripoint pnt = pos; if( pos == p->pos() ) { const std::optional pnt_ = choose_adjacent( _( "Burrow where?" ) ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } pnt = *pnt_; } if( !g->m.has_flag( "MINEABLE", pnt ) ) { p->add_msg_if_player( m_info, _( "You can't burrow there." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( g->m.veh_at( pnt ) ) { p->add_msg_if_player( _( "There's a vehicle in the way!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } // Base time of 60 minutes at 8 strength @@ -3119,15 +3194,17 @@ int iuse::burrow( player *p, item *it, bool, const tripoint &pos ) p->activity->placement = pnt; p->add_msg_if_player( _( "You start tearing into the %1$s with your %2$s." ), g->m.tername( pnt ), it->tname() ); - return 0; // handled when the activity finishes + return std::make_pair( 0, 0_J ); // handled when the activity finishes } -int iuse::geiger( player *p, item *it, bool t, const tripoint &pos ) +std::pair iuse::geiger( player *p, item *it, bool t, const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( t ) { // Every-turn use when it's on const int rads = g->m.get_radiation( pos ); if( rads == 0 ) { - return it->type->charges_to_use(); + return res; } std::string description = rads > 50 ? _( "buzzing" ) : rads > 25 ? _( "rapid clicking" ) : _( "clicking" ); @@ -3137,7 +3214,7 @@ int iuse::geiger( player *p, item *it, bool t, const tripoint &pos ) sounds::sound( pos, 6, sounds::sound_t::alarm, description, true, "tool", sound_var ); if( !p->can_hear( pos, 6 ) ) { // can not hear it, but may have alarmed other creatures - return it->type->charges_to_use(); + return res; } if( rads > 50 ) { add_msg( m_warning, _( "The geiger counter buzzes intensely." ) ); @@ -3154,14 +3231,14 @@ int iuse::geiger( player *p, item *it, bool t, const tripoint &pos ) } else { add_msg( _( "The geiger counter clicks once." ) ); } - return it->type->charges_to_use(); + return res; } // Otherwise, we're activating the geiger counter if( it->typeId() == itype_geiger_on ) { add_msg( _( "The geiger counter's SCANNING LED turns off." ) ); it->convert( itype_geiger_off ); it->deactivate(); - return 0; + return std::make_pair( 0, 0_J ); } int ch = uilist( _( "Geiger counter:" ), { @@ -3176,7 +3253,7 @@ int iuse::geiger( player *p, item *it, bool t, const tripoint &pos ) const std::optional pnt_ = choose_adjacent_highlight( _( "Scan whom?" ), _( "There is no one to scan nearby." ), f, false ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint &pnt = *pnt_; if( pnt == g->u.pos() ) { @@ -3202,33 +3279,37 @@ int iuse::geiger( player *p, item *it, bool t, const tripoint &pos ) it->activate(); break; default: - return 0; + return std::make_pair( 0, 0_J ); } p->mod_moves( -100 ); - return it->type->charges_to_use(); + return res; } -int iuse::teleport( player *p, item *it, bool, const tripoint & ) +std::pair iuse::teleport( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( p->is_npc() ) { // That would be evil - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } - if( !it->ammo_sufficient() ) { - return 0; + if( !it->ammo_sufficient() || !it->energy_sufficient( *p ) ) { + return std::make_pair( 0, 0_J ); } p->moves -= to_moves( 1_seconds ); teleport::teleport( *p ); - return it->type->charges_to_use(); + return res; } -int iuse::can_goo( player *p, item *it, bool, const tripoint & ) +std::pair iuse::can_goo( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + int tries = 0; tripoint goop; goop.z = p->posz(); @@ -3239,7 +3320,7 @@ int iuse::can_goo( player *p, item *it, bool, const tripoint & ) } while( g->m.impassable( goop ) && tries < 10 ); if( tries == 10 ) { add_msg( _( "Nothing happens." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( monster *const mon_ptr = g->critter_at( goop ) ) { monster &critter = *mon_ptr; @@ -3278,15 +3359,18 @@ int iuse::can_goo( player *p, item *it, bool, const tripoint & ) if( it->charges <= it->type->charges_to_use() ) { it->charges = 0; it->convert( itype_canister_empty ); - return 0; + return std::make_pair( 0, 0_J ); } - return it->type->charges_to_use(); + return res; } -int iuse::throwable_extinguisher_act( player *, item *it, bool, const tripoint &pos ) +std::pair iuse::throwable_extinguisher_act( player *, item *it, bool, + const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( pos.x == -999 || pos.y == -999 ) { - return 0; + return std::make_pair( 0, 0_J ); } if( g->m.get_field( pos, fd_fire ) != nullptr ) { sounds::sound( pos, 50, sounds::sound_t::combat, _( "Bang!" ), false, "explosion", "small" ); @@ -3299,25 +3383,29 @@ int iuse::throwable_extinguisher_act( player *, item *it, bool, const tripoint & } } it->charges = -1; - return 1; + return res; } it->deactivate(); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::granade( player *p, item *it, bool, const tripoint & ) +std::pair iuse::granade( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + p->add_msg_if_player( _( "You pull the pin on the Granade." ) ); it->convert( itype_granade_act ); it->charges = 5; it->activate(); - return it->type->charges_to_use(); + return res; } -int iuse::granade_act( player *p, item *it, bool t, const tripoint &pos ) +std::pair iuse::granade_act( player *p, item *it, bool t, const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( pos.x == -999 || pos.y == -999 ) { - return 0; + return std::make_pair( 0, 0_J ); } if( t ) { // Simple timer effects // Vol 0 = only heard if you hold it @@ -3326,7 +3414,7 @@ int iuse::granade_act( player *p, item *it, bool t, const tripoint &pos ) } else if( it->charges > 0 ) { p->add_msg_if_player( m_info, _( "You've already pulled the %s's pin, try throwing it instead." ), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } if( it->charges == 0 ) { // When that timer runs down... @@ -3458,40 +3546,45 @@ int iuse::granade_act( player *p, item *it, bool t, const tripoint &pos ) break; } } - return it->type->charges_to_use(); + return res; } -int iuse::c4( player *p, item *it, bool, const tripoint & ) +std::pair iuse::c4( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + int time; bool got_value = query_int( time, _( "Set the timer to (0 to cancel)?" ) ); if( !got_value || time <= 0 ) { p->add_msg_if_player( _( "Never mind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } p->add_msg_if_player( _( "You set the timer to %d." ), time ); it->convert( itype_c4armed ); it->charges = time; it->activate(); - return it->type->charges_to_use(); + return res; } -int iuse::acidbomb_act( player *p, item *it, bool, const tripoint &pos ) +std::pair iuse::acidbomb_act( player *p, item *it, bool, const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( !p->has_item( *it ) ) { it->charges = -1; for( const tripoint &tmp : g->m.points_in_radius( pos.x == -999 ? p->pos() : pos, 1 ) ) { g->m.add_field( tmp, fd_acid, 3 ); } - return 1; + return res; } - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::grenade_inc_act( player *p, item *it, bool t, const tripoint &pos ) +std::pair iuse::grenade_inc_act( player *p, item *it, bool t, + const tripoint &pos ) { if( pos.x == -999 || pos.y == -999 ) { - return 0; + return std::make_pair( 0, 0_J ); } @@ -3501,7 +3594,7 @@ int iuse::grenade_inc_act( player *p, item *it, bool t, const tripoint &pos ) sounds::sound( pos, 0, sounds::sound_t::alarm, _( "Tick!" ), true, "misc", "bomb_ticking" ); } else if( it->charges > 0 ) { p->add_msg_if_player( m_info, _( "You've already released the handle, try throwing it instead." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( it->charges == 0 ) { // blow up @@ -3523,43 +3616,47 @@ int iuse::grenade_inc_act( player *p, item *it, bool t, const tripoint &pos ) p->rem_morale( MORALE_PYROMANIA_NOFIRE ); p->add_msg_if_player( m_good, _( "Fire… Good…" ) ); } - return 0; + return std::make_pair( 0, 0_J ); } - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::arrow_flammable( player *p, item *it, bool, const tripoint & ) +std::pair iuse::arrow_flammable( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( !p->use_charges_if_avail( itype_fire, 1 ) ) { p->add_msg_if_player( m_info, _( "You need a source of fire!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } p->add_msg_if_player( _( "You light the arrow!" ) ); p->moves -= to_moves( 1_seconds ); if( it->charges == 1 ) { it->convert( itype_arrow_flamming ); - return 0; + return std::make_pair( 0, 0_J ); } detached_ptr lit_arrow = item::spawn( *it ); lit_arrow->convert( itype_arrow_flamming ); lit_arrow->charges = 1; p->i_add( std::move( lit_arrow ) ); - return 1; + return res; } -int iuse::molotov_lit( player *p, item *it, bool t, const tripoint &pos ) +std::pair iuse::molotov_lit( player *p, item *it, bool t, const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( pos.x == -999 || pos.y == -999 ) { - return 0; + return std::make_pair( 0, 0_J ); } else if( !t ) { if( p->has_item( *it ) ) { if( !query_yn( "Really smash it on yourself?" ) ) { p->add_msg_if_player( m_info, _( "You should probably throw it instead." ) ); - return 0; + return std::make_pair( 0, 0_J ); } } for( const tripoint &pt : g->m.points_in_radius( pos, 1, 0 ) ) { @@ -3575,75 +3672,36 @@ int iuse::molotov_lit( player *p, item *it, bool t, const tripoint &pos ) if( it->has_position() ) { it->detach(); } - return 1; + return res; } else if( p->has_item( *it ) && it->charges == 0 ) { - return 0; + return std::make_pair( 0, 0_J ); } - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::firecracker_pack( player *p, item *it, bool, const tripoint & ) +std::pair iuse::firecracker_pack_act( player *, item *it, bool, + const tripoint &pos ) { - if( p->is_underwater() ) { - p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; - } - if( !p->has_charges( itype_fire, 1 ) ) { - p->add_msg_if_player( m_info, _( "You need a source of fire!" ) ); - return 0; - } - p->add_msg_if_player( _( "You light the pack of firecrackers." ) ); - it->convert( itype_firecracker_pack_act ); - it->charges = 26; - it->set_age( 0_turns ); - it->activate(); - return 0; // don't use any charges at all. it has became a new item -} - -int iuse::firecracker_pack_act( player *, item *it, bool, const tripoint &pos ) -{ - time_duration timer = it->age(); - if( timer < 2_turns ) { + // 2 turn delay before it starts popping off + if( it->charges > it->type->tool->def_charges - 2 ) { sounds::sound( pos, 0, sounds::sound_t::alarm, _( "ssss…" ), true, "misc", "lit_fuse" ); it->inc_damage(); } else if( it->charges > 0 ) { - int ex = rng( 4, 6 ); + int ex = std::min( rng( 4, 6 ), it->charges ); int i = 0; - if( ex > it->charges ) { - ex = it->charges; - } for( i = 0; i < ex; i++ ) { sounds::sound( pos, 20, sounds::sound_t::combat, _( "Bang!" ), false, "explosion", "small" ); } it->charges -= ex; } - if( it->charges == 0 ) { - it->charges = -1; - } - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::firecracker( player *p, item *it, bool, const tripoint & ) -{ - if( p->is_underwater() ) { - p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; - } - if( !p->use_charges_if_avail( itype_fire, 1 ) ) { - p->add_msg_if_player( m_info, _( "You need a source of fire!" ) ); - return 0; - } - p->add_msg_if_player( _( "You light the firecracker." ) ); - it->convert( itype_firecracker_act ); - it->charges = 2; - it->activate(); - return it->type->charges_to_use(); -} - -int iuse::firecracker_act( player *p, item *it, bool t, const tripoint &pos ) +std::pair iuse::firecracker_act( player *p, item *it, bool t, + const tripoint &pos ) { if( pos.x == -999 || pos.y == -999 ) { - return 0; + return std::make_pair( 0, 0_J ); } if( t ) { // Simple timer effects @@ -3651,22 +3709,24 @@ int iuse::firecracker_act( player *p, item *it, bool t, const tripoint &pos ) } else if( it->charges > 0 ) { p->add_msg_if_player( m_info, _( "You've already lit the %s, try throwing it instead." ), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } if( it->charges == 0 ) { // When that timer runs down... sounds::sound( pos, 20, sounds::sound_t::combat, _( "Bang!" ), true, "explosion", "small" ); } - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::mininuke( player *p, item *it, bool, const tripoint & ) +std::pair iuse::mininuke( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); int time; + bool got_value = query_int( time, _( "Set the timer to ___ turns (0 to cancel)?" ) ); if( !got_value || time <= 0 ) { p->add_msg_if_player( _( "Never mind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } p->add_msg_if_player( _( "You set the timer to %s." ), to_string( time_duration::from_turns( time ) ) ); @@ -3674,21 +3734,23 @@ int iuse::mininuke( player *p, item *it, bool, const tripoint & ) it->convert( itype_mininuke_act ); it->charges = time; it->activate(); - return it->type->charges_to_use(); + return res; } -int iuse::pheromone( player *p, item *it, bool, const tripoint &pos ) +std::pair iuse::pheromone( player *p, item *it, bool, const tripoint &pos ) { - if( !it->ammo_sufficient() ) { - return 0; + std::pair res( it->type->charges_to_use(), it->energy_required() ); + + if( !it->ammo_sufficient() || !it->energy_sufficient( *p ) ) { + return std::make_pair( 0, 0_J ); } if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( pos.x == -999 || pos.y == -999 ) { - return 0; + return std::make_pair( 0, 0_J ); } p->add_msg_player_or_npc( _( "You squeeze the pheromone ball…" ), @@ -3719,54 +3781,58 @@ int iuse::pheromone( player *p, item *it, bool, const tripoint &pos ) add_msg( m_good, _( "…and several nearby zombies become passive!" ) ); } } - return it->type->charges_to_use(); + return res; } -int iuse::portal( player *p, item *it, bool, const tripoint & ) +std::pair iuse::portal( player *p, item *it, bool, const tripoint & ) { - if( !it->ammo_sufficient() ) { - return 0; + std::pair res( it->type->charges_to_use(), it->energy_required() ); + + if( !it->ammo_sufficient() || !it->energy_sufficient( *p ) ) { + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } tripoint t( p->posx() + rng( -2, 2 ), p->posy() + rng( -2, 2 ), p->posz() ); g->m.trap_set( t, tr_portal ); - return it->type->charges_to_use(); + return res; } -int iuse::tazer( player *p, item *it, bool, const tripoint &pos ) +std::pair iuse::tazer( player *p, item *it, bool, const tripoint &pos ) { - if( !it->units_sufficient( *p ) ) { - return 0; + std::pair res( it->type->charges_to_use(), it->energy_required() ); + + if( !it->units_sufficient() ) { + return std::make_pair( 0, 0_J ); } tripoint pnt = pos; if( pos == p->pos() ) { const std::optional pnt_ = choose_adjacent( _( "Shock where?" ) ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } pnt = *pnt_; } if( pnt == p->pos() ) { p->add_msg_if_player( m_info, _( "Umm. No." ) ); - return 0; + return std::make_pair( 0, 0_J ); } Creature *target = g->critter_at( pnt, true ); if( target == nullptr ) { p->add_msg_if_player( _( "There's nothing to zap there!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } npc *foe = dynamic_cast( target ); if( foe != nullptr && !foe->is_enemy() && !p->query_yn( _( "Really shock %s?" ), target->disp_name() ) ) { - return 0; + return std::make_pair( 0, 0_J ); } /** @EFFECT_DEX slightly increases chance of successfully using tazer */ @@ -3802,28 +3868,15 @@ int iuse::tazer( player *p, item *it, bool, const tripoint &pos ) foe->on_attacked( *p ); } - return it->type->charges_to_use(); + return res; } -int iuse::tazer2( player *p, item *it, bool b, const tripoint &pos ) +std::pair iuse::mp3( player *p, item *it, bool, const tripoint & ) { - if( it->ammo_remaining() >= 100 ) { - // Instead of having a ctrl+c+v of the function above, spawn a fake tazer and use it - // Ugly, but less so than copied blocks - item *fake = item::spawn_temporary( "tazer", calendar::start_of_cataclysm ); - fake->charges = 100; - return tazer( p, fake, b, pos ); - } else { - p->add_msg_if_player( m_info, _( "Insufficient power" ) ); - } - - return 0; -} + std::pair res( it->type->charges_to_use(), it->energy_required() ); -int iuse::mp3( player *p, item *it, bool, const tripoint & ) -{ // TODO: avoid item id hardcoding to make this function usable for pure json-defined devices. - if( !it->units_sufficient( *p ) ) { + if( !it->units_sufficient() || !it->energy_sufficient( *p ) ) { p->add_msg_if_player( m_info, _( "The device's batteries are dead." ) ); } else if( p->has_active_item( itype_mp3_on ) || p->has_active_item( itype_smartphone_music ) || p->has_active_item( itype_afs_atomic_smartphone_music ) || @@ -3846,7 +3899,7 @@ int iuse::mp3( player *p, item *it, bool, const tripoint & ) } p->mod_moves( -200 ); } - return it->type->charges_to_use(); + return res; } static std::string get_music_description() @@ -3910,8 +3963,10 @@ void iuse::play_music( player &p, const tripoint &source, const int volume, cons } } -int iuse::mp3_on( player *p, item *it, bool t, const tripoint &pos ) +std::pair iuse::mp3_on( player *p, item *it, bool t, const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( t ) { // Normal use if( p->has_item( *it ) ) { // mp3 player in inventory, we can listen @@ -3937,14 +3992,14 @@ int iuse::mp3_on( player *p, item *it, bool t, const tripoint &pos ) } p->mod_moves( -200 ); } - return it->type->charges_to_use(); + return res; } -int iuse::rpgdie( player *you, item *die, bool, const tripoint & ) +std::pair iuse::rpgdie( player *you, item *die, bool, const tripoint & ) { if( you->is_mounted() ) { you->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } int num_sides = die->get_var( "die_num_sides", 0 ); if( num_sides == 0 ) { @@ -3960,11 +4015,13 @@ int iuse::rpgdie( player *you, item *die, bool, const tripoint & ) if( roll == num_sides ) { add_msg( m_good, _( "Critical!" ) ); } - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::dive_tank( player *p, item *it, bool t, const tripoint & ) +std::pair iuse::dive_tank( player *p, item *it, bool t, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( t ) { // Normal use if( p->is_worn( *it ) ) { if( p->is_underwater() && p->oxygen < 10 ) { @@ -3973,7 +4030,7 @@ int iuse::dive_tank( player *p, item *it, bool t, const tripoint & ) if( one_in( 15 ) ) { p->add_msg_if_player( m_bad, _( "You take a deep breath from your %s." ), it->tname() ); } - if( it->charges == 0 ) { + if( !( it->ammo_sufficient() || it->energy_sufficient( *p ) ) ) { p->add_msg_if_player( m_bad, _( "Air in your %s runs out." ), it->tname() ); it->set_var( "overwrite_env_resist", 0 ); it->convert( itype_id( it->typeId().str().substr( 0, @@ -3988,7 +4045,7 @@ int iuse::dive_tank( player *p, item *it, bool t, const tripoint & ) } } else { // Turning it on/off - if( it->charges == 0 ) { + if( !( it->ammo_sufficient() || it->energy_sufficient( *p ) ) ) { p->add_msg_if_player( _( "Your %s is empty." ), it->tname() ); } else if( it->is_active() ) { //off p->add_msg_if_player( _( "You turn off the regulator and close the air valve." ) ); @@ -4007,22 +4064,22 @@ int iuse::dive_tank( player *p, item *it, bool t, const tripoint & ) } } } - if( it->charges == 0 ) { + if( !( it->ammo_sufficient() || it->energy_sufficient( *p ) ) ) { it->set_var( "overwrite_env_resist", 0 ); it->convert( itype_id( it->typeId().str().substr( 0, it->typeId().str().size() - 3 ) ) ); it->deactivate(); // 3 = "_on" } - return it->type->charges_to_use(); + return res; } -int iuse::solarpack( player *p, item *it, bool, const tripoint & ) +std::pair iuse::solarpack( player *p, item *it, bool, const tripoint & ) { const bionic_id rem_bid = p->get_remote_fueled_bionic(); if( rem_bid.is_empty() ) { // Cable CBM required p->add_msg_if_player( _( "You have no cable charging system to plug it in, so you leave it alone." ) ); - return 0; + return std::make_pair( 0, 0_J ); } else if( !p->has_active_bionic( rem_bid ) ) { // when OFF it takes no effect p->add_msg_if_player( _( "Activate your cable charging system to take advantage of it." ) ); } @@ -4030,22 +4087,22 @@ int iuse::solarpack( player *p, item *it, bool, const tripoint & ) if( it->is_armor() && !( p->is_worn( *it ) ) ) { p->add_msg_if_player( m_neutral, _( "You need to wear the %1$s before you can unfold it." ), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } // no doubled sources of power if( p->worn_with_flag( flag_SOLARPACK_ON ) ) { p->add_msg_if_player( m_neutral, _( "You cannot use the %1$s with another of it's kind." ), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } p->add_msg_if_player( _( "You unfold solar array from the pack. You still need to connect it with a cable." ) ); it->convert( itype_id( it->typeId().str() + "_on" ) ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::solarpack_off( player *p, item *it, bool, const tripoint & ) +std::pair iuse::solarpack_off( player *p, item *it, bool, const tripoint & ) { if( !p->is_worn( *it ) ) { // folding when not worn p->add_msg_if_player( _( "You fold your portable solar array into the pack." ) ); @@ -4057,11 +4114,13 @@ int iuse::solarpack_off( player *p, item *it, bool, const tripoint & ) it->convert( itype_id( it->typeId().str().substr( 0, it->typeId().str().size() - 3 ) ) ); it->deactivate(); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::gasmask( player *p, item *it, bool t, const tripoint &pos ) +std::pair iuse::gasmask( player *p, item *it, bool t, const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( t ) { // Normal use if( p->is_worn( *it ) ) { // calculate amount of absorbed gas per filter charge @@ -4076,7 +4135,7 @@ int iuse::gasmask( player *p, item *it, bool t, const tripoint &pos ) it->ammo_consume( 1, p->pos() ); it->set_var( "gas_absorbed", 0 ); } - if( it->charges == 0 ) { + if( !( it->ammo_sufficient() || it->energy_sufficient( *p ) ) ) { p->add_msg_player_or_npc( m_bad, _( "Your %s requires new filter!" ), @@ -4085,7 +4144,7 @@ int iuse::gasmask( player *p, item *it, bool t, const tripoint &pos ) } } } else { // activate - if( it->charges == 0 ) { + if( !( it->ammo_sufficient() || it->energy_sufficient( *p ) ) ) { p->add_msg_if_player( _( "Your %s don't have a filter." ), it->tname() ); } else { p->add_msg_if_player( _( "You prepared your %s." ), it->tname() ); @@ -4093,36 +4152,42 @@ int iuse::gasmask( player *p, item *it, bool t, const tripoint &pos ) it->set_var( "overwrite_env_resist", it->get_base_env_resist_w_filter() ); } } - if( it->charges == 0 ) { + if( !( it->ammo_sufficient() || it->energy_sufficient( *p ) ) ) { it->set_var( "overwrite_env_resist", 0 ); it->deactivate(); } - return it->type->charges_to_use(); + return res; } -int iuse::portable_game( player *p, item *it, bool t, const tripoint & ) +std::pair iuse::portable_game( player *p, item *it, bool t, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + auto [chrg, enrg] = res; + // Each use is 15 uses. + chrg *= 15; + enrg *= 15; + if( t ) { - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_npc() ) { // Long action - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->has_trait( trait_ILLITERATE ) ) { p->add_msg_if_player( m_info, _( "You're illiterate!" ) ); - return 0; - } else if( it->units_remaining( *p ) < ( it->ammo_required() * 15 ) ) { + return std::make_pair( 0, 0_J ); + } else if( !( it->units_sufficient( chrg ) || it->energy_sufficient( *p, enrg ) ) ) { p->add_msg_if_player( m_info, _( "You don't have enough charges to play." ) ); - return 0; + return std::make_pair( 0, 0_J ); } else { std::string loaded_software = "robot_finds_kitten"; @@ -4157,7 +4222,7 @@ int iuse::portable_game( player *p, item *it, bool t, const tripoint & ) break; default: //Cancel - return 0; + return std::make_pair( 0, 0_J ); } //Play in 15-minute chunks @@ -4180,53 +4245,55 @@ int iuse::portable_game( player *p, item *it, bool t, const tripoint & ) p->add_morale( MORALE_GAME, game_score, 60, 2_hours, 30_minutes, true ); } } - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::hand_crank( player *p, item *it, bool, const tripoint & ) +std::pair iuse::hand_crank( player *p, item *it, bool, const tripoint & ) { if( p->is_npc() ) { // Long action - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "It's not waterproof enough to work underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->get_fatigue() >= fatigue_levels::dead_tired ) { p->add_msg_if_player( m_info, _( "You're too exhausted to keep cranking." ) ); - return 0; + return std::make_pair( 0, 0_J ); } - item *magazine = it->magazine_current(); - if( magazine && magazine->has_flag( flag_RECHARGE ) ) { + item *battery = it->battery_current(); + if( battery && battery->has_flag( flag_RECHARGE ) ) { // 1600 minutes. It shouldn't ever run this long, but it's an upper bound. // expectation is it runs until the player is too tired. int moves = to_moves( 1600_minutes ); - if( it->ammo_capacity() > it->ammo_remaining() ) { + if( it->energy_capacity() > it->energy_remaining() ) { p->add_msg_if_player( _( "You start cranking the %s to charge its %s." ), it->tname(), it->magazine_current()->tname() ); p->assign_activity( ACT_HAND_CRANK, moves, -1, 0, "hand-cranking" ); p->activity->targets.emplace_back( it ); } else { p->add_msg_if_player( _( "You could use the %s to charge its %s, but it's already charged." ), - it->tname(), magazine->tname() ); + it->tname(), battery->tname() ); } } else { p->add_msg_if_player( m_info, _( "You need a rechargeable battery cell to charge." ) ); } - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::vibe( player *p, item *it, bool, const tripoint & ) +std::pair iuse::vibe( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( p->is_npc() ) { // Long action // Also, that would be creepy as fuck, seriously - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do… that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( ( p->is_underwater() ) && ( !( ( p->has_trait( trait_GILLS ) ) || ( p->has_trait( trait_GILLS_CEPH ) ) || @@ -4234,15 +4301,15 @@ int iuse::vibe( player *p, item *it, bool, const tripoint & ) ( p->is_wearing( itype_rebreather_xl_on ) ) || ( p->is_wearing( itype_mask_h20survivor_on ) ) ) ) ) { p->add_msg_if_player( m_info, _( "It's waterproof, but oxygen maybe?" ) ); - return 0; + return std::make_pair( 0, 0_J ); } - if( !it->units_sufficient( *p ) ) { + if( !( it->units_sufficient() || it->energy_sufficient( *p ) ) ) { p->add_msg_if_player( m_info, _( "The %s's batteries are dead." ), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->get_fatigue() >= fatigue_levels::dead_tired ) { p->add_msg_if_player( m_info, _( "*Your* batteries are dead." ) ); - return 0; + return std::make_pair( 0, 0_J ); } else { int moves = to_moves( 20_minutes ); if( it->ammo_remaining() > 0 ) { @@ -4255,11 +4322,13 @@ int iuse::vibe( player *p, item *it, bool, const tripoint & ) p->assign_activity( ACT_VIBE, moves, -1, 0, "de-stressing" ); p->activity->targets.emplace_back( it ); } - return it->type->charges_to_use(); + return res; } -int iuse::vortex( player *p, item *it, bool, const tripoint & ) +std::pair iuse::vortex( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + std::vector spawn; for( int i = -3; i <= 3; i++ ) { spawn.emplace_back( -3, i ); @@ -4278,20 +4347,22 @@ int iuse::vortex( player *p, item *it, bool, const tripoint & ) p->moves -= to_moves( 1_seconds ); it->convert( itype_spiral_stone ); mon->friendly = -1; - return it->type->charges_to_use(); + return res; } // Only reachable when no monster has been spawned. p->add_msg_if_player( m_warning, _( "Air swirls around you for a moment." ) ); it->convert( itype_spiral_stone ); - return it->type->charges_to_use(); + return res; } -int iuse::dog_whistle( player *p, item *it, bool, const tripoint & ) +std::pair iuse::dog_whistle( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } p->add_msg_if_player( _( "You blow your dog whistle." ) ); for( monster &critter : g->all_monsters() ) { @@ -4310,32 +4381,36 @@ int iuse::dog_whistle( player *p, item *it, bool, const tripoint & ) } } } - return it->type->charges_to_use(); + return res; } -int iuse::call_of_tindalos( player *p, item *it, bool, const tripoint & ) +std::pair iuse::call_of_tindalos( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + for( const tripoint &dest : g->m.points_in_radius( p->pos(), 12 ) ) { if( g->m.is_cornerfloor( dest ) ) { g->m.add_field( dest, fd_tindalos_rift, 3 ); add_msg( m_info, _( "You hear a low-pitched echoing howl." ) ); } } - return it->type->charges_to_use(); + return res; } -int iuse::blood_draw( player *p, item *it, bool, const tripoint & ) +std::pair iuse::blood_draw( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( p->is_npc() ) { - return 0; // No NPCs for now! + return std::make_pair( 0, 0_J ); // No NPCs for now! } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( !it->contents.empty() ) { p->add_msg_if_player( m_info, _( "That %s is full!" ), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } const mtype *mt = nullptr; @@ -4385,7 +4460,7 @@ int iuse::blood_draw( player *p, item *it, bool, const tripoint & ) // NOLINTNEXTLINE(bugprone-use-after-move) it->put_in( std::move( blood ) ); } - return it->type->charges_to_use(); + return res; } } } @@ -4408,7 +4483,7 @@ int iuse::blood_draw( player *p, item *it, bool, const tripoint & ) // NOLINTNEXTLINE(bugprone-use-after-move) it->put_in( std::move( blood ) ); } - return it->type->charges_to_use(); + return res; } if( acid_blood ) { @@ -4418,7 +4493,7 @@ int iuse::blood_draw( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_info, _( "…but acidic blood melts the %s, destroying it!" ), it->tname() ); it->detach(); - return 0; + return std::make_pair( 0, 0_J ); } p->add_msg_if_player( m_info, _( "…but acidic blood damages the %s!" ), it->tname() ); } @@ -4426,18 +4501,20 @@ int iuse::blood_draw( player *p, item *it, bool, const tripoint & ) // NOLINTNEXTLINE(bugprone-use-after-move) it->put_in( std::move( acid ) ); } - return it->type->charges_to_use(); + return res; } - return it->type->charges_to_use(); + return res; } //This is just used for robofac_intercom_mission_2 -int iuse::mind_splicer( player *p, item *it, bool, const tripoint & ) +std::pair iuse::mind_splicer( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } for( auto &map_it : g->m.i_at( point( p->posx(), p->posy() ) ) ) { if( map_it->typeId() == itype_rmi2_corpse && @@ -4454,7 +4531,7 @@ int iuse::mind_splicer( player *p, item *it, bool, const tripoint & ) } if( !loc ) { add_msg( m_info, _( "Nevermind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } item &data_card = *loc; ///\EFFECT_DEX makes using the mind splicer faster @@ -4466,11 +4543,11 @@ int iuse::mind_splicer( player *p, item *it, bool, const tripoint & ) to_moves( time ) ); act->targets.emplace_back( &data_card ); p->assign_activity( std::move( act ) ); - return it->type->charges_to_use(); + return res; } } add_msg( m_info, _( "There's nothing to use the %s on here." ), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } void iuse::cut_log_into_planks( player &p ) @@ -4486,14 +4563,16 @@ void iuse::cut_log_into_planks( player &p ) p.activity->placement = g->m.getabs( p.pos() ); } -int iuse::lumber( player *p, item *it, bool t, const tripoint & ) +std::pair iuse::lumber( player *p, item *it, bool t, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( t ) { - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } // Check if player is standing on any lumber item *standing = nullptr; @@ -4506,7 +4585,7 @@ int iuse::lumber( player *p, item *it, bool t, const tripoint & ) if( standing ) { g->m.i_rem( p->pos(), standing ); cut_log_into_planks( *p ); - return it->type->charges_to_use(); + return res; } // If the player is not standing on a log, check inventory @@ -4521,11 +4600,11 @@ int iuse::lumber( player *p, item *it, bool t, const tripoint & ) if( !loc ) { p->add_msg_if_player( m_info, _( "You do not have that item!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } loc->detach(); cut_log_into_planks( *p ); - return it->type->charges_to_use(); + return res; } int iuse::chop_moves( Character &ch, item &tool ) @@ -4539,14 +4618,16 @@ int iuse::chop_moves( Character &ch, item &tool ) return to_moves( std::max( 10_minutes, time_duration::from_minutes( 60 - attr ) / quality ) ); } -int iuse::chop_tree( player *p, item *it, bool t, const tripoint & ) +std::pair iuse::chop_tree( player *p, item *it, bool t, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( !p || t ) { - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const std::function f = []( const tripoint & pnt ) { if( pnt == g->u.pos() ) { @@ -4558,7 +4639,7 @@ int iuse::chop_tree( player *p, item *it, bool t, const tripoint & ) const std::optional pnt_ = choose_adjacent_highlight( _( "Chop down which tree?" ), _( "There is no tree to chop down nearby." ), f, false ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint &pnt = *pnt_; if( !f( pnt ) ) { @@ -4567,7 +4648,7 @@ int iuse::chop_tree( player *p, item *it, bool t, const tripoint & ) } else { p->add_msg_if_player( m_info, _( "You can't chop down that." ) ); } - return 0; + return std::make_pair( 0, 0_J ); } int moves = chop_moves( *p, *it ); @@ -4581,17 +4662,19 @@ int iuse::chop_tree( player *p, item *it, bool t, const tripoint & ) p->activity->targets.emplace_back( it ); p->activity->placement = g->m.getabs( pnt ); - return it->type->charges_to_use(); + return res; } -int iuse::chop_logs( player *p, item *it, bool t, const tripoint & ) +std::pair iuse::chop_logs( player *p, item *it, bool t, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( !p || t ) { - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const std::set allowed_ter_id { @@ -4607,12 +4690,12 @@ int iuse::chop_logs( player *p, item *it, bool t, const tripoint & ) const std::optional pnt_ = choose_adjacent_highlight( _( "Chop which tree trunk?" ), _( "There is no tree trunk to chop nearby." ), f, false ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint &pnt = *pnt_; if( !f( pnt ) ) { p->add_msg_if_player( m_info, _( "You can't chop that." ) ); - return 0; + return std::make_pair( 0, 0_J ); } int moves = chop_moves( *p, *it ); @@ -4627,23 +4710,23 @@ int iuse::chop_logs( player *p, item *it, bool t, const tripoint & ) p->activity->placement = g->m.getabs( pnt ); p->activity->targets.emplace_back( it ); - return it->type->charges_to_use(); + return res; } -int iuse::oxytorch( player *p, item *it, bool, const tripoint & ) +std::pair iuse::oxytorch( player *p, item *it, bool, const tripoint & ) { if( p->is_npc() ) { // Long action - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } static const quality_id GLARE( "GLARE" ); if( !p->has_quality( GLARE, 2 ) ) { p->add_msg_if_player( m_info, _( "You need welding goggles to do that." ) ); - return 0; + return std::make_pair( 0, 0_J ); } map &here = get_map(); @@ -4662,7 +4745,7 @@ int iuse::oxytorch( player *p, item *it, bool, const tripoint & ) const std::optional pnt_ = choose_adjacent_highlight( _( "Cut up metal where?" ), _( "There is no metal to cut up nearby." ), f, false ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint &pnt = *pnt_; if( !f( pnt ) ) { @@ -4671,24 +4754,24 @@ int iuse::oxytorch( player *p, item *it, bool, const tripoint & ) } else { p->add_msg_if_player( m_info, _( "You can't cut that." ) ); } - return 0; + return std::make_pair( 0, 0_J ); } p->assign_activity( std::make_unique( std::make_unique( pnt, safe_reference( *it ) ) ) ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::hacksaw( player *p, item *it, bool t, const tripoint & ) +std::pair iuse::hacksaw( player *p, item *it, bool t, const tripoint & ) { if( !p || t ) { - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } map &here = get_map(); @@ -4707,7 +4790,7 @@ int iuse::hacksaw( player *p, item *it, bool t, const tripoint & ) const std::optional pnt_ = choose_adjacent_highlight( _( "Cut up metal where?" ), _( "There is no metal to cut up nearby." ), f, false ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint &pnt = *pnt_; if( !f( pnt ) ) { @@ -4717,21 +4800,21 @@ int iuse::hacksaw( player *p, item *it, bool t, const tripoint & ) } else { p->add_msg_if_player( m_info, _( "You can't cut that." ) ); } - return 0; + return std::make_pair( 0, 0_J ); } p->assign_activity( std::make_unique( std::make_unique( pnt, safe_reference( *it ) ) ) ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::boltcutters( player *p, item *it, bool, const tripoint & ) +std::pair iuse::boltcutters( player *p, item *it, bool, const tripoint & ) { if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } map &here = get_map(); @@ -4750,7 +4833,7 @@ int iuse::boltcutters( player *p, item *it, bool, const tripoint & ) const std::optional pnt_ = choose_adjacent_highlight( _( "Cut up metal where?" ), _( "There is no metal to cut up nearby." ), f, false ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint &pnt = *pnt_; if( !f( pnt ) ) { @@ -4760,14 +4843,14 @@ int iuse::boltcutters( player *p, item *it, bool, const tripoint & ) } else { p->add_msg_if_player( m_info, _( "You can't cut that." ) ); } - return 0; + return std::make_pair( 0, 0_J ); } p->assign_activity( std::make_unique( std::make_unique( pnt, safe_reference( *it ) ) ) ); - return 0; + return std::make_pair( 0, 0_J ); } namespace @@ -4785,8 +4868,10 @@ auto mop_blindly( const tripoint &pos ) -> bool } // namespace -auto iuse::mop( player *p, item *it, bool, const tripoint & ) -> int +std::pair iuse::mop( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + const auto mop = p->is_blind() ? mop_blindly : mop_normal; const auto xs = closest_points_first( p->pos(), 1 ); @@ -4801,24 +4886,26 @@ auto iuse::mop( player *p, item *it, bool, const tripoint & ) -> int } p->moves -= 15 * mopped_tiles; - return it->type->charges_to_use(); + return res; } -int iuse::artifact( player *p, item *it, bool, const tripoint & ) +std::pair iuse::artifact( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( p->is_npc() ) { // TODO: Allow this for trusting NPCs - return 0; + return std::make_pair( 0, 0_J ); } if( !it->is_artifact() ) { debugmsg( "iuse::artifact called on a non-artifact item! %s", it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } else if( !it->is_tool() ) { debugmsg( "iuse::artifact called on a non-tool artifact! %s", it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } g->events().send( p->getID(), it->tname( 1, false ) ); @@ -5137,21 +5224,23 @@ int iuse::artifact( player *p, item *it, bool, const tripoint & ) break; } } - return it->type->charges_to_use(); + return res; } -int iuse::spray_can( player *p, item *it, bool, const tripoint & ) +std::pair iuse::spray_can( player *p, item *it, bool, const tripoint & ) { const std::optional dest_ = choose_adjacent( _( "Spray where?" ) ); if( !dest_ ) { - return 0; + return std::make_pair( 0, 0_J ); } return handle_ground_graffiti( *p, it, _( "Spray what?" ), dest_.value() ); } -int iuse::handle_ground_graffiti( player &p, item *it, const std::string &prefix, - const tripoint &where ) +std::pair iuse::handle_ground_graffiti( player &p, item *it, + const std::string &prefix, const tripoint &where ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + string_input_popup popup; std::string message = popup .description( prefix + " " + _( "(To delete, clear the text and confirm)" ) ) @@ -5159,7 +5248,7 @@ int iuse::handle_ground_graffiti( player &p, item *it, const std::string &prefix .identifier( "graffiti" ) .query_string(); if( popup.canceled() ) { - return 0; + return std::make_pair( 0, 0_J ); } bool grave = g->m.ter( where ) == t_grave_new; @@ -5174,7 +5263,7 @@ int iuse::handle_ground_graffiti( player &p, item *it, const std::string &prefix p.add_msg_if_player( m_info, _( "You manage to get rid of the message on the surface." ) ); } } else { - return 0; + return std::make_pair( 0, 0_J ); } } else { g->m.set_graffiti( where, message ); @@ -5187,23 +5276,29 @@ int iuse::handle_ground_graffiti( player &p, item *it, const std::string &prefix } p.moves -= move_cost; if( it != nullptr ) { - return it->type->charges_to_use(); + return res; } else { - return 0; + return std::make_pair( 0, 0_J ); } } -int iuse::towel( player *p, item *it, bool t, const tripoint & ) +std::pair iuse::towel( player *p, item *it, bool t, const tripoint & ) { return towel_common( p, it, t ); } -int iuse::towel_common( player *p, item *it, bool t ) +std::pair iuse::towel_common( player *p, item *it, bool t ) { + std::pair res( 0, 0_J ); + // I have no idea how this use action can be called without an actual item, just roll with it. + if( it ) { + res = std::make_pair( it->type->charges_to_use(), it->energy_required() ); + } + if( t ) { // Continuous usage, do nothing as not initiated by the player, this is for // wet towels only as they are active items. - return 0; + return std::make_pair( 0, 0_J ); } bool slime = p->has_effect( effect_slimed ); bool boom = p->has_effect( effect_boomered ); @@ -5265,29 +5360,29 @@ int iuse::towel_common( player *p, item *it, bool t ) it->activate(); } } - return it ? it->type->charges_to_use() : 0; + return res; } -int iuse::unfold_generic( player *p, item *it, bool, const tripoint & ) +std::pair iuse::unfold_generic( player *p, item *it, bool, const tripoint & ) { if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } map &here = get_map(); vehicle *veh = here.add_vehicle( vproto_id( "none" ), p->pos(), 0_degrees, 0, 0, false ); if( veh == nullptr ) { p->add_msg_if_player( m_info, _( "There's no room to unfold the %s." ), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } veh->name = it->get_var( "vehicle_name" ); if( !veh->restore( it->get_var( "folding_bicycle_parts" ) ) ) { g->m.destroy_vehicle( veh ); - return 0; + return std::make_pair( 0, 0_J ); } const bool can_float = size( veh->get_avail_parts( "FLOATS" ) ) > 2; @@ -5303,7 +5398,7 @@ int iuse::unfold_generic( player *p, item *it, bool, const tripoint & ) if( invalid_pos( pp, can_float ) ) { p->add_msg_if_player( m_info, _( "There's no room to unfold the %s." ), it->tname() ); g->m.destroy_vehicle( veh ); - return 0; + return std::make_pair( 0, 0_J ); } } @@ -5319,13 +5414,16 @@ int iuse::unfold_generic( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_neutral, unfold_msg, veh->name ); p->moves -= it->get_var( "moves", to_turns( 5_seconds ) ); - return 1; + return std::make_pair( 1, 0_J ); } -int iuse::adrenaline_injector( player *p, item *it, bool, const tripoint & ) +std::pair iuse::adrenaline_injector( player *p, item *it, bool, + const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( p->is_npc() && p->get_effect_dur( effect_adrenaline ) >= 3_minutes ) { - return 0; + return std::make_pair( 0, 0_J ); } p->moves -= to_moves( 1_seconds ); @@ -5341,14 +5439,16 @@ int iuse::adrenaline_injector( player *p, item *it, bool, const tripoint & ) p->add_effect( effect_adrenaline, 2_minutes ); - return it->type->charges_to_use(); + return res; } -int iuse::jet_injector( player *p, item *it, bool, const tripoint & ) +std::pair iuse::jet_injector( player *p, item *it, bool, const tripoint & ) { - if( !it->ammo_sufficient() ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + + if( !it->ammo_sufficient() || !it->energy_sufficient( *p ) ) { p->add_msg_if_player( m_info, _( "The jet injector is empty." ) ); - return 0; + return std::make_pair( 0, 0_J ); } else { p->add_msg_if_player( _( "You inject yourself with the jet injector." ) ); // Intensity is 2 here because intensity = 1 is the comedown @@ -5363,20 +5463,22 @@ int iuse::jet_injector( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_warning, _( "Your heart is beating alarmingly fast!" ) ); } } - return it->type->charges_to_use(); + return res; } -int iuse::stimpack( player *p, item *it, bool, const tripoint & ) +std::pair iuse::stimpack( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( p->get_item_position( it ) >= -1 ) { p->add_msg_if_player( m_info, _( "You must wear the stimulant delivery system before you can activate it." ) ); - return 0; + return std::make_pair( 0, 0_J ); } - if( !it->ammo_sufficient() ) { + if( !it->ammo_sufficient() || !it->energy_sufficient( *p ) ) { p->add_msg_if_player( m_info, _( "The stimulant delivery system is empty." ) ); - return 0; + return std::make_pair( 0, 0_J ); } else { p->add_msg_if_player( _( "You inject yourself with the stimulants." ) ); // Intensity is 2 here because intensity = 1 is the comedown @@ -5386,18 +5488,20 @@ int iuse::stimpack( player *p, item *it, bool, const tripoint & ) p->mod_fatigue( -100 ); p->set_stamina( p->get_stamina_max() ); } - return it->type->charges_to_use(); + return res; } -int iuse::radglove( player *p, item *it, bool, const tripoint & ) +std::pair iuse::radglove( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( p->get_item_position( it ) >= -1 ) { p->add_msg_if_player( m_info, _( "You must wear the radiation biomonitor before you can activate it." ) ); - return 0; - } else if( !it->units_sufficient( *p ) ) { + return std::make_pair( 0, 0_J ); + } else if( !it->units_sufficient() || !it->energy_sufficient( *p ) ) { p->add_msg_if_player( m_info, _( "The radiation biomonitor needs batteries to function." ) ); - return 0; + return std::make_pair( 0, 0_J ); } else { p->add_msg_if_player( _( "You activate your radiation biomonitor." ) ); if( p->get_rad() >= 1 ) { @@ -5414,14 +5518,16 @@ int iuse::radglove( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( _( "Have a nice day!" ) ); } - return it->type->charges_to_use(); + return res; } -int iuse::contacts( player *p, item *it, bool, const tripoint & ) +std::pair iuse::contacts( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const time_duration duration = rng( 6_days, 8_days ); if( p->has_effect( effect_contacts ) ) { @@ -5430,28 +5536,30 @@ int iuse::contacts( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( _( "You replace your current %s." ), it->tname() ); p->remove_effect( effect_contacts ); p->add_effect( effect_contacts, duration ); - return it->type->charges_to_use(); + return res; } else { p->add_msg_if_player( _( "You don't do anything with your %s." ), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } } else if( p->has_trait( trait_HYPEROPIC ) || p->has_trait( trait_MYOPIC ) || p->has_trait( trait_URSINE_EYE ) ) { p->moves -= to_moves( 20_seconds ); p->add_msg_if_player( _( "You put the %s in your eyes." ), it->tname() ); p->add_effect( effect_contacts, duration ); - return it->type->charges_to_use(); + return res; } else { p->add_msg_if_player( m_info, _( "Your vision is fine already." ) ); - return 0; + return std::make_pair( 0, 0_J ); } } -int iuse::talking_doll( player *p, item *it, bool, const tripoint & ) +std::pair iuse::talking_doll( player *p, item *it, bool, const tripoint & ) { - if( !it->units_sufficient( *p ) ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + + if( !it->units_sufficient() || !it->energy_sufficient( *p ) ) { p->add_msg_if_player( m_info, _( "The %s's batteries are dead." ), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } const SpeechBubble &speech = get_speech( it->typeId().str() ); @@ -5464,20 +5572,20 @@ int iuse::talking_doll( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( _( "You hear \"%s\"" ), speech.text ); } - return it->type->charges_to_use(); + return res; } -int iuse::gun_clean( player *p, item *, bool, const tripoint & ) +std::pair iuse::gun_clean( player *p, item *, bool, const tripoint & ) { item *loc = game_menus::inv::titled_menu( g->u, ( "Select the firearm to clean or mend" ) ); if( !loc ) { p->add_msg_if_player( m_info, _( "You do not have that item!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } item &fix = *loc; if( !fix.is_firearm() ) { p->add_msg_if_player( m_info, _( "That isn't a firearm!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } const auto is_gunmods_not_faulty = []( const auto & xs ) -> bool { @@ -5486,54 +5594,56 @@ int iuse::gun_clean( player *p, item *, bool, const tripoint & ) if( fix.faults.empty() && is_gunmods_not_faulty( fix.gunmods() ) ) { p->add_msg_if_player( m_info, _( "There's nothing you can clean or mend with this." ) ); - return 0; + return std::make_pair( 0, 0_J ); } avatar_funcs::mend_item( *p->as_avatar(), *loc ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::gun_repair( player *p, item *it, bool, const tripoint & ) +std::pair iuse::gun_repair( player *p, item *it, bool, const tripoint & ) { - if( !it->units_sufficient( *p ) ) { - return 0; + std::pair res( it->type->charges_to_use(), it->energy_required() ); + + if( !it->units_sufficient() || !it->energy_sufficient( *p ) ) { + return std::make_pair( 0, 0_J ); } if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } /** @EFFECT_MECHANICS >1 allows gun repair */ if( p->get_skill_level( skill_mechanics ) < 2 ) { p->add_msg_if_player( m_info, _( "You need a mechanics skill of 2 to use this repair kit." ) ); - return 0; + return std::make_pair( 0, 0_J ); } item *loc = game_menus::inv::titled_menu( g->u, ( "Select the firearm to repair" ) ); if( !loc ) { p->add_msg_if_player( m_info, _( "You do not have that item!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } item &fix = *loc; if( !fix.is_firearm() ) { p->add_msg_if_player( m_info, _( "That isn't a firearm!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( fix.has_flag( flag_NO_REPAIR ) ) { p->add_msg_if_player( m_info, _( "You cannot repair your %s." ), fix.tname() ); - return 0; + return std::make_pair( 0, 0_J ); } if( fix.damage() <= fix.min_damage() ) { p->add_msg_if_player( m_info, _( "You cannot improve your %s any more this way." ), fix.tname() ); - return 0; + return std::make_pair( 0, 0_J ); } if( fix.damage() <= 0 && p->get_skill_level( skill_mechanics ) < 8 ) { p->add_msg_if_player( m_info, _( "Your %s is already in peak condition." ), fix.tname() ); p->add_msg_if_player( m_info, _( "With a higher mechanics skill, you might be able to improve it." ) ); - return 0; + return std::make_pair( 0, 0_J ); } /** @EFFECT_MECHANICS >=8 allows accurizing ranged weapons */ const std::string startdurability = fix.durability_indicator( true ); @@ -5565,41 +5675,41 @@ int iuse::gun_repair( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_good, _( "You repair your %s completely! ( %s-> %s)" ), fix.tname( 1, false ), startdurability, resultdurability ); } - return it->type->charges_to_use(); + return res; } -int iuse::gunmod_attach( player *p, item *it, bool, const tripoint & ) +std::pair iuse::gunmod_attach( player *p, item *it, bool, const tripoint & ) { if( !it || !it->is_gunmod() ) { debugmsg( "tried to attach non-gunmod" ); - return 0; + return std::make_pair( 0, 0_J ); } if( !p ) { - return 0; + return std::make_pair( 0, 0_J ); } auto loc = game_menus::inv::gun_to_modify( *p, *it ); if( !loc ) { add_msg( m_info, _( "Never mind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } avatar_funcs::gunmod_add( *p->as_avatar(), *loc, *it ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::toolmod_attach( player *p, item *it, bool, const tripoint & ) +std::pair iuse::toolmod_attach( player *p, item *it, bool, const tripoint & ) { if( !it || !it->is_toolmod() ) { debugmsg( "tried to attach non-toolmod" ); - return 0; + return std::make_pair( 0, 0_J ); } if( !p ) { - return 0; + return std::make_pair( 0, 0_J ); } auto filter = [&it]( const item & e ) { @@ -5623,22 +5733,24 @@ int iuse::toolmod_attach( player *p, item *it, bool, const tripoint & ) if( !loc ) { add_msg( m_info, _( "Never mind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( loc->ammo_remaining() ) { if( !avatar_funcs::unload_item( *p->as_avatar(), *loc ) ) { p->add_msg_if_player( m_info, _( "You cancel unloading the tool." ) ); - return 0; + return std::make_pair( 0, 0_J ); } } avatar_funcs::toolmod_add( *p->as_avatar(), *loc, *it ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::bell( player *p, item *it, bool, const tripoint & ) +std::pair iuse::bell( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( it->typeId() == itype_cow_bell ) { sounds::sound( p->pos(), 12, sounds::sound_t::music, _( "Clank! Clank!" ), true, "misc", "cow_bell" ); @@ -5656,17 +5768,19 @@ int iuse::bell( player *p, item *it, bool, const tripoint & ) } else { sounds::sound( p->pos(), 4, sounds::sound_t::music, _( "Ring! Ring!" ), true, "misc", "bell" ); } - return it->type->charges_to_use(); + return res; } -int iuse::seed( player *p, item *it, bool, const tripoint & ) +std::pair iuse::seed( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( p->is_npc() || query_yn( _( "Sure you want to eat the %s? You could plant it in a mound of dirt." ), colorize( it->tname(), it->color_in_inventory() ) ) ) { - return it->type->charges_to_use(); //This eats the seed object. + return res; //This eats the seed object. } - return 0; + return std::make_pair( 0, 0_J ); } bool iuse::robotcontrol_can_target( player *p, const monster &m ) @@ -5677,23 +5791,25 @@ bool iuse::robotcontrol_can_target( player *p, const monster &m ) && rl_dist( p->pos(), m.pos() ) <= 10; } -int iuse::robotcontrol( player *p, item *it, bool, const tripoint & ) +std::pair iuse::robotcontrol( player *p, item *it, bool, const tripoint & ) { - if( !it->units_sufficient( *p ) ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + + if( !it->units_sufficient() || !it->energy_sufficient( *p ) ) { p->add_msg_if_player( _( "The %s's batteries are dead." ), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->has_trait( trait_ILLITERATE ) ) { p->add_msg_if_player( _( "You cannot read a computer screen." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->has_trait( trait_HYPEROPIC ) && !p->worn_with_flag( flag_FIX_FARSIGHT ) && !p->has_effect( effect_contacts ) && !p->has_bionic( bio_eye_optic ) ) { p->add_msg_if_player( m_info, _( "You'll need to put on reading glasses before you can see the screen." ) ); - return 0; + return std::make_pair( 0, 0_J ); } int choice = uilist( _( "Welcome to hackPRO!:" ), { @@ -5726,14 +5842,14 @@ int iuse::robotcontrol( player *p, item *it, bool, const tripoint & ) } if( mons.empty() ) { p->add_msg_if_player( m_info, _( "No enemy robots in range." ) ); - return it->type->charges_to_use(); + return res; } pointmenu_cb callback( locations ); pick_robot.callback = &callback; pick_robot.query(); if( pick_robot.ret < 0 || static_cast( pick_robot.ret ) >= mons.size() ) { p->add_msg_if_player( m_info, _( "Never mind" ) ); - return it->type->charges_to_use(); + return res; } const size_t mondex = pick_robot.ret; shared_ptr_fast< monster > z = mons[mondex]; @@ -5748,7 +5864,7 @@ int iuse::robotcontrol( player *p, item *it, bool, const tripoint & ) p->assign_activity( std::move( act ) ); - return it->type->charges_to_use(); + return res; } case 1: { //make all friendly robots stop their purposeless extermination of (un)life. p->moves -= to_moves( 1_seconds ); @@ -5763,9 +5879,9 @@ int iuse::robotcontrol( player *p, item *it, bool, const tripoint & ) } if( f == 0 ) { p->add_msg_if_player( _( "You are not commanding any robots." ) ); - return 0; + return std::make_pair( 0, 0_J ); } - return it->type->charges_to_use(); + return res; } case 2: { //make all friendly robots terminate (un)life with extreme prejudice p->moves -= to_moves( 1_seconds ); @@ -5780,12 +5896,12 @@ int iuse::robotcontrol( player *p, item *it, bool, const tripoint & ) } if( f == 0 ) { p->add_msg_if_player( _( "You are not commanding any robots." ) ); - return 0; + return std::make_pair( 0, 0_J ); } - return it->type->charges_to_use(); + return res; } } - return 0; + return std::make_pair( 0, 0_J ); } static void init_memory_card_with_random_stuff( item &it ) @@ -6029,8 +6145,10 @@ static std::string photo_quality_name( const int index ) return _( names[index] ); } -int iuse::einktabletpc( player *p, item *it, bool t, const tripoint &pos ) +std::pair iuse::einktabletpc( player *p, item *it, bool t, const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( t ) { if( !it->get_var( "EIPC_MUSIC_ON" ).empty() && ( it->ammo_remaining() > 0 ) ) { if( calendar::once_every( 5_minutes ) ) { @@ -6046,10 +6164,10 @@ int iuse::einktabletpc( player *p, item *it, bool t, const tripoint &pos ) p->add_msg_if_player( m_info, _( "Tablet's batteries are dead." ) ); } - return 0; + return std::make_pair( 0, 0_J ); } else if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } else if( !p->is_npc() ) { enum { @@ -6058,17 +6176,17 @@ int iuse::einktabletpc( player *p, item *it, bool t, const tripoint &pos ) if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->has_trait( trait_ILLITERATE ) ) { p->add_msg_if_player( m_info, _( "You cannot read a computer screen." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->has_trait( trait_HYPEROPIC ) && !p->worn_with_flag( flag_FIX_FARSIGHT ) && !p->has_effect( effect_contacts ) && !p->has_bionic( bio_eye_optic ) ) { p->add_msg_if_player( m_info, _( "You'll need to put on reading glasses before you can see the screen." ) ); - return 0; + return std::make_pair( 0, 0_J ); } uilist amenu; @@ -6167,7 +6285,7 @@ int iuse::einktabletpc( player *p, item *it, bool t, const tripoint &pos ) } } - return it->type->charges_to_use(); + return res; } if( ei_music == choice ) { @@ -6187,7 +6305,7 @@ int iuse::einktabletpc( player *p, item *it, bool t, const tripoint &pos ) } - return it->type->charges_to_use(); + return res; } if( ei_recipe == choice ) { @@ -6217,12 +6335,12 @@ int iuse::einktabletpc( player *p, item *it, bool t, const tripoint &pos ) rmenu.query(); - return it->type->charges_to_use(); + return res; } if( ei_uploaded_photos == choice ) { show_photo_selection( *p, *it, "EIPC_EXTENDED_PHOTOS" ); - return it->type->charges_to_use(); + return res; } if( ei_monsters == choice ) { @@ -6263,7 +6381,7 @@ int iuse::einktabletpc( player *p, item *it, bool t, const tripoint &pos ) const monster dummy( monster_photos[choice] ); popup( dummy.type->get_description() ); } while( true ); - return it->type->charges_to_use(); + return res; } avatar *you = p->as_avatar(); @@ -6282,29 +6400,29 @@ int iuse::einktabletpc( player *p, item *it, bool t, const tripoint &pos ) } if( !loc ) { p->add_msg_if_player( m_info, _( "You do not have that item!" ) ); - return it->type->charges_to_use(); + return res; } item &mc = *loc; if( !mc.has_flag( flag_MC_MOBILE ) ) { p->add_msg_if_player( m_info, _( "This is not a compatible memory card." ) ); - return it->type->charges_to_use(); + return res; } init_memory_card_with_random_stuff( mc ); if( mc.has_flag( flag_MC_ENCRYPTED ) ) { p->add_msg_if_player( m_info, _( "This memory card is encrypted." ) ); - return it->type->charges_to_use(); + return res; } if( !mc.has_flag( flag_MC_HAS_DATA ) ) { p->add_msg_if_player( m_info, _( "This memory card does not contain any new data." ) ); - return it->type->charges_to_use(); + return res; } einkpc_download_memory_card( *p, *it, mc ); - return it->type->charges_to_use(); + return res; } if( ei_decrypt == choice ) { @@ -6314,20 +6432,20 @@ int iuse::einktabletpc( player *p, item *it, bool t, const tripoint &pos ) } if( !loc ) { p->add_msg_if_player( m_info, _( "You do not have that item!" ) ); - return it->type->charges_to_use(); + return res; } item &mc = *loc; if( !mc.has_flag( flag_MC_MOBILE ) ) { p->add_msg_if_player( m_info, _( "This is not a compatible memory card." ) ); - return it->type->charges_to_use(); + return res; } init_memory_card_with_random_stuff( mc ); if( !mc.has_flag( flag_MC_ENCRYPTED ) ) { p->add_msg_if_player( m_info, _( "This memory card is not encrypted." ) ); - return it->type->charges_to_use(); + return res; } p->practice( skill_computer, rng( 2, 5 ) ); @@ -6354,10 +6472,10 @@ int iuse::einktabletpc( player *p, item *it, bool t, const tripoint &pos ) mc.convert( itype_mobile_memory_card_used ); } } - return it->type->charges_to_use(); + return res; } } - return 0; + return std::make_pair( 0, 0_J ); } @@ -7129,8 +7247,10 @@ static bool show_photo_selection( player &p, item &it, const std::string &var_na return true; } -int iuse::camera( player *p, item *it, bool, const tripoint & ) +std::pair iuse::camera( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + enum {c_shot, c_photos, c_monsters, c_upload}; // CAMERA_NPC_PHOTOS is old save variable @@ -7157,7 +7277,7 @@ int iuse::camera( player *p, item *it, bool, const tripoint & ) const int choice = amenu.ret; if( choice < 0 ) { - return 0; + return std::make_pair( 0, 0_J ); } if( c_shot == choice ) { @@ -7165,7 +7285,7 @@ int iuse::camera( player *p, item *it, bool, const tripoint & ) if( !aim_point_ ) { p->add_msg_if_player( _( "Never mind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } tripoint aim_point = *aim_point_; bool incorrect_focus = false; @@ -7296,21 +7416,21 @@ int iuse::camera( player *p, item *it, bool, const tripoint & ) if( !monster_vec.empty() ) { item_save_monsters( *p, *it, monster_vec, photo_quality ); } - return it->type->charges_to_use(); + return res; } } - return it->type->charges_to_use(); + return res; } if( c_photos == choice ) { show_photo_selection( *p, *it, "CAMERA_EXTENDED_PHOTOS" ); - return it->type->charges_to_use(); + return res; } if( c_monsters == choice ) { if( p->is_blind() ) { p->add_msg_if_player( _( "You can't see the camera screen, you're blind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } uilist pmenu; @@ -7358,14 +7478,14 @@ int iuse::camera( player *p, item *it, bool, const tripoint & ) } while( true ); - return it->type->charges_to_use(); + return res; } if( c_upload == choice ) { if( p->is_blind() ) { p->add_msg_if_player( _( "You can't see the camera screen, you're blind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } p->moves -= to_moves( 2_seconds ); @@ -7379,25 +7499,25 @@ int iuse::camera( player *p, item *it, bool, const tripoint & ) } if( !loc ) { p->add_msg_if_player( m_info, _( "You do not have that item!" ) ); - return it->type->charges_to_use(); + return res; } item &mc = *loc; if( !mc.has_flag( flag_MC_MOBILE ) ) { p->add_msg_if_player( m_info, _( "This is not a compatible memory card." ) ); - return it->type->charges_to_use(); + return res; } init_memory_card_with_random_stuff( mc ); if( mc.has_flag( flag_MC_ENCRYPTED ) ) { if( !query_yn( _( "This memory card is encrypted. Format and clear data?" ) ) ) { - return it->type->charges_to_use(); + return res; } } if( mc.has_flag( flag_MC_HAS_DATA ) ) { if( !query_yn( _( "Are you sure you want to clear the old data on the card?" ) ) ) { - return it->type->charges_to_use(); + return res; } } @@ -7411,14 +7531,15 @@ int iuse::camera( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_info, _( "You upload your photos and monster collection to memory card." ) ); - return it->type->charges_to_use(); + return res; } - return it->type->charges_to_use(); + return res; } -int iuse::ehandcuffs( player *p, item *it, bool t, const tripoint &pos ) +std::pair iuse::ehandcuffs( player *p, item *it, bool t, const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); if( t ) { @@ -7427,10 +7548,10 @@ int iuse::ehandcuffs( player *p, item *it, bool t, const tripoint &pos ) it->ammo_unset(); it->deactivate(); add_msg( m_good, _( "%s automatically turned off!" ), it->tname() ); - return it->type->charges_to_use(); + return res; } - if( it->charges == 0 ) { + if( !( it->ammo_sufficient() || it->energy_sufficient( *p ) ) ) { sounds::sound( pos, 2, sounds::sound_t::combat, "Click.", true, "tools", "handcuffs" ); it->unset_flag( flag_NO_UNWIELD ); @@ -7440,7 +7561,7 @@ int iuse::ehandcuffs( player *p, item *it, bool t, const tripoint &pos ) add_msg( m_good, _( "%s on your hands opened!" ), it->tname() ); } - return it->type->charges_to_use(); + return res; } if( p->has_item( *it ) ) { @@ -7454,7 +7575,7 @@ int iuse::ehandcuffs( player *p, item *it, bool t, const tripoint &pos ) add_msg( m_good, _( "The %s crackle with electricity from your bionic, then come off your hands!" ), it->tname() ); - return it->type->charges_to_use(); + return res; } } @@ -7493,11 +7614,11 @@ int iuse::ehandcuffs( player *p, item *it, bool t, const tripoint &pos ) it->set_var( "HANDCUFFS_X", pos.x ); it->set_var( "HANDCUFFS_Y", pos.y ); - return it->type->charges_to_use(); + return res; } - return it->type->charges_to_use(); + return res; } @@ -7508,30 +7629,34 @@ int iuse::ehandcuffs( player *p, item *it, bool t, const tripoint &pos ) add_msg( _( "The %s have discharged and can be taken off." ), it->tname() ); } - return it->type->charges_to_use(); + return res; } -int iuse::foodperson( player *p, item *it, bool t, const tripoint &pos ) +std::pair iuse::foodperson( player *p, item *it, bool t, const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( t ) { if( calendar::once_every( 1_minutes ) ) { const SpeechBubble &speech = get_speech( "foodperson_mask" ); sounds::sound( pos, speech.volume, sounds::sound_t::alarm, speech.text.translated(), true, "speech", "foodperson_mask" ); } - return it->type->charges_to_use(); + return res; } - time_duration shift = time_duration::from_turns( it->magazine_current()->ammo_remaining() * - it->type->tool->turns_per_charge - it->type->tool->turns_active ); + time_duration shift = time_duration::from_turns( + it->energy_required() / it->energy_available( *p ) ); p->add_msg_if_player( m_info, _( "Your HUD lights-up: \"Your shift ends in %s\"." ), to_string( shift ) ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::radiocar( player *p, item *it, bool, const tripoint & ) +std::pair iuse::radiocar( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + int choice = -1; item *bomb_it = it->contents.get_item_with( []( const item & c ) { return c.has_flag( flag_RADIOCARITEM ); @@ -7546,13 +7671,13 @@ int iuse::radiocar( player *p, item *it, bool, const tripoint & ) } ); } if( choice < 0 ) { - return 0; + return std::make_pair( 0, 0_J ); } if( choice == 0 ) { //Turn car ON - if( !it->ammo_sufficient() ) { + if( !( it->ammo_sufficient() || it->energy_sufficient( *p ) ) ) { p->add_msg_if_player( _( "The RC car's batteries seem to be dead." ) ); - return 0; + return std::make_pair( 0, 0_J ); } it->convert( itype_radio_car_on ); @@ -7561,7 +7686,7 @@ int iuse::radiocar( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( _( "You turned on your RC car, now place it on ground, and use radio control to play." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( choice == 1 ) { @@ -7577,7 +7702,7 @@ int iuse::radiocar( player *p, item *it, bool, const tripoint & ) } if( !loc ) { p->add_msg_if_player( m_info, _( "You do not have that item!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } item &put = *loc; @@ -7604,20 +7729,22 @@ int iuse::radiocar( player *p, item *it, bool, const tripoint & ) } } - return it->type->charges_to_use(); + return res; } -int iuse::radiocaron( player *p, item *it, bool t, const tripoint &pos ) +std::pair iuse::radiocaron( player *p, item *it, bool t, const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( t ) { //~Sound of a radio controlled car moving around sounds::sound( pos, 6, sounds::sound_t::movement, _( "buzzz…" ), true, "misc", "rc_car_drives" ); - return it->type->charges_to_use(); - } else if( !it->ammo_sufficient() ) { + return res; + } else if( !( it->ammo_sufficient() || it->energy_sufficient( *p ) ) ) { // Deactivate since other mode has an iuse too. it->deactivate(); - return 0; + return std::make_pair( 0, 0_J ); } int choice = uilist( _( "What to do with activated RC car?" ), { @@ -7625,7 +7752,7 @@ int iuse::radiocaron( player *p, item *it, bool t, const tripoint &pos ) } ); if( choice < 0 ) { - return it->type->charges_to_use(); + return res; } if( choice == 0 ) { @@ -7633,10 +7760,10 @@ int iuse::radiocaron( player *p, item *it, bool t, const tripoint &pos ) it->deactivate(); p->add_msg_if_player( _( "You turned off your RC car." ) ); - return it->type->charges_to_use(); + return res; } - return it->type->charges_to_use(); + return res; } /** @@ -7702,17 +7829,19 @@ static void emit_radio_signal( player &p, const flag_id &signal ) } } -int iuse::radiocontrol( player *p, item *it, bool t, const tripoint & ) +std::pair iuse::radiocontrol( player *p, item *it, bool t, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( t ) { - if( !it->units_sufficient( *p ) ) { + if( !( it->units_sufficient() || it->energy_sufficient( *p ) ) ) { it->deactivate(); p->remove_value( "remote_controlling" ); } else if( p->get_value( "remote_controlling" ).empty() ) { it->deactivate(); } - return it->type->charges_to_use(); + return res; } const char *car_action = nullptr; @@ -7729,7 +7858,7 @@ int iuse::radiocontrol( player *p, item *it, bool t, const tripoint & ) } ); if( choice < 0 ) { - return 0; + return std::make_pair( 0, 0_J ); } else if( choice == 0 ) { if( it->is_active() ) { it->deactivate(); @@ -7748,7 +7877,7 @@ int iuse::radiocontrol( player *p, item *it, bool t, const tripoint & ) if( rc_pairs.empty() ) { p->add_msg_if_player( _( "No active RC cars on ground and in range." ) ); - return it->type->charges_to_use(); + return res; } std::vector locations; @@ -7763,7 +7892,7 @@ int iuse::radiocontrol( player *p, item *it, bool t, const tripoint & ) pick_rc.query(); if( pick_rc.ret < 0 || static_cast( pick_rc.ret ) >= rc_pairs.size() ) { p->add_msg_if_player( m_info, _( "Never mind." ) ); - return it->type->charges_to_use(); + return res; } tripoint rc_loc = locations[pick_rc.ret]; @@ -7785,7 +7914,7 @@ int iuse::radiocontrol( player *p, item *it, bool t, const tripoint & ) p->add_msg_if_player( m_warning, _( "The %s in your inventory would explode on this signal. Place it down before sending the signal." ), bombs.front()->display_name() ); - return 0; + return std::make_pair( 0, 0_J ); } p->add_msg_if_player( _( "Click." ) ); @@ -7793,7 +7922,7 @@ int iuse::radiocontrol( player *p, item *it, bool t, const tripoint & ) p->moves -= to_moves( 2_seconds ); } - return it->type->charges_to_use(); + return res; } static bool hackveh( player &p, item &it, vehicle &veh ) @@ -7893,12 +8022,14 @@ static vehicle *pickveh( const tripoint ¢er, bool advanced ) } } -int iuse::remoteveh( player *p, item *it, bool t, const tripoint &pos ) +std::pair iuse::remoteveh( player *p, item *it, bool t, const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + vehicle *remote = g->remoteveh(); if( t ) { bool stop = false; - if( !it->units_sufficient( *p ) ) { + if( !( it->units_sufficient() || it->energy_sufficient( *p ) ) ) { p->add_msg_if_player( m_bad, _( "The remote control's battery goes dead." ) ); stop = true; } else if( remote == nullptr ) { @@ -7913,7 +8044,7 @@ int iuse::remoteveh( player *p, item *it, bool t, const tripoint &pos ) g->setremoteveh( nullptr ); } - return it->type->charges_to_use(); + return res; } bool controlling = it->is_active() && remote != nullptr; @@ -7923,13 +8054,13 @@ int iuse::remoteveh( player *p, item *it, bool t, const tripoint &pos ) } ); if( choice < 0 || choice > 1 ) { - return 0; + return std::make_pair( 0, 0_J ); } if( choice == 0 && controlling ) { it->deactivate(); g->setremoteveh( nullptr ); - return 0; + return std::make_pair( 0, 0_J ); } point p2( g->u.view_offset.xy() ); @@ -7937,11 +8068,11 @@ int iuse::remoteveh( player *p, item *it, bool t, const tripoint &pos ) vehicle *veh = pickveh( pos, choice == 0 ); if( veh == nullptr ) { - return 0; + return std::make_pair( 0, 0_J ); } if( !hackveh( *p, *it, *veh ) ) { - return 0; + return std::make_pair( 0, 0_J ); } if( choice == 0 ) { @@ -7968,7 +8099,7 @@ int iuse::remoteveh( player *p, item *it, bool t, const tripoint &pos ) g->u.view_offset.x = p2.x; g->u.view_offset.y = p2.y; - return it->type->charges_to_use(); + return res; } static bool multicooker_hallu( player &p ) @@ -8023,20 +8154,20 @@ static bool multicooker_hallu( player &p ) } -int iuse::autoclave( player *p, item *, bool, const tripoint &pos ) +std::pair iuse::autoclave( player *p, item *, bool, const tripoint &pos ) { iexamine::autoclave_empty( *p, pos ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) +std::pair iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) { static const std::set multicooked_subcats = { "CSC_FOOD_MEAT", "CSC_FOOD_VEGGI", "CSC_FOOD_PASTA" }; - static const int charges_to_start = 50; + static const units::energy energy_to_start = 50_kJ; if( t ) { - if( !it->units_sufficient( *p ) ) { + if( !( it->units_sufficient() || it->energy_sufficient( *p ) ) ) { it->deactivate(); - return 0; + return std::make_pair( 0, 0_J ); } int cooktime = it->get_var( "COOKTIME", 0 ); @@ -8061,10 +8192,10 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) //~ sound of a multi-cooker finishing its cycle! sounds::sound( pos, 8, sounds::sound_t::alarm, _( "ding!" ), true, "misc", "ding" ); - return 0; + return std::make_pair( 0, 0_J ); } else { it->set_var( "COOKTIME", cooktime ); - return 0; + return std::make_pair( 0, 0_J ); } } else { @@ -8074,18 +8205,18 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) if( p->is_underwater() ) { p->add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->has_trait( trait_ILLITERATE ) ) { p->add_msg_if_player( m_info, _( "You cannot read, and don't understand the screen or the buttons!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->has_effect( effect_hallu ) || p->has_effect( effect_visuals ) ) { if( multicooker_hallu( *p ) ) { - return 0; + return std::make_pair( 0, 0_J ); } } @@ -8093,7 +8224,7 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) !p->has_effect( effect_contacts ) ) { p->add_msg_if_player( m_info, _( "You'll need to put on reading glasses before you can see the screen." ) ); - return 0; + return std::make_pair( 0, 0_J ); } uilist menu; @@ -8108,9 +8239,9 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) menu.addentry( mc_stop, true, 's', _( "Stop cooking" ) ); } else { if( dish_it == nullptr ) { - if( it->ammo_remaining() < charges_to_start ) { + if( it->energy_sufficient( *p, energy_to_start ) ) { p->add_msg_if_player( _( "Batteries are low." ) ); - return 0; + return std::make_pair( 0, 0_J ); } menu.addentry( mc_start, true, 's', _( "Start cooking" ) ); @@ -8138,7 +8269,7 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) int choice = menu.ret; if( choice < 0 ) { - return 0; + return std::make_pair( 0, 0_J ); } if( mc_stop == choice ) { @@ -8148,7 +8279,7 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) it->erase_var( "COOKTIME" ); it->erase_var( "RECIPE" ); } - return 0; + return std::make_pair( 0, 0_J ); } if( mc_take == choice ) { @@ -8160,7 +8291,7 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) p->add_msg_if_player( m_info, _( "You don't have a suitable container to store your %s." ), dish_name ); - return 0; + return std::make_pair( 0, 0_J ); } liquid_handler::handle_all_liquid( std::move( dish ), PICKUP_RANGE ); } else { @@ -8172,7 +8303,7 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) p->add_msg_if_player( m_good, _( "You got the %s from the multi-cooker." ), dish_name ); - return 0; + return std::make_pair( 0, 0_J ); } if( mc_start == choice ) { @@ -8209,32 +8340,32 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) int choice = dmenu.ret; if( choice < 0 ) { - return 0; + return std::make_pair( 0, 0_J ); } else { const recipe *meal = dishes[choice]; int mealtime; if( it->get_var( "MULTI_COOK_UPGRADE" ) == "UPGRADE" ) { - mealtime = meal->time; + mealtime = meal->time / 100; } else { - mealtime = meal->time * 2; + mealtime = meal->time * 2 / 100; } - const int all_charges = charges_to_start + mealtime / ( it->type->tool->power_draw / 10000 ); + const units::energy all_charges = energy_to_start + it->energy_required() * mealtime; - if( it->ammo_remaining() < all_charges ) { + if( it->energy_sufficient( *p, all_charges ) ) { p->add_msg_if_player( m_warning, - _( "The multi-cooker needs %d charges to cook this dish." ), - all_charges ); + _( "The multi-cooker needs %s to cook this dish." ), + units::display( all_charges ) ); - return 0; + return std::make_pair( 0, 0_J ); } const auto filter = is_crafting_component; const requirement_data *reqs = meal->deduped_requirements().select_alternative( *p, filter ); if( !reqs ) { - return 0; + return std::make_pair( 0, 0_J ); } for( const auto &component : reqs->get_components() ) { @@ -8250,11 +8381,11 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) it->convert( itype_multi_cooker_filled ); it->activate(); - it->ammo_consume( charges_to_start, pos ); + it->energy_consume( energy_to_start, pos ); p->practice( skill_cooking, meal->difficulty * 3 ); //little bonus - return 0; + return std::make_pair( 0, 0_J ); } } @@ -8262,7 +8393,7 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) if( !p->has_morale_to_craft() ) { p->add_msg_if_player( m_info, _( "Your morale is too low to craft…" ) ); - return 0; + return std::make_pair( 0, 0_J ); } bool has_tools = true; @@ -8283,7 +8414,7 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) } if( !has_tools ) { - return 0; + return std::make_pair( 0, 0_J ); } p->practice( skill_electronics, rng( 5, 10 ) ); @@ -8307,7 +8438,7 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) it->set_var( "MULTI_COOK_UPGRADE", "UPGRADE" ); - return 0; + return std::make_pair( 0, 0_J ); } else { @@ -8320,7 +8451,7 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) it->set_var( "MULTI_COOK_UPGRADE", "DAMAGED" ); } - return 0; + return std::make_pair( 0, 0_J ); } @@ -8328,14 +8459,14 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos ) } - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::tow_attach( player *p, item *it, bool, const tripoint & ) +std::pair iuse::tow_attach( player *p, item *it, bool, const tripoint & ) { std::string initial_state = it->get_var( "state", "attach_first" ); if( !p ) { - return 0; + return std::make_pair( 0, 0_J ); } const auto set_cable_active = []( player * p, item * it, const std::string & state ) { it->set_var( "state", state ); @@ -8349,24 +8480,24 @@ int iuse::tow_attach( player *p, item *it, bool, const tripoint & ) const std::optional posp_ = choose_adjacent( _( "Attach cable to the vehicle that will do the towing." ) ); if( !posp_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint posp = *posp_; const optional_vpart_position vp = g->m.veh_at( posp ); if( !vp ) { p->add_msg_if_player( _( "There's no vehicle there." ) ); - return 0; + return std::make_pair( 0, 0_J ); } else { vehicle *const source_veh = veh_pointer_or_null( vp ); if( source_veh ) { if( source_veh->has_tow_attached() || source_veh->is_towed() || source_veh->is_towing() ) { p->add_msg_if_player( _( "That vehicle already has a tow-line attached." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( !source_veh->is_external_part( posp ) ) { p->add_msg_if_player( _( "You can't attach the tow-line to an internal part." ) ); - return 0; + return std::make_pair( 0, 0_J ); } } const tripoint &abspos = g->m.getabs( posp ); @@ -8402,43 +8533,43 @@ int iuse::tow_attach( player *p, item *it, bool, const tripoint & ) int choice = kmenu.ret; if( choice < 0 ) { - return 0; // we did nothing. + return std::make_pair( 0, 0_J ); // we did nothing. } else if( choice == 0 ) { // unconnect & respool it->reset_cable( p ); - return 0; + return std::make_pair( 0, 0_J ); } const optional_vpart_position source_vp = confirm_source_vehicle( p, it, paying_out ); vehicle *const source_veh = veh_pointer_or_null( source_vp ); if( source_veh == nullptr && paying_out ) { - return 0; + return std::make_pair( 0, 0_J ); } const std::optional vpos_ = choose_adjacent( _( "Attach cable to vehicle that will be towed." ) ); if( !vpos_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint vpos = *vpos_; const optional_vpart_position target_vp = g->m.veh_at( vpos ); if( !target_vp ) { p->add_msg_if_player( _( "There's no vehicle there." ) ); - return 0; + return std::make_pair( 0, 0_J ); } else { vehicle *const target_veh = &target_vp->vehicle(); if( target_veh && ( target_veh->has_tow_attached() || target_veh->is_towed() || target_veh->is_towing() ) ) { p->add_msg_if_player( _( "That vehicle already has a tow-line attached." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( source_veh == target_veh ) { if( p->has_item( *it ) ) { p->add_msg_if_player( m_warning, _( "You cannot set a vehicle to tow itself!" ) ); } - return 0; + return std::make_pair( 0, 0_J ); } if( !target_veh->is_external_part( vpos ) ) { p->add_msg_if_player( _( "You can't attach the tow-line to an internal part." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const vpart_id vpid( it->typeId().str() ); point vcoords = source_vp->mount(); @@ -8453,14 +8584,14 @@ int iuse::tow_attach( player *p, item *it, bool, const tripoint & ) source_veh->name, target_veh->name ); } source_veh->tow_data.set_towing( source_veh, target_veh ); - return 1; // Let the cable be destroyed. + return std::make_pair( 1, 0_J ); // Let the cable be destroyed. } } - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::cable_attach( player *p, item *it, bool, const tripoint & ) +std::pair iuse::cable_attach( player *p, item *it, bool, const tripoint & ) { std::string initial_state = it->get_var( "state", "attach_first" ); const bool has_bio_cable = !p->get_remote_fueled_bionic().is_empty(); @@ -8509,41 +8640,41 @@ int iuse::cable_attach( player *p, item *it, bool, const tripoint & ) int choice = kmenu.ret; if( choice < 0 ) { - return 0; // we did nothing. + return std::make_pair( 0, 0_J ); // we did nothing. } else if( choice == 1 ) { set_cable_active( p, it, "cable_charger" ); p->add_msg_if_player( m_info, _( "You attach the cable to your Cable Charger System." ) ); - return 0; + return std::make_pair( 0, 0_J ); } else if( choice == 2 ) { set_cable_active( p, it, "solar_pack" ); p->add_msg_if_player( m_info, _( "You attach the cable to the solar pack." ) ); - return 0; + return std::make_pair( 0, 0_J ); } else if( choice == 3 ) { if( you != nullptr ) { loc = game_menus::inv::titled_filter_menu( filter, *you, choose_ups, dont_have_ups ); } if( !loc ) { add_msg( _( "Never mind" ) ); - return 0; + return std::make_pair( 0, 0_J ); } item &chosen = *loc; chosen.set_var( "cable", "plugged_in" ); chosen.activate(); set_cable_active( p, it, "UPS" ); p->add_msg_if_player( m_info, _( "You attach the cable to the UPS." ) ); - return 0; + return std::make_pair( 0, 0_J ); } // fall through for attaching to a vehicle } const std::optional posp_ = choose_adjacent( _( "Attach cable to vehicle where?" ) ); if( !posp_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint posp = *posp_; const optional_vpart_position vp = g->m.veh_at( posp ); if( !vp ) { p->add_msg_if_player( _( "There's no vehicle there." ) ); - return 0; + return std::make_pair( 0, 0_J ); } else { const auto abspos = g->m.getabs( posp ); it->set_var( "source_x", abspos.x ); @@ -8592,24 +8723,24 @@ int iuse::cable_attach( player *p, item *it, bool, const tripoint & ) int choice = kmenu.ret; if( choice < 0 ) { - return 0; // we did nothing. + return std::make_pair( 0, 0_J ); // we did nothing. } else if( choice == 0 ) { // unconnect & respool p->reset_remote_fuel(); it->reset_cable( p ); - return 0; + return std::make_pair( 0, 0_J ); } else if( choice == 2 ) { // connect self while other end already connected p->add_msg_if_player( m_info, _( "You attach the cable to the Cable Charger System." ) ); // connecting self, solar backpack connected if( solar_pack ) { set_cable_active( p, it, "solar_pack_link" ); p->add_msg_if_player( m_good, _( "You are now plugged to the solar backpack." ) ); - return 0; + return std::make_pair( 0, 0_J ); } // connecting self, UPS connected if( UPS ) { set_cable_active( p, it, "UPS_link" ); p->add_msg_if_player( m_good, _( "You are now plugged to the UPS." ) ); - return 0; + return std::make_pair( 0, 0_J ); } // connecting self, vehicle connected const optional_vpart_position source_vp = confirm_source_vehicle( p, it, true ); @@ -8617,36 +8748,36 @@ int iuse::cable_attach( player *p, item *it, bool, const tripoint & ) set_cable_active( p, it, "cable_charger_link" ); p->add_msg_if_player( m_good, _( "You are now plugged to the vehicle." ) ); } - return 0; + return std::make_pair( 0, 0_J ); } else if( choice == 3 ) { // connecting self to solar backpack set_cable_active( p, it, "solar_pack_link" ); p->add_msg_if_player( m_good, _( "You are now plugged to the solar backpack." ) ); - return 0; + return std::make_pair( 0, 0_J ); } else if( choice == 4 ) { loc = game_menus::inv::titled_filter_menu( filter, *you, choose_ups, dont_have_ups ); // connecting self to UPS if( !loc ) { add_msg( _( "Never mind" ) ); - return 0; + return std::make_pair( 0, 0_J ); } item &chosen = *loc; chosen.set_var( "cable", "plugged_in" ); chosen.activate(); set_cable_active( p, it, "UPS_link" ); p->add_msg_if_player( m_good, _( "You are now plugged to the UPS." ) ); - return 0; + return std::make_pair( 0, 0_J ); } // connecting self to vehicle const optional_vpart_position source_vp = confirm_source_vehicle( p, it, paying_out ); vehicle *const source_veh = veh_pointer_or_null( source_vp ); if( source_veh == nullptr && paying_out ) { - return 0; + return std::make_pair( 0, 0_J ); } const std::optional vpos_ = choose_adjacent( _( "Attach cable where?" ) ); if( !vpos_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint vpos = *vpos_; @@ -8656,7 +8787,7 @@ int iuse::cable_attach( player *p, item *it, bool, const tripoint & ) ( target_global ); if( !target_vp && !grid_connection ) { p->add_msg_if_player( _( "There's no vehicle or grid connection there." ) ); - return 0; + return std::make_pair( 0, 0_J ); } else if( cable_cbm ) { const auto abspos = g->m.getabs( vpos ); it->set_var( "source_x", abspos.x ); @@ -8664,7 +8795,7 @@ int iuse::cable_attach( player *p, item *it, bool, const tripoint & ) it->set_var( "source_z", g->get_levz() ); set_cable_active( p, it, "cable_charger_link" ); p->add_msg_if_player( m_good, _( "You are now plugged to the vehicle." ) ); - return 0; + return std::make_pair( 0, 0_J ); } else { tripoint source_global( it->get_var( "source_x", 0 ), it->get_var( "source_y", 0 ), @@ -8690,7 +8821,7 @@ int iuse::cable_attach( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_warning, _( "The %s already has access to its own electric system!" ), source_veh->name ); } - return 0; + return std::make_pair( 0, 0_J ); } source_part.target.first = target_global.raw(); @@ -8711,18 +8842,20 @@ int iuse::cable_attach( player *p, item *it, bool, const tripoint & ) } } - return 1; // Let the cable be destroyed. + return std::make_pair( 1, 0_J ); // Let the cable be destroyed. } } - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::shavekit( player *p, item *it, bool, const tripoint & ) +std::pair iuse::shavekit( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( !it->ammo_sufficient() ) { p->add_msg_if_player( _( "You need soap to use this." ) ); @@ -8730,21 +8863,23 @@ int iuse::shavekit( player *p, item *it, bool, const tripoint & ) const int moves = to_moves( 5_minutes ); p->assign_activity( ACT_SHAVE, moves ); } - return it->type->charges_to_use(); + return res; } -int iuse::hairkit( player *p, item *it, bool, const tripoint & ) +std::pair iuse::hairkit( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const int moves = to_moves( 30_minutes ); p->assign_activity( ACT_HAIRCUT, moves ); - return it->type->charges_to_use(); + return res; } -int iuse::weather_tool( player *p, item *it, bool, const tripoint & ) +std::pair iuse::weather_tool( player *p, item *it, bool, const tripoint & ) { const weather_manager &weather = get_weather(); const w_point &weatherPoint = get_weather().get_precise(); @@ -8826,26 +8961,29 @@ int iuse::weather_tool( player *p, item *it, bool, const tripoint & ) units::to_fahrenheit( player_local_temp ) ) ); } - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::directional_hologram( player *p, item *it, bool, const tripoint &pos ) +std::pair iuse::directional_hologram( player *p, item *it, bool, + const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( it->is_armor() && !( p->is_worn( *it ) ) ) { p->add_msg_if_player( m_neutral, _( "You need to wear the %1$s before activating it." ), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } const std::optional posp_ = choose_adjacent( _( "Choose hologram direction." ) ); if( !posp_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint posp = *posp_; monster *const hologram = g->place_critter_at( mon_hologram, posp ); if( !hologram ) { p->add_msg_if_player( m_info, _( "Can't create a hologram there." ) ); - return 0; + return std::make_pair( 0, 0_J ); } tripoint target = pos; target.x = p->posx() + 4 * SEEX * ( posp.x - p->posx() ); @@ -8856,22 +8994,23 @@ int iuse::directional_hologram( player *p, item *it, bool, const tripoint &pos ) hologram->set_summon_time( 60_seconds ); hologram->set_dest( target ); p->mod_moves( -to_turns( 1_seconds ) ); - return it->type->charges_to_use(); + return res; } -int iuse::capture_monster_veh( player *p, item *it, bool, const tripoint &pos ) +std::pair iuse::capture_monster_veh( player *p, item *it, bool, + const tripoint &pos ) { if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( !it->has_flag( flag_VEHICLE ) ) { p->add_msg_if_player( m_info, _( "The %s must be installed in a vehicle before being loaded." ), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } capture_monster_act( p, it, false, pos ); - return 0; + return std::make_pair( 0, 0_J ); } bool item::release_monster( const tripoint &target, const int radius ) @@ -8895,11 +9034,11 @@ bool item::release_monster( const tripoint &target, const int radius ) // didn't want to drag the monster:: definition into item.h, so just reacquire the monster // at target -int item::contain_monster( const tripoint &target ) +std::pair item::contain_monster( const tripoint &target ) { const monster *const mon_ptr = g->critter_at( target ); if( !mon_ptr ) { - return 0; + return std::make_pair( 0, 0_J ); } const monster &f = *mon_ptr; @@ -8910,14 +9049,15 @@ int item::contain_monster( const tripoint &target ) // Need to add the weight of the empty container because item::weight uses the "weight" variable directly. set_var( "weight", to_milligram( type->weight + f.get_weight() ) ); g->remove_zombie( f ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::capture_monster_act( player *p, item *it, bool, const tripoint &pos ) +std::pair iuse::capture_monster_act( player *p, item *it, bool, + const tripoint &pos ) { if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot capture a creature mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( it->has_var( "contained_name" ) ) { // Remember contained_name for messages after release_monster erases it @@ -8925,37 +9065,37 @@ int iuse::capture_monster_act( player *p, item *it, bool, const tripoint &pos ) if( it->release_monster( pos ) ) { // It's been activated somewhere where there isn't a player or monster, good. - return 0; + return std::make_pair( 0, 0_J ); } if( it->has_flag( flag_PLACE_RANDOMLY ) ) { if( it->release_monster( p->pos(), 1 ) ) { - return 0; + return std::make_pair( 0, 0_J ); } p->add_msg_if_player( _( "There is no place to put the %s." ), contained_name ); - return 0; + return std::make_pair( 0, 0_J ); } else { const std::string query = string_format( _( "Place the %s where?" ), contained_name ); const std::optional pos_ = choose_adjacent( query ); if( !pos_ ) { - return 0; + return std::make_pair( 0, 0_J ); } if( it->release_monster( *pos_ ) ) { p->add_msg_if_player( _( "You release the %s." ), contained_name ); - return 0; + return std::make_pair( 0, 0_J ); } p->add_msg_if_player( m_info, _( "You cannot place the %s there!" ), contained_name ); - return 0; + return std::make_pair( 0, 0_J ); } } else { if( !it->has_property( "creature_size_capacity" ) ) { debugmsg( "%s has no creature_size_capacity.", it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } const std::string capacity = it->get_property_string( "creature_size_capacity" ); if( !Creature::size_map.contains( capacity ) ) { debugmsg( "%s has invalid creature_size_capacity %s.", it->tname(), capacity.c_str() ); - return 0; + return std::make_pair( 0, 0_J ); } const std::function adjacent_capturable = []( const tripoint & pnt ) { const monster *mon_ptr = g->critter_at( pnt ); @@ -8967,7 +9107,7 @@ int iuse::capture_monster_act( player *p, item *it, bool, const tripoint &pos ) _( "There is no creature nearby you can capture." ), adjacent_capturable, false ); if( !target_ ) { p->add_msg_if_player( m_info, _( "You cannot use a %s there." ), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } const tripoint target = *target_; @@ -8978,7 +9118,7 @@ int iuse::capture_monster_act( player *p, item *it, bool, const tripoint &pos ) if( f.get_size() > Creature::size_map.find( capacity )->second ) { p->add_msg_if_player( m_info, _( "The %1$s is too big to put in your %2$s." ), f.type->nname(), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } // TODO: replace this with some kind of melee check. int chance = f.hp_percentage() / 10; @@ -8996,37 +9136,37 @@ int iuse::capture_monster_act( player *p, item *it, bool, const tripoint &pos ) p->moves -= to_moves( 1_seconds ); } else { add_msg( _( "The %s can't capture nothing" ), it->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } } - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::ladder( player *p, item *, bool, const tripoint & ) +std::pair iuse::ladder( player *p, item *, bool, const tripoint & ) { if( !g->m.has_zlevels() ) { debugmsg( "Ladder can't be used in non-z-level mode" ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const std::optional pnt_ = choose_adjacent( _( "Put the ladder where?" ) ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint pnt = *pnt_; if( !g->is_empty( pnt ) || g->m.has_furn( pnt ) ) { p->add_msg_if_player( m_bad, _( "Can't place it there." ) ); - return 0; + return std::make_pair( 0, 0_J ); } p->add_msg_if_player( _( "You set down the ladder." ) ); p->moves -= to_moves( 5_seconds ); g->m.furn_set( pnt, furn_str_id( "f_ladder" ) ); - return 1; + return std::make_pair( 1, 0_J ); } washing_requirements washing_requirements_for_volume( const units::volume &vol ) @@ -9037,73 +9177,73 @@ washing_requirements washing_requirements_for_volume( const units::volume &vol ) return { water, cleanser, time }; } -static int wash_items( player *p, bool soft_items, bool hard_items ); +static std::pair wash_items( player *p, bool soft_items, bool hard_items ); -int iuse::wash_soft_items( player *p, item *, bool, const tripoint & ) +std::pair iuse::wash_soft_items( player *p, item *, bool, const tripoint & ) { if( !character_funcs::can_see_fine_details( *p ) ) { p->add_msg_if_player( _( "You can't see to do that!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } // Check that player isn't over volume limit as this might cause it to break... this is a hack. // TODO: find a better solution. if( p->volume_capacity() < p->volume_carried() ) { p->add_msg_if_player( _( "You're carrying too much to clean anything." ) ); - return 0; + return std::make_pair( 0, 0_J ); } wash_items( p, true, false ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::wash_hard_items( player *p, item *, bool, const tripoint & ) +std::pair iuse::wash_hard_items( player *p, item *, bool, const tripoint & ) { if( !character_funcs::can_see_fine_details( *p ) ) { p->add_msg_if_player( _( "You can't see to do that!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } // Check that player isn't over volume limit as this might cause it to break... this is a hack. // TODO: find a better solution. if( p->volume_capacity() < p->volume_carried() ) { p->add_msg_if_player( _( "You're carrying too much to clean anything." ) ); - return 0; + return std::make_pair( 0, 0_J ); } wash_items( p, false, true ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::wash_all_items( player *p, item *, bool, const tripoint & ) +std::pair iuse::wash_all_items( player *p, item *, bool, const tripoint & ) { if( !character_funcs::can_see_fine_details( *p ) ) { p->add_msg_if_player( _( "You can't see to do that!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } // Check that player isn't over volume limit as this might cause it to break... this is a hack. // TODO: find a better solution. if( p->volume_capacity() < p->volume_carried() ) { p->add_msg_if_player( _( "You're carrying too much to clean anything." ) ); - return 0; + return std::make_pair( 0, 0_J ); } wash_items( p, true, true ); - return 0; + return std::make_pair( 0, 0_J ); } -int wash_items( player *p, bool soft_items, bool hard_items ) +std::pair wash_items( player *p, bool soft_items, bool hard_items ) { if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } p->inv_restack( ); const inventory &crafting_inv = p->crafting_inventory(); @@ -9123,7 +9263,7 @@ int wash_items( player *p, bool soft_items, bool hard_items ) hard_items ); if( to_clean.empty() ) { - return 0; + return std::make_pair( 0, 0_J ); } // Determine if we have enough water and cleanser for all the items. @@ -9131,7 +9271,7 @@ int wash_items( player *p, bool soft_items, bool hard_items ) for( const iuse_location &iloc : to_clean ) { if( !iloc.loc ) { p->add_msg_if_player( m_info, _( "Never mind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } item &i = *iloc.loc; total_volume += i.volume() * iloc.count / i.count(); @@ -9143,12 +9283,12 @@ int wash_items( player *p, bool soft_items, bool hard_items ) !crafting_inv.has_charges( itype_water_clean, required.water, is_liquid ) ) { p->add_msg_if_player( _( "You need %1$i charges of water or clean water to wash these items." ), required.water ); - return 0; + return std::make_pair( 0, 0_J ); } else if( !crafting_inv.has_charges( itype_soap, required.cleanser ) && !crafting_inv.has_charges( itype_detergent, required.cleanser ) ) { p->add_msg_if_player( _( "You need %1$i charges of cleansing agent to wash these items." ), required.cleanser ); - return 0; + return std::make_pair( 0, 0_J ); } const std::vector helpers = character_funcs::get_crafting_helpers( *p, 3 ); @@ -9162,11 +9302,13 @@ int wash_items( player *p, bool soft_items, bool hard_items ) ( to_clean, required.time ) ) ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::weak_antibiotic( player *p, item *it, bool, const tripoint & ) +std::pair iuse::weak_antibiotic( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + p->add_msg_player_or_npc( m_neutral, _( "You take some weak antibiotics." ), _( " takes some weak antibiotics." ) ); @@ -9174,11 +9316,13 @@ int iuse::weak_antibiotic( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_good, _( "The throbbing of the infection diminishes. Slightly." ) ); } p->add_effect( effect_weak_antibiotic, 12_hours ); - return it->type->charges_to_use(); + return res; } -int iuse::strong_antibiotic( player *p, item *it, bool, const tripoint & ) +std::pair iuse::strong_antibiotic( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + p->add_msg_player_or_npc( m_neutral, _( "You take some strong antibiotics." ), _( " takes some strong antibiotics." ) ); @@ -9186,25 +9330,25 @@ int iuse::strong_antibiotic( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_good, _( "You feel much better - almost entirely." ) ); } p->add_effect( effect_strong_antibiotic, 12_hours ); - return it->type->charges_to_use(); + return res; } -int iuse::craft( player *p, item *it, bool, const tripoint &pos ) +std::pair iuse::craft( player *p, item *it, bool, const tripoint &pos ) { if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const std::string craft_name = it->tname(); if( !it->is_craft() ) { debugmsg( "Attempted to start working on non craft '%s.' Aborting.", craft_name ); - return 0; + return std::make_pair( 0, 0_J ); } if( !p->can_continue_craft( *it ) ) { - return 0; + return std::make_pair( 0, 0_J ); } const recipe &rec = it->get_making(); if( p->has_recipe( &rec, p->crafting_inventory(), @@ -9213,7 +9357,7 @@ int iuse::craft( player *p, item *it, bool, const tripoint &pos ) _( "You don't know the recipe for the %s and can't continue crafting." ), _( " doesn't know the recipe for the %s and can't continue crafting." ), rec.result_name() ); - return 0; + return std::make_pair( 0, 0_J ); } bench_location best_bench = find_best_bench( *p, *it ); @@ -9239,7 +9383,7 @@ int iuse::craft( player *p, item *it, bool, const tripoint &pos ) where = it; } else { debugmsg( "Incomplete item couldn't be found" ); - return 0; + return std::make_pair( 0, 0_J ); } } p->activity->targets.emplace_back( where ); @@ -9248,50 +9392,52 @@ int iuse::craft( player *p, item *it, bool, const tripoint &pos ) // Ugly p->activity->values.push_back( static_cast( best_bench.type ) ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::disassemble( player *p, item *it, bool, const tripoint & ) +std::pair iuse::disassemble( player *p, item *it, bool, const tripoint & ) { if( !p->is_avatar() ) { debugmsg( "disassemble iuse is not implemented for NPCs." ); - return 0; + return std::make_pair( 0, 0_J ); } if( p->is_mounted() ) { p->add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( !p->has_item( *it ) ) { - return 0; + return std::make_pair( 0, 0_J ); } crafting::disassemble( *p->as_avatar(), *it ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::melatonin_tablet( player *p, item *it, bool, const tripoint & ) +std::pair iuse::melatonin_tablet( player *p, item *it, bool, const tripoint & ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + p->add_msg_if_player( _( "You pop a %s." ), it->tname() ); if( p->has_effect( effect_melatonin_supplements ) ) { p->add_msg_if_player( m_warning, _( "Simply taking more melatonin won't help. You have to go to sleep for it to work." ) ); } p->add_effect( effect_melatonin_supplements, 16_hours ); - return it->type->charges_to_use(); + return res; } -int iuse::coin_flip( player *p, item *it, bool, const tripoint & ) +std::pair iuse::coin_flip( player *p, item *it, bool, const tripoint & ) { p->add_msg_if_player( m_info, _( "You flip a %s." ), it->tname() ); p->add_msg_if_player( m_info, one_in( 2 ) ? _( "Heads!" ) : _( "Tails!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::play_game( player *p, item *it, bool t, const tripoint & ) +std::pair iuse::play_game( player *p, item *it, bool t, const tripoint & ) { if( t ) { - return 0; + return std::make_pair( 0, 0_J ); } if( query_yn( _( "Play a game with the %s?" ), it->tname() ) ) { @@ -9299,10 +9445,10 @@ int iuse::play_game( player *p, item *it, bool t, const tripoint & ) p->assign_activity( ACT_GENERIC_GAME, to_moves( 30_minutes ), -1, p->get_item_position( it ), "gaming" ); } - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::magic_8_ball( player *p, item *it, bool, const tripoint & ) +std::pair iuse::magic_8_ball( player *p, item *it, bool, const tripoint & ) { enum { BALL8_GOOD, @@ -9337,10 +9483,10 @@ int iuse::magic_8_ball( player *p, item *it, bool, const tripoint & ) int rn = rng( 0, tab.size() - 1 ); auto color = ( rn >= BALL8_BAD ? m_bad : rn >= BALL8_UNK ? m_info : m_good ); p->add_msg_if_player( color, _( "The %s says: %s" ), it->tname(), _( tab[rn] ) ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::toggle_heats_food( player *p, item *it, bool, const tripoint & ) +std::pair iuse::toggle_heats_food( player *p, item *it, bool, const tripoint & ) { static const flag_id json_flag_HEATS_FOOD( flag_HEATS_FOOD ); if( !it->has_flag( json_flag_HEATS_FOOD ) ) { @@ -9353,10 +9499,11 @@ int iuse::toggle_heats_food( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( _( "You will no longer use %s to heat food." ), it->tname().c_str() ); } - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::toggle_ups_charging( player *p, item *it, bool, const tripoint & ) +std::pair iuse::toggle_ups_charging( player *p, item *it, bool, + const tripoint & ) { static const flag_id json_flag_USE_UPS( flag_USE_UPS ); if( !it->has_flag( json_flag_USE_UPS ) ) { @@ -9369,10 +9516,11 @@ int iuse::toggle_ups_charging( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( _( "You will no longer recharge the %s via UPS." ), it->tname().c_str() ); } - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::report_grid_charge( player *p, item *, bool, const tripoint &pos ) +std::pair iuse::report_grid_charge( player *p, item *, bool, + const tripoint &pos ) { tripoint_abs_ms pos_abs( get_map().getabs( pos ) ); const distribution_grid &gr = get_distribution_grid_tracker().grid_at( pos_abs ); @@ -9380,10 +9528,11 @@ int iuse::report_grid_charge( player *p, item *, bool, const tripoint &pos ) int amt = gr.get_resource(); p->add_msg_if_player( _( "This electric grid stores %d kJ of electric power." ), amt ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::report_grid_connections( player *p, item *, bool, const tripoint &pos ) +std::pair iuse::report_grid_connections( player *p, item *, bool, + const tripoint &pos ) { tripoint_abs_omt pos_abs = project_to( tripoint_abs_ms( get_map().getabs( pos ) ) ); std::vector connections = overmap_buffer.electric_grid_connectivity_at( pos_abs ); @@ -9404,11 +9553,13 @@ int iuse::report_grid_connections( player *p, item *, bool, const tripoint &pos } p->add_msg_if_player( msg ); - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::modify_grid_connections( player *p, item *it, bool, const tripoint &pos ) +std::pair iuse::modify_grid_connections( player *p, item *it, bool, + const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); tripoint_abs_omt pos_abs = project_to( tripoint_abs_ms( get_map().getabs( pos ) ) ); std::vector connections = overmap_buffer.electric_grid_connectivity_at( pos_abs ); @@ -9431,7 +9582,7 @@ int iuse::modify_grid_connections( player *p, item *it, bool, const tripoint &po ui.query(); if( ui.ret < 0 ) { - return 0; + return std::make_pair( 0, 0_J ); } size_t ret = static_cast( ui.ret ); @@ -9471,7 +9622,7 @@ int iuse::modify_grid_connections( player *p, item *it, bool, const tripoint &po grid_connection_string, reqs.list_missing(), reqs.list_all() ) ); - return 0; + return std::make_pair( 0, 0_J ); } // TODO: Long action @@ -9482,7 +9633,7 @@ int iuse::modify_grid_connections( player *p, item *it, bool, const tripoint &po grid_connection_string, reqs.list_all() ) ) ) {} else { - return 0; + return std::make_pair( 0, 0_J ); } @@ -9496,23 +9647,25 @@ int iuse::modify_grid_connections( player *p, item *it, bool, const tripoint &po bool success = overmap_buffer.add_grid_connection( pos_abs, destination_pos_abs ); if( success ) { - return it->type->charges_to_use(); + return res; } } - return 0; + return std::make_pair( 0, 0_J ); } -int iuse::amputate( player *, item *it, bool, const tripoint &pos ) +std::pair iuse::amputate( player *, item *it, bool, const tripoint &pos ) { + std::pair res( it->type->charges_to_use(), it->energy_required() ); + if( !it->ammo_sufficient() ) { - return 0; + return std::make_pair( 0, 0_J ); } Creature *patient = g->critter_at( pos ); if( !patient ) { add_msg( m_info, _( "Nevermind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } auto &body = patient->get_body(); @@ -9528,7 +9681,7 @@ int iuse::amputate( player *, item *it, bool, const tripoint &pos ) bp_menu.query(); if( bp_menu.ret < 0 ) { add_msg( m_info, _( "Nevermind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } auto bp_iter = std::next( body.begin(), bp_menu.ret ); @@ -9536,7 +9689,7 @@ int iuse::amputate( player *, item *it, bool, const tripoint &pos ) add_msg( m_bad, _( "Body part removed: %s" ), bp_iter->first->name_as_heading.translated() ); body.erase( bp_iter ); - return it->type->charges_to_use(); + return res; } void use_function::dump_info( const item &it, std::vector &dump ) const @@ -9557,7 +9710,8 @@ ret_val use_function::can_call( const Character &p, const item &it, bool t return actor->can_use( p, it, t, pos ); } -int use_function::call( player &p, item &it, bool active, const tripoint &pos ) const +std::pair use_function::call( player &p, item &it, bool active, + const tripoint &pos ) const { return actor->use( p, it, active, pos ); } diff --git a/src/iuse.h b/src/iuse.h index 8cbcb5fba9db..59e3fb9911c2 100644 --- a/src/iuse.h +++ b/src/iuse.h @@ -24,200 +24,199 @@ struct tripoint; namespace iuse { // FOOD AND DRUGS (ADMINISTRATION) -int sewage( player *, item *, bool, const tripoint & ); -int honeycomb( player *, item *, bool, const tripoint & ); -int alcohol_weak( player *, item *, bool, const tripoint & ); -int alcohol_medium( player *, item *, bool, const tripoint & ); -int alcohol_strong( player *, item *, bool, const tripoint & ); -int xanax( player *, item *, bool, const tripoint & ); -int smoking( player *, item *, bool, const tripoint & ); -int ecig( player *, item *, bool, const tripoint & ); -int antibiotic( player *, item *, bool, const tripoint & ); -int eyedrops( player *, item *, bool, const tripoint & ); -int fungicide( player *, item *, bool, const tripoint & ); -int antifungal( player *, item *, bool, const tripoint & ); -int antiparasitic( player *, item *, bool, const tripoint & ); -int anticonvulsant( player *, item *, bool, const tripoint & ); -int weed_cake( player *, item *, bool, const tripoint & ); -int meth( player *, item *, bool, const tripoint & ); -int vaccine( player *, item *, bool, const tripoint & ); -int poison( player *, item *, bool, const tripoint & ); -int meditate( player *, item *, bool, const tripoint & ); -int thorazine( player *, item *, bool, const tripoint & ); -int prozac( player *, item *, bool, const tripoint & ); -int sleep( player *, item *, bool, const tripoint & ); -int datura( player *, item *, bool, const tripoint & ); -int flumed( player *, item *, bool, const tripoint & ); -int flusleep( player *, item *, bool, const tripoint & ); -int inhaler( player *, item *, bool, const tripoint & ); -int blech( player *, item *, bool, const tripoint & ); -int blech_because_unclean( player *, item *, bool, const tripoint & ); -int plantblech( player *, item *, bool, const tripoint & ); -int chew( player *, item *, bool, const tripoint & ); -int purifier( player *, item *, bool, const tripoint & ); -int purify_iv( player *, item *, bool, const tripoint & ); -int purify_smart( player *, item *, bool, const tripoint & ); -int marloss( player *, item *, bool, const tripoint & ); -int marloss_seed( player *, item *, bool, const tripoint & ); -int marloss_gel( player *, item *, bool, const tripoint & ); -int mycus( player *, item *, bool, const tripoint & ); -int petfood( player *, item *, bool, const tripoint & ); -int antiasthmatic( player *, item *, bool, const tripoint & ); +std::pair sewage( player *, item *, bool, const tripoint & ); +std::pair honeycomb( player *, item *, bool, const tripoint & ); +std::pair alcohol_weak( player *, item *, bool, const tripoint & ); +std::pair alcohol_medium( player *, item *, bool, const tripoint & ); +std::pair alcohol_strong( player *, item *, bool, const tripoint & ); +std::pair xanax( player *, item *, bool, const tripoint & ); +std::pair smoking( player *, item *, bool, const tripoint & ); +std::pair ecig( player *, item *, bool, const tripoint & ); +std::pair antibiotic( player *, item *, bool, const tripoint & ); +std::pair eyedrops( player *, item *, bool, const tripoint & ); +std::pair fungicide( player *, item *, bool, const tripoint & ); +std::pair antifungal( player *, item *, bool, const tripoint & ); +std::pair antiparasitic( player *, item *, bool, const tripoint & ); +std::pair anticonvulsant( player *, item *, bool, const tripoint & ); +std::pair weed_cake( player *, item *, bool, const tripoint & ); +std::pair meth( player *, item *, bool, const tripoint & ); +std::pair vaccine( player *, item *, bool, const tripoint & ); +std::pair poison( player *, item *, bool, const tripoint & ); +std::pair meditate( player *, item *, bool, const tripoint & ); +std::pair thorazine( player *, item *, bool, const tripoint & ); +std::pair prozac( player *, item *, bool, const tripoint & ); +std::pair sleep( player *, item *, bool, const tripoint & ); +std::pair datura( player *, item *, bool, const tripoint & ); +std::pair flumed( player *, item *, bool, const tripoint & ); +std::pair flusleep( player *, item *, bool, const tripoint & ); +std::pair inhaler( player *, item *, bool, const tripoint & ); +std::pair blech( player *, item *, bool, const tripoint & ); +std::pair blech_because_unclean( player *, item *, bool, const tripoint & ); +std::pair plantblech( player *, item *, bool, const tripoint & ); +std::pair chew( player *, item *, bool, const tripoint & ); +std::pair purifier( player *, item *, bool, const tripoint & ); +std::pair purify_iv( player *, item *, bool, const tripoint & ); +std::pair purify_smart( player *, item *, bool, const tripoint & ); +std::pair marloss( player *, item *, bool, const tripoint & ); +std::pair marloss_seed( player *, item *, bool, const tripoint & ); +std::pair marloss_gel( player *, item *, bool, const tripoint & ); +std::pair mycus( player *, item *, bool, const tripoint & ); +std::pair petfood( player *, item *, bool, const tripoint & ); +std::pair antiasthmatic( player *, item *, bool, const tripoint & ); // TOOLS -int amputate( player *, item *, bool, const tripoint & ); -int extinguisher( player *, item *, bool, const tripoint & ); -int hammer( player *, item *, bool, const tripoint & ); -int water_purifier( player *, item *, bool, const tripoint & ); -int directional_antenna( player *, item *, bool, const tripoint & ); -int radio_off( player *, item *, bool, const tripoint & ); -int radio_on( player *, item *, bool, const tripoint & ); -int noise_emitter_off( player *, item *, bool, const tripoint & ); -int noise_emitter_on( player *, item *, bool, const tripoint & ); -int note_bionics( player *, item *, bool, const tripoint & ); -int ma_manual( player *, item *, bool, const tripoint & ); -int crowbar( player *, item *, bool, const tripoint & ); -int makemound( player *, item *, bool, const tripoint & ); -int dig( player *, item *, bool, const tripoint & ); -int dig_channel( player *, item *, bool, const tripoint & ); -int fill_pit( player *, item *, bool, const tripoint & ); -int clear_rubble( player *, item *, bool, const tripoint & ); -int siphon( player *, item *, bool, const tripoint & ); -int jackhammer( player *, item *, bool, const tripoint & ); -int pickaxe( player *, item *, bool, const tripoint & ); -int burrow( player *, item *, bool, const tripoint & ); -int geiger( player *, item *, bool, const tripoint & ); -int teleport( player *, item *, bool, const tripoint & ); -int can_goo( player *, item *, bool, const tripoint & ); -int throwable_extinguisher_act( player *, item *, bool, const tripoint & ); -int directional_hologram( player *, item *, bool, const tripoint & ); -int capture_monster_veh( player *, item *, bool, const tripoint & ); -int capture_monster_act( player *, item *, bool, const tripoint & ); -int granade( player *, item *, bool, const tripoint & ); -int granade_act( player *, item *, bool, const tripoint & ); -int c4( player *, item *, bool, const tripoint & ); -int arrow_flammable( player *, item *, bool, const tripoint & ); -int acidbomb_act( player *, item *, bool, const tripoint & ); -int grenade_inc_act( player *, item *, bool, const tripoint & ); -int molotov_lit( player *, item *, bool, const tripoint & ); -int firecracker_pack( player *, item *, bool, const tripoint & ); -int firecracker_pack_act( player *, item *, bool, const tripoint & ); -int firecracker( player *, item *, bool, const tripoint & ); -int firecracker_act( player *, item *, bool, const tripoint & ); -int mininuke( player *, item *, bool, const tripoint & ); -int pheromone( player *, item *, bool, const tripoint & ); -int pick_lock( player *, item *, bool, const tripoint & ); -int portal( player *, item *, bool, const tripoint & ); -int tazer( player *, item *, bool, const tripoint & ); -int tazer2( player *, item *, bool, const tripoint & ); -int mp3( player *, item *, bool, const tripoint & ); -int mp3_on( player *, item *, bool, const tripoint & ); -int rpgdie( player *, item *, bool, const tripoint & ); -int dive_tank( player *, item *, bool, const tripoint & ); -int gasmask( player *, item *, bool, const tripoint & ); -int portable_game( player *, item *, bool, const tripoint & ); -int vibe( player *, item *, bool, const tripoint & ); -int hand_crank( player *, item *, bool, const tripoint & ); -int vortex( player *, item *, bool, const tripoint & ); -int dog_whistle( player *, item *, bool, const tripoint & ); -int call_of_tindalos( player *, item *, bool, const tripoint & ); -int blood_draw( player *, item *, bool, const tripoint & ); -int mind_splicer( player *, item *, bool, const tripoint & ); +std::pair amputate( player *, item *, bool, const tripoint & ); +std::pair extinguisher( player *, item *, bool, const tripoint & ); +std::pair hammer( player *, item *, bool, const tripoint & ); +std::pair water_purifier( player *, item *, bool, const tripoint & ); +std::pair directional_antenna( player *, item *, bool, const tripoint & ); +std::pair radio_off( player *, item *, bool, const tripoint & ); +std::pair radio_on( player *, item *, bool, const tripoint & ); +std::pair noise_emitter_off( player *, item *, bool, const tripoint & ); +std::pair noise_emitter_on( player *, item *, bool, const tripoint & ); +std::pair note_bionics( player *, item *, bool, const tripoint & ); +std::pair ma_manual( player *, item *, bool, const tripoint & ); +std::pair crowbar( player *, item *, bool, const tripoint & ); +std::pair makemound( player *, item *, bool, const tripoint & ); +std::pair dig( player *, item *, bool, const tripoint & ); +std::pair dig_channel( player *, item *, bool, const tripoint & ); +std::pair fill_pit( player *, item *, bool, const tripoint & ); +std::pair clear_rubble( player *, item *, bool, const tripoint & ); +std::pair siphon( player *, item *, bool, const tripoint & ); +std::pair jackhammer( player *, item *, bool, const tripoint & ); +std::pair pickaxe( player *, item *, bool, const tripoint & ); +std::pair burrow( player *, item *, bool, const tripoint & ); +std::pair geiger( player *, item *, bool, const tripoint & ); +std::pair teleport( player *, item *, bool, const tripoint & ); +std::pair can_goo( player *, item *, bool, const tripoint & ); +std::pair throwable_extinguisher_act( player *, item *, bool, + const tripoint & ); +std::pair directional_hologram( player *, item *, bool, const tripoint & ); +std::pair capture_monster_veh( player *, item *, bool, const tripoint & ); +std::pair capture_monster_act( player *, item *, bool, const tripoint & ); +std::pair granade( player *, item *, bool, const tripoint & ); +std::pair granade_act( player *, item *, bool, const tripoint & ); +std::pair c4( player *, item *, bool, const tripoint & ); +std::pair arrow_flammable( player *, item *, bool, const tripoint & ); +std::pair acidbomb_act( player *, item *, bool, const tripoint & ); +std::pair grenade_inc_act( player *, item *, bool, const tripoint & ); +std::pair molotov_lit( player *, item *, bool, const tripoint & ); +std::pair firecracker_pack_act( player *, item *, bool, const tripoint & ); +std::pair firecracker_act( player *, item *, bool, const tripoint & ); +std::pair mininuke( player *, item *, bool, const tripoint & ); +std::pair pheromone( player *, item *, bool, const tripoint & ); +std::pair pick_lock( player *, item *, bool, const tripoint & ); +std::pair portal( player *, item *, bool, const tripoint & ); +std::pair tazer( player *, item *, bool, const tripoint & ); +std::pair mp3( player *, item *, bool, const tripoint & ); +std::pair mp3_on( player *, item *, bool, const tripoint & ); +std::pair rpgdie( player *, item *, bool, const tripoint & ); +std::pair dive_tank( player *, item *, bool, const tripoint & ); +std::pair gasmask( player *, item *, bool, const tripoint & ); +std::pair portable_game( player *, item *, bool, const tripoint & ); +std::pair vibe( player *, item *, bool, const tripoint & ); +std::pair hand_crank( player *, item *, bool, const tripoint & ); +std::pair vortex( player *, item *, bool, const tripoint & ); +std::pair dog_whistle( player *, item *, bool, const tripoint & ); +std::pair call_of_tindalos( player *, item *, bool, const tripoint & ); +std::pair blood_draw( player *, item *, bool, const tripoint & ); +std::pair mind_splicer( player *, item *, bool, const tripoint & ); void cut_log_into_planks( player & ); -int lumber( player *, item *, bool, const tripoint & ); -int chop_tree( player *, item *, bool, const tripoint & ); -int chop_logs( player *, item *, bool, const tripoint & ); -int oxytorch( player *, item *, bool, const tripoint & ); -int hacksaw( player *, item *, bool, const tripoint & ); -int boltcutters( player *, item *, bool, const tripoint & ); -int mop( player *, item *, bool, const tripoint & ); -int spray_can( player *, item *, bool, const tripoint & ); -int towel( player *, item *, bool, const tripoint & ); -int unfold_generic( player *, item *, bool, const tripoint & ); -int adrenaline_injector( player *, item *, bool, const tripoint & ); -int jet_injector( player *, item *, bool, const tripoint & ); -int stimpack( player *, item *, bool, const tripoint & ); -int contacts( player *, item *, bool, const tripoint & ); -int talking_doll( player *, item *, bool, const tripoint & ); -int bell( player *, item *, bool, const tripoint & ); -int seed( player *, item *, bool, const tripoint & ); -int oxygen_bottle( player *, item *, bool, const tripoint & ); -int radio_mod( player *, item *, bool, const tripoint & ); -int remove_all_mods( player *, item *, bool, const tripoint & ); -int fishing_rod( player *, item *, bool, const tripoint & ); -int fish_trap( player *, item *, bool, const tripoint & ); -int gun_clean( player *, item *, bool, const tripoint & ); -int gun_repair( player *, item *, bool, const tripoint & ); -int gunmod_attach( player *, item *, bool, const tripoint & ); -int toolmod_attach( player *, item *, bool, const tripoint & ); -int unpack_item( player *, item *, bool, const tripoint & ); -int pack_cbm( player *p, item *it, bool, const tripoint & ); -int pack_item( player *, item *, bool, const tripoint & ); -int radglove( player *, item *, bool, const tripoint & ); -int robotcontrol( player *, item *, bool, const tripoint & ); +std::pair lumber( player *, item *, bool, const tripoint & ); +std::pair chop_tree( player *, item *, bool, const tripoint & ); +std::pair chop_logs( player *, item *, bool, const tripoint & ); +std::pair oxytorch( player *, item *, bool, const tripoint & ); +std::pair hacksaw( player *, item *, bool, const tripoint & ); +std::pair boltcutters( player *, item *, bool, const tripoint & ); +std::pair mop( player *, item *, bool, const tripoint & ); +std::pair spray_can( player *, item *, bool, const tripoint & ); +std::pair towel( player *, item *, bool, const tripoint & ); +std::pair unfold_generic( player *, item *, bool, const tripoint & ); +std::pair adrenaline_injector( player *, item *, bool, const tripoint & ); +std::pair jet_injector( player *, item *, bool, const tripoint & ); +std::pair stimpack( player *, item *, bool, const tripoint & ); +std::pair contacts( player *, item *, bool, const tripoint & ); +std::pair talking_doll( player *, item *, bool, const tripoint & ); +std::pair bell( player *, item *, bool, const tripoint & ); +std::pair seed( player *, item *, bool, const tripoint & ); +std::pair oxygen_bottle( player *, item *, bool, const tripoint & ); +std::pair radio_mod( player *, item *, bool, const tripoint & ); +std::pair remove_all_mods( player *, item *, bool, const tripoint & ); +std::pair fishing_rod( player *, item *, bool, const tripoint & ); +std::pair fish_trap( player *, item *, bool, const tripoint & ); +std::pair gun_clean( player *, item *, bool, const tripoint & ); +std::pair gun_repair( player *, item *, bool, const tripoint & ); +std::pair gunmod_attach( player *, item *, bool, const tripoint & ); +std::pair toolmod_attach( player *, item *, bool, const tripoint & ); +std::pair unpack_item( player *, item *, bool, const tripoint & ); +std::pair pack_cbm( player *p, item *it, bool, const tripoint & ); +std::pair pack_item( player *, item *, bool, const tripoint & ); +std::pair radglove( player *, item *, bool, const tripoint & ); +std::pair robotcontrol( player *, item *, bool, const tripoint & ); // Helper for validating a potential taget of robot control bool robotcontrol_can_target( player *, const monster & ); -int einktabletpc( player *, item *, bool, const tripoint & ); -int camera( player *, item *, bool, const tripoint & ); -int ehandcuffs( player *, item *, bool, const tripoint & ); -int foodperson( player *, item *, bool, const tripoint & ); -int tow_attach( player *, item *, bool, const tripoint & ); -int cable_attach( player *, item *, bool, const tripoint & ); -int shavekit( player *, item *, bool, const tripoint & ); -int hairkit( player *, item *, bool, const tripoint & ); -int weather_tool( player *, item *, bool, const tripoint & ); -int ladder( player *, item *, bool, const tripoint & ); -int wash_soft_items( player *, item *, bool, const tripoint & ); -int wash_hard_items( player *, item *, bool, const tripoint & ); -int wash_all_items( player *, item *, bool, const tripoint & ); -int solarpack( player *, item *, bool, const tripoint & ); -int solarpack_off( player *, item *, bool, const tripoint & ); -int weak_antibiotic( player *, item *, bool, const tripoint & ); -int strong_antibiotic( player *, item *, bool, const tripoint & ); -int melatonin_tablet( player *, item *, bool, const tripoint & ); -int coin_flip( player *, item *, bool, const tripoint & ); -int play_game( player *, item *, bool, const tripoint & ); -int magic_8_ball( player *, item *, bool, const tripoint & ); -int toggle_heats_food( player *, item *, bool, const tripoint & ); -int toggle_ups_charging( player *, item *, bool, const tripoint & ); -int report_grid_charge( player *, item *, bool, const tripoint & ); -int report_grid_connections( player *, item *, bool, const tripoint & ); -int modify_grid_connections( player *, item *, bool, const tripoint & ); +std::pair einktabletpc( player *, item *, bool, const tripoint & ); +std::pair camera( player *, item *, bool, const tripoint & ); +std::pair ehandcuffs( player *, item *, bool, const tripoint & ); +std::pair foodperson( player *, item *, bool, const tripoint & ); +std::pair tow_attach( player *, item *, bool, const tripoint & ); +std::pair cable_attach( player *, item *, bool, const tripoint & ); +std::pair shavekit( player *, item *, bool, const tripoint & ); +std::pair hairkit( player *, item *, bool, const tripoint & ); +std::pair weather_tool( player *, item *, bool, const tripoint & ); +std::pair ladder( player *, item *, bool, const tripoint & ); +std::pair wash_soft_items( player *, item *, bool, const tripoint & ); +std::pair wash_hard_items( player *, item *, bool, const tripoint & ); +std::pair wash_all_items( player *, item *, bool, const tripoint & ); +std::pair solarpack( player *, item *, bool, const tripoint & ); +std::pair solarpack_off( player *, item *, bool, const tripoint & ); +std::pair weak_antibiotic( player *, item *, bool, const tripoint & ); +std::pair strong_antibiotic( player *, item *, bool, const tripoint & ); +std::pair melatonin_tablet( player *, item *, bool, const tripoint & ); +std::pair coin_flip( player *, item *, bool, const tripoint & ); +std::pair play_game( player *, item *, bool, const tripoint & ); +std::pair magic_8_ball( player *, item *, bool, const tripoint & ); +std::pair toggle_heats_food( player *, item *, bool, const tripoint & ); +std::pair toggle_ups_charging( player *, item *, bool, const tripoint & ); +std::pair report_grid_charge( player *, item *, bool, const tripoint & ); +std::pair report_grid_connections( player *, item *, bool, const tripoint & ); +std::pair modify_grid_connections( player *, item *, bool, const tripoint & ); // MACGUFFINS -int radiocar( player *, item *, bool, const tripoint & ); -int radiocaron( player *, item *, bool, const tripoint & ); -int radiocontrol( player *, item *, bool, const tripoint & ); +std::pair radiocar( player *, item *, bool, const tripoint & ); +std::pair radiocaron( player *, item *, bool, const tripoint & ); +std::pair radiocontrol( player *, item *, bool, const tripoint & ); -int autoclave( player *, item *, bool, const tripoint & ); +std::pair autoclave( player *, item *, bool, const tripoint & ); -int multicooker( player *, item *, bool, const tripoint & ); +std::pair multicooker( player *, item *, bool, const tripoint & ); -int remoteveh( player *, item *, bool, const tripoint & ); +std::pair remoteveh( player *, item *, bool, const tripoint & ); -int craft( player *, item *, bool, const tripoint & ); +std::pair craft( player *, item *, bool, const tripoint & ); -int disassemble( player *, item *, bool, const tripoint & ); +std::pair disassemble( player *, item *, bool, const tripoint & ); // ARTIFACTS /* This function is used when an artifact is activated. It examines the item's artifact-specific properties. See artifact.h for a list. */ -int artifact( player *, item *, bool, const tripoint & ); +std::pair artifact( player *, item *, bool, const tripoint & ); // Helper for listening to music, might deserve a better home, but not sure where. void play_music( player &p, const tripoint &source, int volume, int max_morale ); -int towel_common( player *, item *, bool ); +std::pair towel_common( player *, item *, bool ); // Helper for handling pesky wannabe-artists -int handle_ground_graffiti( player &p, item *it, const std::string &prefix, - const tripoint &where ); +std::pair handle_ground_graffiti( player &p, item *it, + const std::string &prefix, + const tripoint &where ); // Helper for wood chopping int chop_moves( Character &ch, item &tool ); // LEGACY -int cauterize_hotplate( player *, item *, bool, const tripoint & ); +std::pair cauterize_hotplate( player *, item *, bool, const tripoint & ); } // namespace iuse @@ -231,12 +230,14 @@ struct washing_requirements { }; washing_requirements washing_requirements_for_volume( const units::volume & ); -using use_function_pointer = int ( * )( player *, item *, bool, const tripoint & ); +using use_function_pointer = std::pair ( * )( player *, item *, bool, + const tripoint & ); class iuse_actor { protected: - iuse_actor( const std::string &type, int cost = -1 ) : type( type ), cost( cost ) {} + iuse_actor( const std::string &type, int cost = -1, units::energy e_cost = -1_J ) : + type( type ), cost( cost ), e_cost( e_cost ) {} public: /** @@ -247,10 +248,12 @@ class iuse_actor /** Units of ammo required per invocation (or use value from base item if negative) */ int cost; + units::energy e_cost; virtual ~iuse_actor() = default; virtual void load( const JsonObject &jo ) = 0; - virtual int use( player &, item &, bool, const tripoint & ) const = 0; + virtual std::pair use( player &, item &, bool, + const tripoint & ) const = 0; virtual ret_val can_use( const Character &, const item &, bool, const tripoint & ) const; virtual void info( const item &, std::vector & ) const {} /** @@ -288,7 +291,7 @@ struct use_function { use_function( const std::string &type, use_function_pointer f ); use_function( std::unique_ptr f ) : actor( std::move( f ) ) {} - int call( player &, item &, bool, const tripoint & ) const; + std::pair call( player &, item &, bool, const tripoint & ) const; ret_val can_call( const Character &, const item &, bool t, const tripoint &pos ) const; iuse_actor *get_actor_ptr() { diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index abed5e974ee4..14998666d9aa 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -213,10 +213,13 @@ void iuse_transform::load( const JsonObject &obj ) obj.read( "menu_text", menu_text ); } -int iuse_transform::use( player &p, item &it, bool t, const tripoint &pos ) const +std::pair iuse_transform::use( player &p, item &it, bool t, + const tripoint &pos ) const { + std::pair res( cost >= 0 ? cost : it.type->charges_to_use(), + e_cost >= 0_J ? e_cost : it.energy_required() ); if( t ) { - return 0; // invoked from active item processing, do nothing. + return std::make_pair( 0, 0_J ); // invoked from active item processing, do nothing. } const bool possess = p.has_item( it ) || @@ -224,11 +227,11 @@ int iuse_transform::use( player &p, item &it, bool t, const tripoint &pos ) cons if( possess && need_worn && !p.is_worn( it ) ) { p.add_msg_if_player( m_info, _( "You need to wear the %1$s before activating it." ), it.tname() ); - return 0; + return std::make_pair( 0, 0_J ); } if( possess && need_wielding && !p.is_wielding( it ) ) { p.add_msg_if_player( m_info, _( "You need to wield the %1$s before activating it." ), it.tname() ); - return 0; + return std::make_pair( 0, 0_J ); } // No charge consumption at this point, there are still points of failure later. if( need_charges || transform_charges ) { @@ -237,16 +240,16 @@ int iuse_transform::use( player &p, item &it, bool t, const tripoint &pos ) cons const int bio_power = units::to_kilojoule( p.get_power_level() ); if( bio_power < need_charges || bio_power < transform_charges ) { p.add_msg_if_player( m_info, need_charges_msg, it.tname() ); - return 0; + return std::make_pair( 0, 0_J ); } } else { - return 0; + return std::make_pair( 0, 0_J ); } } else { - const int item_charges = it.units_remaining( p ); + const int item_charges = it.units_remaining(); if( item_charges < need_charges || item_charges < transform_charges ) { p.add_msg_if_player( m_info, need_charges_msg, it.tname() ); - return 0; + return std::make_pair( 0, 0_J ); } } } @@ -255,20 +258,14 @@ int iuse_transform::use( player &p, item &it, bool t, const tripoint &pos ) cons if( need_fire && possess ) { if( !p.use_charges_if_avail( itype_fire, need_fire ) ) { p.add_msg_if_player( m_info, need_fire_msg, it.tname() ); - return 0; + return std::make_pair( 0, 0_J ); } if( p.is_underwater() ) { p.add_msg_if_player( m_info, _( "You can't do that while underwater" ) ); - return 0; + return std::make_pair( 0, 0_J ); } } - // All checks complete the damn thing can finally transform - // Consume charges if necessary at this point. - if( transform_charges ) { - p.consume_charges( it, transform_charges ); - } - if( possess && !msg_transform.empty() ) { p.add_msg_if_player( m_neutral, msg_transform, it.tname() ); } @@ -319,7 +316,7 @@ int iuse_transform::use( player &p, item &it, bool t, const tripoint &pos ) cons // Check for gaining or losing night vision, eye encumbrance effects, clairvoyance from transforming relics, etc. p.recalc_sight_limits(); - return 0; + return res; } ret_val iuse_transform::can_use( const Character &p, const item &, bool, @@ -409,7 +406,7 @@ void unpack_actor::load( const JsonObject &obj ) assign( obj, "filthy_volume_threshold", filthy_vol_threshold ); } -int unpack_actor::use( player &p, item &it, bool, const tripoint & ) const +std::pair unpack_actor::use( player &p, item &it, bool, const tripoint & ) const { std::vector> items = item_group::items_from( unpack_group, calendar::turn ); item *last_armor = &null_item_reference(); @@ -440,7 +437,7 @@ int unpack_actor::use( player &p, item &it, bool, const tripoint & ) const it.detach( ); - return 0; + return std::make_pair( 0, 0_J ); } void unpack_actor::info( const item &, std::vector &dump ) const @@ -461,14 +458,15 @@ void countdown_actor::load( const JsonObject &obj ) obj.read( "message", message ); } -int countdown_actor::use( player &p, item &it, bool t, const tripoint &pos ) const +std::pair countdown_actor::use( player &p, item &it, bool t, + const tripoint &pos ) const { if( t ) { - return 0; + return std::make_pair( 0, 0_J ); } if( it.is_active() ) { - return 0; + return std::make_pair( 0, 0_J ); } if( p.sees( pos ) && !message.empty() ) { @@ -477,7 +475,7 @@ int countdown_actor::use( player &p, item &it, bool t, const tripoint &pos ) con it.item_counter = interval > 0 ? interval : it.type->countdown_interval; it.activate(); - return 0; + return std::make_pair( 0, 0_J ); } ret_val countdown_actor::can_use( const Character &, const item &it, bool, @@ -567,7 +565,8 @@ void explosion_iuse::load( const JsonObject &obj ) obj.read( "no_deactivate_msg", no_deactivate_msg ); } -int explosion_iuse::use( player &p, item &it, bool t, const tripoint &pos ) const +std::pair explosion_iuse::use( player &p, item &it, bool t, + const tripoint &pos ) const { if( t ) { if( sound_volume >= 0 ) { @@ -583,12 +582,12 @@ int explosion_iuse::use( player &p, item &it, bool t, const tripoint &pos ) cons p.add_msg_if_player( m_info, _( no_deactivate_msg ), it.tname() ); } } - return 0; + return std::make_pair( 0, 0_J ); } if( it.charges == 0 ) { trigger_explosion( pos, it.activated_by ); } - return 1; + return std::make_pair( 1, 0_J ); } void explosion_iuse::trigger_explosion( const tripoint &pos, Creature *source ) const @@ -661,29 +660,30 @@ void unfold_vehicle_iuse::load( const JsonObject &obj ) obj.read( "tools_needed", tools_needed ); } -int unfold_vehicle_iuse::use( player &p, item &it, bool, const tripoint & ) const +std::pair unfold_vehicle_iuse::use( player &p, item &it, bool, + const tripoint & ) const { if( p.is_underwater() ) { p.add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p.is_mounted() ) { p.add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } for( const auto &tool : tools_needed ) { // Amount == -1 means need one, but don't consume it. if( !p.has_amount( tool.first, 1 ) ) { p.add_msg_if_player( _( "You need %s to do it!" ), item::nname( tool.first ) ); - return 0; + return std::make_pair( 0, 0_J ); } } vehicle *veh = get_map().add_vehicle( vehicle_id, p.pos(), 0_degrees, 0, 0, false ); if( veh == nullptr ) { p.add_msg_if_player( m_info, _( "There's no room to unfold the %s." ), it.tname() ); - return 0; + return std::make_pair( 0, 0_J ); } veh->set_owner( p ); @@ -698,7 +698,7 @@ int unfold_vehicle_iuse::use( player &p, item &it, bool, const tripoint & ) cons // Restore HP of parts if we stashed them previously. if( it.has_var( "folding_bicycle_parts" ) ) { // Brand new, no HP stored - return 1; + return std::make_pair( 1, 0_J ); } std::istringstream veh_data; const auto data = it.get_var( "folding_bicycle_parts" ); @@ -732,7 +732,7 @@ int unfold_vehicle_iuse::use( player &p, item &it, bool, const tripoint & ) cons debugmsg( "Error restoring vehicle: %s", e.c_str() ); } } - return 1; + return std::make_pair( 1, 0_J ); } std::unique_ptr consume_drug_iuse::clone() const @@ -816,7 +816,8 @@ void consume_drug_iuse::info( const item &, std::vector &dump ) const } } -int consume_drug_iuse::use( player &p, item &it, bool, const tripoint & ) const +std::pair consume_drug_iuse::use( player &p, item &it, bool, + const tripoint & ) const { auto need_these = tools_needed; if( need_these.contains( itype_syringe ) && p.has_bionic( bio_syringe ) ) { @@ -830,7 +831,7 @@ int consume_drug_iuse::use( player &p, item &it, bool, const tripoint & ) const _( "I need a %1$s to consume %2$s!" ), item::nname( tool.first ), it.type_name( 1 ) ); - return -1; + return std::make_pair( -1, 0_J ); } } for( const auto &consumable : charges_needed ) { @@ -841,7 +842,7 @@ int consume_drug_iuse::use( player &p, item &it, bool, const tripoint & ) const _( "I need a %1$s to consume %2$s!" ), item::nname( consumable.first ), it.type_name( 1 ) ); - return -1; + return std::make_pair( -1, 0_J ); } } // Apply the various effects. @@ -891,7 +892,7 @@ int consume_drug_iuse::use( player &p, item &it, bool, const tripoint & ) const } p.moves -= moves; - return it.type->charges_to_use(); + return std::make_pair( it.type->charges_to_use(), 0_J ); } std::unique_ptr delayed_transform_iuse::clone() const @@ -912,11 +913,12 @@ int delayed_transform_iuse::time_to_do( const item &it ) const return transform_age - to_turns( it.age() ); } -int delayed_transform_iuse::use( player &p, item &it, bool t, const tripoint &pos ) const +std::pair delayed_transform_iuse::use( player &p, item &it, bool t, + const tripoint &pos ) const { if( time_to_do( it ) > 0 ) { p.add_msg_if_player( m_info, _( not_ready_msg ) ); - return 0; + return std::make_pair( 0, 0_J ); } return iuse_transform::use( p, it, t, pos ); } @@ -941,10 +943,12 @@ void set_transform_iuse::load( const JsonObject &obj ) set_charges = std::max( set_charges, 0 ); } -int set_transform_iuse::use( player &p, item &it, bool t, const tripoint &pos ) const +std::pair set_transform_iuse::use( player &p, item &it, bool t, + const tripoint &pos ) const { if( t ) { - return 0; // invoked from active item processing, do nothing. + // invoked from active item processing, do nothing. + return std::make_pair( 0, 0_J ); } const bool possess = p.has_item( it ) || @@ -956,13 +960,13 @@ int set_transform_iuse::use( player &p, item &it, bool t, const tripoint &pos ) if( possess ) { p.add_msg_if_player( m_info, set_charges_msg, it.tname() ); } - return 0; + return std::make_pair( 0, 0_J ); } - } else if( it.units_remaining( p ) < set_charges ) { + } else if( it.units_remaining() < set_charges ) { if( possess ) { p.add_msg_if_player( m_info, set_charges_msg, it.tname() ); } - return 0; + return std::make_pair( 0, 0_J ); } } @@ -984,7 +988,7 @@ int set_transform_iuse::use( player &p, item &it, bool t, const tripoint &pos ) } } } - return 0; + return std::make_pair( 0, 0_J ); } std::unique_ptr set_transformed_iuse::clone() const @@ -999,18 +1003,20 @@ void set_transformed_iuse::load( const JsonObject &obj ) obj.read( "dependencies", dependencies ); } -int set_transformed_iuse::use( player &p, item &it, bool t, const tripoint &pos ) const +std::pair set_transformed_iuse::use( player &p, item &it, bool t, + const tripoint &pos ) const { if( t ) { - return 0; // invoked from active item processing, do nothing. + return std::make_pair( 0, 0_J ); // invoked from active item processing, do nothing. } iuse_transform::use( p, it, t, pos ); - return 0; + return std::make_pair( 0, 0_J ); } -int set_transformed_iuse::bypass( player &p, item &it, bool t, const tripoint &pos ) const +std::pair set_transformed_iuse::bypass( player &p, item &it, bool t, + const tripoint &pos ) const { return iuse_transform::use( p, it, t, pos ); } @@ -1033,6 +1039,7 @@ std::unique_ptr place_monster_iuse::clone() const void place_monster_iuse::load( const JsonObject &obj ) { mtypeid = mtype_id( obj.get_string( "monster_id" ) ); + assign( obj, "e_cost", e_cost ); obj.read( "friendly_msg", friendly_msg ); obj.read( "hostile_msg", hostile_msg ); obj.read( "difficulty", difficulty ); @@ -1047,8 +1054,11 @@ void place_monster_iuse::load( const JsonObject &obj ) } } -int place_monster_iuse::use( player &p, item &it, bool, const tripoint &pos ) const +std::pair place_monster_iuse::use( player &p, item &it, bool, + const tripoint &pos ) const { + std::pair res( it.type->charges_to_use(), + e_cost >= 0_J ? e_cost : it.energy_required() ); shared_ptr_fast newmon_ptr = make_shared_fast( mtypeid ); monster &newmon = *newmon_ptr; newmon.init_from_item( it ); @@ -1061,18 +1071,18 @@ int place_monster_iuse::use( player &p, item &it, bool, const tripoint &pos ) co newmon.name() ); // If remotely triggered due to ACT_ON_RANGED_HIT, set it back to being inactive so it won't spawn infinitely it.deactivate(); - return 0; + return std::make_pair( 0, 0_J ); } } else { const std::string query = string_format( _( "Place the %s where?" ), newmon.name() ); const std::optional pnt_ = choose_adjacent( query ); if( !pnt_ ) { - return 0; + return std::make_pair( 0, 0_J ); } // place_critter_at returns the same pointer as its parameter (or null) if( !g->place_critter_at( newmon_ptr, *pnt_ ) ) { p.add_msg_if_player( m_info, _( "You cannot place a %s there." ), newmon.name() ); - return 0; + return std::make_pair( 0, 0_J ); } } // If it's active then we know it was triggered by ACT_ON_RANGED_HIT and did not deactivate from lack of room earlier @@ -1136,7 +1146,7 @@ int place_monster_iuse::use( player &p, item &it, bool, const tripoint &pos ) co if( newmon.type->id == mtype_id( "mon_laserturret" ) && !g->is_in_sunlight( newmon.pos() ) ) { p.add_msg_if_player( _( "A flashing LED on the laser turret appears to indicate low light." ) ); } - return 1; + return res; } std::unique_ptr place_npc_iuse::clone() const @@ -1152,8 +1162,9 @@ void place_npc_iuse::load( const JsonObject &obj ) obj.read( "place_randomly", place_randomly ); } -int place_npc_iuse::use( player &p, item &, bool, const tripoint & ) const +std::pair place_npc_iuse::use( player &p, item &, bool, const tripoint & ) const { + std::pair res( 1, 0_J ); map &here = get_map(); std::optional target_pos; if( place_randomly ) { @@ -1166,17 +1177,17 @@ int place_npc_iuse::use( player &p, item &, bool, const tripoint & ) const target_pos = choose_adjacent( _( "Place npc where?" ) ); } if( !target_pos ) { - return 0; + return std::make_pair( 0, 0_J ); } if( !here.passable( target_pos.value() ) ) { p.add_msg_if_player( m_info, _( "There is no square to spawn npc in!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } here.place_npc( target_pos.value().xy(), npc_class_id ); p.mod_moves( -moves ); p.add_msg_if_player( m_info, "%s", _( summon_msg ) ); - return 1; + return res; } std::unique_ptr deploy_furn_actor::clone() const @@ -1233,27 +1244,28 @@ void deploy_furn_actor::load( const JsonObject &obj ) furn_type = furn_str_id( obj.get_string( "furn_type" ) ); } -int deploy_furn_actor::use( player &p, item &it, bool t, const tripoint &pos ) const +std::pair deploy_furn_actor::use( player &p, item &it, bool t, + const tripoint &pos ) const { if( t ) { - return 0; + return std::make_pair( 0, 0_J ); } if( p.is_mounted() ) { p.add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } tripoint pnt = pos; if( const std::optional pnt_ = choose_adjacent( _( "Deploy where?" ) ) ) { pnt = *pnt_; } else { - return 0; + return std::make_pair( 0, 0_J ); } if( pnt == p.pos() ) { p.add_msg_if_player( m_info, _( "You attempt to become one with the furniture. It doesn't work." ) ); - return 0; + return std::make_pair( 0, 0_J ); } map &here = get_map(); @@ -1263,23 +1275,23 @@ int deploy_furn_actor::use( player &p, item &it, bool t, const tripoint &pos ) c // and/or integrate furniture deployment with construction (which already seems to perform these checks sometimes?) p.add_msg_if_player( m_info, _( "The space under %s is too cramped to deploy a %s in." ), veh_there.value().vehicle().disp_name(), it.tname() ); - return 0; + return std::make_pair( 0, 0_J ); } // For example: dirt = 2, long grass = 3 if( here.move_cost( pnt ) != 2 && here.move_cost( pnt ) != 3 ) { p.add_msg_if_player( m_info, _( "You can't deploy a %s there." ), it.tname() ); - return 0; + return std::make_pair( 0, 0_J ); } if( here.has_furn( pnt ) ) { p.add_msg_if_player( m_info, _( "There is already furniture at that location." ) ); - return 0; + return std::make_pair( 0, 0_J ); } here.furn_set( pnt, furn_type ); p.mod_moves( to_turns( 2_seconds ) ); - return 1; + return std::make_pair( 1, 0_J ); } std::unique_ptr reveal_map_actor::clone() const @@ -1318,18 +1330,19 @@ void reveal_map_actor::reveal_targets( const tripoint_abs_omt ¢er, } } -int reveal_map_actor::use( player &p, item &it, bool, const tripoint & ) const +std::pair reveal_map_actor::use( player &p, item &it, bool, + const tripoint & ) const { if( it.already_used_by_player( p ) ) { p.add_msg_if_player( _( "There isn't anything new on the %s." ), it.tname() ); - return 0; + return std::make_pair( 0, 0_J ); } else if( g->get_levz() < 0 ) { p.add_msg_if_player( _( "You should read your %s when you get to the surface." ), it.tname() ); - return 0; + return std::make_pair( 0, 0_J ); } else if( !character_funcs::can_see_fine_details( p ) ) { p.add_msg_if_player( _( "It's too dark to read." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const tripoint_abs_omt center( it.get_var( "reveal_map_center_omt", p.global_omt_location().raw() ) ); @@ -1342,14 +1355,16 @@ int reveal_map_actor::use( player &p, item &it, bool, const tripoint & ) const p.add_msg_if_player( m_good, "%s", _( message ) ); } it.mark_as_used_by_player( p ); - return 0; + return std::make_pair( 0, 0_J ); } void firestarter_actor::load( const JsonObject &obj ) { - moves_cost_fast = obj.get_int( "moves", moves_cost_fast ); - moves_cost_slow = obj.get_int( "moves_slow", moves_cost_fast * 10 ); - need_sunlight = obj.get_bool( "need_sunlight", false ); + assign( obj, "cost", cost ); + assign( obj, "e_cost", e_cost ); + assign( obj, "moves", moves_cost_fast ); + assign( obj, "moves_slow", moves_cost_slow ); + assign( obj, "need_sunlight", need_sunlight ); } std::unique_ptr firestarter_actor::clone() const @@ -1455,16 +1470,19 @@ int firestarter_actor::moves_cost_by_fuel( const tripoint &pos ) const return moves_cost_slow; } -int firestarter_actor::use( player &p, item &it, bool t, const tripoint &spos ) const +std::pair firestarter_actor::use( player &p, item &it, bool t, + const tripoint &spos ) const { + std::pair res( cost >= 0 ? cost : it.type->charges_to_use(), + e_cost >= 0_J ? e_cost : it.energy_required() ); if( t ) { - return 0; + return std::make_pair( 0, 0_J ); } tripoint pos = spos; float light = light_mod( p.pos() ); if( !prep_firestarter_use( p, pos ) ) { - return 0; + return std::make_pair( 0, 0_J ); } double skill_level = p.get_skill_level( skill_survival ); @@ -1485,7 +1503,7 @@ int firestarter_actor::use( player &p, item &it, bool t, const tripoint &spos ) // If less than 2 turns, don't start a long action resolve_firestarter_use( p, pos ); p.mod_moves( -moves ); - return it.type->charges_to_use(); + return res; } // skill gains are handled by the activity, but stored here in the index field @@ -1497,7 +1515,7 @@ int firestarter_actor::use( player &p, item &it, bool t, const tripoint &spos ) p.activity->values.push_back( g->natural_light_level( pos.z ) ); p.activity->placement = pos; // charges to use are handled by the activity - return 0; + return std::make_pair( 0, 0_J ); } void salvage_actor::load( const JsonObject &obj ) @@ -1516,24 +1534,25 @@ std::unique_ptr salvage_actor::clone() const return std::make_unique( *this ); } -int salvage_actor::use( player &p, item &it, bool t, const tripoint & ) const +std::pair salvage_actor::use( player &p, item &it, bool t, + const tripoint & ) const { if( t ) { - return 0; + return std::make_pair( 0, 0_J ); } auto item_loc = game_menus::inv::salvage( p, this ); if( !item_loc ) { add_msg( _( "Never mind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( !try_to_cut_up( p, *item_loc ) ) { // Messages should have already been displayed. - return 0; + return std::make_pair( 0, 0_J ); } - return cut_up( p, it, *item_loc ); + return std::make_pair( cut_up( p, it, *item_loc ), 0_J ); } // Helper to visit instances of all the sub-materials of an item. @@ -1764,6 +1783,7 @@ int salvage_actor::cut_up( player &p, item &it, item &cut ) const void inscribe_actor::load( const JsonObject &obj ) { assign( obj, "cost", cost ); + assign( obj, "e_cost", e_cost ); assign( obj, "on_items", on_items ); assign( obj, "on_terrain", on_terrain ); assign( obj, "material_restricted", material_restricted ); @@ -1857,10 +1877,13 @@ bool inscribe_actor::item_inscription( item &tool, item &cut ) const return true; } -int inscribe_actor::use( player &p, item &it, bool t, const tripoint & ) const +std::pair inscribe_actor::use( player &p, item &it, bool t, + const tripoint & ) const { + std::pair res( cost >= 0 ? cost : it.type->charges_to_use(), + e_cost >= 0_J ? e_cost : it.energy_required() ); if( t ) { - return 0; + return std::make_pair( 0, 0_J ); } int choice = INT_MAX; @@ -1878,13 +1901,13 @@ int inscribe_actor::use( player &p, item &it, bool t, const tripoint & ) const } if( choice < 0 || choice > 1 ) { - return 0; + return std::make_pair( 0, 0_J ); } if( choice == 0 ) { const std::optional dest_ = choose_adjacent( _( "Write where?" ) ); if( !dest_ ) { - return 0; + return std::make_pair( 0, 0_J ); } return iuse::handle_ground_graffiti( p, &it, string_format( _( "%s what?" ), verb ), dest_.value() ); @@ -1893,25 +1916,26 @@ int inscribe_actor::use( player &p, item &it, bool t, const tripoint & ) const item *loc = game_menus::inv::titled_menu( get_avatar(), _( "Inscribe which item?" ) ); if( !loc ) { p.add_msg_if_player( m_info, _( "Never mind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } item &cut = *loc; if( &cut == &it ) { p.add_msg_if_player( _( "You try to bend your %s, but fail." ), it.tname() ); - return 0; + return std::make_pair( 0, 0_J ); } // inscribe_item returns false if the action fails or is canceled somehow. if( item_inscription( it, cut ) ) { - return cost >= 0 ? cost : it.ammo_required(); + return res; } - return 0; + return std::make_pair( 0, 0_J ); } void cauterize_actor::load( const JsonObject &obj ) { assign( obj, "cost", cost ); + assign( obj, "e_cost", e_cost ); assign( obj, "flame", flame ); } @@ -1956,14 +1980,17 @@ bool cauterize_actor::cauterize_effect( player &p, item &it, bool force ) return false; } -int cauterize_actor::use( player &p, item &it, bool t, const tripoint & ) const +std::pair cauterize_actor::use( player &p, item &it, bool t, + const tripoint & ) const { + std::pair res( cost >= 0 ? cost : it.type->charges_to_use(), + e_cost >= 0_J ? e_cost : it.energy_required() ); if( t ) { - return 0; + return std::make_pair( 0, 0_J ); } if( p.is_mounted() ) { p.add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } bool has_disease = p.has_effect( effect_bite ) || p.has_effect( effect_bleed ); bool did_cauterize = false; @@ -1980,15 +2007,15 @@ int cauterize_actor::use( player &p, item &it, bool t, const tripoint & ) const } if( !did_cauterize ) { - return 0; + return std::make_pair( 0, 0_J ); } if( flame ) { p.use_charges( itype_fire, 4 ); - return 0; + return std::make_pair( 0, 0_J ); } else { - return cost >= 0 ? cost : it.ammo_required(); + return res; } } @@ -2014,7 +2041,7 @@ ret_val cauterize_actor::can_use( const Character &p, const item &it, bool _( "You need a source of flame (4 charges worth) before you can cauterize yourself." ) ); } } else { - if( !it.units_sufficient( p ) ) { + if( !it.units_sufficient() ) { return ret_val::make_failure( _( "You need at least %d charges to cauterize wounds." ), it.ammo_required() ); } @@ -2030,6 +2057,7 @@ ret_val cauterize_actor::can_use( const Character &p, const item &it, bool void enzlave_actor::load( const JsonObject &obj ) { assign( obj, "cost", cost ); + assign( obj, "e_cost", e_cost ); } std::unique_ptr enzlave_actor::clone() const @@ -2037,14 +2065,17 @@ std::unique_ptr enzlave_actor::clone() const return std::make_unique( *this ); } -int enzlave_actor::use( player &p, item &it, bool t, const tripoint & ) const +std::pair enzlave_actor::use( player &p, item &it, bool t, + const tripoint & ) const { + std::pair res( cost >= 0 ? cost : it.type->charges_to_use(), + e_cost >= 0_J ? e_cost : it.energy_required() ); if( t ) { - return 0; + return std::make_pair( 0, 0_J ); } if( p.is_mounted() ) { p.add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } map_stack items = get_map().i_at( point( p.posx(), p.posy() ) ); std::vector corpses; @@ -2061,7 +2092,7 @@ int enzlave_actor::use( player &p, item &it, bool t, const tripoint & ) const if( corpses.empty() ) { p.add_msg_if_player( _( "No suitable corpses" ) ); - return 0; + return std::make_pair( 0, 0_J ); } int tolerance_level = 9; @@ -2080,7 +2111,7 @@ int enzlave_actor::use( player &p, item &it, bool t, const tripoint & ) const skill_survival ) ) ) - 150 ) { add_msg( m_neutral, _( "The prospect of cutting up the corpse and letting it rise again as a slave is too much for you to deal with right now." ) ); - return 0; + return std::make_pair( 0, 0_J ); } uilist amenu; @@ -2094,7 +2125,7 @@ int enzlave_actor::use( player &p, item &it, bool t, const tripoint & ) const if( amenu.ret < 0 ) { p.add_msg_if_player( _( "Make love, not zlave." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( tolerance_level == 0 ) { @@ -2151,7 +2182,7 @@ int enzlave_actor::use( player &p, item &it, bool t, const tripoint & ) const p.activity->values.push_back( success ); p.activity->str_values.push_back( corpses[selected_corpse]->display_name() ); - return cost >= 0 ? cost : it.ammo_required(); + return res; } ret_val enzlave_actor::can_use( const Character &p, const item &, bool, @@ -2179,111 +2210,6 @@ ret_val enzlave_actor::can_use( const Character &p, const item &, bool, return ret_val::make_success(); } -void fireweapon_off_actor::load( const JsonObject &obj ) -{ - obj.read( "target_id", target_id, true ); - success_message = obj.get_string( "success_message", "hsss" ); - lacks_fuel_message = obj.get_string( "lacks_fuel_message" ); - failure_message = obj.get_string( "failure_message", "hsss" ); - noise = obj.get_int( "noise", 0 ); - moves = obj.get_int( "moves", 0 ); - success_chance = obj.get_int( "success_chance", INT_MIN ); -} - -std::unique_ptr fireweapon_off_actor::clone() const -{ - return std::make_unique( *this ); -} - -int fireweapon_off_actor::use( player &p, item &it, bool t, const tripoint & ) const -{ - if( t ) { - return 0; - } - - if( it.charges <= 0 ) { - p.add_msg_if_player( _( lacks_fuel_message ) ); - return 0; - } - - p.moves -= moves; - if( rng( 0, 10 ) - it.damage_level( 4 ) > success_chance && !p.is_underwater() ) { - if( noise > 0 ) { - sounds::sound( p.pos(), noise, sounds::sound_t::combat, _( success_message ) ); - } - p.add_msg_if_player( _( success_message ) ); - - it.convert( target_id ); - it.activate(); - } else if( !failure_message.empty() ) { - p.add_msg_if_player( m_bad, _( failure_message ) ); - } - - return it.type->charges_to_use(); -} - -ret_val fireweapon_off_actor::can_use( const Character &p, const item &it, bool, - const tripoint & ) const -{ - if( it.charges < it.type->charges_to_use() ) { - return ret_val::make_failure( _( "This tool doesn't have enough charges." ) ); - } - - if( p.is_underwater() ) { - return ret_val::make_failure( _( "You can't do that while underwater." ) ); - } - - return ret_val::make_success(); -} - -void fireweapon_on_actor::load( const JsonObject &obj ) -{ - noise_message = obj.get_string( "noise_message", "hsss" ); - voluntary_extinguish_message = obj.get_string( "voluntary_extinguish_message" ); - charges_extinguish_message = obj.get_string( "charges_extinguish_message" ); - water_extinguish_message = obj.get_string( "water_extinguish_message" ); - noise = obj.get_int( "noise", 0 ); - noise_chance = obj.get_int( "noise_chance", 1 ); - auto_extinguish_chance = obj.get_int( "auto_extinguish_chance", 0 ); - if( auto_extinguish_chance > 0 ) { - auto_extinguish_message = obj.get_string( "auto_extinguish_message" ); - } -} - -std::unique_ptr fireweapon_on_actor::clone() const -{ - return std::make_unique( *this ); -} - -int fireweapon_on_actor::use( player &p, item &it, bool t, const tripoint & ) const -{ - bool extinguish = true; - if( it.charges == 0 ) { - p.add_msg_if_player( m_bad, _( charges_extinguish_message ) ); - } else if( p.is_underwater() ) { - p.add_msg_if_player( m_bad, _( water_extinguish_message ) ); - } else if( auto_extinguish_chance > 0 && one_in( auto_extinguish_chance ) ) { - p.add_msg_if_player( m_bad, _( auto_extinguish_message ) ); - } else if( !t ) { - p.add_msg_if_player( _( voluntary_extinguish_message ) ); - } else { - extinguish = false; - } - - if( extinguish ) { - it.revert( &p, false ); - it.deactivate(); - - } else if( one_in( noise_chance ) ) { - if( noise > 0 ) { - sounds::sound( p.pos(), noise, sounds::sound_t::combat, _( noise_message ) ); - } - p.add_msg_if_player( _( noise_message ) ); - } - - return it.type->charges_to_use(); -} - void manualnoise_actor::load( const JsonObject &obj ) { no_charges_message = obj.get_string( "no_charges_message" ); @@ -2300,14 +2226,18 @@ std::unique_ptr manualnoise_actor::clone() const return std::make_unique( *this ); } -int manualnoise_actor::use( player &p, item &it, bool t, const tripoint & ) const +std::pair manualnoise_actor::use( player &p, item &it, bool t, + const tripoint & ) const { + std::pair res( cost >= 0 ? cost : it.type->charges_to_use(), + e_cost >= 0_J ? e_cost : it.energy_required() ); if( t ) { - return 0; + return std::make_pair( 0, 0_J ); } - if( it.type->charges_to_use() != 0 && it.charges < it.type->charges_to_use() ) { + if( !it.units_sufficient( it.type->charges_to_use() ) && + !( it.energy_sufficient( p, it.energy_required() ) ) ) { p.add_msg_if_player( _( no_charges_message ) ); - return 0; + return std::make_pair( 0, 0_J ); } { p.moves -= moves; @@ -2317,7 +2247,7 @@ int manualnoise_actor::use( player &p, item &it, bool t, const tripoint & ) cons } p.add_msg_if_player( _( use_message ) ); } - return it.type->charges_to_use(); + return res; } ret_val manualnoise_actor::can_use( const Character &, const item &it, bool, @@ -2348,20 +2278,21 @@ void musical_instrument_actor::load( const JsonObject &obj ) npc_descriptions = obj.get_string_array( "npc_descriptions" ); } -int musical_instrument_actor::use( player &p, item &it, bool t, const tripoint & ) const +std::pair musical_instrument_actor::use( player &p, item &it, bool t, + const tripoint & ) const { if( p.is_mounted() ) { p.add_msg_player_or_npc( m_bad, _( "You can't play music while mounted." ), _( " can't play music while mounted." ) ); it.deactivate(); - return 0; + return std::make_pair( 0, 0_J ); } if( p.is_underwater() ) { p.add_msg_player_or_npc( m_bad, _( "You can't play music underwater" ), _( " can't play music underwater" ) ); it.deactivate(); - return 0; + return std::make_pair( 0, 0_J ); } if( p.has_effect( effect_sleep ) || p.has_effect( effect_stunned ) || @@ -2371,7 +2302,7 @@ int musical_instrument_actor::use( player &p, item &it, bool t, const tripoint & _( " stops playing their %s" ), it.display_name() ); it.deactivate(); - return 0; + return std::make_pair( 0, 0_J ); } if( !t && it.is_active() ) { @@ -2379,7 +2310,7 @@ int musical_instrument_actor::use( player &p, item &it, bool t, const tripoint & _( " stops playing their %s" ), it.display_name() ); it.deactivate(); - return 0; + return std::make_pair( 0, 0_J ); } // Check for worn or wielded - no "floating"/bionic instruments for now @@ -2391,7 +2322,7 @@ int musical_instrument_actor::use( player &p, item &it, bool t, const tripoint & _( " needs to hold or wear %s to play it" ), it.display_name() ); it.deactivate(); - return 0; + return std::make_pair( 0, 0_J ); } // At speed this low you can't coordinate your actions well enough to play the instrument @@ -2401,7 +2332,7 @@ int musical_instrument_actor::use( player &p, item &it, bool t, const tripoint & _( " feels too weak to play their %s" ), it.display_name() ); it.deactivate(); - return 0; + return std::make_pair( 0, 0_J ); } // We can play the music now @@ -2455,7 +2386,7 @@ int musical_instrument_actor::use( player &p, item &it, bool t, const tripoint & p.add_morale( MORALE_MUSIC, sign, morale_effect, 5_minutes, 2_minutes, true ); } - return 0; + return std::make_pair( 0, 0_J ); } ret_val musical_instrument_actor::can_use( const Character &p, const item &, bool, @@ -2497,11 +2428,12 @@ void learn_spell_actor::info( const item &, std::vector &dump ) const } } -int learn_spell_actor::use( player &p, item &, bool, const tripoint & ) const +std::pair learn_spell_actor::use( player &p, item &, bool, + const tripoint & ) const { if( !character_funcs::can_see_fine_details( p ) ) { p.add_msg_if_player( _( "It's too dark to read." ) ); - return 0; + return std::make_pair( 0, 0_J ); } std::vector uilist_initializer; uilist spellbook_uilist; @@ -2534,7 +2466,7 @@ int learn_spell_actor::use( player &p, item &, bool, const tripoint & ) const if( know_it_all ) { add_msg( m_info, _( "You already know everything this could teach you." ) ); - return 0; + return std::make_pair( 0, 0_J ); } spellbook_uilist.entries = uilist_initializer; @@ -2546,7 +2478,7 @@ int learn_spell_actor::use( player &p, item &, bool, const tripoint & ) const spellbook_uilist.query(); const int action = spellbook_uilist.ret; if( action < 0 ) { - return 0; + return std::make_pair( 0, 0_J ); } const bool knows_spell = p.magic->knows_spell( spells[action] ); std::unique_ptr study_spell = std::make_unique( ACT_STUDY_SPELL, @@ -2567,7 +2499,7 @@ int learn_spell_actor::use( player &p, item &, bool, const tripoint & ) const { 10100, true, -1, _( "Until you gain a spell level" ) } } ); if( study_time <= 0 ) { - return 0; + return std::make_pair( 0, 0_J ); } study_spell->moves_total = study_time; } @@ -2579,7 +2511,7 @@ int learn_spell_actor::use( player &p, item &, bool, const tripoint & ) const } study_spell->name = spells[action]; p.assign_activity( std::move( study_spell ), false ); - return 0; + return std::make_pair( 0, 0_J ); } std::unique_ptr cast_spell_actor::clone() const @@ -2607,15 +2539,16 @@ void cast_spell_actor::info( const item &, std::vector &dump ) const } } -int cast_spell_actor::use( player &p, item &it, bool, const tripoint & ) const +std::pair cast_spell_actor::use( player &p, item &it, bool, + const tripoint & ) const { if( need_worn && !p.is_worn( it ) ) { p.add_msg_if_player( m_info, _( "You need to wear the %1$s before activating it." ), it.tname() ); - return 0; + return std::make_pair( 0, 0_J ); } if( need_wielding && !p.is_wielding( it ) ) { p.add_msg_if_player( m_info, _( "You need to wield the %1$s before activating it." ), it.tname() ); - return 0; + return std::make_pair( 0, 0_J ); } spell casting = spell( spell_id( item_spell ) ); @@ -2641,7 +2574,7 @@ int cast_spell_actor::use( player &p, item &it, bool, const tripoint & ) const } p.assign_activity( std::move( cast_spell ), false ); p.activity->targets.emplace_back( &it ); - return 0; + return std::make_pair( 0, 0_J ); } std::unique_ptr holster_actor::clone() const @@ -2737,11 +2670,12 @@ detached_ptr holster_actor::store( player &p, item &holster, detached_ptr< return detached_ptr(); } -int holster_actor::use( player &p, item &it, bool, const tripoint & ) const +std::pair holster_actor::use( player &p, item &it, bool, + const tripoint & ) const { if( p.is_wielding( it ) ) { p.add_msg_if_player( _( "You need to unwield your %s before using it." ), it.tname() ); - return 0; + return std::make_pair( 0, 0_J ); } int pos = 0; @@ -2778,7 +2712,7 @@ int holster_actor::use( player &p, item &it, bool, const tripoint & ) const if( pos < -1 ) { p.add_msg_if_player( _( "Never mind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( pos >= 0 ) { @@ -2799,12 +2733,12 @@ int holster_actor::use( player &p, item &it, bool, const tripoint & ) const if( !loc ) { p.add_msg_if_player( _( "Never mind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } store( p, it, loc->detach() ); } - return 0; + return std::make_pair( 0, 0_J ); } void holster_actor::info( const item &, std::vector &dump ) const @@ -2934,12 +2868,13 @@ bool bandolier_actor::reload( player &p, item &obj ) const return true; } -int bandolier_actor::use( player &p, item &it, bool, const tripoint & ) const +std::pair bandolier_actor::use( player &p, item &it, bool, + const tripoint & ) const { if( p.is_wielding( it ) ) { p.add_msg_if_player( _( "You need to unwield your %s before using it." ), it.type_name() ); - return 0; + return std::make_pair( 0, 0_J ); } uilist menu; @@ -2971,7 +2906,7 @@ int bandolier_actor::use( player &p, item &it, bool, const tripoint & ) const actions[ menu.ret ](); } - return 0; + return std::make_pair( 0, 0_J ); } units::volume bandolier_actor::max_stored_volume() const @@ -3006,14 +2941,14 @@ void ammobelt_actor::info( const item &, std::vector &dump ) const item::nname( belt ) ) ); } -int ammobelt_actor::use( player &p, item &, bool, const tripoint & ) const +std::pair ammobelt_actor::use( player &p, item &, bool, const tripoint & ) const { detached_ptr mag = item::spawn( belt ); mag->ammo_unset(); if( !p.can_reload( *mag ) ) { p.add_msg_if_player( _( "Insufficient ammunition to assemble %s" ), mag->tname() ); - return 0; + return std::make_pair( 0, 0_J ); } item_reload_option opt = character_funcs::select_ammo( p, *mag, true ); @@ -3024,7 +2959,7 @@ int ammobelt_actor::use( player &p, item &, bool, const tripoint & ) const p.i_add( std::move( mag ) ); } - return 0; + return std::make_pair( 0, 0_J ); } void repair_item_actor::load( const JsonObject &obj ) @@ -3070,7 +3005,7 @@ bool repair_item_actor::can_use_tool( const player &p, const item &tool, bool pr } return false; } - if( !tool.units_sufficient( p ) ) { + if( !tool.units_sufficient() ) { if( print_msg ) { p.add_msg_if_player( m_info, _( "Your tool does not have enough charges to do that." ) ); } @@ -3080,10 +3015,11 @@ bool repair_item_actor::can_use_tool( const player &p, const item &tool, bool pr return true; } -int repair_item_actor::use( player &p, item &it, bool, const tripoint & ) const +std::pair repair_item_actor::use( player &p, item &it, bool, + const tripoint & ) const { if( !can_use_tool( p, it, true ) ) { - return 0; + return std::make_pair( 0, 0_J ); } p.assign_activity( ACT_REPAIR_ITEM, 0, p.get_item_position( &it ), INT_MIN ); @@ -3092,7 +3028,7 @@ int repair_item_actor::use( player &p, item &it, bool, const tripoint & ) const // storing of item_location to support repairs by tools on the ground p.activity->targets.emplace_back( &it ); // All repairs are done in the activity, including charge cost and target item selection - return 0; + return std::make_pair( 0, 0_J ); } std::unique_ptr repair_item_actor::clone() const @@ -3582,15 +3518,18 @@ std::string repair_item_actor::get_name() const void heal_actor::load( const JsonObject &obj ) { // Mandatory - move_cost = obj.get_int( "move_cost" ); - limb_power = obj.get_float( "limb_power", 0 ); + assign( obj, "move_cost", move_cost ); + assign( obj, "limb_power", limb_power ); // Optional - bandages_power = obj.get_float( "bandages_power", 0 ); + assign( obj, "bandages_power", bandages_power ); bandages_scaling = obj.get_float( "bandages_scaling", 0.25f * bandages_power ); - disinfectant_power = obj.get_float( "disinfectant_power", 0 ); + assign( obj, "disinfectant_power", disinfectant_power ); disinfectant_scaling = obj.get_float( "disinfectant_scaling", 0.25f * disinfectant_power ); + assign( obj, "cost", cost ); + assign( obj, "e_cost", e_cost ); + head_power = obj.get_float( "head_power", 0.8f * limb_power ); torso_power = obj.get_float( "torso_power", 1.5f * limb_power ); @@ -3639,25 +3578,28 @@ static player &get_patient( player &healer, const tripoint &pos ) return *person; } -int heal_actor::use( player &p, item &it, bool, const tripoint &pos ) const +std::pair heal_actor::use( player &p, item &it, bool, + const tripoint &pos ) const { + std::pair res( cost >= 0 ? cost : it.type->charges_to_use(), + e_cost >= 0_J ? e_cost : it.energy_required() ); if( p.is_underwater() ) { p.add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p.is_mounted() ) { p.add_msg_if_player( m_info, _( "You can't do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( get_option( "FILTHY_WOUNDS" ) && it.is_filthy() ) { p.add_msg_if_player( m_info, _( "You can't use filthy items for healing." ) ); - return 0; + return std::make_pair( 0, 0_J ); } player &patient = get_patient( p, pos ); const bodypart_str_id hpp = use_healing_item( p, patient, it, false ); if( !hpp ) { - return 0; + return std::make_pair( 0, 0_J ); } int cost = move_cost; @@ -3675,12 +3617,12 @@ int heal_actor::use( player &p, item &it, bool, const tripoint &pos ) const p.activity->targets.emplace_back( &it ); p.activity->str_values.push_back( hpp.str() ); p.moves = 0; - return 0; + return std::make_pair( 0, 0_J ); } p.moves -= cost; p.add_msg_if_player( m_good, _( "You use your %s." ), it.tname() ); - return it.type->charges_to_use(); + return res; } std::unique_ptr heal_actor::clone() const @@ -4042,6 +3984,7 @@ void place_trap_actor::data::load( const JsonObject &obj ) void place_trap_actor::load( const JsonObject &obj ) { + assign( obj, "e_cost", e_cost ); assign( obj, "allow_underwater", allow_underwater ); assign( obj, "allow_under_player", allow_under_player ); assign( obj, "needs_solid_neighbor", needs_solid_neighbor ); @@ -4127,26 +4070,28 @@ static void place_and_add_as_known( player &p, const tripoint &pos, const trap_s } } -int place_trap_actor::use( player &p, item &it, bool, const tripoint & ) const +std::pair place_trap_actor::use( player &p, item &it, bool, + const tripoint & ) const { + std::pair res( it.type->charges_to_use(), e_cost ); const bool could_bury = !bury_question.empty(); if( !allow_underwater && p.is_underwater() ) { p.add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p.is_mounted() ) { p.add_msg_if_player( m_info, _( "You can't do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const std::optional pos_ = choose_adjacent( string_format( _( "Place %s where?" ), it.tname() ) ); if( !pos_ ) { - return 0; + return std::make_pair( 0, 0_J ); } tripoint pos = *pos_; if( !is_allowed( p, pos, it.tname() ) ) { - return 0; + return std::make_pair( 0, 0_J ); } map &here = get_map(); @@ -4162,7 +4107,7 @@ int place_trap_actor::use( player &p, item &it, bool, const tripoint & ) const p.add_msg_if_player( m_info, _( "That trap needs a space in %d tiles radius to be clear, centered %d tiles from you." ), outer_layer_trap.obj().get_trap_radius(), distance_to_trap_center ); - return 0; + return std::make_pair( 0, 0_J ); } } } @@ -4185,7 +4130,7 @@ int place_trap_actor::use( player &p, item &it, bool, const tripoint & ) const place_and_add_as_known( p, t, outer_layer_trap ); } } - return 1; + return res; } void emit_actor::load( const JsonObject &obj ) @@ -4194,7 +4139,7 @@ void emit_actor::load( const JsonObject &obj ) assign( obj, "scale_qty", scale_qty ); } -int emit_actor::use( player &, item &it, bool, const tripoint &pos ) const +std::pair emit_actor::use( player &, item &it, bool, const tripoint &pos ) const { map &here = get_map(); const float scaling = scale_qty ? it.charges : 1; @@ -4202,7 +4147,7 @@ int emit_actor::use( player &, item &it, bool, const tripoint &pos ) const here.emit_field( pos, e, scaling ); } - return 1; + return std::make_pair( 1, e_cost ); } std::unique_ptr emit_actor::clone() const @@ -4233,24 +4178,25 @@ void saw_barrel_actor::load( const JsonObject &jo ) assign( jo, "cost", cost ); } -int saw_barrel_actor::use( player &p, item &it, bool t, const tripoint & ) const +std::pair saw_barrel_actor::use( player &p, item &it, bool t, + const tripoint & ) const { if( t ) { - return 0; + return std::make_pair( 0, 0_J ); } auto loc = game_menus::inv::saw_barrel( p, it ); if( !loc ) { p.add_msg_if_player( _( "Never mind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } loc->obtain( p ); p.add_msg_if_player( _( "You saw down the barrel of your %s." ), loc->tname() ); loc->put_in( item::spawn( "barrel_small", calendar::turn ) ); - return 0; + return std::make_pair( 0, 0_J ); } ret_val saw_barrel_actor::can_use_on( const player &, const item &, const item &target ) const @@ -4290,24 +4236,25 @@ void saw_stock_actor::load( const JsonObject &jo ) assign( jo, "cost", cost ); } -int saw_stock_actor::use( player &p, item &it, bool t, const tripoint & ) const +std::pair saw_stock_actor::use( player &p, item &it, bool t, + const tripoint & ) const { if( t ) { - return 0; + return std::make_pair( 0, 0_J ); } auto loc = game_menus::inv::saw_stock( p, it ); if( !loc ) { p.add_msg_if_player( _( "Never mind." ) ); - return 0; + return std::make_pair( 0, 0_J ); } loc->obtain( p ); p.add_msg_if_player( _( "You saw down the stock of your %s." ), loc->tname() ); loc->put_in( item::spawn( "stock_small", calendar::turn ) ); - return 0; + return std::make_pair( 0, 0_J ); } ret_val saw_stock_actor::can_use_on( const player &, const item &, const item &target ) const @@ -4362,12 +4309,14 @@ std::unique_ptr saw_stock_actor::clone() const return std::make_unique( *this ); } -int install_bionic_actor::use( player &p, item &it, bool, const tripoint & ) const +std::pair install_bionic_actor::use( player &p, item &it, bool, + const tripoint & ) const { + std::pair res( it.type->charges_to_use(), it.energy_required() ); if( p.can_install_bionics( *it.type, p, false ) ) { - return p.install_bionics( *it.type, p, false ) ? it.type->charges_to_use() : 0; + return p.install_bionics( *it.type, p, false ) ? res : std::make_pair( 0, 0_J ); } else { - return 0; + return std::make_pair( 0, 0_J ); } } @@ -4420,7 +4369,8 @@ void install_bionic_actor::finalize( const itype_id &my_item_type ) } } -int detach_gunmods_actor::use( player &p, item &it, bool, const tripoint & ) const +std::pair detach_gunmods_actor::use( player &p, item &it, bool, + const tripoint & ) const { auto mods = it.gunmods(); @@ -4443,7 +4393,7 @@ int detach_gunmods_actor::use( player &p, item &it, bool, const tripoint & ) con p.add_msg_if_player( _( "Never mind." ) ); } - return 0; + return std::make_pair( 0, 0_J ); } ret_val detach_gunmods_actor::can_use( const Character &p, const item &it, bool, @@ -4494,13 +4444,15 @@ void mutagen_actor::load( const JsonObject &obj ) is_strong = obj.get_bool( "is_strong", false ); } -int mutagen_actor::use( player &p, item &it, bool, const tripoint & ) const +std::pair mutagen_actor::use( player &p, item &it, bool, + const tripoint & ) const { + std::pair res( it.type->charges_to_use(), 0_J ); mutagen_attempt checks = mutagen_common_checks( p, it, false, mutagen_technique::consumed_mutagen ); if( !checks.allowed ) { - return checks.charges_used; + return std::make_pair( checks.charges_used, 0_J ); } bool no_category = mutation_category == mutation_category_id( "ANY" ); @@ -4509,11 +4461,11 @@ int mutagen_actor::use( player &p, item &it, bool, const tripoint & ) const if( balanced && !is_strong && is_weak && accumulated_mutagen < 2 && no_category && !p.query_yn( _( "Looking at it just makes you tired. It probably won't work. Do you want to try anyway?" ) ) ) { - return 0; + return std::make_pair( 0, 0_J ); } if( is_weak && !one_in( 3 ) && !balanced ) { // Nothing! Mutagenic flesh often just fails to work. - return it.type->charges_to_use(); + return res; } if( balanced && no_category ) { @@ -4549,7 +4501,7 @@ int mutagen_actor::use( player &p, item &it, bool, const tripoint & ) const p.mod_thirst( m_category.mutagen_thirst * mut_count ); p.mod_fatigue( m_category.mutagen_fatigue * mut_count ); - return it.type->charges_to_use(); + return res; } std::unique_ptr mutagen_iv_actor::clone() const @@ -4562,13 +4514,15 @@ void mutagen_iv_actor::load( const JsonObject &obj ) mutation_category = mutation_category_id( obj.get_string( "mutation_category", "ANY" ) ); } -int mutagen_iv_actor::use( player &p, item &it, bool, const tripoint & ) const +std::pair mutagen_iv_actor::use( player &p, item &it, bool, + const tripoint & ) const { + std::pair res( it.type->charges_to_use(), 0_J ); mutagen_attempt checks = mutagen_common_checks( p, it, false, mutagen_technique::injected_mutagen ); if( !checks.allowed ) { - return checks.charges_used; + return std::make_pair( checks.charges_used, 0_J ); } const mutation_category_trait &m_category = mutation_category_trait::get_category( @@ -4624,7 +4578,7 @@ int mutagen_iv_actor::use( player &p, item &it, bool, const tripoint & ) const // try crossing again after getting new in-category mutations. test_crossing_threshold( p, m_category ); - return it.type->charges_to_use(); + return res; } std::unique_ptr deploy_tent_actor::clone() const @@ -4643,17 +4597,18 @@ void deploy_tent_actor::load( const JsonObject &obj ) assign( obj, "broken_type", broken_type ); } -int deploy_tent_actor::use( player &p, item &it, bool, const tripoint & ) const +std::pair deploy_tent_actor::use( player &p, item &it, bool, + const tripoint & ) const { int diam = 2 * radius + 1; if( p.is_mounted() ) { p.add_msg_if_player( _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } const std::optional dir = choose_direction( string_format( _( "Put up the %s where (%dx%d clear area)?" ), it.tname(), diam, diam ) ); if( !dir ) { - return 0; + return std::make_pair( 0, 0_J ); } const tripoint direction = *dir; @@ -4666,20 +4621,20 @@ int deploy_tent_actor::use( player &p, item &it, bool, const tripoint & ) const for( const tripoint &dest : here.points_in_radius( center, radius ) ) { if( const auto vp = here.veh_at( dest ) ) { add_msg( m_info, _( "The %s is in the way." ), vp->vehicle().name ); - return 0; + return std::make_pair( 0, 0_J ); } if( const Creature *const c = g->critter_at( dest ) ) { add_msg( m_info, _( "%s is in the way." ), c->disp_name( false, true ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( here.impassable( dest ) || !here.has_flag( "FLAT", dest ) ) { add_msg( m_info, _( "The %s in that direction isn't suitable for placing the %s." ), here.name( dest ), it.tname() ); - return 0; + return std::make_pair( 0, 0_J ); } if( here.has_furn( dest ) ) { add_msg( m_info, _( "There is already furniture (%s) there." ), here.furnname( dest ) ); - return 0; + return std::make_pair( 0, 0_J ); } } // Make a square of floor surrounded by wall. @@ -4696,7 +4651,7 @@ int deploy_tent_actor::use( player &p, item &it, bool, const tripoint & ) const here.furn_set( p.pos() + direction, door_closed ); add_msg( m_info, _( "You set up the %s on the ground." ), it.tname() ); add_msg( m_info, _( "Examine the center square to pack it up again." ) ); - return 1; + return std::make_pair( 1, 0_J ); } bool deploy_tent_actor::check_intact( const tripoint ¢er ) const @@ -4729,11 +4684,12 @@ void weigh_self_actor::info( const item &, std::vector &dump ) const _( "Use this item to weigh yourself. Includes everything you are wearing." ) ); } -int weigh_self_actor::use( player &p, item &, bool, const tripoint & ) const +std::pair weigh_self_actor::use( player &p, item &, bool, + const tripoint & ) const { if( p.is_mounted() ) { p.add_msg_if_player( m_info, _( "You cannot weigh yourself while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } // this is a weight, either in kgs or in lbs. double weight = convert_weight( p.get_weight() ); @@ -4742,7 +4698,7 @@ int weigh_self_actor::use( player &p, item &, bool, const tripoint & ) const } else { popup( "%.0f %s", weight, weight_units() ); } - return 0; + return std::make_pair( 0, 0_J ); } void weigh_self_actor::load( const JsonObject &jo ) @@ -4773,23 +4729,26 @@ void sew_advanced_actor::load( const JsonObject &obj ) } } -int sew_advanced_actor::use( player &p, item &it, bool, const tripoint & ) const +std::pair sew_advanced_actor::use( player &p, item &it, bool, + const tripoint & ) const { + std::pair res( 0, 0_J ); + auto [chrg, enrg] = res; if( p.is_npc() ) { - return 0; + return std::make_pair( 0, 0_J ); } if( p.is_mounted() ) { p.add_msg_if_player( m_info, _( "You cannot do that while mounted." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( p.is_underwater() ) { p.add_msg_if_player( m_info, _( "You can't do that while underwater." ) ); - return 0; + return std::make_pair( 0, 0_J ); } if( !character_funcs::can_see_fine_details( p ) ) { add_msg( m_info, _( "You can't see to sew!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } auto filter = [this]( const item & itm ) { @@ -4801,13 +4760,13 @@ int sew_advanced_actor::use( player &p, item &it, bool, const tripoint & ) const filter, *p.as_avatar(), _( "Enhance which clothing?" ) ); if( !loc ) { p.add_msg_if_player( m_info, _( "You do not have that item!" ) ); - return 0; + return std::make_pair( 0, 0_J ); } item &mod = *loc; if( &mod == &it ) { p.add_msg_if_player( m_info, _( "This can be used to repair or modify other items, not itself." ) ); - return 0; + return std::make_pair( 0, 0_J ); } // Gives us an item with the mod added or removed (toggled) @@ -4947,7 +4906,7 @@ int sew_advanced_actor::use( player &p, item &it, bool, const tripoint & ) const const int choice = tmenu.ret; if( choice < 0 || choice >= static_cast( clothing_mods.size() ) ) { - return 0; + return std::make_pair( 0, 0_J ); } // The mod player picked @@ -4960,7 +4919,7 @@ int sew_advanced_actor::use( player &p, item &it, bool, const tripoint & ) const } mod.update_clothing_mod_val(); - return 0; + return std::make_pair( 0, 0_J ); } // Get the id of the material used @@ -4989,26 +4948,28 @@ int sew_advanced_actor::use( player &p, item &it, bool, const tripoint & ) const p.add_msg_if_player( m_bad, _( "You destroy it!" ) ); p.i_rem_keep_contents( p.get_item_position( &mod ) ); } - return thread_needed / 2; + chrg /= 2; + return res; } else if( rn <= 10 ) { p.add_msg_if_player( m_bad, _( "You fail to modify the clothing, and you waste thread and materials." ) ); p.consume_items( comps, 1, is_crafting_component ); - return thread_needed; + return res; } else if( rn <= 14 ) { p.add_msg_if_player( m_mixed, _( "You modify your %s, but waste a lot of thread." ), mod.tname() ); p.consume_items( comps, 1, is_crafting_component ); mod.set_flag( the_mod ); mod.update_clothing_mod_val(); - return thread_needed; + return res; } p.add_msg_if_player( m_good, _( "You modify your %s!" ), mod.tname() ); mod.set_flag( the_mod ); mod.update_clothing_mod_val(); p.consume_items( comps, 1, is_crafting_component ); - return thread_needed / 2; + chrg /= 2; + return res; } std::unique_ptr sew_advanced_actor::clone() const @@ -5028,14 +4989,17 @@ void change_scent_iuse::load( const JsonObject &obj ) } } assign( obj, "moves", moves ); - assign( obj, "charges_to_use", charges_to_use ); + assign( obj, "cost", cost ); + assign( obj, "e_cost", e_cost ); assign( obj, "scent_mod", scent_mod ); assign( obj, "duration", duration ); assign( obj, "waterproof", waterproof ); } -int change_scent_iuse::use( player &p, item &it, bool, const tripoint & ) const +std::pair change_scent_iuse::use( player &p, item &it, bool, + const tripoint & ) const { + std::pair res( cost, e_cost ); p.set_value( "prev_scent", p.get_type_of_scent().c_str() ); if( waterproof ) { p.set_value( "waterproof_scent", "true" ); @@ -5052,7 +5016,7 @@ int change_scent_iuse::use( player &p, item &it, bool, const tripoint & ) const p.get_effect( eff.id, convert_bp( eff.bp ) ).set_permanent(); } } - return charges_to_use; + return res; } std::unique_ptr change_scent_iuse::clone() const diff --git a/src/iuse_actor.h b/src/iuse_actor.h index 858e0f7b284f..35a0a9d15a07 100644 --- a/src/iuse_actor.h +++ b/src/iuse_actor.h @@ -109,7 +109,7 @@ class iuse_transform : public iuse_actor ~iuse_transform() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; ret_val can_use( const Character &, const item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; std::string get_name() const override; @@ -136,7 +136,7 @@ class unpack_actor : public iuse_actor ~unpack_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &p, item &it, bool, const tripoint & ) const override; + std::pair use( player &p, item &it, bool, const tripoint & ) const override; std::unique_ptr clone() const override; void info( const item &, std::vector &dump ) const override; }; @@ -157,7 +157,7 @@ class countdown_actor : public iuse_actor ~countdown_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; ret_val can_use( const Character &, const item &it, bool, const tripoint & ) const override; std::string get_name() const override; @@ -203,7 +203,7 @@ class explosion_iuse : public iuse_actor ~explosion_iuse() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; void info( const item &, std::vector & ) const override; @@ -230,7 +230,7 @@ class unfold_vehicle_iuse : public iuse_actor ~unfold_vehicle_iuse() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; @@ -275,7 +275,7 @@ class consume_drug_iuse : public iuse_actor ~consume_drug_iuse() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; void info( const item &, std::vector & ) const override; @@ -309,7 +309,7 @@ class delayed_transform_iuse : public iuse_transform ~delayed_transform_iuse() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; @@ -341,7 +341,7 @@ class set_transform_iuse : public iuse_transform ~set_transform_iuse() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; @@ -364,13 +364,13 @@ class set_transformed_iuse : public iuse_transform std::string dependencies; /** Hack: Bypasses normal checks to transform an item.*/ - int bypass( player &p, item &it, bool t, const tripoint &pos ) const; + std::pair bypass( player &p, item &it, bool t, const tripoint &pos ) const; set_transformed_iuse( const std::string &type = "set_transformed" ) : iuse_transform( type ) {} ~set_transformed_iuse() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; ret_val can_use( const Character &, const item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; @@ -402,7 +402,7 @@ class place_monster_iuse : public iuse_actor place_monster_iuse() : iuse_actor( "place_monster" ) { } ~place_monster_iuse() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; @@ -416,8 +416,6 @@ class change_scent_iuse : public iuse_actor scenttype_id scenttypeid; /** How many move points this action takes. */ int moves = 100; - /**How many charge are consumed on use*/ - int charges_to_use = 1; /**Scent value modifier*/ int scent_mod = 0; /**How long does the scent stays*/ @@ -430,7 +428,7 @@ class change_scent_iuse : public iuse_actor change_scent_iuse() : iuse_actor( "change_scent" ) { } ~change_scent_iuse() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; @@ -448,7 +446,7 @@ class place_npc_iuse : public iuse_actor place_npc_iuse() : iuse_actor( "place_npc" ) { } ~place_npc_iuse() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; @@ -467,7 +465,7 @@ class deploy_furn_actor : public iuse_actor ~deploy_furn_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; void info( const item &, std::vector & ) const override; }; @@ -503,7 +501,7 @@ class reveal_map_actor : public iuse_actor ~reveal_map_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; @@ -540,7 +538,7 @@ class firestarter_actor : public iuse_actor ~firestarter_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; ret_val can_use( const Character &, const item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; @@ -584,7 +582,7 @@ class salvage_actor : public iuse_actor ~salvage_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; @@ -623,7 +621,7 @@ class inscribe_actor : public iuse_actor ~inscribe_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; @@ -642,7 +640,7 @@ class cauterize_actor : public iuse_actor ~cauterize_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; ret_val can_use( const Character &, const item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; @@ -657,59 +655,11 @@ class enzlave_actor : public iuse_actor ~enzlave_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; ret_val can_use( const Character &, const item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; -/** - * Try to turn on a burning melee weapon - * Not iuse_transform, because they don't have that much in common - */ -class fireweapon_off_actor : public iuse_actor -{ - public: - itype_id target_id; - std::string success_message; - std::string lacks_fuel_message; - std::string failure_message; // Due to bad roll - int noise = 0; // If > 0 success message is a success sound instead - int moves = 0; - // Lower is better: rng(0, 10) - item.damage_level( 4 ) > this variable - int success_chance = INT_MIN; - - fireweapon_off_actor() : iuse_actor( "fireweapon_off" ) {} - - ~fireweapon_off_actor() override = default; - void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; - ret_val can_use( const Character &, const item &, bool, const tripoint & ) const override; - std::unique_ptr clone() const override; -}; - -/** - * Active burning melee weapon - */ -class fireweapon_on_actor : public iuse_actor -{ - public: - std::string noise_message; // If noise is 0, message content instead - std::string voluntary_extinguish_message; - std::string charges_extinguish_message; - std::string water_extinguish_message; - std::string auto_extinguish_message; - int noise = 0; // If 0, it produces a message instead of noise - int noise_chance = 1; // one_in(this variable) - int auto_extinguish_chance = 0; // one_in(this) per turn to fail - - fireweapon_on_actor( const std::string &type = "fireweapon_on" ) : iuse_actor( type ) {} - - ~fireweapon_on_actor() override = default; - void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; - std::unique_ptr clone() const override; -}; - /** * Makes noise of a given volume */ @@ -728,7 +678,7 @@ class manualnoise_actor : public iuse_actor ~manualnoise_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; ret_val can_use( const Character &, const item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; @@ -772,7 +722,7 @@ class musical_instrument_actor : public iuse_actor ~musical_instrument_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; ret_val can_use( const Character &, const item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; @@ -790,7 +740,7 @@ class learn_spell_actor : public iuse_actor ~learn_spell_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &p, item &, bool, const tripoint & ) const override; + std::pair use( player &p, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; void info( const item &, std::vector & ) const override; }; @@ -815,7 +765,7 @@ class cast_spell_actor : public iuse_actor ~cast_spell_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &p, item &it, bool, const tripoint & ) const override; + std::pair use( player &p, item &it, bool, const tripoint & ) const override; std::unique_ptr clone() const override; void info( const item &, std::vector & ) const override; }; @@ -855,7 +805,7 @@ class holster_actor : public iuse_actor ~holster_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; void info( const item &, std::vector & ) const override; @@ -890,7 +840,7 @@ class bandolier_actor : public iuse_actor ~bandolier_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; void info( const item &, std::vector & ) const override; @@ -906,7 +856,7 @@ class ammobelt_actor : public iuse_actor ~ammobelt_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; void info( const item &, std::vector & ) const override; }; @@ -982,7 +932,7 @@ class repair_item_actor : public iuse_actor ~repair_item_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; std::string get_name() const override; @@ -1050,7 +1000,7 @@ class heal_actor : public iuse_actor ~heal_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; void info( const item &, std::vector & ) const override; }; @@ -1097,7 +1047,7 @@ class place_trap_actor : public iuse_actor place_trap_actor( const std::string &type = "place_trap" ); ~place_trap_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; @@ -1111,7 +1061,7 @@ class emit_actor : public iuse_actor emit_actor( const std::string &type = "emit_actor" ) : iuse_actor( type ) {} ~emit_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; void finalize( const itype_id &my_item_type ) override; }; @@ -1122,7 +1072,8 @@ class saw_barrel_actor : public iuse_actor saw_barrel_actor( const std::string &type = "saw_barrel" ) : iuse_actor( type ) {} void load( const JsonObject &jo ) override; - int use( player &p, item &it, bool t, const tripoint &pnt ) const override; + std::pair use( player &p, item &it, bool t, + const tripoint &pnt ) const override; std::unique_ptr clone() const override; ret_val can_use_on( const player &p, const item &it, const item &target ) const; @@ -1134,7 +1085,8 @@ class saw_stock_actor : public iuse_actor saw_stock_actor( const std::string &type = "saw_stock" ) : iuse_actor( type ) {} void load( const JsonObject &jo ) override; - int use( player &p, item &it, bool t, const tripoint &pnt ) const override; + std::pair use( player &p, item &it, bool t, + const tripoint &pnt ) const override; std::unique_ptr clone() const override; ret_val can_use_on( const player &p, const item &it, const item &target ) const; @@ -1146,7 +1098,8 @@ class install_bionic_actor : public iuse_actor install_bionic_actor( const std::string &type = "install_bionic" ) : iuse_actor( type ) {} void load( const JsonObject & ) override {} - int use( player &p, item &it, bool t, const tripoint &pnt ) const override; + std::pair use( player &p, item &it, bool t, + const tripoint &pnt ) const override; ret_val can_use( const Character &, const item &it, bool, const tripoint & ) const override; std::unique_ptr clone() const override; void finalize( const itype_id &my_item_type ) override; @@ -1158,7 +1111,8 @@ class detach_gunmods_actor : public iuse_actor detach_gunmods_actor( const std::string &type = "detach_gunmods" ) : iuse_actor( type ) {} void load( const JsonObject & ) override {} - int use( player &p, item &it, bool t, const tripoint &pnt ) const override; + std::pair use( player &p, item &it, bool t, + const tripoint &pnt ) const override; ret_val can_use( const Character &, const item &it, bool, const tripoint & ) const override; std::unique_ptr clone() const override; void finalize( const itype_id &my_item_type ) override; @@ -1175,7 +1129,7 @@ class mutagen_actor : public iuse_actor ~mutagen_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; @@ -1188,7 +1142,7 @@ class mutagen_iv_actor : public iuse_actor ~mutagen_iv_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; @@ -1207,7 +1161,7 @@ class deploy_tent_actor : public iuse_actor ~deploy_tent_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; bool check_intact( const tripoint ¢er ) const; @@ -1226,7 +1180,7 @@ class weigh_self_actor : public iuse_actor ~weigh_self_actor() override = default; void load( const JsonObject &jo ) override; - int use( player &p, item &, bool, const tripoint & ) const override; + std::pair use( player &p, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; void info( const item &, std::vector & ) const override; }; @@ -1248,7 +1202,7 @@ class sew_advanced_actor : public iuse_actor ~sew_advanced_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; @@ -1264,7 +1218,7 @@ class heat_food_actor : public iuse_actor ~heat_food_actor() override = default; void load( const JsonObject &obj ) override; - int use( player &, item &, bool, const tripoint & ) const override; + std::pair use( player &, item &, bool, const tripoint & ) const override; ret_val can_use( const Character &, const item &, bool, const tripoint & ) const override; std::unique_ptr clone() const override; }; diff --git a/src/map.cpp b/src/map.cpp index ac12b6746329..c5a8882ccd3e 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -4773,8 +4773,7 @@ static void process_vehicle_items( vehicle &cur_veh, int part ) if( !n.has_flag( flag_RECHARGE ) && !n.has_flag( flag_USE_UPS ) ) { return VisitResponse::NEXT; } - if( n.ammo_capacity() > n.ammo_remaining() || - ( n.type->battery && n.type->battery->max_capacity > n.energy_remaining() ) ) { + if( n.is_battery() && n.energy_capacity() > n.energy_remaining() ) { int power = recharge_part.info().bonus; while( power >= 1000 || x_in_y( power, 1000 ) ) { const int missing = cur_veh.discharge_battery( 1, false ); @@ -4782,11 +4781,7 @@ static void process_vehicle_items( vehicle &cur_veh, int part ) out_of_battery = true; return VisitResponse::ABORT; } - if( n.is_battery() ) { - n.mod_energy( 1_kJ ); - } else { - n.ammo_set( itype_battery, n.ammo_remaining() + 1 ); - } + n.mod_energy( 1_kJ ); power -= 1000; } return VisitResponse::ABORT; diff --git a/src/melee.cpp b/src/melee.cpp index bbb975fe29c0..5453ab4cbaf1 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -444,7 +444,7 @@ void Character::melee_attack( Creature &t, bool allow_special, const matec_id *f mons->get_name() ); mattack::smash_specific( mons, &t ); } else { - mons->use_mech_power( -2 ); + mons->use_mech_power( -2_kJ ); mons->melee_attack( t ); } mod_moves( -mons->type->attack_cost ); diff --git a/src/monattack.cpp b/src/monattack.cpp index 761a323b2393..64096fb48fed 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -1108,7 +1108,7 @@ void mattack::smash_specific( monster *z, Creature *target ) return; } if( z->has_flag( MF_RIDEABLE_MECH ) ) { - z->use_mech_power( -5 ); + z->use_mech_power( -5_kJ ); } z->set_goal( target->pos() ); smash( z ); diff --git a/src/monster.cpp b/src/monster.cpp index 85e368dab082..9f7d9e8a05d7 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -2702,14 +2702,13 @@ void monster::die( Creature *nkiller ) } } -bool monster::use_mech_power( int amt ) +bool monster::use_mech_power( units::energy amt ) { if( is_hallucination() || !has_flag( MF_RIDEABLE_MECH ) || !battery_item ) { return false; } - amt = -amt; - battery_item->ammo_consume( amt, pos() ); - return battery_item->ammo_remaining() > 0; + battery_item->energy_consume( amt, pos() ); + return battery_item->energy_remaining() > 0_J; } int monster::mech_str_addition() const diff --git a/src/monster.h b/src/monster.h index 18d6cb72e161..81db2a2b7399 100644 --- a/src/monster.h +++ b/src/monster.h @@ -449,7 +449,7 @@ class monster : public Creature, public location_visitable // Add an item to inventory void add_item( detached_ptr &&it ); // check mech power levels and modify it. - bool use_mech_power( int amt ); + bool use_mech_power( units::energy amt ); bool check_mech_powered() const; int mech_str_addition() const; diff --git a/src/npc.cpp b/src/npc.cpp index b4b7474babc4..6b39eb0f720c 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -1541,11 +1541,10 @@ void npc::decide_needs() elem = 20; } if( primary_weapon().is_gun() ) { - int ups_drain = primary_weapon().get_gun_ups_drain(); - if( ups_drain > 0 ) { - int ups_charges = charges_of( itype_UPS_off, ups_drain ) + - charges_of( itype_UPS_off, ups_drain ); - needrank[need_ammo] = static_cast( ups_charges ) / ups_drain; + units::energy ups_drain = primary_weapon().get_gun_ups_drain(); + if( ups_drain > 0_J ) { + units::energy ups_charges = energy_of( itype_UPS_off, ups_drain ); + needrank[need_ammo] = ups_charges / ups_drain; } else { needrank[need_ammo] = character_funcs::get_ammo_items( *this, ammotype( *primary_weapon().type->gun->ammo.begin() ) diff --git a/src/npcmove.cpp b/src/npcmove.cpp index 5f6ee01cb28c..86cdc2824ee7 100644 --- a/src/npcmove.cpp +++ b/src/npcmove.cpp @@ -2424,7 +2424,7 @@ void npc::move_to( const tripoint &pt, bool no_bashing, std::set *nomo const double encumb_moves = get_weight() / 4800.0_gram; moves -= static_cast( std::ceil( base_moves + encumb_moves ) ); if( mounted_creature->has_flag( MF_RIDEABLE_MECH ) ) { - mounted_creature->use_mech_power( -1 ); + mounted_creature->use_mech_power( -1_kJ ); } } else { moves -= run_cost( here.combined_movecost( pos(), p ), diag ); @@ -3701,8 +3701,9 @@ void npc::heal_player( player &patient ) return; } if( !is_hallucination() ) { - int charges_used = used.type->invoke( *this, used, patient.pos(), "heal" ); - consume_charges( used, charges_used ); + auto [chrg, enrg] = used.type->invoke( *this, used, patient.pos(), "heal" ); + consume_charges( used, chrg ); + used.energy_consume( enrg, patient.pos() ); } else { pretend_heal( patient, used ); } @@ -3750,9 +3751,11 @@ void npc::heal_self() } warn_about( "heal_self", 1_turns ); - int charges_used = used.type->invoke( *this, used, pos(), "heal" ); + auto[chrg, enrg] = used.type->invoke( *this, used, pos(), "heal" ); if( used.is_medication() ) { - consume_charges( used, charges_used ); + consume_charges( used, chrg ); + } else { + used.energy_consume( enrg, pos() ); } } diff --git a/src/npctalk.cpp b/src/npctalk.cpp index 6fd3ff9b8082..317b0edde226 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -3369,7 +3369,7 @@ static consumption_result try_consume( npc &p, item &it, std::string &reason ) reason = _( "Thanks, I feel better already." ); } if( to_eat.type->has_use() ) { - amount_used = to_eat.type->invoke( p, to_eat, p.pos() ); + amount_used = to_eat.type->invoke( p, to_eat, p.pos() ).first; if( amount_used <= 0 ) { reason = _( "It doesn't look like a good idea to consume this…" ); return REFUSED; diff --git a/src/profession.cpp b/src/profession.cpp index 5de12dae8790..8a438a065628 100644 --- a/src/profession.cpp +++ b/src/profession.cpp @@ -391,7 +391,7 @@ std::vector> profession::items( bool male, std::vector> result; auto add_legacy_items = [&result]( const itypedecvec & vec ) { for( const itypedec &elem : vec ) { - detached_ptr it = item::spawn( elem.type_id, advanced_spawn_time(), item::default_charges_tag {} ); + detached_ptr it = item::spawn( elem.type_id, advanced_spawn_time() ); if( !elem.snip_id.is_null() ) { it->set_snippet( elem.snip_id ); } @@ -418,7 +418,7 @@ std::vector> profession::items( bool male, std::vector bonus = item_substitutions.get_bonus_items( traits ); for( const itype_id &elem : bonus ) { if( elem != no_bonus ) { - result.push_back( item::spawn( elem, advanced_spawn_time(), item::default_charges_tag {} ) ); + result.push_back( item::spawn( elem, advanced_spawn_time() ) ); } } for( auto iter = result.begin(); iter != result.end(); ) { diff --git a/src/ranged.cpp b/src/ranged.cpp index 788dac3fdb10..3dfc5d2bade4 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -863,6 +863,12 @@ int ranged::fire_gun( Character &who, const tripoint &target, int max_shots, ite return 0; } + if( gun.energy_required() > 0_J && !gun.energy_sufficient( who ) ) { + debugmsg( "%s's gun %s does not have enough energy.", who.name, + gun.tname() ); + return 0; + } + bool is_mech_weapon = false; if( who.is_mounted() && who.mounted_creature->has_flag( MF_RIDEABLE_MECH ) ) { is_mech_weapon = true; @@ -876,8 +882,8 @@ int ranged::fire_gun( Character &who, const tripoint &target, int max_shots, ite } // cap our maximum burst size by the amount of UPS power left - if( !gun.has_flag( flag_VEHICLE ) && gun.get_gun_ups_drain() > 0 ) { - shots = std::min( shots, ( who.charges_of( itype_UPS ) / + if( !gun.has_flag( flag_VEHICLE ) && gun.get_gun_ups_drain() > 0_J ) { + shots = std::min( shots, ( gun.energy_available( who ) / gun.get_gun_ups_drain() ) ); } @@ -987,7 +993,11 @@ int ranged::fire_gun( Character &who, const tripoint &target, int max_shots, ite } if( !gun.has_flag( flag_VEHICLE ) ) { - who.use_charges( itype_UPS, gun.get_gun_ups_drain() ); + units::energy power_con = gun.get_gun_ups_drain(); + power_con -= gun.energy_consume( gun.get_gun_ups_drain(), who.pos() ); + if( power_con > 0_J && !who.use_energy_if_avail( itype_UPS, power_con ) ) { + debugmsg( "Unexpected shortage of energy whilst firing %s", gun.tname() ); + } } if( aoe_attack ) { @@ -1237,7 +1247,7 @@ dealt_projectile_attack throw_item( Character &who, const tripoint &target, if( mons->mech_str_addition() != 0 ) { throw_assist = true; throw_assist_str = mons->mech_str_addition(); - mons->use_mech_power( -3 ); + mons->use_mech_power( -3_kJ ); } } if( !throw_assist ) { @@ -3175,7 +3185,7 @@ void target_ui::update_ammo_range_from_gun_mode() if( mode == TargetMode::TurretManual ) { itype_id ammo_current = turret->ammo_current(); // Test no-ammo and not a UPS weapon - if( !ammo_current && ( relevant->get_gun_ups_drain() == 0 ) ) { + if( !ammo_current && ( relevant->get_gun_ups_drain() == 0_J ) ) { ammo = nullptr; range = 0; } else { @@ -3841,9 +3851,8 @@ auto ranged::gunmode_checks_weapon( avatar &you, const map &m, std::vectorget_gun_ups_drain() > 0 ) { - const int ups_drain = gmode->get_gun_ups_drain(); - const int adv_ups_drain = std::max( 1, ups_drain / 2 ); + if( gmode->get_gun_ups_drain() > 0_J ) { + const units::energy ups_drain = gmode->get_gun_ups_drain(); bool is_mech_weapon = false; if( you.is_mounted() ) { monster *mons = get_player_character().mounted_creature.get(); @@ -3852,17 +3861,16 @@ auto ranged::gunmode_checks_weapon( avatar &you, const map &m, std::vector= units::from_kilojoule( ups_drain ) ) ) ) { + you.get_power_level() >= ups_drain ) ) ) { messages.push_back( string_format( - _( "You need a UPS with at least %2$d charges or an advanced UPS with at least %3$d charges to fire the %1$s!" ), - gmode->tname(), ups_drain, adv_ups_drain ) ); + _( "You need a UPS with at least %2$d charges to fire the %1$s!" ), + gmode->tname(), ups_drain ) ); result = false; } } else { - if( !you.has_charges( itype_UPS, ups_drain ) ) { + if( !you.has_energy( itype_UPS, ups_drain ) ) { messages.push_back( string_format( _( "Your mech has an empty battery, its %s will not fire." ), gmode->tname() ) ); result = false; diff --git a/src/recipe.cpp b/src/recipe.cpp index 5af8f858ee4c..fd29beaa305f 100644 --- a/src/recipe.cpp +++ b/src/recipe.cpp @@ -377,7 +377,7 @@ std::string recipe::get_consistency_error() const detached_ptr recipe::create_result() const { - detached_ptr newit = item::spawn( result_, calendar::turn, item::default_charges_tag{} ); + detached_ptr newit = item::spawn( result_, calendar::turn ); if( charges ) { newit->charges = *charges; } @@ -426,7 +426,7 @@ std::vector> recipe::create_byproducts( int batch ) const { std::vector> bps; for( const auto &e : byproducts ) { - detached_ptr obj = item::spawn( e.first, calendar::turn, item::default_charges_tag{} ); + detached_ptr obj = item::spawn( e.first, calendar::turn ); if( obj->has_flag( flag_VARSIZE ) ) { obj->set_flag( flag_FIT ); } diff --git a/src/savegame_json.cpp b/src/savegame_json.cpp index a1be2df9c56d..715f47606565 100644 --- a/src/savegame_json.cpp +++ b/src/savegame_json.cpp @@ -2156,7 +2156,7 @@ void item::io( Archive &archive ) archive.io( "charges", charges, 0 ); charges = std::max( charges, 0 ); - archive.io( "energy", energy, 0_J ); + archive.io( "power", energy, 0_J ); archive.io( "burnt", burnt, 0 ); archive.io( "poison", poison, 0 ); @@ -2341,6 +2341,14 @@ void item::deserialize( JsonIn &jsin ) if( contents.empty() && is_non_resealable_container() ) { convert( type->container->unseals_into ); } + + // Battery item migration. Items with the obsoleted battery charge ammo get their battery charge converted into power + if( contents.front().typeId() == itype_id( "battery" ) ) { + item &bat = contents.front(); + mod_energy( units::from_kilojoule( bat.charges ) ); + remove_item( bat ); + bat.destroy(); + } } void item::serialize( JsonOut &json ) const diff --git a/src/units.cpp b/src/units.cpp index 85035c6777b8..9bceee11a70c 100644 --- a/src/units.cpp +++ b/src/units.cpp @@ -58,12 +58,20 @@ void angle::deserialize( JsonIn &jsin ) std::string display( const units::energy v ) { - const int kj = units::to_kilojoule( v ); const int j = units::to_joule( v ); // at least 1 kJ and there is no fraction - if( kj >= 1 && float( j ) / kj == 1000 ) { - return std::to_string( kj ) + ' ' + pgettext( "energy unit: kilojoule", "kJ" ); + if( j > 1000 ) { + if( float( j % 1000 ) == 0 ) { + return string_format( "%d %s", j / 1000, pgettext( "energy unit: kilojoule", "kJ" ) ); + } else { + float kj = j / 1000.f; + std::string kJ_string = string_format( "%.3f", kj ); + while( kJ_string.back() == '0' ) { + kJ_string.pop_back(); + } + return string_format( "%s %s", kJ_string, pgettext( "energy unit: kilojoule", "kJ" ) ); + } } - return std::to_string( j ) + ' ' + pgettext( "energy unit: joule", "J" ); + return string_format( "%d %s", j, pgettext( "energy unit: joule", "J" ) ); } } // namespace units diff --git a/src/units_energy.h b/src/units_energy.h index 744bab82297d..bea10252188b 100644 --- a/src/units_energy.h +++ b/src/units_energy.h @@ -73,4 +73,4 @@ constexpr units::quantity operator"" _kJ( } -#endif // CATA_SRC_UNITS_ENERGY_H \ No newline at end of file +#endif // CATA_SRC_UNITS_ENERGY_H diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 2636cc39df84..5e25595c72ac 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -3568,6 +3568,7 @@ int vehicle::fuel_left( const itype_id &ftype, bool recurse ) const return fl; } + int vehicle::fuel_left( const int p, bool recurse ) const { return fuel_left( parts[ p ].fuel_current(), recurse ); @@ -5290,91 +5291,117 @@ void traverse( StartPoint &start, } // namespace distribution_graph -int vehicle::charge_battery( int amount, bool include_other_vehicles ) +units::energy vehicle::charge_battery( units::energy amount, bool include_other_vehicles ) { - // Key parts by percentage charge level. - std::multimap chargeable_parts; + // This is the reverse of discharge_battery + // Total the capacity of batteries that can be charged. + std::vector chargeable_parts; + units::energy total_capacity = 0_J; for( vehicle_part &p : parts ) { - if( p.is_available() && p.is_battery() && p.ammo_capacity() > p.ammo_remaining() ) { - chargeable_parts.insert( { ( p.ammo_remaining() * 100 ) / p.ammo_capacity(), &p } ); + if( p.is_available() && p.is_battery() && p.energy_remaining() < p.energy_capacity() ) { + chargeable_parts.push_back( &p ); + total_capacity += p.energy_capacity(); } } - while( amount > 0 && !chargeable_parts.empty() ) { - // Grab first part, charge until it reaches the next %, then re-insert with new % key. - auto iter = chargeable_parts.begin(); - int charge_level = iter->first; - vehicle_part *p = iter->second; - chargeable_parts.erase( iter ); - // Calculate number of charges to reach the next %, but insure it's at least - // one more than current charge. - int next_charge_level = ( ( charge_level + 1 ) * p->ammo_capacity() ) / 100; - next_charge_level = std::max( next_charge_level, p->ammo_remaining() + 1 ); - int qty = std::min( amount, next_charge_level - p->ammo_remaining() ); - p->ammo_set( fuel_type_battery, p->ammo_remaining() + qty ); - amount -= qty; - if( p->ammo_capacity() > p->ammo_remaining() ) { - chargeable_parts.insert( { ( p->ammo_remaining() * 100 ) / p->ammo_capacity(), p } ); - } + + // Sort so that highest charge % is in front. + auto comp = [&]( vehicle_part a, vehicle_part b ) -> bool { + // Multiply by 1.0f to prevent integer division. + float a_ratio = 1.0f * a.energy_remaining() / a.energy_capacity(); + float b_ratio = 1.0f * b.energy_remaining() / b.energy_capacity(); + return ( a_ratio > b_ratio ); + }; + std::stable_sort( chargeable_parts.begin(), chargeable_parts.end(), comp ); + + for( vehicle_part *p : chargeable_parts ) { + // Use a ratio of this battery's energy capacity to the total capacity to get the energy needed for + // the average percentage over the entire vehicle on this battery. + units::energy p_to_charge = amount * ( p->energy_capacity() / total_capacity ); + // amount is reduced by p_to_charge or if that's too big, the difference between current and max energy. + // This is why we sorted the highest first, so if that gets filled the extra to be charged is shunted + // to the larger batteries, as this will increase the average percentage to be charged. + // If we hit the end and there is still energy left over, then all batteries are full anyway, no need to recheck. + amount += p->base->energy_recharge( p_to_charge ); + // Reduce total capacity by this battery's capacity so the next part gets the appropriate ratio. + // ie: amount was to be spread over 6 batteries, 1 has been filled, 5 batteries left. + total_capacity -= p->energy_capacity(); + } + + if( total_capacity != 0_J ) { + debugmsg( "discharge_battery code has encountered an error." ); } - if( amount > 0 && include_other_vehicles ) { + if( amount > 0_J && include_other_vehicles ) { // still a bit of charge we could send out... using tvr = distribution_graph::traverse_visitor_result; auto charge_veh = [&amount]( vehicle & veh ) { g->u.add_msg_if_player( m_debug, "CHv: %d", amount ); amount = veh.charge_battery( amount, false ); - return amount > 0 ? tvr::continue_further : tvr::stop; + return amount > 0_J ? tvr::continue_further : tvr::stop; }; auto charge_grid = [&amount]( distribution_grid & grid ) { g->u.add_msg_if_player( m_debug, "CHg: %d", amount ); amount = grid.mod_resource( amount, false ); - return amount > 0 ? tvr::continue_further : tvr::stop; + return amount > 0_J ? tvr::continue_further : tvr::stop; }; distribution_graph::traverse( *this, charge_veh, charge_grid ); } - return amount; } -int vehicle::discharge_battery( int amount, bool recurse ) +units::energy vehicle::discharge_battery( units::energy amount, bool recurse ) { - // Key parts by percentage charge level. - std::multimap dischargeable_parts; + // Make a list of parts with energy > 0_J + // Total their capacity + std::vector dischargeable_parts; + units::energy total_capacity = 0_J; for( vehicle_part &p : parts ) { - if( p.is_available() && p.is_battery() && p.ammo_remaining() > 0 ) { - dischargeable_parts.insert( { ( p.ammo_remaining() * 100 ) / p.ammo_capacity(), &p } ); + if( p.is_available() && p.is_battery() && p.energy_remaining() > 0_J ) { + dischargeable_parts.push_back( &p ); + total_capacity += p.energy_capacity(); } } - while( amount > 0 && !dischargeable_parts.empty() ) { - // Grab first part, discharge until it reaches the next %, then re-insert with new % key. - auto iter = std::prev( dischargeable_parts.end() ); - int charge_level = iter->first; - vehicle_part *p = iter->second; - dischargeable_parts.erase( iter ); - // Calculate number of charges to reach the previous %. - int prev_charge_level = ( ( charge_level - 1 ) * p->ammo_capacity() ) / 100; - prev_charge_level = std::max( 0, prev_charge_level ); - int amount_to_discharge = std::min( p->ammo_remaining() - prev_charge_level, amount ); - p->ammo_consume( amount_to_discharge, global_part_pos3( *p ) ); - amount -= amount_to_discharge; - if( p->ammo_remaining() > 0 ) { - dischargeable_parts.insert( { ( p->ammo_remaining() * 100 ) / p->ammo_capacity(), p } ); - } + + // Sort so that lowest charge % is in front. + auto comp = [&]( vehicle_part a, vehicle_part b ) -> bool { + // Multiply by 1.0f to prevent integer division. + float a_ratio = 1.0f * a.energy_remaining() / a.energy_capacity(); + float b_ratio = 1.0f * b.energy_remaining() / b.energy_capacity(); + return ( a_ratio < b_ratio ); + }; + std::stable_sort( dischargeable_parts.begin(), dischargeable_parts.end(), comp ); + + for( vehicle_part *p : dischargeable_parts ) { + // Use a ratio of this battery's energy capacity to the total capacity to get the energy needed for + // the average percentage over the entire vehicle on this battery. + units::energy p_needed = amount * ( p->energy_capacity() / total_capacity ); + // amount is reduced by p_needed or if that's too big, the total energy in the part. + // This is why we sorted the smallest first, so if that gets drained dry the extra needed is shunted + // to the larger batteries, as this will increase the average percentage to be consumed. + // If we hit the end and energy is still needed, then all batteries are dry anyway, no need to recheck. + amount -= p->base->energy_consume( p_needed, global_part_pos3( *p ) ); + // Reduce total capacity by this battery's capacity so the next part gets the appropriate ratio. + // ie: amount was to be spread over 6 batteries, 1 has been drained, 5 batteries left. + total_capacity -= p->energy_capacity(); + } + + if( total_capacity != 0_J ) { + debugmsg( "discharge_battery code has encountered an error." ); } - if( amount > 0 && recurse ) { + if( amount > 0_J && recurse ) { // need more power! using tvr = distribution_graph::traverse_visitor_result; auto discharge_vehicle = [&amount]( vehicle & veh ) { g->u.add_msg_if_player( m_debug, "CHv: %d", amount ); amount = veh.discharge_battery( amount, false ); - return amount > 0 ? tvr::continue_further : tvr::stop; + return amount > 0_J ? tvr::continue_further : tvr::stop; }; auto discharge_grid = [&amount]( distribution_grid & grid ) { g->u.add_msg_if_player( m_debug, "CHg: %d", amount ); amount = -grid.mod_resource( -amount, false ); - return amount > 0 ? tvr::continue_further : tvr::stop; + return amount > 0_J ? tvr::continue_further : tvr::stop; }; distribution_graph::traverse( *this, discharge_vehicle, discharge_grid ); } diff --git a/src/vehicle.h b/src/vehicle.h index 279aa75c3257..053b23452e24 100644 --- a/src/vehicle.h +++ b/src/vehicle.h @@ -947,13 +947,13 @@ class vehicle * Try to charge our (and, optionally, connected vehicles') batteries by the given amount. * @return amount of charge left over. */ - int charge_battery( int amount, bool include_other_vehicles = true ); + units::energy charge_battery( units::energy amount, bool include_other_vehicles = true ); /** * Try to discharge our (and, optionally, connected vehicles') batteries by the given amount. * @return amount of request unfulfilled (0 if totally successful). */ - int discharge_battery( int amount, bool recurse = true ); + units::energy discharge_battery( units::energy amount, bool recurse = true ); /** * Mark mass caches and pivot cache as dirty diff --git a/src/vehicle_part.cpp b/src/vehicle_part.cpp index 0b84ef0e8879..74a3ec251c11 100644 --- a/src/vehicle_part.cpp +++ b/src/vehicle_part.cpp @@ -385,6 +385,26 @@ int vehicle_part::ammo_consume( int qty, const tripoint &pos ) return base->ammo_consume( qty, pos ); } +units::energy vehicle_part::energy_capacity() const +{ + return base->energy_capacity(); +} + +units::energy vehicle_part::energy_remaining() const +{ + return base->energy_remaining(); +} + +units::energy vehicle_part::energy_set( const units::energy enrg ) +{ + units::energy ret = -1_J; + if( base->energy_capacity() > 0_J ) { + ret = std::min( enrg, base->energy_capacity() ); + base->set_energy( ret ); + } + return ret; +} + double vehicle_part::consume_energy( const itype_id &ftype, double energy_j ) { if( base->contents.empty() || !is_fuel_store() ) { diff --git a/src/vehicle_part.h b/src/vehicle_part.h index d7161b884dd9..7869f97231ab 100644 --- a/src/vehicle_part.h +++ b/src/vehicle_part.h @@ -107,6 +107,19 @@ struct vehicle_part { */ int ammo_consume( int qty, const tripoint &pos ); + + /** Maximum amount of energy that can be contained by a part */ + units::energy energy_capacity() const; + + /** Amount of fuel, charges or ammunition currently contained by a part */ + units::energy energy_remaining() const; + + /** + * Set energy contained by this part + * @param enrg amount of energy to set (vehicle part must be a battery) + * @return amount of energy actually set or negative on failure + */ + units::energy energy_set( const units::energy enrg ); /** * Consume fuel by energy content. * @param ftype Type of fuel to consume diff --git a/src/visitable.cpp b/src/visitable.cpp index 72b171bcc1fd..82833e851497 100644 --- a/src/visitable.cpp +++ b/src/visitable.cpp @@ -950,6 +950,127 @@ void location_visitable::remove_items_with( const } } +template +static units::energy energy_of_internal( const T &self, const M &main, const itype_id &id, + units::energy limit, + const std::function &filter, + std::function visitor ) +{ + units::energy power_found = 0_J; + + bool found_tool_with_UPS = false; + self.visit_items( [&]( const item * e ) { + if( ( e->typeId() == id || id == itype_id( "any" ) ) && filter( *e ) ) { + power_found = units::from_joule( sum_no_wrap( units::to_joule( power_found ), + units::to_joule( e->energy_remaining() ) ) ); + if( e->has_flag( STATIC( flag_id( "USE_UPS" ) ) ) ) { + found_tool_with_UPS = true; + } + return power_found < limit ? VisitResponse::SKIP : VisitResponse::ABORT; + } + // recurse through any nested containers + return power_found < limit ? VisitResponse::NEXT : VisitResponse::ABORT; + } ); + + if( power_found < limit && found_tool_with_UPS ) { + power_found += main.energy_of( itype_UPS, limit - power_found ); + if( visitor ) { + visitor( power_found ); + } + } + + return std::min( power_found, limit ); +} + +/** @relates visitable */ +template +units::energy visitable::energy_of( const itype_id &what, units::energy limit, + const std::function &filter, + std::function visitor ) const +{ + return energy_of_internal( *this, *this, what, limit, filter, visitor ); +} + +/** @relates visitable */ +template <> +units::energy visitable::energy_of( const itype_id &what, units::energy limit, + const std::function &filter, + std::function visitor ) const +{ + const auto &binned = static_cast( this )->get_binned_items(); + const auto iter = binned.find( what ); + if( iter == binned.end() && what != itype_id( "any" ) ) { + return 0_J; + } + + units::energy res = 0_J; + if( what == itype_id( "any" ) ) { + for( const auto &kv : binned ) { + for( const item *it : kv.second ) { + res = sum_no_wrap( res, energy_of_internal( *it, *this, what, limit, filter, visitor ) ); + if( res >= limit ) { + break; + } + } + } + } else { + for( const item *it : iter->second ) { + res = sum_no_wrap( res, energy_of_internal( *it, *this, what, limit, filter, visitor ) ); + if( res >= limit ) { + break; + } + } + } + return std::min( limit, res ); +} + +template <> +units::energy visitable::energy_of( const itype_id &what, units::energy limit, + const std::function &filter, + std::function visitor ) const +{ + + auto inv = static_cast( this ); + return inv->inv.energy_of( what, limit, filter, std::move( visitor ) ); +} + +/** @relates visitable */ +template <> +units::energy visitable::energy_of( const itype_id &what, units::energy limit, + const std::function &filter, + std::function visitor ) const +{ + auto self = static_cast( this ); + auto p = dynamic_cast( self ); + + if( what == itype_toolset ) { + if( p && p->has_active_bionic( bio_tools ) ) { + return std::min( p->get_power_level(), limit ); + } else { + return 0_J; + } + } + + if( what == itype_bio_armor ) { + float efficiency = 1; + units::energy power_charges = 0_J; + + for( const bionic &bio : *self->my_bionics ) { + if( bio.powered && bio.info().has_flag( flag_BIONIC_ARMOR_INTERFACE ) ) { + efficiency = std::max( efficiency, bio.info().fuel_efficiency ); + } + } + if( efficiency == 1 ) { + debugmsg( "Character lacks a bionic armor interface with fuel efficiency field." ); + } + power_charges = self->as_player()->get_power_level() * efficiency; + + return std::min( power_charges, limit ); + } + + return energy_of_internal( *this, *this, what, limit, filter, std::move( visitor ) ); +} + template static int charges_of_internal( const T &self, const M &main, const itype_id &id, int limit, const std::function &filter, @@ -1048,39 +1169,6 @@ int visitable::charges_of( const itype_id &what, int limit, auto self = static_cast( this ); auto p = dynamic_cast( self ); - if( what == itype_toolset ) { - if( p && p->has_active_bionic( bio_tools ) ) { - return std::min( units::to_kilojoule( p->get_power_level() ), limit ); - } else { - return 0; - } - } - - if( what == itype_voltmeter_bionic ) { - if( p && p->has_bionic( bio_electrosense_voltmeter ) ) { - return std::min( units::to_kilojoule( p->get_power_level() ), limit ); - } else { - return 0; - } - } - - if( what == itype_bio_armor ) { - float efficiency = 1; - int power_charges = 0; - - for( const bionic &bio : *self->my_bionics ) { - if( bio.powered && bio.info().has_flag( flag_BIONIC_ARMOR_INTERFACE ) ) { - efficiency = std::max( efficiency, bio.info().fuel_efficiency ); - } - } - if( efficiency == 1 ) { - debugmsg( "Character lacks a bionic armor interface with fuel efficiency field." ); - } - power_charges = units::to_kilojoule( self->as_player()->get_power_level() ) * efficiency; - - return std::min( power_charges, limit ); - } - if( what == itype_UPS ) { int qty = 0; qty = sum_no_wrap( qty, charges_of( itype_UPS_off ) ); @@ -1097,6 +1185,22 @@ int visitable::charges_of( const itype_id &what, int limit, return std::min( qty, limit ); } + if( what == itype_toolset ) { + if( p && p->has_active_bionic( bio_tools ) ) { + return std::min( units::to_kilojoule( p->get_power_level() ), limit ); + } else { + return 0; + } + } + + if( what == itype_voltmeter_bionic ) { + if( p && p->has_bionic( bio_electrosense_voltmeter ) ) { + return std::min( units::to_kilojoule( p->get_power_level() ), limit ); + } else { + return 0; + } + } + return charges_of_internal( *this, *this, what, limit, filter, std::move( visitor ) ); } diff --git a/src/visitable.h b/src/visitable.h index e945d225fc9b..5125b7a7f0f2 100644 --- a/src/visitable.h +++ b/src/visitable.h @@ -10,6 +10,7 @@ #include "filter_utils.h" #include "type_id.h" +#include "units.h" class item; template @@ -89,6 +90,17 @@ class visitable const std::function &filter = return_true, std::function visitor = nullptr ) const; + /** + * Count maximum available energy from this instance and any contained items + * @param what ID of item to count charges of + * @param limit stop searching after this much energy has been found + * @param filter only count energy of items that match the filter + * @param visitor is called when UPS charge is used (parameter is the charge itself) + */ + units::energy energy_of( const itype_id &what, units::energy limit = units::energy_max, + const std::function &filter = return_true, + std::function visitor = nullptr ) const; + /** * Count items matching id including both this instance and any contained items * @param what ID of items to count. "any" will count all items (usually used with a filter) diff --git a/tests/active_item_cache_test.cpp b/tests/active_item_cache_test.cpp index 033106cdd427..0a71d3fc8548 100644 --- a/tests/active_item_cache_test.cpp +++ b/tests/active_item_cache_test.cpp @@ -23,8 +23,7 @@ TEST_CASE( "place_active_item_at_various_coordinates", "[item]" ) } REQUIRE( g->m.get_submaps_with_active_items().empty() ); // An arbitrary active item. - item &active = *item::spawn_temporary( "firecracker_act", calendar::start_of_cataclysm, - item::default_charges_tag() ); + item &active = *item::spawn_temporary( "firecracker_act", calendar::start_of_cataclysm ); active.activate(); // For each space in a wide area place the item and check if the cache has been updated. diff --git a/tests/item_test.cpp b/tests/item_test.cpp index 9979bee82907..9aadeaa30559 100644 --- a/tests/item_test.cpp +++ b/tests/item_test.cpp @@ -18,8 +18,7 @@ TEST_CASE( "item_volume", "[item]" ) { // Need to pick some item here which is count_by_charges and for which each // charge is at least 1_ml. Battery works for now. - item &i = *item::spawn_temporary( "battery", calendar::start_of_cataclysm, - item::default_charges_tag() ); + item &i = *item::spawn_temporary( "battery", calendar::start_of_cataclysm ); REQUIRE( i.count_by_charges() ); // Would be better with Catch2 generators const units::volume big_volume = units::from_milliliter( std::numeric_limits::max() / 2 ); diff --git a/tests/iuse_actor_test.cpp b/tests/iuse_actor_test.cpp index a1b53cfadaca..769f83c414bb 100644 --- a/tests/iuse_actor_test.cpp +++ b/tests/iuse_actor_test.cpp @@ -45,8 +45,7 @@ TEST_CASE( "manhack", "[iuse_actor][manhack]" ) player &dummy = g->u; g->clear_zombies(); - detached_ptr det = item::spawn( "bot_manhack", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "bot_manhack", calendar::start_of_cataclysm ); item &test_item = *det; dummy.i_add( std::move( det ) ); diff --git a/tests/iuse_test.cpp b/tests/iuse_test.cpp index b893bfd035c5..f10b0f53964c 100644 --- a/tests/iuse_test.cpp +++ b/tests/iuse_test.cpp @@ -18,8 +18,7 @@ TEST_CASE( "eyedrops", "[iuse][eyedrops]" ) { avatar dummy; - detached_ptr det = item::spawn( "saline", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "saline", calendar::start_of_cataclysm ); item &eyedrops = *det; dummy.i_add( std::move( det ) ); int charges_before = eyedrops.charges; @@ -58,8 +57,7 @@ TEST_CASE( "eyedrops", "[iuse][eyedrops]" ) TEST_CASE( "antifungal", "[iuse][antifungal]" ) { avatar dummy; - detached_ptr det = item::spawn( "antifungal", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "antifungal", calendar::start_of_cataclysm ); item &antifungal = *det; dummy.i_add( std::move( det ) ); int charges_before = antifungal.charges; @@ -103,8 +101,7 @@ TEST_CASE( "antifungal", "[iuse][antifungal]" ) TEST_CASE( "antiparasitic", "[iuse][antiparasitic]" ) { avatar dummy; - detached_ptr det = item::spawn( "antiparasitic", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "antiparasitic", calendar::start_of_cataclysm ); item &antiparasitic = *det; dummy.i_add( std::move( det ) ); @@ -162,8 +159,7 @@ TEST_CASE( "antiparasitic", "[iuse][antiparasitic]" ) TEST_CASE( "anticonvulsant", "[iuse][anticonvulsant]" ) { avatar dummy; - detached_ptr det = item::spawn( "diazepam", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "diazepam", calendar::start_of_cataclysm ); item &anticonvulsant = *det; dummy.i_add( std::move( det ) ); @@ -196,8 +192,7 @@ TEST_CASE( "anticonvulsant", "[iuse][anticonvulsant]" ) TEST_CASE( "oxygen tank", "[iuse][oxygen_bottle]" ) { avatar dummy; - detached_ptr det = item::spawn( "oxygen_tank", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "oxygen_tank", calendar::start_of_cataclysm ); item &oxygen = *det; dummy.i_add( std::move( det ) ); @@ -315,8 +310,7 @@ TEST_CASE( "caffeine and atomic caffeine", "[iuse][caff][atomic_caff]" ) SECTION( "coffee reduces fatigue" ) { - detached_ptr det = item::spawn( "coffee", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "coffee", calendar::start_of_cataclysm ); item &coffee = *det; dummy.i_add( std::move( det ) ); dummy.consume_item( item::spawn( coffee ) ); @@ -325,8 +319,7 @@ TEST_CASE( "caffeine and atomic caffeine", "[iuse][caff][atomic_caff]" ) SECTION( "atomic caffeine greatly reduces fatigue" ) { - detached_ptr det = item::spawn( "atomic_coffee", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "atomic_coffee", calendar::start_of_cataclysm ); item &atomic_coffee = *det; dummy.i_add( std::move( det ) ); dummy.consume_item( item::spawn( atomic_coffee ) ); @@ -339,8 +332,7 @@ TEST_CASE( "towel", "[iuse][towel]" ) { avatar dummy; dummy.set_body(); - detached_ptr det = item::spawn( "towel", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "towel", calendar::start_of_cataclysm ); item &towel = *det; dummy.i_add( std::move( det ) ); @@ -468,8 +460,7 @@ TEST_CASE( "thorazine", "[iuse][thorazine]" ) { avatar dummy; dummy.set_fatigue( 0 ); - detached_ptr det = item::spawn( "thorazine", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "thorazine", calendar::start_of_cataclysm ); item &thorazine = *det; dummy.i_add( std::move( det ) ); int charges_before = thorazine.charges; @@ -515,8 +506,7 @@ TEST_CASE( "thorazine", "[iuse][thorazine]" ) TEST_CASE( "prozac", "[iuse][prozac]" ) { avatar dummy; - detached_ptr det = item::spawn( "prozac", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "prozac", calendar::start_of_cataclysm ); item &prozac = *det; dummy.i_add( std::move( det ) ); @@ -540,8 +530,7 @@ TEST_CASE( "prozac", "[iuse][prozac]" ) TEST_CASE( "inhaler", "[iuse][inhaler]" ) { avatar dummy; - detached_ptr det = item::spawn( "inhaler", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "inhaler", calendar::start_of_cataclysm ); item &inhaler = *det; dummy.i_add( std::move( det ) ); @@ -579,8 +568,7 @@ TEST_CASE( "inhaler", "[iuse][inhaler]" ) TEST_CASE( "panacea", "[iuse][panacea]" ) { avatar dummy; - detached_ptr det = item::spawn( "panacea", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "panacea", calendar::start_of_cataclysm ); item &panacea = *det; dummy.i_add( std::move( det ) ); @@ -595,8 +583,7 @@ TEST_CASE( "panacea", "[iuse][panacea]" ) TEST_CASE( "xanax", "[iuse][xanax]" ) { avatar dummy; - detached_ptr det = item::spawn( "xanax", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "xanax", calendar::start_of_cataclysm ); item &xanax = *det; dummy.i_add( std::move( det ) ); diff --git a/tests/modify_morale_test.cpp b/tests/modify_morale_test.cpp index d860fe2f37a8..2064261cad53 100644 --- a/tests/modify_morale_test.cpp +++ b/tests/modify_morale_test.cpp @@ -49,8 +49,7 @@ TEST_CASE( "food enjoyability", "[food][modify_morale][fun]" ) std::pair fun; GIVEN( "food with positive fun" ) { - detached_ptr det = item::spawn( "jihelucake", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "jihelucake", calendar::start_of_cataclysm ); item &jihelucake = *det; dummy.i_add( std::move( det ) ); fun = dummy.fun_for( jihelucake ); @@ -63,8 +62,7 @@ TEST_CASE( "food enjoyability", "[food][modify_morale][fun]" ) } GIVEN( "food with negative fun" ) { - detached_ptr det = item::spawn( "garlic", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "garlic", calendar::start_of_cataclysm ); item &garlic = *det; dummy.i_add( std::move( det ) ); fun = dummy.fun_for( garlic ); @@ -117,8 +115,7 @@ TEST_CASE( "cannibalism", "[food][modify_morale][cannibal]" ) { avatar dummy; - detached_ptr det = item::spawn( "bone_human", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "bone_human", calendar::start_of_cataclysm ); item &human = *det; dummy.i_add( std::move( det ) ); REQUIRE( human.has_vitamin( vitamin_human_flesh_vitamin ) ); @@ -162,8 +159,7 @@ TEST_CASE( "sweet junk food", "[food][modify_morale][junk][sweet]" ) avatar dummy; GIVEN( "some sweet junk food" ) { - detached_ptr det = item::spawn( "neccowafers", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "neccowafers", calendar::start_of_cataclysm ); item &necco = *det; dummy.i_add( std::move( det ) ); @@ -216,8 +212,7 @@ TEST_CASE( "junk food that is not ingested", "[modify_morale][junk][no_ingest]" { avatar dummy; - detached_ptr det = item::spawn( "caff_gum", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "caff_gum", calendar::start_of_cataclysm ); item &caff_gum = *det; dummy.i_add( std::move( det ) ); @@ -289,8 +284,7 @@ TEST_CASE( "food allergies and intolerances", "[food][modify_morale][allergy]" ) REQUIRE( dummy.has_trait( trait_VEGETARIAN ) ); THEN( "they get a morale penalty for eating meat" ) { - detached_ptr det = item::spawn( "meat", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "meat", calendar::start_of_cataclysm ); item &meat = *det; dummy.i_add( std::move( det ) ); REQUIRE( meat.has_flag( flag_ALLERGEN_MEAT ) ); @@ -305,8 +299,7 @@ TEST_CASE( "food allergies and intolerances", "[food][modify_morale][allergy]" ) REQUIRE( dummy.has_trait( trait_LACTOSE ) ); THEN( "they get a morale penalty for drinking milk" ) { - detached_ptr det = item::spawn( "milk", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "milk", calendar::start_of_cataclysm ); item &milk = *det; dummy.i_add( std::move( det ) ); REQUIRE( milk.has_flag( flag_ALLERGEN_MILK ) ); @@ -321,8 +314,7 @@ TEST_CASE( "food allergies and intolerances", "[food][modify_morale][allergy]" ) REQUIRE( dummy.has_trait( trait_ANTIWHEAT ) ); THEN( "they get a morale penalty for eating wheat" ) { - detached_ptr det = item::spawn( "wheat", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "wheat", calendar::start_of_cataclysm ); item &wheat = *det; dummy.i_add( std::move( det ) ); REQUIRE( wheat.has_flag( flag_ALLERGEN_WHEAT ) ); @@ -337,8 +329,7 @@ TEST_CASE( "food allergies and intolerances", "[food][modify_morale][allergy]" ) REQUIRE( dummy.has_trait( trait_MEATARIAN ) ); THEN( "they get a morale penalty for eating vegetables" ) { - detached_ptr det = item::spawn( "broccoli", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "broccoli", calendar::start_of_cataclysm ); item &veggy = *det; dummy.i_add( std::move( det ) ); REQUIRE( veggy.has_flag( flag_ALLERGEN_VEGGY ) ); @@ -353,8 +344,7 @@ TEST_CASE( "food allergies and intolerances", "[food][modify_morale][allergy]" ) REQUIRE( dummy.has_trait( trait_ANTIFRUIT ) ); THEN( "they get a morale penalty for eating fruit" ) { - detached_ptr det = item::spawn( "apple", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "apple", calendar::start_of_cataclysm ); item &fruit = *det; dummy.i_add( std::move( det ) ); REQUIRE( fruit.has_flag( flag_ALLERGEN_FRUIT ) ); @@ -369,8 +359,7 @@ TEST_CASE( "food allergies and intolerances", "[food][modify_morale][allergy]" ) REQUIRE( dummy.has_trait( trait_ANTIJUNK ) ); THEN( "they get a morale penalty for eating junk food" ) { - detached_ptr det = item::spawn( "neccowafers", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "neccowafers", calendar::start_of_cataclysm ); item &junk = *det; dummy.i_add( std::move( det ) ); REQUIRE( junk.has_flag( flag_ALLERGEN_JUNK ) ); @@ -391,8 +380,7 @@ TEST_CASE( "saprophage character", "[food][modify_morale][saprophage]" ) REQUIRE( dummy.has_trait( trait_SAPROPHAGE ) ); AND_GIVEN( "some rotten chewable food" ) { - detached_ptr det = item::spawn( "jihelucake", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "jihelucake", calendar::start_of_cataclysm ); item &jihelucake = *det; dummy.i_add( std::move( det ) ); // food rot > 1.0 is rotten @@ -406,8 +394,7 @@ TEST_CASE( "saprophage character", "[food][modify_morale][saprophage]" ) } AND_GIVEN( "some fresh chewable food" ) { - detached_ptr det = item::spawn( "jihelucake", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "jihelucake", calendar::start_of_cataclysm ); item &jihelucake = *det; dummy.i_add( std::move( det ) ); // food rot < 0.1 is fresh @@ -426,8 +413,7 @@ TEST_CASE( "ursine honey", "[food][modify_morale][ursine][honey]" ) { avatar dummy; - detached_ptr det = item::spawn( "honeycomb", calendar::start_of_cataclysm, - item::default_charges_tag{} ); + detached_ptr det = item::spawn( "honeycomb", calendar::start_of_cataclysm ); item &honeycomb = *det; dummy.i_add( std::move( det ) ); REQUIRE( honeycomb.has_flag( flag_URSINE_HONEY ) ); diff --git a/tests/reloading_test.cpp b/tests/reloading_test.cpp index 4175df80e2e1..5610a47820ee 100644 --- a/tests/reloading_test.cpp +++ b/tests/reloading_test.cpp @@ -32,10 +32,10 @@ TEST_CASE( "reload_gun_with_integral_magazine", "[reload],[gun]" ) // Make sure the player doesn't drop anything :P dummy.wear_item( item::spawn( "backpack", bday ) ); - detached_ptr det = item::spawn( "40sw", bday, item::default_charges_tag{} ); + detached_ptr det = item::spawn( "40sw", bday ); item &ammo = *det; dummy.i_add( std::move( det ) ); - det = item::spawn( "sw_610", bday, item::default_charges_tag{} ); + det = item::spawn( "sw_610", bday ); item &gun = *det; dummy.i_add( std::move( det ) ); int ammo_pos = dummy.inv_position_by_item( &ammo ); @@ -58,7 +58,7 @@ TEST_CASE( "reload_gun_with_integral_magazine_using_speedloader", "[reload],[gun // Make sure the player doesn't drop anything :P dummy.wear_item( item::spawn( "backpack", bday ) ); - detached_ptr det = item::spawn( "38_special", bday, item::default_charges_tag{} ); + detached_ptr det = item::spawn( "38_special", bday ); item &ammo = *det; dummy.i_add( std::move( det ) ); det = item::spawn( "38_speedloader", bday, false ); @@ -99,7 +99,7 @@ TEST_CASE( "reload_gun_with_swappable_magazine", "[reload],[gun]" ) // Make sure the player doesn't drop anything :P dummy.wear_item( item::spawn( "backpack", bday ) ); - detached_ptr det = item::spawn( "9mm", bday, item::default_charges_tag{} ); + detached_ptr det = item::spawn( "9mm", bday ); item &ammo = *det; dummy.i_add( std::move( det ) ); const cata::value_ptr &ammo_type = ammo.type->ammo; @@ -110,7 +110,7 @@ TEST_CASE( "reload_gun_with_swappable_magazine", "[reload],[gun]" ) REQUIRE( magazine_type ); REQUIRE( magazine_type->type.count( ammo_type->type ) != 0 ); - det = item::spawn( itype_glock_19, bday, item::default_charges_tag{} ); + det = item::spawn( itype_glock_19, bday ); item &gun = *det; dummy.i_add( std::move( det ) ); REQUIRE( gun.ammo_types().count( ammo_type->type ) != 0 ); @@ -174,7 +174,7 @@ TEST_CASE( "automatic_reloading_action", "[reload],[gun]" ) } GIVEN( "a player armed with a revolver and ammo for it" ) { - detached_ptr det = item::spawn( "40sw", bday, item::default_charges_tag{} ); + detached_ptr det = item::spawn( "40sw", bday ); item &ammo = *det; dummy.i_add( std::move( det ) ); REQUIRE( ammo.is_ammo() );