diff --git a/Makefile b/Makefile index f7431a5b6d854..663bcd98853ee 100644 --- a/Makefile +++ b/Makefile @@ -63,6 +63,8 @@ # make DYNAMIC_LINKING=1 # Use MSYS2 as the build environment on Windows # make MSYS2=1 +# Turn off all optimizations, even debug-friendly optimizations +# make NOOPT=1 # Astyle all source files. # make astyle # Check if source files are styled properly. @@ -303,10 +305,18 @@ ifdef RELEASE endif ifndef RELEASE - ifeq ($(shell $(CXX) -E -Og - < /dev/null > /dev/null 2>&1 && echo fog),fog) - OPTLEVEL = -Og - else + ifdef NOOPT + # While gcc claims to include all information required for + # debugging at -Og, at least with gcc 8.3, control flow + # doesn't move line-by-line at -Og. Provide a command-line + # way to turn off optimization (make NOOPT=1) entirely. OPTLEVEL = -O0 + else + ifeq ($(shell $(CXX) -E -Og - < /dev/null > /dev/null 2>&1 && echo fog),fog) + OPTLEVEL = -Og + else + OPTLEVEL = -O0 + endif endif CXXFLAGS += $(OPTLEVEL) endif diff --git a/build-scripts/get_all_mods.py b/build-scripts/get_all_mods.py index 27f0e8cd55784..85ae466df2301 100755 --- a/build-scripts/get_all_mods.py +++ b/build-scripts/get_all_mods.py @@ -14,6 +14,6 @@ mod_info = json.load(open(info)) mods.extend(e["ident"] for e in mod_info if e["type"] == "MOD_INFO") -mods_to_keep = [mod for mod in mods if mod not in blacklist] +mods_to_keep = [mod for mod in mods if mod not in blacklist and mod != "dda"] print(','.join(mods_to_keep)) diff --git a/build-scripts/mod_test_blacklist b/build-scripts/mod_test_blacklist index b84b5bbdb5c4e..23bccd6e5f47f 100644 --- a/build-scripts/mod_test_blacklist +++ b/build-scripts/mod_test_blacklist @@ -29,7 +29,6 @@ No_Anthills No_Bees no_faults no_filthy_clothing -No_Fungi no_medieval_items no_npc_food No_Rail_Stations diff --git a/data/json/construction.json b/data/json/construction.json index 8d7c3527e4e4e..b2e1932d5b9d6 100644 --- a/data/json/construction.json +++ b/data/json/construction.json @@ -1117,6 +1117,30 @@ "pre_terrain": "t_rock_wall_half", "post_terrain": "t_rock_wall" }, + { + "type": "construction", + "description": "Build Dry Stone Wall", + "//": "Step 1: half the wall", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 1 ] ], + "time": "180 m", + "qualities": [ [ { "id": "DIG", "level": 1 } ] ], + "components": [ [ [ "rock", 12 ] ] ], + "pre_special": "check_empty", + "post_terrain": "t_drystone_wall_half" + }, + { + "type": "construction", + "description": "Build Dry Stone Wall", + "//": "Step 2: the full wall", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 3 ] ], + "time": "180 m", + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ [ [ "rock", 16 ] ] ], + "pre_terrain": "t_drystone_wall_half", + "post_terrain": "t_drystone_wall" + }, { "type": "construction", "description": "Build Pony Wall", diff --git a/data/json/flags.json b/data/json/flags.json index 4782a1a3ee211..d61ab7c6c3ea1 100644 --- a/data/json/flags.json +++ b/data/json/flags.json @@ -666,6 +666,12 @@ "context": [ "SPELL" ], "//": "Chooses a spell at random to cast from extra_effects. See MAGIC.md for details" }, + { + "id": "PAIN_NORESIST", + "type": "json_flag", + "context": [ "SPELL" ], + "//": "pain altering spells can't be resisted (like with the deadened trait)" + }, { "id": "NON_THRESH", "type": "json_flag", diff --git a/data/json/furniture_and_terrain/terrain-walls.json b/data/json/furniture_and_terrain/terrain-walls.json index 5a5f91f6c905b..bb3426965b7c0 100644 --- a/data/json/furniture_and_terrain/terrain-walls.json +++ b/data/json/furniture_and_terrain/terrain-walls.json @@ -1323,5 +1323,46 @@ { "item": "scrap", "count": [ 2, 4 ] } ] } + }, + { + "type": "terrain", + "id": "t_drystone_wall", + "name": "field stone wall", + "description": "A sturdy dry stone wall. Just rocks fitted together without mortar.", + "symbol": "LINE_OXOX", + "color": "light_gray", + "move_cost": 0, + "coverage": 100, + "roof": "t_flat_roof", + "flags": [ "NOITEM", "WALL", "AUTO_WALL_SYMBOL", "MINEABLE", "BLOCK_WIND" ], + "connects_to": "WALL", + "bash": { + "str_min": 50, + "str_max": 200, + "sound": "crash!", + "sound_fail": "whump!", + "ter_set": "t_null", + "items": [ { "item": "rock", "count": [ 8, 18 ] }, { "item": "pebble", "count": [ 20, 38 ] } ] + } + }, + { + "type": "terrain", + "id": "t_drystone_wall_half", + "name": "field stone half-wall", + "description": "A half height sturdy dry stone wall. Just rocks fitted together without mortar. Complete as is or with extensive work it could be doubled in height.", + "symbol": "#", + "color": "light_gray", + "move_cost": 4, + "coverage": 60, + "flags": [ "TRANSPARENT", "NOITEM", "REDUCE_SCENT", "MOUNTABLE", "MINEABLE" ], + "connects_to": "WALL", + "bash": { + "str_min": 30, + "str_max": 120, + "sound": "crash!", + "sound_fail": "whump!", + "ter_set": "t_null", + "items": [ { "item": "rock", "count": [ 3, 8 ] }, { "item": "pebble", "count": [ 20, 38 ] } ] + } } ] diff --git a/data/json/itemgroups/clothing.json b/data/json/itemgroups/clothing.json index 5a7b6381a3ed5..7c755b8408d86 100644 --- a/data/json/itemgroups/clothing.json +++ b/data/json/itemgroups/clothing.json @@ -516,7 +516,93 @@ [ "jade_brooch", 80 ], [ "pearl_collar", 50 ], [ "silver_bracelet", 30 ], - [ "gold_bracelet", 20 ] + [ "gold_bracelet", 20 ], + { "group": "earrings_silver", "prob": 10 }, + { "group": "earrings_gold", "prob": 10 }, + { "group": "earrings_platinum", "prob": 10 } + ] + }, + { + "id": "dental_grills", + "type": "item_group", + "items": [ + [ "gold_dental_grill", 50 ], + [ "platinum_dental_grill", 50 ], + [ "citrine_dental_grill", 50 ], + [ "diamond_dental_grill", 50 ], + [ "emerald_dental_grill", 50 ], + [ "peridot_dental_grill", 50 ], + [ "amethyst_dental_grill", 50 ], + [ "sapphire_dental_grill", 50 ], + [ "aquamarine_dental_grill", 50 ], + [ "blue_topaz_dental_grill", 50 ], + [ "tourmaline_dental_grill", 50 ], + [ "alexandrite_dental_grill", 50 ], + [ "ruby_dental_grill", 50 ], + [ "garnet_dental_grill", 50 ] + ] + }, + { + "id": "earrings_silver", + "type": "item_group", + "items": [ + [ "silver_ear", 50 ], + [ "citrine_silver_earring", 50 ], + [ "diamond_silver_earring", 50 ], + [ "emerald_silver_earring", 50 ], + [ "peridot_silver_earring", 50 ], + [ "amethyst_silver_earring", 50 ], + [ "sapphire_silver_earring", 50 ], + [ "aquamarine_silver_earring", 50 ], + [ "blue_topaz_silver_earring", 50 ], + [ "tourmaline_silver_earring", 50 ], + [ "alexandrite_silver_earring", 50 ], + [ "pearl_silver_earring", 50 ], + [ "opal_silver_earring", 50 ], + [ "ruby_silver_earring", 50 ], + [ "garnet_silver_earring", 50 ] + ] + }, + { + "id": "earrings_gold", + "type": "item_group", + "items": [ + [ "gold_ear", 50 ], + [ "citrine_gold_earring", 50 ], + [ "diamond_gold_earring", 50 ], + [ "emerald_gold_earring", 50 ], + [ "peridot_gold_earring", 50 ], + [ "amethyst_gold_earring", 50 ], + [ "sapphire_gold_earring", 50 ], + [ "aquamarine_gold_earring", 50 ], + [ "blue_topaz_gold_earring", 50 ], + [ "tourmaline_gold_earring", 50 ], + [ "alexandrite_gold_earring", 50 ], + [ "pearl_gold_earring", 50 ], + [ "opal_gold_earring", 50 ], + [ "ruby_gold_earring", 50 ], + [ "garnet_gold_earring", 50 ] + ] + }, + { + "id": "earrings_platinum", + "type": "item_group", + "items": [ + [ "platinum_ear", 50 ], + [ "citrine_platinum_earring", 50 ], + [ "diamond_platinum_earring", 50 ], + [ "emerald_platinum_earring", 50 ], + [ "peridot_platinum_earring", 50 ], + [ "amethyst_platinum_earring", 50 ], + [ "sapphire_platinum_earring", 50 ], + [ "aquamarine_platinum_earring", 50 ], + [ "blue_topaz_platinum_earring", 50 ], + [ "tourmaline_platinum_earring", 50 ], + [ "alexandrite_platinum_earring", 50 ], + [ "pearl_platinum_earring", 50 ], + [ "opal_platinum_earring", 50 ], + [ "ruby_platinum_earring", 50 ], + [ "garnet_platinum_earring", 50 ] ] }, { diff --git a/data/json/itemgroups/item_groups.json b/data/json/itemgroups/item_groups.json index fbcf51ce1d9a5..52558f52f7a0e 100644 --- a/data/json/itemgroups/item_groups.json +++ b/data/json/itemgroups/item_groups.json @@ -4010,6 +4010,11 @@ "type": "item_group", "id": "jewelry_front", "items": [ + { "group": "earrings_silver", "prob": 30 }, + { "group": "earrings_gold", "prob": 10 }, + { "group": "earrings_platinum", "prob": 5 }, + { "group": "dental_grills", "prob": 10 }, + { "group": "gemstones", "prob": 30 }, [ "gold_ring", 30 ], [ "gold_ear", 30 ], [ "gold_bracelet", 30 ], @@ -4117,7 +4122,34 @@ { "type": "item_group", "id": "jewelry_safe", - "items": [ [ "platinum_small", 80 ], [ "gold_small", 80 ], [ "silver_small", 85 ], [ "diamond", 75 ] ] + "items": [ + [ "platinum_small", 80 ], + [ "gold_small", 80 ], + [ "silver_small", 85 ], + [ "diamond", 75 ], + [ "diamond", 75 ], + { "group": "gemstones", "prob": 75 } + ] + }, + { + "id": "gemstones", + "type": "item_group", + "items": [ + [ "citrine", 50 ], + [ "diamond", 50 ], + [ "emerald", 50 ], + [ "peridot", 50 ], + [ "amethyst", 50 ], + [ "sapphire", 50 ], + [ "aquamarine", 50 ], + [ "blue_topaz", 50 ], + [ "tourmaline", 50 ], + [ "alexandrite", 50 ], + [ "pearl", 50 ], + [ "opal", 50 ], + [ "ruby", 50 ], + [ "garnet", 50 ] + ] }, { "type": "item_group", diff --git a/data/json/items/armor.json b/data/json/items/armor.json index 46023a909649f..c26e39682a163 100644 --- a/data/json/items/armor.json +++ b/data/json/items/armor.json @@ -455,6 +455,7 @@ "storage": "1 L", "warmth": 60, "material_thickness": 4, + "valid_mods": [ "steel_padded" ], "flags": [ "VARSIZE", "POCKETS", "WATERPROOF", "STURDY" ] }, { @@ -565,6 +566,7 @@ "storage": "20 L", "warmth": 40, "material_thickness": 5, + "valid_mods": [ "steel_padded" ], "environmental_protection": 1, "flags": [ "VARSIZE", "POCKETS" ] }, @@ -587,6 +589,7 @@ "storage": "12500 ml", "warmth": 10, "material_thickness": 4, + "valid_mods": [ "steel_padded" ], "environmental_protection": 1, "flags": [ "VARSIZE", "POCKETS" ] }, @@ -698,6 +701,7 @@ "storage": "20 L", "warmth": 40, "material_thickness": 5, + "valid_mods": [ "steel_padded" ], "environmental_protection": 2, "flags": [ "VARSIZE", "POCKETS", "STURDY", "WATERPROOF" ] }, @@ -1093,6 +1097,7 @@ "storage": "500 ml", "warmth": 20, "material_thickness": 3, + "valid_mods": [ "steel_padded" ], "flags": [ "VARSIZE", "FANCY" ] }, { @@ -1492,6 +1497,7 @@ "storage": "2500 ml", "warmth": 30, "material_thickness": 4, + "valid_mods": [ "steel_padded" ], "environmental_protection": 6, "flags": [ "VARSIZE", "POCKETS", "STURDY", "WATERPROOF", "RAINPROOF", "OUTER" ] }, @@ -1517,6 +1523,7 @@ "storage": "1500 ml", "warmth": 30, "material_thickness": 4, + "valid_mods": [ "steel_padded" ], "environmental_protection": 6, "flags": [ "VARSIZE", "POCKETS", "STURDY", "WATERPROOF", "OUTER" ] }, @@ -2057,6 +2064,7 @@ "storage": "1 L", "warmth": 80, "material_thickness": 4, + "valid_mods": [ "steel_padded" ], "environmental_protection": 2, "flags": [ "VARSIZE", "POCKETS", "OUTER" ] }, @@ -2092,6 +2100,7 @@ "storage": "1250 ml", "warmth": 90, "material_thickness": 4, + "valid_mods": [ "steel_padded" ], "environmental_protection": 2, "flags": [ "VARSIZE", "POCKETS", "OUTER", "SUPER_FANCY" ] }, @@ -2176,6 +2185,7 @@ "storage": "3 L", "warmth": 70, "material_thickness": 4, + "valid_mods": [ "steel_padded" ], "environmental_protection": 1, "flags": [ "VARSIZE", "POCKETS", "HOOD", "COLLAR", "OUTER" ] }, @@ -2409,6 +2419,7 @@ "encumbrance": 8, "warmth": 12, "material_thickness": 3, + "//": "Ceramic disks inside block addition of steel plating modification", "flags": [ "STURDY", "OUTER", "NO_REPAIR" ] }, { @@ -2577,6 +2588,7 @@ "storage": "6 L", "warmth": 50, "material_thickness": 3, + "valid_mods": [ "steel_padded" ], "environmental_protection": 1, "flags": [ "VARSIZE", "POCKETS", "OUTER", "WATERPROOF", "RAINPROOF" ] }, @@ -2635,6 +2647,7 @@ "storage": "9 L", "warmth": 10, "material_thickness": 3, + "valid_mods": [ "steel_padded" ], "environmental_protection": 3, "flags": [ "VARSIZE", "POCKETS", "HOOD", "COLLAR", "STURDY", "WATERPROOF", "RAINPROOF", "OUTER" ] }, @@ -2788,6 +2801,7 @@ "encumbrance": 5, "warmth": 25, "material_thickness": 3, + "valid_mods": [ "steel_padded" ], "flags": [ "STURDY" ] }, { @@ -3123,6 +3137,7 @@ "storage": "10 L", "warmth": 15, "material_thickness": 4, + "valid_mods": [ "steel_padded" ], "environmental_protection": 10, "flags": [ "VARSIZE", "WATERPROOF", "POCKETS", "RAINPROOF", "STURDY" ] }, @@ -3165,6 +3180,7 @@ "encumbrance": 15, "warmth": 30, "material_thickness": 5, + "valid_mods": [ "steel_padded" ], "flags": [ "VARSIZE", "STURDY" ] }, { @@ -3225,7 +3241,6 @@ "warmth": 15, "material_thickness": 3, "environmental_protection": 1, - "valid_mods": [ "steel_padded" ], "flags": [ "VARSIZE", "STURDY", "ALLOWS_NATURAL_ATTACKS" ] }, { @@ -4075,6 +4090,7 @@ "storage": "5500 ml", "warmth": 50, "material_thickness": 4, + "valid_mods": [ "steel_padded" ], "environmental_protection": 1, "flags": [ "VARSIZE", "POCKETS", "COLLAR", "OUTER" ] }, @@ -7181,6 +7197,7 @@ "storage": "1 L", "warmth": 80, "material_thickness": 3, + "valid_mods": [ "steel_padded" ], "environmental_protection": 3, "flags": [ "VARSIZE", "POCKETS" ] }, @@ -7259,6 +7276,7 @@ "storage": "3500 ml", "warmth": 15, "material_thickness": 4, + "valid_mods": [ "steel_padded" ], "environmental_protection": 3, "flags": [ "VARSIZE", "POCKETS", "STURDY", "WATERPROOF" ] }, @@ -7281,6 +7299,7 @@ "storage": "2500 ml", "warmth": 50, "material_thickness": 4, + "valid_mods": [ "steel_padded" ], "flags": [ "VARSIZE", "POCKETS", "COLLAR", "OUTER", "FANCY" ] }, { @@ -7838,6 +7857,7 @@ "storage": 8, "warmth": 80, "material_thickness": 5, + "valid_mods": [ "steel_padded" ], "environmental_protection": 3, "flags": [ "VARSIZE", "POCKETS", "HOOD", "COLLAR", "OUTER" ] }, @@ -8021,6 +8041,7 @@ "storage": "6 L", "warmth": 50, "material_thickness": 3, + "valid_mods": [ "steel_padded" ], "environmental_protection": 1, "flags": [ "VARSIZE", "POCKETS", "OUTER", "WATERPROOF", "RAINPROOF" ] }, @@ -8080,6 +8101,7 @@ "storage": "9 L", "warmth": 10, "material_thickness": 3, + "valid_mods": [ "steel_padded" ], "environmental_protection": 3, "flags": [ "VARSIZE", "POCKETS", "HOOD", "COLLAR", "STURDY", "WATERPROOF", "RAINPROOF", "OUTER" ] }, @@ -8126,6 +8148,7 @@ "storage": "6 L", "warmth": 50, "material_thickness": 3, + "valid_mods": [ "steel_padded" ], "environmental_protection": 1, "flags": [ "VARSIZE", "POCKETS", "OUTER" ] }, @@ -8160,8 +8183,8 @@ "storage": "6 L", "warmth": 30, "material_thickness": 3, - "environmental_protection": 1, "valid_mods": [ "steel_padded" ], + "environmental_protection": 1, "flags": [ "VARSIZE", "POCKETS", "OUTER" ] }, { @@ -8185,6 +8208,7 @@ "storage": "9 L", "warmth": 10, "material_thickness": 3, + "valid_mods": [ "steel_padded" ], "environmental_protection": 3, "flags": [ "VARSIZE", "POCKETS", "HOOD", "COLLAR", "STURDY", "WATERPROOF", "RAINPROOF", "OUTER" ] }, @@ -8693,6 +8717,7 @@ "storage": "7 L", "warmth": 15, "material_thickness": 4, + "valid_mods": [ "steel_padded" ], "environmental_protection": 3, "flags": [ "VARSIZE", "WATERPROOF", "POCKETS", "HOOD", "RAINPROOF", "STURDY" ] }, @@ -8738,6 +8763,7 @@ "storage": "5 L", "warmth": 35, "material_thickness": 7, + "valid_mods": [ "steel_padded" ], "environmental_protection": 4, "flags": [ "POCKETS", "STURDY" ] }, @@ -8758,6 +8784,7 @@ "encumbrance": 10, "warmth": 40, "material_thickness": 3, + "valid_mods": [ "steel_padded" ], "flags": [ "VARSIZE" ] }, { @@ -8777,6 +8804,7 @@ "encumbrance": 10, "warmth": 30, "material_thickness": 3, + "valid_mods": [ "steel_padded" ], "flags": [ "VARSIZE" ] }, { @@ -9101,6 +9129,7 @@ "storage": "250 ml", "warmth": 25, "material_thickness": 3, + "valid_mods": [ "steel_padded" ], "environmental_protection": 2, "flags": [ "VARSIZE", "WATERPROOF", "RAINPROOF" ] }, @@ -9145,6 +9174,7 @@ "storage": "6 L", "warmth": 50, "material_thickness": 3, + "valid_mods": [ "steel_padded" ], "environmental_protection": 1, "flags": [ "VARSIZE", "POCKETS", "OUTER" ] }, @@ -9202,6 +9232,7 @@ "storage": "9 L", "warmth": 10, "material_thickness": 3, + "valid_mods": [ "steel_padded" ], "environmental_protection": 3, "flags": [ "VARSIZE", "POCKETS", "HOOD", "COLLAR", "STURDY", "WATERPROOF", "RAINPROOF", "OUTER" ] }, @@ -9654,6 +9685,7 @@ "storage": "3500 ml", "warmth": 50, "material_thickness": 3, + "valid_mods": [ "steel_padded" ], "flags": [ "VARSIZE", "POCKETS", "HOOD", "OUTER", "WATERPROOF" ] }, { @@ -9675,6 +9707,7 @@ "storage": "2500 ml", "warmth": 50, "material_thickness": 3, + "valid_mods": [ "steel_padded" ], "flags": [ "VARSIZE", "POCKETS" ] }, { @@ -9717,6 +9750,7 @@ "storage": "2250 ml", "warmth": 45, "material_thickness": 3, + "valid_mods": [ "steel_padded" ], "flags": [ "VARSIZE", "OUTER", "POCKETS", "HOOD" ] }, { @@ -9760,6 +9794,7 @@ "storage": "6 L", "warmth": 75, "material_thickness": 5, + "valid_mods": [ "steel_padded" ], "environmental_protection": 5, "flags": [ "VARSIZE", "WATERPROOF", "POCKETS", "HOOD", "RAINPROOF", "STURDY" ] }, @@ -9784,6 +9819,7 @@ "storage": "8500 ml", "warmth": 15, "material_thickness": 4, + "valid_mods": [ "steel_padded" ], "environmental_protection": 3, "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "POCKETS", "HOOD", "RAINPROOF", "STURDY" ] }, diff --git a/data/json/items/armor/jewelry.json b/data/json/items/armor/jewelry.json index 1f3e4dd15d8e9..f47be12b3d7ea 100644 --- a/data/json/items/armor/jewelry.json +++ b/data/json/items/armor/jewelry.json @@ -27,7 +27,7 @@ "price_postapoc": 100, "material": [ "wood" ], "symbol": "[", - "looks_like": "earrings", + "looks_like": "gold_ear", "color": "brown" }, { @@ -95,6 +95,104 @@ "encumbrance": 10, "flags": [ "SUPER_FANCY", "SKINTIGHT" ] }, + { + "id": "garnet_dental_grill", + "type": "ARMOR", + "name": "garnet dental grill", + "description": "Fake teeth inlaid with garnets, worn over the teeth. It looks very shiny.", + "weight": "10 g", + "volume": 0, + "price": 30000, + "price_postapoc": 500, + "bashing": 3, + "cutting": 3, + "material": [ "gold", "gemstone" ], + "symbol": "[", + "looks_like": "gold_dental_grill", + "color": "red", + "covers": [ "MOUTH" ], + "encumbrance": 10, + "flags": [ "FANCY", "SKINTIGHT" ] + }, + { + "id": "amethyst_dental_grill", + "type": "ARMOR", + "name": "amethyst dental grill", + "copy-from": "garnet_dental_grill", + "description": "Fake teeth inlaid with amethysts, worn over the teeth. It looks very shiny.", + "color": "blue" + }, + { + "id": "aquamarine_dental_grill", + "type": "ARMOR", + "name": "aquamarine dental grill", + "copy-from": "garnet_dental_grill", + "description": "Fake teeth inlaid with aquamarines, worn over the teeth. It looks very shiny.", + "color": "cyan" + }, + { + "id": "emerald_dental_grill", + "type": "ARMOR", + "name": "emerald dental grill", + "copy-from": "garnet_dental_grill", + "description": "Fake teeth inlaid with emeralds, worn over the teeth. It looks very shiny.", + "color": "green" + }, + { + "id": "alexandrite_dental_grill", + "type": "ARMOR", + "name": "alexandrite dental grill", + "copy-from": "garnet_dental_grill", + "description": "Fake teeth inlaid with alexandrites, worn over the teeth. It looks very shiny.", + "color": "green" + }, + { + "id": "ruby_dental_grill", + "type": "ARMOR", + "name": "ruby dental grill", + "copy-from": "garnet_dental_grill", + "description": "Fake teeth inlaid with rubys, worn over the teeth. It looks very shiny." + }, + { + "id": "peridot_dental_grill", + "type": "ARMOR", + "name": "peridot dental grill", + "copy-from": "garnet_dental_grill", + "description": "Fake teeth inlaid with peridots, worn over the teeth. It looks very shiny.", + "color": "light_green" + }, + { + "id": "sapphire_dental_grill", + "type": "ARMOR", + "name": "sapphire dental grill", + "copy-from": "garnet_dental_grill", + "description": "Fake teeth inlaid with sapphires, worn over the teeth. It looks very shiny.", + "color": "blue" + }, + { + "id": "tourmaline_dental_grill", + "type": "ARMOR", + "name": "tourmaline dental grill", + "copy-from": "garnet_dental_grill", + "description": "Fake teeth inlaid with tourmaline, worn over the teeth. It looks very shiny.", + "color": "light_red" + }, + { + "id": "citrine_dental_grill", + "type": "ARMOR", + "name": "citrine dental grill", + "copy-from": "garnet_dental_grill", + "description": "Fake teeth inlaid with citrines, worn over the teeth. It looks very shiny.", + "color": "yellow" + }, + { + "id": "blue_topaz_dental_grill", + "type": "ARMOR", + "name": "blue_topaz dental grill", + "copy-from": "garnet_dental_grill", + "description": "Fake teeth inlaid with blue topaz, worn over the teeth. It looks very shiny.", + "color": "light_blue" + }, { "id": "diamond_ring", "type": "ARMOR", @@ -171,7 +269,7 @@ "price_postapoc": 50, "material": [ "copper" ], "symbol": "[", - "looks_like": "earrings", + "looks_like": "gold_ear", "color": "brown" }, { @@ -1012,5 +1110,410 @@ "symbol": "s", "color": "dark_gray", "flags": [ "FANCY" ] + }, + { + "id": "diamond_gold_earring", + "copy-from": "garnet_gold_earring", + "type": "ARMOR", + "name": "pair of diamond and gold earrings", + "name_plural": "pairs of diamond and gold earrings", + "description": "A pair of shiny diamond and gold earrings. You can wear it if you like, but it won't provide any effects.", + "price": 13000, + "price_postapoc": 500, + "material": [ "gold", "diamond" ], + "color": "white" + }, + { + "id": "garnet_gold_earring", + "type": "ARMOR", + "name": "pair of garnet and gold earrings", + "name_plural": "pairs of garnet and gold earrings", + "description": "A pair of shiny garnet and gold earrings. You can wear it if you like, but it won't provide any effects.", + "weight": "2700 mg", + "volume": 0, + "price": 10000, + "price_postapoc": 300, + "material": [ "gold", "gemstone" ], + "looks_like": "gold_ear", + "symbol": "[", + "color": "red", + "flags": [ "FANCY" ] + }, + { + "id": "amethyst_gold_earring", + "copy-from": "garnet_gold_earring", + "type": "ARMOR", + "name": "pair of amethyst and gold earrings", + "name_plural": "pairs of amethyst and gold earrings", + "description": "A pair of shiny amethyst and gold earrings. You can wear it if you like, but it won't provide any effects.", + "color": "blue" + }, + { + "id": "aquamarine_gold_earring", + "copy-from": "garnet_gold_earring", + "type": "ARMOR", + "name": "pair of aquamarine and gold earrings", + "name_plural": "pairs of aquamarine and gold earrings", + "description": "A pair of shiny aquamarine and gold earrings. You can wear it if you like, but it won't provide any effects.", + "color": "light_blue" + }, + { + "id": "emerald_gold_earring", + "copy-from": "garnet_gold_earring", + "type": "ARMOR", + "name": "pair of emerald and gold earrings", + "name_plural": "pairs of emerald and gold earrings", + "description": "A pair of shiny emerald and gold earrings. You can wear it if you like, but it won't provide any effects.", + "color": "green" + }, + { + "id": "alexandrite_gold_earring", + "copy-from": "garnet_gold_earring", + "type": "ARMOR", + "name": "pair of alexandrite and gold earrings", + "name_plural": "pairs of alexandrite and gold earrings", + "description": "A pair of shiny alexandrite and gold earrings. You can wear it if you like, but it won't provide any effects.", + "color": "green" + }, + { + "id": "ruby_gold_earring", + "copy-from": "garnet_gold_earring", + "type": "ARMOR", + "name": "pair of ruby and gold earrings", + "name_plural": "pairs of ruby and gold earrings", + "description": "A pair of shiny ruby and gold earrings. You can wear it if you like, but it won't provide any effects." + }, + { + "id": "peridot_gold_earring", + "copy-from": "garnet_gold_earring", + "type": "ARMOR", + "name": "pair of peridot and gold earrings", + "name_plural": "pairs of peridot and gold earrings", + "description": "A pair of shiny peridot and gold earrings. You can wear it if you like, but it won't provide any effects.", + "color": "light_green" + }, + { + "id": "sapphire_gold_earring", + "copy-from": "garnet_gold_earring", + "type": "ARMOR", + "name": "pair of sapphire and gold earrings", + "name_plural": "pairs of sapphire and gold earrings", + "description": "A pair of shiny sapphire and gold earrings. You can wear it if you like, but it won't provide any effects.", + "color": "blue" + }, + { + "id": "tourmaline_gold_earring", + "copy-from": "garnet_gold_earring", + "type": "ARMOR", + "name": "pair of tourmaline and gold earrings", + "name_plural": "pairs of tourmaline and gold earrings", + "description": "A pair of shiny tourmaline and gold earrings. You can wear it if you like, but it won't provide any effects.", + "color": "light_red" + }, + { + "id": "citrine_gold_earring", + "copy-from": "garnet_gold_earring", + "type": "ARMOR", + "name": "pair of citrine and gold earrings", + "name_plural": "pairs of citrine and gold earrings", + "description": "A pair of shiny citrine and gold earrings. You can wear it if you like, but it won't provide any effects.", + "color": "yellow" + }, + { + "id": "blue_topaz_gold_earring", + "copy-from": "garnet_gold_earring", + "type": "ARMOR", + "name": "pair of blue topaz and gold earrings", + "name_plural": "pairs of blue topaz and gold earrings", + "description": "A pair of shiny blue topaz and gold earrings. You can wear it if you like, but it won't provide any effects.", + "color": "light_blue" + }, + { + "id": "opal_gold_earring", + "copy-from": "garnet_gold_earring", + "type": "ARMOR", + "name": "pair of opal and gold earrings", + "name_plural": "pairs of opal and gold earrings", + "description": "A pair of shiny opal and gold earrings. You can wear it if you like, but it won't provide any effects.", + "color": "white" + }, + { + "id": "pearl_gold_earring", + "copy-from": "garnet_gold_earring", + "type": "ARMOR", + "name": "pair of pearl and gold earrings", + "name_plural": "pairs of pearl and gold earrings", + "description": "A pair of shiny pearl and gold earrings. You can wear it if you like, but it won't provide any effects.", + "color": "white" + }, + { + "id": "diamond_silver_earring", + "copy-from": "garnet_silver_earring", + "type": "ARMOR", + "name": "pair of diamond and silver earrings", + "name_plural": "pairs of diamond and silver earrings", + "description": "A pair of shiny diamond and silver earrings. You can wear it if you like, but it won't provide any effects.", + "price": 8000, + "price_postapoc": 200, + "material": [ "silver", "diamond" ], + "color": "white" + }, + { + "id": "garnet_silver_earring", + "type": "ARMOR", + "name": "pair of garnet and silver earrings", + "name_plural": "pairs of garnet and silver earrings", + "description": "A pair of shiny garnet and silver earrings. You can wear it if you like, but it won't provide any effects.", + "weight": "2700 mg", + "volume": 0, + "price": 6000, + "price_postapoc": 100, + "material": [ "silver", "gemstone" ], + "looks_like": "silver_ear", + "symbol": "[", + "color": "red", + "flags": [ "FANCY" ] + }, + { + "id": "amethyst_silver_earring", + "copy-from": "garnet_silver_earring", + "type": "ARMOR", + "name": "pair of amethyst and silver earrings", + "name_plural": "pairs of amethyst and silver earrings", + "description": "A pair of shiny amethyst and silver earrings. You can wear it if you like, but it won't provide any effects.", + "color": "blue" + }, + { + "id": "aquamarine_silver_earring", + "copy-from": "garnet_silver_earring", + "type": "ARMOR", + "name": "pair of aquamarine and silver earrings", + "name_plural": "pairs of aquamarine and silver earrings", + "description": "A pair of shiny aquamarine and silver earrings. You can wear it if you like, but it won't provide any effects.", + "color": "light_blue" + }, + { + "id": "emerald_silver_earring", + "copy-from": "garnet_silver_earring", + "type": "ARMOR", + "name": "pair of emerald and silver earrings", + "name_plural": "pairs of emerald and silver earrings", + "description": "A pair of shiny emerald and silver earrings. You can wear it if you like, but it won't provide any effects.", + "color": "green" + }, + { + "id": "alexandrite_silver_earring", + "copy-from": "garnet_silver_earring", + "type": "ARMOR", + "name": "pair of alexandrite and silver earrings", + "name_plural": "pairs of alexandrite and silver earrings", + "description": "A pair of shiny alexandrite and silver earrings. You can wear it if you like, but it won't provide any effects.", + "color": "green" + }, + { + "id": "ruby_silver_earring", + "copy-from": "garnet_silver_earring", + "type": "ARMOR", + "name": "pair of ruby and silver earrings", + "name_plural": "pairs of ruby and silver earrings", + "description": "A pair of shiny ruby and silver earrings. You can wear it if you like, but it won't provide any effects." + }, + { + "id": "peridot_silver_earring", + "copy-from": "garnet_silver_earring", + "type": "ARMOR", + "name": "pair of peridot and silver earrings", + "name_plural": "pairs of peridot and silver earrings", + "description": "A pair of shiny peridot and silver earrings. You can wear it if you like, but it won't provide any effects.", + "color": "light_green" + }, + { + "id": "sapphire_silver_earring", + "copy-from": "garnet_silver_earring", + "type": "ARMOR", + "name": "pair of sapphire and silver earrings", + "name_plural": "pairs of sapphire and silver earrings", + "description": "A pair of shiny sapphire and silver earrings. You can wear it if you like, but it won't provide any effects.", + "color": "blue" + }, + { + "id": "tourmaline_silver_earring", + "copy-from": "garnet_silver_earring", + "type": "ARMOR", + "name": "pair of tourmaline and silver earrings", + "name_plural": "pairs of tourmaline and silver earrings", + "description": "A pair of shiny tourmaline and silver earrings. You can wear it if you like, but it won't provide any effects.", + "color": "light_red" + }, + { + "id": "citrine_silver_earring", + "copy-from": "garnet_silver_earring", + "type": "ARMOR", + "name": "pair of citrine and silver earrings", + "name_plural": "pairs of citrine and silver earrings", + "description": "A pair of shiny citrine and silver earrings. You can wear it if you like, but it won't provide any effects.", + "color": "yellow" + }, + { + "id": "blue_topaz_silver_earring", + "copy-from": "garnet_silver_earring", + "type": "ARMOR", + "name": "pair of blue topaz and silver earrings", + "name_plural": "pairs of blue topaz and silver earrings", + "description": "A pair of shiny blue topaz and silver earrings. You can wear it if you like, but it won't provide any effects.", + "color": "light_blue" + }, + { + "id": "pearl_silver_earring", + "copy-from": "garnet_silver_earring", + "type": "ARMOR", + "name": "pair of pearl and silver earrings", + "name_plural": "pairs of pearl and silver earrings", + "description": "A pair of shiny pearl and silver earrings. You can wear it if you like, but it won't provide any effects.", + "color": "white" + }, + { + "id": "opal_silver_earring", + "copy-from": "garnet_silver_earring", + "type": "ARMOR", + "name": "pair of opal and silver earrings", + "name_plural": "pairs of opal and silver earrings", + "description": "A pair of shiny opal and silver earrings. You can wear it if you like, but it won't provide any effects.", + "color": "white" + }, + { + "id": "diamond_platinum_earring", + "copy-from": "garnet_platinum_earring", + "type": "ARMOR", + "name": "pair of diamond and platinum earrings", + "name_plural": "pairs of diamond and platinum earrings", + "description": "A pair of shiny diamond and platinum earrings. You can wear it if you like, but it won't provide any effects.", + "price": 12000, + "price_postapoc": 2900, + "material": [ "platinum", "diamond" ], + "color": "white" + }, + { + "id": "garnet_platinum_earring", + "type": "ARMOR", + "name": "pair of garnet and platinum earrings", + "name_plural": "pairs of garnet and platinum earrings", + "description": "A pair of shiny garnet and platinum earrings. You can wear it if you like, but it won't provide any effects.", + "weight": "2700 mg", + "volume": 0, + "price": 10000, + "price_postapoc": 1800, + "material": [ "platinum", "gemstone" ], + "looks_like": "platinum_ear", + "symbol": "[", + "color": "red", + "flags": [ "FANCY" ] + }, + { + "id": "amethyst_platinum_earring", + "copy-from": "garnet_platinum_earring", + "type": "ARMOR", + "name": "pair of amethyst and platinum earrings", + "name_plural": "pairs of amethyst and platinum earrings", + "description": "A pair of shiny amethyst and platinum earrings. You can wear it if you like, but it won't provide any effects.", + "color": "blue" + }, + { + "id": "aquamarine_platinum_earring", + "copy-from": "garnet_platinum_earring", + "type": "ARMOR", + "name": "pair of aquamarine and platinum earrings", + "name_plural": "pairs of aquamarine and platinum earrings", + "description": "A pair of shiny aquamarine and platinum earrings. You can wear it if you like, but it won't provide any effects.", + "color": "light_blue" + }, + { + "id": "emerald_platinum_earring", + "copy-from": "garnet_platinum_earring", + "type": "ARMOR", + "name": "pair of emerald and platinum earrings", + "name_plural": "pairs of emerald and platinum earrings", + "description": "A pair of shiny emerald and platinum earrings. You can wear it if you like, but it won't provide any effects.", + "color": "green" + }, + { + "id": "alexandrite_platinum_earring", + "copy-from": "garnet_platinum_earring", + "type": "ARMOR", + "name": "pair of alexandrite and platinum earrings", + "name_plural": "pairs of alexandrite and platinum earrings", + "description": "A pair of shiny alexandrite and platinum earrings. You can wear it if you like, but it won't provide any effects.", + "color": "green" + }, + { + "id": "ruby_platinum_earring", + "copy-from": "garnet_platinum_earring", + "type": "ARMOR", + "name": "pair of ruby and platinum earrings", + "name_plural": "pairs of ruby and platinum earrings", + "description": "A pair of shiny ruby and platinum earrings. You can wear it if you like, but it won't provide any effects." + }, + { + "id": "peridot_platinum_earring", + "copy-from": "garnet_platinum_earring", + "type": "ARMOR", + "name": "pair of peridot and platinum earrings", + "name_plural": "pairs of peridot and platinum earrings", + "description": "A pair of shiny peridot and platinum earrings. You can wear it if you like, but it won't provide any effects.", + "color": "light_green" + }, + { + "id": "sapphire_platinum_earring", + "copy-from": "garnet_platinum_earring", + "type": "ARMOR", + "name": "pair of sapphire and platinum earrings", + "name_plural": "pairs of sapphire and platinum earrings", + "description": "A pair of shiny sapphire and platinum earrings. You can wear it if you like, but it won't provide any effects.", + "color": "blue" + }, + { + "id": "tourmaline_platinum_earring", + "copy-from": "garnet_platinum_earring", + "type": "ARMOR", + "name": "pair of tourmaline and platinum earrings", + "name_plural": "pairs of tourmaline and platinum earrings", + "description": "A pair of shiny tourmaline and platinum earrings. You can wear it if you like, but it won't provide any effects.", + "color": "light_red" + }, + { + "id": "citrine_platinum_earring", + "copy-from": "garnet_platinum_earring", + "type": "ARMOR", + "name": "pair of citrine and platinum earrings", + "name_plural": "pairs of citrine and platinum earrings", + "description": "A pair of shiny citrine and platinum earrings. You can wear it if you like, but it won't provide any effects.", + "color": "yellow" + }, + { + "id": "blue_topaz_platinum_earring", + "copy-from": "garnet_platinum_earring", + "type": "ARMOR", + "name": "pair of blue topaz and platinum earrings", + "name_plural": "pairs of blue topaz and platinum earrings", + "description": "A pair of shiny blue topaz and platinum earrings. You can wear it if you like, but it won't provide any effects.", + "color": "light_blue" + }, + { + "id": "opal_platinum_earring", + "copy-from": "garnet_platinum_earring", + "type": "ARMOR", + "name": "pair of opal and platinum earrings", + "name_plural": "pairs of opal and platinum earrings", + "description": "A pair of shiny opal and platinum earrings. You can wear it if you like, but it won't provide any effects.", + "color": "white" + }, + { + "id": "pearl_platinum_earring", + "copy-from": "garnet_platinum_earring", + "type": "ARMOR", + "name": "pair of pearl and platinum earrings", + "name_plural": "pairs of pearl and platinum earrings", + "description": "A pair of shiny pearl and platinum earrings. You can wear it if you like, but it won't provide any effects.", + "color": "white" } ] diff --git a/data/json/items/book/misc.json b/data/json/items/book/misc.json index 626e171e2dd21..2910271ea11b2 100644 --- a/data/json/items/book/misc.json +++ b/data/json/items/book/misc.json @@ -117,7 +117,84 @@ "intelligence": 6, "time": "18 m", "chapters": 24, - "fun": 3 + "fun": 3, + "//": "The ids below represent the Aarne-Thompson System of folklore classification. Do not change.", + "snippet_category": [ + { + "id": "fairyat_41", + "text": "This fairy tale is about a wolf who eats so much salted meat she becomes trapped in the butcher's cellar." + }, + { + "id": "fairyat_50", + "text": "In this traditional story of beastly intrigue a clever fox convinces an elderly lion to kill a derogatory wolf." + }, + { + "id": "fairyat_111", + "text": "This is an illustrated fairy tale book about a conversation between a mouse and a cat." + }, + { + "id": "fairyat_171", + "text": "An amusing collection of stories featuring \"Goldilocks and The Three Bears\" on the cover." + }, + { + "id": "fairyat_222", + "text": "This is a well illustrated fairy tale about a war between the birds and the beasts, with particulars on the wartime conduct and eventual fate of the bat." + }, + { + "id": "fairyat_285", + "text": "This book, titled \"The Rattlesnake's Vengeance\" is a collection of Cherokee myths and legends. \"285D\" is hand-written in pencil on the title page." + }, + { "id": "fairyat_328", "text": "This fairy tale book is a regional variant of \"Jack and the Beanstalk.\"" }, + { + "id": "fairyat_333", + "text": "This fairy tale book is entitled \"Little Red Cap\". It details a red-cloaked child's various encounters with talking wolves." + }, + { + "id": "fairyat_366", + "text": "A collection of ghost stories warning about the dangers of stealing from the dead." + }, + { + "id": "fairyat_408", + "text": "A book of Italian fairy tales translated in English. The cover features an orange fairy juggling a lemon, a lime, and a tangerine." + }, + { "id": "fairyat_451", "text": "A book of fables about people who change into birds." }, + { + "id": "fairyat_475", + "text": "This compendium of amusing folk tales about the devil is titled \"Hell's Kettle: Legends of the Devil.\"" + }, + { + "id": "fairyat_530", + "text": "This charming book of Swedish fables is titled, \"The Glass Mountain and the Princess.\"" + }, + { + "id": "fairyat_555", + "text": "This is a collection of fairy tale stories warning against the consequences of extreme greed." + }, + { "id": "fairyat_591", "text": "This book is titled, \"The Thieving Pot: Folktales of the Arab World.\"" }, + { "id": "fairyat_653", "text": "This is a book of legends collected by Traveller Johnny Cassidy in the 1960s." }, + { "id": "fairyat_758", "text": "A book by the Brothers Grimm titled, \"Eve's Unequal Children.\"" }, + { "id": "fairyat_766", "text": "This book of fables expands upon the legend of the Seven Sleepers of Ephesus." }, + { + "id": "fairyat_1060", + "text": "In this fairy tale a strong man frightens an ogre by squeezing water out of a stone." + }, + { + "id": "fairyat_1084", + "text": "This book of rustic folk tales bears the title: \"How to Shout Down the Devil.\"" + }, + { + "id": "fairyat_1287", + "text": "The title of this book is \"Village Folk-tales of Ceylon.\" It includes fables about logical errors and foolish misjudgements of the Kadambawa men." + }, + { + "id": "fairyat_1461", + "text": "This book of folk tales is titled, \"The Girl with the Ugly Name, and Other Stories.\"" + }, + { + "id": "fairyat_2025", + "text": "Titled \"The Fleeing Pancake\", this collection of silly folk tales is suitable for small children." + } + ] }, { "id": "guidebook", diff --git a/data/json/items/generic.json b/data/json/items/generic.json index aa79018eea7e0..4928f42018dfa 100644 --- a/data/json/items/generic.json +++ b/data/json/items/generic.json @@ -2127,10 +2127,120 @@ "price": 1000000, "price_postapoc": 100, "material": "diamond", - "weight": "120 g", - "volume": "250 ml", + "weight": "200 mg", + "volume": "6 ml", + "to_hit": -5 + }, + { + "type": "GENERIC", + "id": "garnet", + "symbol": "*", + "color": "red", + "name": "garnet", + "description": "A sparkling garnet.", + "price": 800000, + "price_postapoc": 80, + "material": "gemstone", + "weight": "200 mg", + "volume": "6 ml", "to_hit": -5 }, + { + "type": "GENERIC", + "id": "amethyst", + "copy-from": "garnet", + "color": "blue", + "name": "amethyst", + "description": "A sparkling amethyst." + }, + { + "type": "GENERIC", + "id": "aquamarine", + "copy-from": "garnet", + "color": "cyan", + "name": "aquamarine", + "description": "A sparkling aquamarine." + }, + { + "type": "GENERIC", + "id": "emerald", + "copy-from": "garnet", + "color": "green", + "name": "emerald", + "description": "A sparkling emerald." + }, + { + "type": "GENERIC", + "id": "alexandrite", + "copy-from": "garnet", + "color": "green", + "name": "alexandrite", + "description": "A sparkling alexandrite." + }, + { + "type": "GENERIC", + "id": "pearl", + "copy-from": "garnet", + "color": "white", + "name": "pearl", + "description": "A lustrous pearl." + }, + { + "type": "GENERIC", + "id": "ruby", + "copy-from": "garnet", + "color": "red", + "name": "ruby", + "description": "A sparkling ruby." + }, + { + "type": "GENERIC", + "id": "peridot", + "copy-from": "garnet", + "color": "green", + "name": "peridot", + "description": "A sparkling peridot." + }, + { + "type": "GENERIC", + "id": "sapphire", + "copy-from": "garnet", + "color": "blue", + "name": "sapphire", + "description": "A sparkling sapphire." + }, + { + "type": "GENERIC", + "id": "opal", + "copy-from": "garnet", + "color": "white", + "name": "opal", + "description": "A lustrous opal." + }, + { + "type": "GENERIC", + "id": "tourmaline", + "copy-from": "garnet", + "color": "light_red", + "name": "tourmaline", + "description": "A sparkling tourmaline." + }, + { + "type": "GENERIC", + "id": "citrine", + "copy-from": "garnet", + "color": "yellow", + "name": "citrine", + "description": "A sparkling citrine." + }, + { + "type": "GENERIC", + "id": "blue_topaz", + "copy-from": "garnet", + "color": "light_blue", + "name": "topaz", + "description": "A sparkling blue topaz." + }, { "type": "GENERIC", "id": "cured_hide", diff --git a/data/json/mapgen/map_extras/wilderness.json b/data/json/mapgen/map_extras/wilderness.json index 25c63ed69f8f9..1c09726ef2364 100644 --- a/data/json/mapgen/map_extras/wilderness.json +++ b/data/json/mapgen/map_extras/wilderness.json @@ -10,10 +10,10 @@ "|": [ "t_region_groundcover", [ "t_grass_long", 10 ] ] }, "furniture": { - ".": [ [ "f_null", 200 ], [ "f_region_weed", 7 ], [ "f_boulder_small", 2 ], "f_boulder_medium", "f_boulder_large" ], - ",": [ [ "f_null", 200 ], [ "f_region_weed", 8 ], [ "f_boulder_small", 2 ], "f_boulder_medium", "f_boulder_large" ], - ";": [ [ "f_null", 200 ], [ "f_region_weed", 9 ], [ "f_boulder_small", 2 ], "f_boulder_medium", "f_boulder_large" ], - "|": [ [ "f_null", 200 ], [ "f_region_weed", 10 ], [ "f_boulder_small", 2 ], "f_boulder_medium", "f_boulder_large" ] + ".": [ [ "f_null", 2000 ], [ "f_region_weed", 20 ], [ "f_boulder_small", 6 ], "f_boulder_medium", "f_boulder_large" ], + ",": [ [ "f_null", 2000 ], [ "f_region_weed", 40 ], [ "f_boulder_small", 6 ], "f_boulder_medium", "f_boulder_large" ], + ";": [ [ "f_null", 2000 ], [ "f_region_weed", 50 ], [ "f_boulder_small", 6 ], "f_boulder_medium", "f_boulder_large" ], + "|": [ [ "f_null", 2000 ], [ "f_region_weed", 60 ], [ "f_boulder_small", 6 ], "f_boulder_medium", "f_boulder_large" ] } }, { @@ -27,9 +27,9 @@ "|": [ [ "t_region_groundcover_forest", 7 ], "t_water_sh" ] }, "furniture": { - ".": [ [ "f_null", 200 ], [ "f_region_weed", 7 ] ], - ",": [ [ "f_null", 200 ], [ "f_region_weed", 8 ] ], - ";": [ [ "f_null", 200 ], [ "f_region_weed", 10 ] ] + ".": [ [ "f_null", 2000 ], [ "f_region_weed", 20 ], [ "f_boulder_small", 6 ], "f_boulder_medium", "f_boulder_large" ], + ",": [ [ "f_null", 2000 ], [ "f_region_weed", 40 ], [ "f_boulder_small", 6 ], [ "f_boulder_medium", 2 ], "f_boulder_large" ], + ";": [ [ "f_null", 2000 ], [ "f_region_weed", 60 ], [ "f_boulder_small", 6 ], [ "f_boulder_medium", 2 ], "f_boulder_large" ] } }, { diff --git a/data/json/materials.json b/data/json/materials.json index e08a228dbaf48..3d3c62ff3727b 100644 --- a/data/json/materials.json +++ b/data/json/materials.json @@ -276,6 +276,24 @@ "bash_dmg_verb": "chipped", "cut_dmg_verb": "scratched" }, + { + "type": "material", + "ident": "gemstone", + "name": "Gemstone", + "density": 14, + "specific_heat_liquid": 0.52, + "specific_heat_solid": 0.52, + "latent_heat": 5200, + "bash_resist": 14, + "cut_resist": 20, + "acid_resist": 10, + "fire_resist": 3, + "elec_resist": 3, + "chip_resist": 100, + "dmg_adj": [ "marked", "chipped", "cracked", "shattered" ], + "bash_dmg_verb": "chipped", + "cut_dmg_verb": "scratched" + }, { "type": "material", "ident": "egg", diff --git a/data/json/monsters/mammal.json b/data/json/monsters/mammal.json index 6bfe9815f3bf2..99007c03d5e7e 100644 --- a/data/json/monsters/mammal.json +++ b/data/json/monsters/mammal.json @@ -1697,10 +1697,11 @@ "morale": -7, "melee_cut": 0, "dodge": 6, + "reproduction": { "baby_monster": "mon_rabbit", "baby_count": 3, "baby_timer": 55 }, "harvest": "mammal_small_fur", "fear_triggers": [ "SOUND", "PLAYER_CLOSE" ], "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM" ] + "flags": [ "SEES", "HEARS", "SMELLS", "ANIMAL", "PATH_AVOID_DANGER_1", "CATTLEFODDER", "PET_WONT_FOLLOW", "WARM" ] }, { "id": "mon_raccoon", diff --git a/data/json/npcs/classes.json b/data/json/npcs/classes.json index 275401f058bca..b3e991bbb5910 100644 --- a/data/json/npcs/classes.json +++ b/data/json/npcs/classes.json @@ -210,7 +210,8 @@ "traits": [ { "group": "BG_survival_story_CRIMINAL" }, { "group": "NPC_starting_traits" }, - { "group": "Appearance_demographics" } + { "group": "Appearance_demographics" }, + [ "FELINE_EARS", 100 ] ], "bonus_dex": { "rng": [ -2, 0 ] }, "bonus_int": { "rng": [ -2, 0 ] }, diff --git a/data/json/recipes/recipe_electronics.json b/data/json/recipes/recipe_electronics.json index 79ead961b9f6a..81a9cb9088491 100644 --- a/data/json/recipes/recipe_electronics.json +++ b/data/json/recipes/recipe_electronics.json @@ -1896,6 +1896,36 @@ [ [ "turret_chassis", 1 ] ] ] }, + { + "type": "recipe", + "result": "bot_turret_searchlight", + "category": "CC_ELECTRONIC", + "subcategory": "CSC_ELECTRONIC_OTHER", + "skill_used": "electronics", + "skills_required": [ [ "mechanics", 4 ], [ "computer", 2 ] ], + "reversible": true, + "decomp_learn": 5, + "book_learn": [ [ "schematics_searchlight", 7 ] ], + "difficulty": 3, + "time": "1 h 15 m", + "using": [ [ "soldering_standard", 10 ] ], + "qualities": [ + { "id": "SCREW", "level": 1 }, + { "id": "SCREW_FINE", "level": 1 }, + { "id": "WRENCH", "level": 2 }, + { "id": "WRENCH_FINE", "level": 1 } + ], + "components": [ + [ [ "ai_module_basic", 1 ] ], + [ [ "identification_module", 1 ] ], + [ [ "sensor_module", 1 ] ], + [ [ "targeting_module", 1 ] ], + [ [ "medium_storage_battery", 3 ] ], + [ [ "power_supply", 1 ] ], + [ [ "floodlight", 1 ] ], + [ [ "turret_chassis", 1 ] ] + ] + }, { "type": "recipe", "result": "control_laptop", diff --git a/data/json/regional_map_settings.json b/data/json/regional_map_settings.json index 5b4f1cea42e3d..b958b7ac3dc94 100644 --- a/data/json/regional_map_settings.json +++ b/data/json/regional_map_settings.json @@ -438,7 +438,7 @@ } }, "field": { - "chance": 3, + "chance": 6, "extras": { "mx_helicopter": 6, "mx_military": 2, @@ -449,12 +449,12 @@ "mx_portal": 1, "mx_crater": 15, "mx_portal_in": 1, - "mx_point_dead_vegetation": 100, - "mx_grass": 600, - "mx_trees": 200, - "mx_fallen_shed": 150, - "mx_pond": 120, - "mx_point_burned_ground": 100, + "mx_point_dead_vegetation": 50, + "mx_grass": 700, + "mx_trees": 100, + "mx_fallen_shed": 20, + "mx_pond": 20, + "mx_point_burned_ground": 50, "mx_casings": 20, "mx_corpses": 3 } diff --git a/data/mods/Magiclysm/Spells/animist.json b/data/mods/Magiclysm/Spells/animist.json index 59a496a6208a0..cb25a76bded04 100644 --- a/data/mods/Magiclysm/Spells/animist.json +++ b/data/mods/Magiclysm/Spells/animist.json @@ -57,7 +57,7 @@ "base_casting_time": 50000, "base_energy_cost": 5000, "energy_increment": 500, - "flags": [ "SOMATIC", "VERBAL" ], + "flags": [ "SOMATIC", "VERBAL", "PAIN_NORESIST" ], "final_energy_cost": 10000 }, { diff --git a/data/mods/Magiclysm/worldgen/regional_overlay.json b/data/mods/Magiclysm/worldgen/regional_overlay.json index ca57b13045260..867da6b6052af 100644 --- a/data/mods/Magiclysm/worldgen/regional_overlay.json +++ b/data/mods/Magiclysm/worldgen/regional_overlay.json @@ -4,6 +4,6 @@ "//id": "magiclysm_buildings_overlay", "regions": [ "all" ], "city": { "shops": { "magic_shop": 100, "used_bookstore": 225 }, "basements": { "magic_basement": 50 } }, - "field_coverage": { "other": { "f_glow_boulder": 0.3333 } } + "field_coverage": { "other": { "f_boulder_large": 0.6667, "f_glow_boulder": 0.3333 } } } ] diff --git a/data/mods/No_Fungi/comestibles.json b/data/mods/No_Fungi/comestibles.json index 613eef103274e..e08e4ab404ab7 100644 --- a/data/mods/No_Fungi/comestibles.json +++ b/data/mods/No_Fungi/comestibles.json @@ -4,7 +4,7 @@ "id": "marloss_berry", "name": "berry-shaped anomaly", "name_plural": "berry-shaped anomalies", - "weight": 177, + "weight": "177 g", "color": "pink", "use_action": "BLECH", "comestible_type": "FOOD", @@ -20,7 +20,7 @@ "id": "marloss_seed", "name": "seed-shaped anomaly", "name_plural": "seed-shaped anomalies", - "weight": 177, + "weight": "177 g", "color": "cyan", "use_action": "BLECH", "comestible_type": "FOOD", @@ -35,7 +35,7 @@ "id": "marloss_gel", "name": "gelatin", "name_plural": "marloss gelatin", - "weight": 177, + "weight": "177 g", "color": "yellow", "use_action": "BLECH", "comestible_type": "FOOD", @@ -51,12 +51,12 @@ "id": "mycus_fruit", "name": "fruit-shaped anomaly", "name_plural": "fruit-shaped anomalies", - "weight": 354, + "weight": "354 g", "color": "light_gray", "use_action": "BLECH", "comestible_type": "FOOD", "symbol": "%", - "description": "We do not exist at the moment. Clever little human, no doubt debugging to see this? We will not permit you to join us while we are modded out.", + "description": "We do not exist at the moment. Clever little human, no doubt debugging to see this? We will not permit you to join us while we are modded out.", "material": "fruit", "volume": 1, "charges": 1, diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 2e6518e21efff..f78304f382d1d 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -1015,7 +1015,7 @@ void activity_handlers::butcher_finish( player_activity *act, player *p ) return; } - item_location &target = act->targets.back(); + item_location target = act->targets.back(); // Corpses can disappear (rezzing!), so check for that if( !target || !target->is_corpse() ) { @@ -1130,7 +1130,9 @@ void activity_handlers::butcher_finish( player_activity *act, player *p ) }; // all action types - yields butchery_drops_harvest( &corpse_item, *corpse, *p, roll_butchery, action, roll_drops ); - + // after this point, if there was a liquid handling from the harvest, + // and the liquid handling was interrupted, then the activity was cancelled, + // therefore operations on this activities targets and values may be invalidated. // reveal hidden items / hidden content if( action != F_DRESS && action != SKIN ) { for( auto &content : contents ) { @@ -1156,14 +1158,18 @@ void activity_handlers::butcher_finish( player_activity *act, player *p ) // Remove the target from the map target.remove_item(); - act->targets.pop_back(); + if( !act->targets.empty() ) { + act->targets.pop_back(); + } break; case BUTCHER_FULL: p->add_msg_if_player( m_good, _( "You finish butchering the %s." ), corpse_item.tname() ); // Remove the target from the map target.remove_item(); - act->targets.pop_back(); + if( !act->targets.empty() ) { + act->targets.pop_back(); + } break; case F_DRESS: // partial failure @@ -1220,7 +1226,9 @@ void activity_handlers::butcher_finish( player_activity *act, player *p ) } } - act->targets.pop_back(); + if( !act->targets.empty() ) { + act->targets.pop_back(); + } break; case SKIN: switch( rng( 1, 4 ) ) { @@ -1242,7 +1250,9 @@ void activity_handlers::butcher_finish( player_activity *act, player *p ) break; } corpse_item.set_flag( "SKINNED" ); - act->targets.pop_back(); + if( !act->targets.empty() ) { + act->targets.pop_back(); + } break; case DISMEMBER: switch( rng( 1, 3 ) ) { @@ -1258,14 +1268,18 @@ void activity_handlers::butcher_finish( player_activity *act, player *p ) // Remove the target from the map target.remove_item(); - act->targets.pop_back(); + if( !act->targets.empty() ) { + act->targets.pop_back(); + } break; case DISSECT: p->add_msg_if_player( m_good, _( "You finish dissecting the %s." ), corpse_item.tname() ); // Remove the target from the map target.remove_item(); - act->targets.pop_back(); + if( !act->targets.empty() ) { + act->targets.pop_back(); + } break; } diff --git a/src/artifact.cpp b/src/artifact.cpp index 45d88b054a101..9833c6caccda0 100644 --- a/src/artifact.cpp +++ b/src/artifact.cpp @@ -1165,9 +1165,8 @@ void it_artifact_tool::deserialize( const JsonObject &jo ) // Assumption, perhaps dangerous, that we won't wind up with m1 and m2 and // a materials array in our serialized objects at the same time. if( jo.has_array( "materials" ) ) { - JsonArray jarr = jo.get_array( "materials" ); - for( size_t i = 0; i < jarr.size(); ++i ) { - materials.push_back( material_id( jarr.get_string( i ) ) ); + for( const std::string &id : jo.get_array( "materials" ) ) { + materials.push_back( material_id( id ) ); } } volume = jo.get_int( "volume" ) * units::legacy_volume_factor; @@ -1185,9 +1184,8 @@ void it_artifact_tool::deserialize( const JsonObject &jo ) // Artifacts in older saves store ammo as string. if( jo.has_array( "ammo" ) ) { - JsonArray atypes = jo.get_array( "ammo" ); - for( size_t i = 0; i < atypes.size(); ++i ) { - tool->ammo_id.insert( ammotype( atypes.get_string( i ) ) ); + for( const std::string &id : jo.get_array( "ammo" ) ) { + tool->ammo_id.insert( ammotype( id ) ); } } else if( jo.has_string( "ammo" ) ) { tool->ammo_id.insert( ammotype( jo.get_string( "ammo" ) ) ); @@ -1209,36 +1207,31 @@ void it_artifact_tool::deserialize( const JsonObject &jo ) artifact->charge_req = ACR_NULL; } - JsonArray ja = jo.get_array( "effects_wielded" ); - while( ja.has_more() ) { - artifact->effects_wielded.push_back( static_cast( ja.next_int() ) ); + for( const int entry : jo.get_array( "effects_wielded" ) ) { + artifact->effects_wielded.push_back( static_cast( entry ) ); } - ja = jo.get_array( "effects_activated" ); - while( ja.has_more() ) { - artifact->effects_activated.push_back( static_cast( ja.next_int() ) ); + for( const int entry : jo.get_array( "effects_activated" ) ) { + artifact->effects_activated.push_back( static_cast( entry ) ); } - ja = jo.get_array( "effects_carried" ); - while( ja.has_more() ) { - artifact->effects_carried.push_back( static_cast( ja.next_int() ) ); + for( const int entry : jo.get_array( "effects_carried" ) ) { + artifact->effects_carried.push_back( static_cast( entry ) ); } //Generate any missing dream data (due to e.g. old save) if( !jo.has_array( "dream_unmet" ) ) { artifact->dream_msg_unmet = artifact_dream_data[static_cast( artifact->charge_req )].msg_unmet; } else { - ja = jo.get_array( "dream_unmet" ); - while( ja.has_more() ) { - artifact->dream_msg_unmet.push_back( ja.next_string() ); + for( const std::string &line : jo.get_array( "dream_unmet" ) ) { + artifact->dream_msg_unmet.push_back( line ); } } if( !jo.has_array( "dream_met" ) ) { artifact->dream_msg_met = artifact_dream_data[static_cast( artifact->charge_req )].msg_met; } else { - ja = jo.get_array( "dream_met" ); - while( ja.has_more() ) { - artifact->dream_msg_met.push_back( ja.next_string() ); + for( const std::string &line : jo.get_array( "dream_met" ) ) { + artifact->dream_msg_met.push_back( line ); } } if( jo.has_int( "dream_freq_unmet" ) ) { @@ -1280,9 +1273,8 @@ void it_artifact_armor::deserialize( const JsonObject &jo ) // Assumption, perhaps dangerous, that we won't wind up with m1 and m2 and // a materials array in our serialized objects at the same time. if( jo.has_array( "materials" ) ) { - JsonArray jarr = jo.get_array( "materials" ); - for( size_t i = 0; i < jarr.size(); ++i ) { - materials.push_back( material_id( jarr.get_string( i ) ) ); + for( const std::string &id : jo.get_array( "materials" ) ) { + materials.push_back( material_id( id ) ); } } volume = jo.get_int( "volume" ) * units::legacy_volume_factor; @@ -1303,9 +1295,8 @@ void it_artifact_armor::deserialize( const JsonObject &jo ) armor->storage = jo.get_int( "storage" ) * units::legacy_volume_factor; armor->power_armor = jo.get_bool( "power_armor" ); - JsonArray ja = jo.get_array( "effects_worn" ); - while( ja.has_more() ) { - artifact->effects_worn.push_back( static_cast( ja.next_int() ) ); + for( const int entry : jo.get_array( "effects_worn" ) ) { + artifact->effects_worn.push_back( static_cast( entry ) ); } } diff --git a/src/bionics.cpp b/src/bionics.cpp index 8f583517fd7a5..2940a53f9d2c6 100644 --- a/src/bionics.cpp +++ b/src/bionics.cpp @@ -2308,30 +2308,22 @@ void load_bionic( const JsonObject &jsobj ) jsobj.read( "fuel_options", new_bionic.fuel_opts ); jsobj.read( "fuel_capacity", new_bionic.fuel_capacity ); - JsonArray jsr = jsobj.get_array( "stat_bonus" ); - while( jsr.has_more() ) { - JsonArray ja = jsr.next_array(); + for( JsonArray ja : jsobj.get_array( "stat_bonus" ) ) { new_bionic.stat_bonus.emplace( io::string_to_enum( ja.get_string( 0 ) ), ja.get_int( 1 ) ); } - JsonArray jsar = jsobj.get_array( "encumbrance" ); - while( jsar.has_more() ) { - JsonArray ja = jsar.next_array(); + for( JsonArray ja : jsobj.get_array( "encumbrance" ) ) { new_bionic.encumbrance.emplace( get_body_part_token( ja.get_string( 0 ) ), ja.get_int( 1 ) ); } - JsonArray jsarr = jsobj.get_array( "occupied_bodyparts" ); - while( jsarr.has_more() ) { - JsonArray ja = jsarr.next_array(); + for( JsonArray ja : jsobj.get_array( "occupied_bodyparts" ) ) { new_bionic.occupied_bodyparts.emplace( get_body_part_token( ja.get_string( 0 ) ), ja.get_int( 1 ) ); } - JsonArray json_arr = jsobj.get_array( "env_protec" ); - while( json_arr.has_more() ) { - JsonArray ja = json_arr.next_array(); + for( JsonArray ja : jsobj.get_array( "env_protec" ) ) { new_bionic.env_protec.emplace( get_body_part_token( ja.get_string( 0 ) ), ja.get_int( 1 ) ); } @@ -2529,9 +2521,8 @@ void bionic::deserialize( JsonIn &jsin ) auto_start_threshold = jo.get_float( "auto_start_threshold" ); } if( jo.has_array( "bionic_tags" ) ) { - JsonArray jsar = jo.get_array( "bionic_tags" ); - while( jsar.has_more() ) { - bionic_tags.insert( jsar.next_string() ); + for( const std::string &line : jo.get_array( "bionic_tags" ) ) { + bionic_tags.insert( line ); } } diff --git a/src/cata_tiles.cpp b/src/cata_tiles.cpp index c748b590ef9b4..1d47d43202dcb 100644 --- a/src/cata_tiles.cpp +++ b/src/cata_tiles.cpp @@ -542,9 +542,7 @@ void tileset_loader::load( const std::string &tileset_id, const bool precheck ) config.throw_error( "\"tile_info\" missing" ); } - JsonArray info = config.get_array( "tile_info" ); - while( info.has_more() ) { - JsonObject curr_info = info.next_object(); + for( const JsonObject &curr_info : config.get_array( "tile_info" ) ) { ts.tile_height = curr_info.get_int( "height" ); ts.tile_width = curr_info.get_int( "width" ); tile_iso = curr_info.get_bool( "iso", false ); @@ -581,9 +579,7 @@ void tileset_loader::load( const std::string &tileset_id, const bool precheck ) int num_in_file = 1; if( mod_config_json.test_array() ) { - JsonArray mod_config_array = mod_config_json.get_array(); - while( mod_config_array.has_more() ) { - JsonObject mod_config = mod_config_array.next_object(); + for( const JsonObject &mod_config : mod_config_json.get_array() ) { if( mod_config.get_string( "type" ) == "mod_tileset" ) { if( num_in_file == mts.num_in_file() ) { load_internal( mod_config, tileset_root, img_path ); @@ -628,9 +624,7 @@ void tileset_loader::load_internal( const JsonObject &config, const std::string // new system, several entries // When loading multiple tileset images this defines where // the tiles from the most recently loaded image start from. - JsonArray tiles_new = config.get_array( "tiles-new" ); - while( tiles_new.has_more() ) { - JsonObject tile_part_def = tiles_new.next_object(); + for( const JsonObject &tile_part_def : config.get_array( "tiles-new" ) ) { const std::string tileset_image_path = tileset_root + '/' + tile_part_def.get_string( "file" ); R = -1; G = -1; @@ -728,9 +722,7 @@ void tileset_loader::load_ascii( const JsonObject &config ) if( !config.has_member( "ascii" ) ) { config.throw_error( "\"ascii\" section missing" ); } - JsonArray ascii = config.get_array( "ascii" ); - while( ascii.has_more() ) { - JsonObject entry = ascii.next_object(); + for( const JsonObject &entry : config.get_array( "ascii" ) ) { load_ascii_set( entry ); } } @@ -850,10 +842,7 @@ void tileset_loader::load_tilejson_from_file( const JsonObject &config ) config.throw_error( "\"tiles\" section missing" ); } - JsonArray tiles = config.get_array( "tiles" ); - while( tiles.has_more() ) { - JsonObject entry = tiles.next_object(); - + for( const JsonObject &entry : config.get_array( "tiles" ) ) { std::vector ids; if( entry.has_string( "id" ) ) { ids.push_back( entry.get_string( "id" ) ); @@ -868,9 +857,7 @@ void tileset_loader::load_tilejson_from_file( const JsonObject &config ) int t_h3d = entry.get_int( "height_3d", 0 ); if( t_multi ) { // fetch additional tiles - JsonArray subentries = entry.get_array( "additional_tiles" ); - while( subentries.has_more() ) { - JsonObject subentry = subentries.next_object(); + for( const JsonObject &subentry : entry.get_array( "additional_tiles" ) ) { const std::string s_id = subentry.get_string( "id" ); const std::string m_id = t_id + "_" + s_id; tile_type &curr_subtile = load_tile( subentry, m_id ); @@ -921,8 +908,8 @@ void tileset_loader::load_tile_spritelists( const JsonObject &entry, // create one variation, populate sprite_ids with list of ints if( g_array.test_int() ) { std::vector v; - while( g_array.has_more() ) { - const int sprite_id = g_array.next_int() + sprite_id_offset; + for( const int entry : g_array ) { + const int sprite_id = entry + sprite_id_offset; if( sprite_id >= 0 ) { v.push_back( sprite_id ); } @@ -932,9 +919,8 @@ void tileset_loader::load_tile_spritelists( const JsonObject &entry, // object elements of array indicates variations // create one variation per object else if( g_array.test_object() ) { - while( g_array.has_more() ) { + for( const JsonObject &vo : g_array ) { std::vector v; - JsonObject vo = g_array.next_object(); int weight = vo.get_int( "weight" ); // negative weight is invalid if( weight < 0 ) { @@ -949,9 +935,8 @@ void tileset_loader::load_tile_spritelists( const JsonObject &entry, } // array sprite means rotations else if( vo.has_array( "sprite" ) ) { - JsonArray sprites = vo.get_array( "sprite" ); - while( sprites.has_more() ) { - const int sprite_id = sprites.next_int() + sprite_id_offset; + for( const int entry : vo.get_array( "sprite" ) ) { + const int sprite_id = entry + sprite_id_offset; if( sprite_id >= 0 && sprite_id < size ) { v.push_back( sprite_id ); } else { diff --git a/src/clothing_mod.cpp b/src/clothing_mod.cpp index 51cf5eeea1264..e28f7ad4be378 100644 --- a/src/clothing_mod.cpp +++ b/src/clothing_mod.cpp @@ -64,24 +64,21 @@ void clothing_mod::load( const JsonObject &jo, const std::string & ) mandatory( jo, was_loaded, "destroy_prompt", destroy_prompt ); optional( jo, was_loaded, "restricted", restricted, false ); - JsonArray jarr = jo.get_array( "mod_value" ); - while( jarr.has_more() ) { - JsonObject mv_jo = jarr.next_object(); + for( const JsonObject &mv_jo : jo.get_array( "mod_value" ) ) { mod_value mv; std::string temp_str; mandatory( mv_jo, was_loaded, "type", temp_str ); mv.type = io::string_to_enum( temp_str ); mandatory( mv_jo, was_loaded, "value", mv.value ); optional( mv_jo, was_loaded, "round_up", mv.round_up ); - JsonArray jarr_prop = mv_jo.get_array( "proportion" ); - while( jarr_prop.has_more() ) { - std::string str = jarr_prop.next_string(); + for( const JsonValue &entry : mv_jo.get_array( "proportion" ) ) { + const std::string &str = entry.get_string(); if( str == "thickness" ) { mv.thickness_propotion = true; } else if( str == "coverage" ) { mv.coverage_propotion = true; } else { - jarr_prop.throw_error( R"(Invalid value, valid are: "coverage" and "thickness")" ); + entry.throw_error( R"(Invalid value, valid are: "coverage" and "thickness")" ); } } mod_values.push_back( mv ); diff --git a/src/condition.cpp b/src/condition.cpp index 9925b46a53426..8a196f95fb223 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -894,17 +894,14 @@ conditional_t::conditional_t( const JsonObject &jo ) bool found_sub_member = false; const auto parse_array = []( const JsonObject & jo, const std::string & type ) { std::vector conditionals; - JsonArray ja = jo.get_array( type ); - while( ja.has_more() ) { - if( ja.test_string() ) { - conditional_t type_condition( ja.next_string() ); + for( const JsonValue &entry : jo.get_array( type ) ) { + if( entry.test_string() ) { + conditional_t type_condition( entry.get_string() ); conditionals.emplace_back( type_condition ); - } else if( ja.test_object() ) { - JsonObject cond = ja.next_object(); + } else { + JsonObject cond = entry.get_object(); conditional_t type_condition( cond ); conditionals.emplace_back( type_condition ); - } else { - ja.skip_value(); } } return conditionals; diff --git a/src/construction.cpp b/src/construction.cpp index 32e20794772ec..fbbb405a8ba58 100644 --- a/src/construction.cpp +++ b/src/construction.cpp @@ -1344,9 +1344,7 @@ void load_construction( const JsonObject &jo ) con.description = jo.get_string( "description" ); if( jo.has_member( "required_skills" ) ) { - auto sk = jo.get_array( "required_skills" ); - while( sk.has_more() ) { - auto arr = sk.next_array(); + for( JsonArray arr : jo.get_array( "required_skills" ) ) { con.required_skills[skill_id( arr.get_string( 0 ) )] = arr.get_int( 1 ); } } else { @@ -1371,10 +1369,7 @@ void load_construction( const JsonObject &jo ) if( jo.has_string( "using" ) ) { con.reqs_using = { { requirement_id( jo.get_string( "using" ) ), 1} }; } else if( jo.has_array( "using" ) ) { - auto arr = jo.get_array( "using" ); - - while( arr.has_more() ) { - auto cur = arr.next_array(); + for( JsonArray cur : jo.get_array( "using" ) ) { con.reqs_using.emplace_back( requirement_id( cur.get_string( 0 ) ), cur.get_int( 1 ) ); } } @@ -1403,8 +1398,8 @@ void load_construction( const JsonObject &jo ) con.post_flags = jo.get_tags( "post_flags" ); if( jo.has_member( "byproducts" ) ) { - JsonIn &stream = *jo.get_raw( "byproducts" ); - con.byproduct_item_group = item_group::load_item_group( stream, "collection" ); + con.byproduct_item_group = item_group::load_item_group( jo.get_member( "byproducts" ), + "collection" ); } static const std::map> pre_special_map = {{ diff --git a/src/crafting.cpp b/src/crafting.cpp index 755c32d465ba0..cea5d6c85cd02 100644 --- a/src/crafting.cpp +++ b/src/crafting.cpp @@ -1211,10 +1211,10 @@ void player::complete_craft( item &craft, const tripoint &loc ) if( newit.made_of( LIQUID ) ) { liquid_handler::handle_all_liquid( newit, PICKUP_RANGE ); - } else if( loc == tripoint_zero ) { + } else if( loc == tripoint_zero && can_wield( newit ).success() ) { wield_craft( *this, newit ); } else { - set_item_map_or_vehicle( *this, loc, newit ); + set_item_map_or_vehicle( *this, pos(), newit ); } } diff --git a/src/crafting_gui.cpp b/src/crafting_gui.cpp index c68a233dd21bd..ca4bf9e5d0850 100644 --- a/src/crafting_gui.cpp +++ b/src/crafting_gui.cpp @@ -82,10 +82,8 @@ void load_recipe_category( const JsonObject &jsobj ) const std::string cat_name = get_cat_unprefixed( category ); - craft_subcat_list[category] = std::vector(); - JsonArray subcats = jsobj.get_array( "recipe_subcategories" ); - while( subcats.has_more() ) { - const std::string subcat_id = subcats.next_string(); + craft_subcat_list[category].clear(); + for( const std::string &subcat_id : jsobj.get_array( "recipe_subcategories" ) ) { if( subcat_id.find( "CSC_" + cat_name + "_" ) != 0 && subcat_id != "CSC_ALL" ) { jsobj.throw_error( "Crafting sub-category id has to be prefixed with CSC__" ); } @@ -425,15 +423,16 @@ const recipe *select_crafting_recipe( int &batch_size ) _( "Press to attempt to craft object." ) ); } // Draw borders - for( int i = 1; i < width - 1; ++i ) { // _ + for( int i = 1; i < width - 1; ++i ) { // - mvwputch( w_data, point( i, dataHeight - 1 ), BORDER_COLOR, LINE_OXOX ); } for( int i = 0; i < dataHeight - 1; ++i ) { // | mvwputch( w_data, point( 0, i ), BORDER_COLOR, LINE_XOXO ); mvwputch( w_data, point( width - 1, i ), BORDER_COLOR, LINE_XOXO ); } - mvwputch( w_data, point( 0, dataHeight - 1 ), BORDER_COLOR, LINE_XXOO ); // _| - mvwputch( w_data, point( width - 1, dataHeight - 1 ), BORDER_COLOR, LINE_XOOX ); // |_ + mvwvline( w_iteminfo, point( getmaxx( w_iteminfo ) - 1, 0 ), LINE_XOXO, getmaxy( w_iteminfo ) ); + mvwputch( w_data, point( 0, dataHeight - 1 ), BORDER_COLOR, LINE_XXOO ); // |_ + mvwputch( w_data, point( width - 1, dataHeight - 1 ), BORDER_COLOR, LINE_XOOX ); // _| int recmin = 0, recmax = current.size(); if( recmax > dataLines ) { @@ -1007,9 +1006,15 @@ static void draw_recipe_tabs( const catacurses::window &w, const std::string &ta break; } case FILTERED: + mvwhline( w, point( 0, getmaxy( w ) - 1 ), LINE_OXOX, getmaxx( w ) - 1 ); + mvwputch( w, point( 0, getmaxy( w ) - 1 ), BORDER_COLOR, LINE_OXXO ); // |^ + mvwputch( w, point( getmaxx( w ) - 1, getmaxy( w ) - 1 ), BORDER_COLOR, LINE_OOXX ); // ^| draw_tab( w, 2, _( "Searched" ), true ); break; case BATCH: + mvwhline( w, point( 0, getmaxy( w ) - 1 ), LINE_OXOX, getmaxx( w ) - 1 ); + mvwputch( w, point( 0, getmaxy( w ) - 1 ), BORDER_COLOR, LINE_OXXO ); // |^ + mvwputch( w, point( getmaxx( w ) - 1, getmaxy( w ) - 1 ), BORDER_COLOR, LINE_OOXX ); // ^| draw_tab( w, 2, _( "Batch" ), true ); break; } @@ -1025,17 +1030,17 @@ static void draw_recipe_subtabs( const catacurses::window &w, const std::string int width = getmaxx( w ); for( int i = 0; i < width; i++ ) { if( i == 0 ) { - mvwputch( w, point( i, 2 ), BORDER_COLOR, LINE_XXXO ); + mvwputch( w, point( i, 2 ), BORDER_COLOR, LINE_XXXO ); // |- } else if( i == width ) { // TODO: that is always false! - mvwputch( w, point( i, 2 ), BORDER_COLOR, LINE_XOXX ); + mvwputch( w, point( i, 2 ), BORDER_COLOR, LINE_XOXX ); // -| } else { - mvwputch( w, point( i, 2 ), BORDER_COLOR, LINE_OXOX ); + mvwputch( w, point( i, 2 ), BORDER_COLOR, LINE_OXOX ); // - } } for( int i = 0; i < 3; i++ ) { - mvwputch( w, point( 0, i ), BORDER_COLOR, LINE_XOXO ); // |^ - mvwputch( w, point( width - 1, i ), BORDER_COLOR, LINE_XOXO ); // ^| + mvwputch( w, point( 0, i ), BORDER_COLOR, LINE_XOXO ); // | + mvwputch( w, point( width - 1, i ), BORDER_COLOR, LINE_XOXO ); // | } switch( mode ) { @@ -1055,8 +1060,8 @@ static void draw_recipe_subtabs( const catacurses::window &w, const std::string case BATCH: werase( w ); for( int i = 0; i < 3; i++ ) { - mvwputch( w, point( 0, i ), BORDER_COLOR, LINE_XOXO ); // |^ - mvwputch( w, point( width - 1, i ), BORDER_COLOR, LINE_XOXO ); // ^| + mvwputch( w, point( 0, i ), BORDER_COLOR, LINE_XOXO ); // | + mvwputch( w, point( width - 1, i ), BORDER_COLOR, LINE_XOXO ); // | } break; } diff --git a/src/damage.cpp b/src/damage.cpp index d871128c9a897..1e3dd442ef0a0 100644 --- a/src/damage.cpp +++ b/src/damage.cpp @@ -146,8 +146,7 @@ void damage_instance::deserialize( JsonIn &jsin ) JsonObject jo = jsin.get_object(); damage_units = load_damage_instance( jo ).damage_units; } else if( jsin.test_array() ) { - JsonArray ja = jsin.get_array(); - damage_units = load_damage_instance( ja ).damage_units; + damage_units = load_damage_instance( jsin.get_array() ).damage_units; } else { jsin.error( "Expected object or array for damage_instance" ); } @@ -304,9 +303,7 @@ damage_instance load_damage_instance( const JsonObject &jo ) { damage_instance di; if( jo.has_array( "values" ) ) { - JsonArray jarr = jo.get_array( "values" ); - while( jarr.has_more() ) { - JsonObject curr = jarr.next_object(); + for( const JsonObject &curr : jo.get_array( "values" ) ) { di.damage_units.push_back( load_damage_unit( curr ) ); } } else if( jo.has_string( "damage_type" ) ) { @@ -316,11 +313,10 @@ damage_instance load_damage_instance( const JsonObject &jo ) return di; } -damage_instance load_damage_instance( JsonArray &jarr ) +damage_instance load_damage_instance( const JsonArray &jarr ) { damage_instance di; - while( jarr.has_more() ) { - JsonObject curr = jarr.next_object(); + for( const JsonObject &curr : jarr ) { di.damage_units.push_back( load_damage_unit( curr ) ); } diff --git a/src/damage.h b/src/damage.h index e4ebf3f94bde4..2c63574bb02fa 100644 --- a/src/damage.h +++ b/src/damage.h @@ -111,7 +111,7 @@ std::string name_by_dt( const damage_type &dt ); const skill_id &skill_by_dt( damage_type dt ); damage_instance load_damage_instance( const JsonObject &jo ); -damage_instance load_damage_instance( JsonArray &jarr ); +damage_instance load_damage_instance( const JsonArray &jarr ); resistances load_resistances_instance( const JsonObject &jo ); diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index cae9d6ec93230..85f9f02830f8b 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -150,7 +150,8 @@ enum debug_menu_index { DEBUG_DISPLAY_LIGHTING, DEBUG_DISPLAY_RADIATION, DEBUG_LEARN_SPELLS, - DEBUG_LEVEL_SPELLS + DEBUG_LEVEL_SPELLS, + DEBUG_TEST_MAP_EXTRA_DISTRIBUTION }; class mission_debug @@ -219,6 +220,7 @@ static int info_uilist( bool display_all_entries = true ) { uilist_entry( DEBUG_PRINT_FACTION_INFO, true, 'f', _( "Print faction info to console" ) ) }, { uilist_entry( DEBUG_PRINT_NPC_MAGIC, true, 'M', _( "Print NPC magic info to console" ) ) }, { uilist_entry( DEBUG_TEST_WEATHER, true, 'W', _( "Test weather" ) ) }, + { uilist_entry( DEBUG_TEST_MAP_EXTRA_DISTRIBUTION, true, 'e', _( "Test map extra list" ) ) }, }; uilist_initializer.insert( uilist_initializer.begin(), debug_only_options.begin(), debug_only_options.end() ); @@ -1699,6 +1701,9 @@ void debug() add_msg( m_good, _( "%s is now level %d!" ), spells[action]->name(), spells[action]->get_level() ); break; } + case DEBUG_TEST_MAP_EXTRA_DISTRIBUTION: + MapExtras::debug_spawn_test(); + break; } catacurses::erase(); m.invalidate_map_cache( g->get_levz() ); diff --git a/src/effect.cpp b/src/effect.cpp index de0ab1df9e2b9..78a790962e87c 100644 --- a/src/effect.cpp +++ b/src/effect.cpp @@ -452,9 +452,7 @@ bool effect_type::is_show_in_info() const bool effect_type::load_miss_msgs( const JsonObject &jo, const std::string &member ) { if( jo.has_array( member ) ) { - JsonArray outer = jo.get_array( member ); - while( outer.has_more() ) { - JsonArray inner = outer.next_array(); + for( JsonArray inner : jo.get_array( member ) ) { miss_msgs.push_back( std::make_pair( inner.get_string( 0 ), inner.get_int( 1 ) ) ); } return true; @@ -464,9 +462,7 @@ bool effect_type::load_miss_msgs( const JsonObject &jo, const std::string &membe bool effect_type::load_decay_msgs( const JsonObject &jo, const std::string &member ) { if( jo.has_array( member ) ) { - JsonArray outer = jo.get_array( member ); - while( outer.has_more() ) { - JsonArray inner = outer.next_array(); + for( JsonArray inner : jo.get_array( member ) ) { std::string msg = inner.get_string( 0 ); std::string r = inner.get_string( 1 ); game_message_type rate = m_neutral; @@ -1213,11 +1209,10 @@ void load_effect_type( const JsonObject &jo ) new_etype.id = efftype_id( jo.get_string( "id" ) ); if( jo.has_member( "name" ) ) { - JsonArray jsarr = jo.get_array( "name" ); - while( jsarr.has_more() ) { + for( const JsonValue &entry : jo.get_array( "name" ) ) { translation name; - if( !jsarr.read_next( name ) ) { - jsarr.throw_error( "Error reading effect names" ); + if( !entry.read( name ) ) { + entry.throw_error( "Error reading effect names" ); } new_etype.name.emplace_back( name ); } @@ -1227,17 +1222,15 @@ void load_effect_type( const JsonObject &jo ) new_etype.speed_mod_name = jo.get_string( "speed_name", "" ); if( jo.has_member( "desc" ) ) { - JsonArray jsarr = jo.get_array( "desc" ); - while( jsarr.has_more() ) { - new_etype.desc.push_back( jsarr.next_string() ); + for( const std::string &line : jo.get_array( "desc" ) ) { + new_etype.desc.push_back( line ); } } else { new_etype.desc.push_back( "" ); } if( jo.has_member( "reduced_desc" ) ) { - JsonArray jsarr = jo.get_array( "reduced_desc" ); - while( jsarr.has_more() ) { - new_etype.reduced_desc.push_back( jsarr.next_string() ); + for( const std::string &line : jo.get_array( "reduced_desc" ) ) { + new_etype.reduced_desc.push_back( line ); } } else { new_etype.reduced_desc = new_etype.desc; diff --git a/src/fault.cpp b/src/fault.cpp index 0991520cab024..5ee6719394b79 100644 --- a/src/fault.cpp +++ b/src/fault.cpp @@ -39,9 +39,7 @@ void fault::load_fault( const JsonObject &jo ) mandatory( jo, false, "name", f.name_ ); mandatory( jo, false, "description", f.description_ ); - JsonArray ja_methods = jo.get_array( "mending_methods" ); - while( ja_methods.has_more() ) { - JsonObject jo_method = ja_methods.next_object(); + for( const JsonObject &jo_method : jo.get_array( "mending_methods" ) ) { mending_method m; mandatory( jo_method, false, "id", m.id ); @@ -50,9 +48,7 @@ void fault::load_fault( const JsonObject &jo ) mandatory( jo_method, false, "success_msg", m.success_msg ); mandatory( jo_method, false, "time", m.time ); - JsonArray jo_skills = jo_method.get_array( "skills" ); - while( jo_skills.has_more() ) { - JsonObject jo_skill = jo_skills.next_object(); + for( const JsonObject &jo_skill : jo_method.get_array( "skills" ) ) { skill_id sk_id; mandatory( jo_skill, false, "id", sk_id ); m.skills.emplace( sk_id, jo_skill.get_int( "level" ) ); diff --git a/src/field_type.cpp b/src/field_type.cpp index 3de5c96d72a39..cde0d93f26d4f 100644 --- a/src/field_type.cpp +++ b/src/field_type.cpp @@ -121,14 +121,10 @@ const field_intensity_level &field_type::get_intensity_level( int level ) const void field_type::load( const JsonObject &jo, const std::string & ) { optional( jo, was_loaded, "legacy_enum_id", legacy_enum_id, -1 ); - JsonArray ja = jo.get_array( "intensity_levels" ); - if( !jo.has_array( "intensity_levels" ) || ja.empty() ) { - jo.throw_error( "No intensity levels defined for field type", "id" ); - } - for( size_t i = 0; i < ja.size(); ++i ) { + for( const JsonObject &jao : jo.get_array( "intensity_levels" ) ) { field_intensity_level intensity_level; - field_intensity_level fallback_intensity_level = i > 0 ? intensity_levels[i - 1] : intensity_level; - JsonObject jao = ja.get_object( i ); + field_intensity_level fallback_intensity_level = !intensity_levels.empty() ? intensity_levels.back() + : intensity_level; optional( jao, was_loaded, "name", intensity_level.name, fallback_intensity_level.name ); optional( jao, was_loaded, "sym", intensity_level.symbol, unicode_codepoint_from_symbol_reader, fallback_intensity_level.symbol ); @@ -169,9 +165,7 @@ void field_type::load( const JsonObject &jo, const std::string & ) optional( jao, was_loaded, "convection_temperature_mod", intensity_level.convection_temperature_mod, fallback_intensity_level.convection_temperature_mod ); if( jao.has_array( "effects" ) ) { - JsonArray jae = jao.get_array( "effects" ); - for( size_t j = 0; j < jae.size(); ++j ) { - JsonObject joe = jae.next_object(); + for( const JsonObject &joe : jao.get_array( "effects" ) ) { field_effect fe; mandatory( joe, was_loaded, "effect_id", fe.id ); optional( joe, was_loaded, "min_duration", fe.min_duration ); @@ -199,6 +193,9 @@ void field_type::load( const JsonObject &jo, const std::string & ) fallback_intensity_level.scent_neutralization ); intensity_levels.emplace_back( intensity_level ); } + if( intensity_levels.empty() ) { + jo.throw_error( "No intensity levels defined for field type", "id" ); + } if( jo.has_object( "npc_complain" ) ) { JsonObject joc = jo.get_object( "npc_complain" ); @@ -214,13 +211,10 @@ void field_type::load( const JsonObject &jo, const std::string & ) } JsonObject jid = jo.get_object( "immunity_data" ); - JsonArray jidt = jid.get_array( "traits" ); - while( jidt.has_more() ) { - immunity_data_traits.emplace_back( trait_id( jidt.next_string() ) ); + for( const std::string &id : jid.get_array( "traits" ) ) { + immunity_data_traits.emplace_back( id ); } - JsonArray jidr = jid.get_array( "body_part_env_resistance" ); - while( jidr.has_more() ) { - JsonArray jao = jidr.next_array(); + for( JsonArray jao : jid.get_array( "body_part_env_resistance" ) ) { immunity_data_body_part_env_resistance.emplace_back( std::make_pair( get_body_part_token( jao.get_string( 0 ) ), jao.get_int( 1 ) ) ); } diff --git a/src/handle_action.cpp b/src/handle_action.cpp index f506760ac912c..8718a3b2ce943 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -675,7 +675,7 @@ static void smash() maybe_corpse.get_mtype()->has_flag( MF_REVIVES ) ) { // do activity forever. ACT_PULP stops itself u.assign_activity( activity_id( "ACT_PULP" ), calendar::INDEFINITELY_LONG, 0 ); - u.activity.placement = smashp; + u.activity.placement = g->m.getabs( smashp ); return; // don't smash terrain if we've smashed a corpse } } diff --git a/src/harvest.cpp b/src/harvest.cpp index 4d1db71646bb7..cc29a1e18029f 100644 --- a/src/harvest.cpp +++ b/src/harvest.cpp @@ -85,9 +85,7 @@ const harvest_id &harvest_list::load( const JsonObject &jo, const std::string &s ret.message_ = jo.get_string( "message" ); } - JsonArray jo_entries = jo.get_array( "entries" ); - while( jo_entries.has_more() ) { - JsonObject current_entry = jo_entries.next_object(); + for( const JsonObject ¤t_entry : jo.get_array( "entries" ) ) { ret.entries_.push_back( harvest_entry::load( current_entry, src ) ); } diff --git a/src/input.cpp b/src/input.cpp index 597c1ee9d6819..488752476348a 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -217,11 +217,8 @@ void input_manager::load( const std::string &file_name, bool is_user_preferences actions[action_id].name = action.get_string( "name" ); } - // Iterate over the bindings JSON array - JsonArray bindings = action.get_array( "bindings" ); t_input_event_list events; - while( bindings.has_more() ) { - JsonObject keybinding = bindings.next_object(); + for( const JsonObject &keybinding : action.get_array( "bindings" ) ) { std::string input_method = keybinding.get_string( "input_method" ); input_event new_event; if( input_method == "keyboard" ) { @@ -233,11 +230,8 @@ void input_manager::load( const std::string &file_name, bool is_user_preferences } if( keybinding.has_array( "key" ) ) { - JsonArray keys = keybinding.get_array( "key" ); - while( keys.has_more() ) { - new_event.sequence.push_back( - get_keycode( keys.next_string() ) - ); + for( const std::string &line : keybinding.get_array( "key" ) ) { + new_event.sequence.push_back( get_keycode( line ) ); } } else { // assume string if not array, and throw if not string new_event.sequence.push_back( diff --git a/src/item_factory.cpp b/src/item_factory.cpp index a2562458d6417..8f3c228238ca7 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -77,9 +77,7 @@ static void assign( const JsonObject &jo, const std::string &name, return; } mods.clear(); - JsonArray jarr = jo.get_array( name ); - while( jarr.has_more() ) { - JsonArray curr = jarr.next_array(); + for( JsonArray curr : jo.get_array( name ) ) { mods.emplace( gun_mode_id( curr.get_string( 0 ) ), gun_modifier_data( curr.get_string( 1 ), curr.get_int( 2 ), curr.size() >= 4 ? curr.get_tags( 3 ) : std::set() ) ); } @@ -109,9 +107,8 @@ static bool assign_coverage_from_json( const JsonObject &jo, const std::string & }; if( jo.has_array( key ) ) { - JsonArray arr = jo.get_array( key ); - while( arr.has_more() ) { - parse( arr.next_string() ); + for( const std::string &line : jo.get_array( key ) ) { + parse( line ); } return true; @@ -1409,9 +1406,8 @@ void Item_factory::load( islot_gun &slot, const JsonObject &jo, const std::strin assign( jo, "skill", slot.skill_used, strict ); if( jo.has_array( "ammo" ) ) { slot.ammo.clear(); - JsonArray atypes = jo.get_array( "ammo" ); - for( size_t i = 0; i < atypes.size(); ++i ) { - slot.ammo.insert( ammotype( atypes.get_string( i ) ) ); + for( const std::string &id : jo.get_array( "ammo" ) ) { + slot.ammo.insert( ammotype( id ) ); } } else if( jo.has_string( "ammo" ) ) { slot.ammo.clear(); @@ -1446,9 +1442,7 @@ void Item_factory::load( islot_gun &slot, const JsonObject &jo, const std::strin if( jo.has_array( "valid_mod_locations" ) ) { slot.valid_mod_locations.clear(); - JsonArray jarr = jo.get_array( "valid_mod_locations" ); - while( jarr.has_more() ) { - JsonArray curr = jarr.next_array(); + for( JsonArray curr : jo.get_array( "valid_mod_locations" ) ) { slot.valid_mod_locations.emplace( curr.get_string( 0 ), curr.get_int( 1 ) ); } } @@ -1522,9 +1516,8 @@ void Item_factory::load( islot_tool &slot, const JsonObject &jo, const std::stri bool strict = src == "dda"; if( jo.has_array( "ammo" ) ) { - JsonArray atypes = jo.get_array( "ammo" ); - for( size_t i = 0; i < atypes.size(); ++i ) { - slot.ammo_id.insert( ammotype( atypes.get_string( i ) ) ); + for( const std::string &id : jo.get_array( "ammo" ) ) { + slot.ammo_id.insert( ammotype( id ) ); } } else if( jo.has_string( "ammo" ) ) { slot.ammo_id.insert( ammotype( jo.get_string( "ammo" ) ) ); @@ -1540,16 +1533,17 @@ void Item_factory::load( islot_tool &slot, const JsonObject &jo, const std::stri assign( jo, "sub", slot.subtype, strict ); if( jo.has_array( "rand_charges" ) ) { - JsonArray jarr = jo.get_array( "rand_charges" ); if( jo.has_member( "initial_charges" ) ) { - jarr.throw_error( "You can have a fixed initial amount of charges, or randomized. Not both." ); + jo.throw_error( "You can have a fixed initial amount of charges, or randomized. Not both.", + "rand_charges" ); } - while( jarr.has_more() ) { - slot.rand_charges.push_back( jarr.next_int() ); + 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 - jarr.throw_error( "a rand_charges array with only one entry will be ignored, it needs at least 2 entries!" ); + jo.throw_error( "a rand_charges array with only one entry will be ignored, it needs at least 2 entries!", + "rand_charges" ); } } } @@ -1573,9 +1567,8 @@ void Item_factory::load( islot_mod &slot, const JsonObject &jo, const std::strin bool strict = src == "dda"; if( jo.has_array( "ammo_modifier" ) ) { - JsonArray atypes = jo.get_array( "ammo_modifier" ); - for( size_t i = 0; i < atypes.size(); ++i ) { - slot.ammo_modifier.insert( ammotype( atypes.get_string( i ) ) ); + for( const std::string &id : jo.get_array( "ammo_modifier" ) ) { + slot.ammo_modifier.insert( ammotype( id ) ); } } else if( jo.has_string( "ammo_modifier" ) ) { slot.ammo_modifier.insert( ammotype( jo.get_string( "ammo_modifier" ) ) ); @@ -1593,14 +1586,11 @@ void Item_factory::load( islot_mod &slot, const JsonObject &jo, const std::strin if( !mags.empty() ) { slot.magazine_adaptor.clear(); } - while( mags.has_more() ) { - JsonArray arr = mags.next_array(); - + for( JsonArray arr : mags ) { ammotype ammo( arr.get_string( 0 ) ); // an ammo type (e.g. 9mm) - JsonArray compat = arr.get_array( 1 ); // compatible magazines for this ammo type - - while( compat.has_more() ) { - slot.magazine_adaptor[ ammo ].insert( compat.next_string() ); + // compatible magazines for this ammo type + for( const std::string &line : arr.get_array( 1 ) ) { + slot.magazine_adaptor[ ammo ].insert( line ); } } } @@ -1734,9 +1724,7 @@ void Item_factory::load( islot_comestible &slot, const JsonObject &jo, const std // any specification of vitamins suppresses use of material defaults @see Item_factory::finalize if( jo.has_array( "vitamins" ) ) { - auto vits = jo.get_array( "vitamins" ); - while( vits.has_more() ) { - auto pair = vits.next_array(); + for( JsonArray pair : jo.get_array( "vitamins" ) ) { vitamin_id vit( pair.get_string( 0 ) ); slot.default_nutrition.vitamins[ vit ] = pair.get_int( 1 ); } @@ -1748,9 +1736,7 @@ void Item_factory::load( islot_comestible &slot, const JsonObject &jo, const std slot.default_nutrition.vitamins[ v.first ] += relative.get_int( "vitamins" ); } } else if( relative.has_array( "vitamins" ) ) { - auto vits = relative.get_array( "vitamins" ); - while( vits.has_more() ) { - auto pair = vits.next_array(); + for( JsonArray pair : relative.get_array( "vitamins" ) ) { vitamin_id vit( pair.get_string( 0 ) ); slot.default_nutrition.vitamins[ vit ] += pair.get_int( 1 ); } @@ -1847,9 +1833,7 @@ void Item_factory::load( islot_gunmod &slot, const JsonObject &jo, const std::st assign( jo, "min_str_required_mod", slot.min_str_required_mod ); if( jo.has_array( "add_mod" ) ) { slot.add_mod.clear(); - JsonArray jarr = jo.get_array( "add_mod" ); - while( jarr.has_more() ) { - JsonArray curr = jarr.next_array(); + for( JsonArray curr : jo.get_array( "add_mod" ) ) { slot.add_mod.emplace( curr.get_string( 0 ), curr.get_int( 1 ) ); } } @@ -1870,9 +1854,8 @@ void Item_factory::load( islot_magazine &slot, const JsonObject &jo, const std:: { bool strict = src == "dda"; if( jo.has_array( "ammo_type" ) ) { - JsonArray atypes = jo.get_array( "ammo_type" ); - for( size_t i = 0; i < atypes.size(); ++i ) { - slot.type.insert( ammotype( atypes.get_string( i ) ) ); + for( const std::string &id : jo.get_array( "ammo_type" ) ) { + slot.type.insert( ammotype( id ) ); } } else if( jo.has_string( "ammo_type" ) ) { slot.type.insert( ammotype( jo.get_string( "ammo_type" ) ) ); @@ -2054,8 +2037,7 @@ void Item_factory::load_basic_info( const JsonObject &jo, itype &def, const std: assign( jo, "insulation", def.insulation_factor ); if( jo.has_member( "thrown_damage" ) ) { - JsonArray jarr = jo.get_array( "thrown_damage" ); - def.thrown_damage = load_damage_instance( jarr ); + def.thrown_damage = load_damage_instance( jo.get_array( "thrown_damage" ) ); } else { // TODO: Move to finalization def.thrown_damage.clear(); @@ -2106,10 +2088,7 @@ void Item_factory::load_basic_info( const JsonObject &jo, itype &def, const std: def.magazine_default.clear(); def.magazines.clear(); - JsonArray mags = jo.get_array( "magazines" ); - while( mags.has_more() ) { - JsonArray arr = mags.next_array(); - + for( JsonArray arr : jo.get_array( "magazines" ) ) { ammotype ammo( arr.get_string( 0 ) ); // an ammo type (e.g. 9mm) JsonArray compat = arr.get_array( 1 ); // compatible magazines for this ammo type @@ -2126,8 +2105,7 @@ void Item_factory::load_basic_info( const JsonObject &jo, itype &def, const std: if( !jarr.empty() ) { def.min_skills.clear(); } - while( jarr.has_more() ) { - JsonArray cur = jarr.next_array(); + for( JsonArray cur : jarr ) { const auto sk = skill_id( cur.get_string( 0 ) ); if( !sk.is_valid() ) { jo.throw_error( string_format( "invalid skill: %s", sk.c_str() ), "min_skills" ); @@ -2182,9 +2160,7 @@ void Item_factory::load_basic_info( const JsonObject &jo, itype &def, const std: if( jo.has_member( "conditional_names" ) ) { def.conditional_names.clear(); - JsonArray jarr = jo.get_array( "conditional_names" ); - while( jarr.has_more() ) { - JsonObject curr = jarr.next_object(); + for( const JsonObject &curr : jo.get_array( "conditional_names" ) ) { conditional_name cname; cname.type = curr.get_enum_value( "type" ); cname.condition = curr.get_string( "condition" ); @@ -2229,8 +2205,7 @@ void Item_factory::load_basic_info( const JsonObject &jo, itype &def, const std: // auto-create a category that is unlikely to already be used and put the // snippets in it. def.snippet_category = std::string( "auto:" ) + def.id; - JsonArray jarr = jo.get_array( "snippet_category" ); - SNIPPET.add_snippets_from_json( def.snippet_category, jarr ); + SNIPPET.add_snippets_from_json( def.snippet_category, jo.get_array( "snippet_category" ) ); } else { def.snippet_category = jo.get_string( "snippet_category", "" ); } @@ -2254,9 +2229,8 @@ void Item_factory::load_migration( const JsonObject &jo ) m.id = jo.get_string( "id" ); migrations[ m.id ] = m; } else if( jo.has_array( "id" ) ) { - JsonArray ja = jo.get_array( "id" ); - while( ja.has_more() ) { - m.id = ja.next_string(); + for( const std::string &line : jo.get_array( "id" ) ) { + m.id = line; migrations[ m.id ] = m; } } else { @@ -2301,9 +2275,7 @@ void Item_factory::set_qualities_from_json( const JsonObject &jo, const std::str itype &def ) { if( jo.has_array( member ) ) { - JsonArray jarr = jo.get_array( member ); - while( jarr.has_more() ) { - JsonArray curr = jarr.next_array(); + for( JsonArray curr : jo.get_array( member ) ) { const auto quali = std::pair( quality_id( curr.get_string( 0 ) ), curr.get_int( 1 ) ); if( def.qualities.count( quali.first ) > 0 ) { @@ -2320,9 +2292,7 @@ void Item_factory::set_properties_from_json( const JsonObject &jo, const std::st itype &def ) { if( jo.has_array( member ) ) { - JsonArray jarr = jo.get_array( member ); - while( jarr.has_more() ) { - JsonArray curr = jarr.next_array(); + for( JsonArray curr : jo.get_array( member ) ) { const auto prop = std::pair( curr.get_string( 0 ), curr.get_string( 1 ) ); if( def.properties.count( prop.first ) > 0 ) { curr.throw_error( "Duplicated property", 0 ); @@ -2420,9 +2390,8 @@ bool Item_factory::load_sub_ref( std::unique_ptr &ptr, const Js } else if( name != "contents" ) { obj.throw_error( string_format( "You can't use an array for '%s'", arr_name ) ); } - JsonArray arr = obj.get_array( arr_name ); - while( arr.has_more() ) { - entries.push_back( std::make_pair( arr.next_string(), isgroup ) ); + for( const std::string &line : obj.get_array( arr_name ) ) { + entries.emplace_back( line, isgroup ); } }; get_array( iname, false ); @@ -2474,10 +2443,9 @@ bool Item_factory::load_string( std::vector &vec, const JsonObject std::string temp; if( obj.has_array( name ) ) { - JsonArray arr = obj.get_array( name ); - while( arr.has_more() ) { - result |= arr.read_next( temp ); - vec.push_back( temp ); + for( const std::string &line : obj.get_array( name ) ) { + result |= true; + vec.push_back( line ); } } else if( obj.has_member( name ) ) { result |= obj.read( name, temp ); @@ -2502,8 +2470,7 @@ void Item_factory::add_entry( Item_group &ig, const JsonObject &obj ) jarr = obj.get_array( "distribution" ); } if( gptr ) { - while( jarr.has_more() ) { - JsonObject job2 = jarr.next_object(); + for( const JsonObject &job2 : jarr ) { add_entry( *gptr, job2 ); } ig.add_entry( std::move( gptr ) ); @@ -2548,16 +2515,14 @@ void Item_factory::load_item_group( const JsonObject &jsobj ) load_item_group( jsobj, group_id, subtype ); } -void Item_factory::load_item_group( JsonArray &entries, const Group_tag &group_id, - const bool is_collection, int ammo_chance, - int magazine_chance ) +void Item_factory::load_item_group( const JsonArray &entries, const Group_tag &group_id, + const bool is_collection, const int ammo_chance, const int magazine_chance ) { const auto type = is_collection ? Item_group::G_COLLECTION : Item_group::G_DISTRIBUTION; std::unique_ptr &isd = m_template_groups[group_id]; Item_group *const ig = make_group_or_throw( group_id, isd, type, ammo_chance, magazine_chance ); - while( entries.has_more() ) { - JsonObject subobj = entries.next_object(); + for( const JsonObject &subobj : entries ) { add_entry( *ig, subobj ); } } @@ -2577,13 +2542,12 @@ void Item_factory::load_item_group( const JsonObject &jsobj, const Group_tag &gr jsobj.get_int( "magazine", 0 ) ); if( subtype == "old" ) { - JsonArray items = jsobj.get_array( "items" ); - while( items.has_more() ) { - if( items.test_object() ) { - JsonObject subobj = items.next_object(); + for( const JsonValue &entry : jsobj.get_array( "items" ) ) { + if( entry.test_object() ) { + JsonObject subobj = entry.get_object(); add_entry( *ig, subobj ); } else { - JsonArray pair = items.next_array(); + JsonArray pair = entry.get_array(); ig->add_item_entry( pair.get_string( 0 ), pair.get_int( 1 ) ); } } @@ -2591,36 +2555,32 @@ void Item_factory::load_item_group( const JsonObject &jsobj, const Group_tag &gr } if( jsobj.has_member( "entries" ) ) { - JsonArray items = jsobj.get_array( "entries" ); - while( items.has_more() ) { - JsonObject subobj = items.next_object(); + for( const JsonObject &subobj : jsobj.get_array( "entries" ) ) { add_entry( *ig, subobj ); } } if( jsobj.has_member( "items" ) ) { - JsonArray items = jsobj.get_array( "items" ); - while( items.has_more() ) { - if( items.test_string() ) { - ig->add_item_entry( items.next_string(), 100 ); - } else if( items.test_array() ) { - JsonArray subitem = items.next_array(); + for( const JsonValue &entry : jsobj.get_array( "items" ) ) { + if( entry.test_string() ) { + ig->add_item_entry( entry.get_string(), 100 ); + } else if( entry.test_array() ) { + JsonArray subitem = entry.get_array(); ig->add_item_entry( subitem.get_string( 0 ), subitem.get_int( 1 ) ); } else { - JsonObject subobj = items.next_object(); + JsonObject subobj = entry.get_object(); add_entry( *ig, subobj ); } } } if( jsobj.has_member( "groups" ) ) { - JsonArray items = jsobj.get_array( "groups" ); - while( items.has_more() ) { - if( items.test_string() ) { - ig->add_group_entry( items.next_string(), 100 ); - } else if( items.test_array() ) { - JsonArray subitem = items.next_array(); + for( const JsonValue &entry : jsobj.get_array( "groups" ) ) { + if( entry.test_string() ) { + ig->add_group_entry( entry.get_string(), 100 ); + } else if( entry.test_array() ) { + JsonArray subitem = entry.get_array(); ig->add_group_entry( subitem.get_string( 0 ), subitem.get_int( 1 ) ); } else { - JsonObject subobj = items.next_object(); + JsonObject subobj = entry.get_object(); add_entry( *ig, subobj ); } } @@ -2636,16 +2596,15 @@ void Item_factory::set_use_methods_from_json( const JsonObject &jo, const std::s use_methods.clear(); if( jo.has_array( member ) ) { - JsonArray jarr = jo.get_array( member ); - while( jarr.has_more() ) { - if( jarr.test_string() ) { - std::string type = jarr.next_string(); + for( const JsonValue &entry : jo.get_array( member ) ) { + if( entry.test_string() ) { + std::string type = entry.get_string(); use_methods.emplace( type, usage_from_string( type ) ); - } else if( jarr.test_object() ) { - auto obj = jarr.next_object(); + } else if( entry.test_object() ) { + auto obj = entry.get_object(); use_methods.insert( usage_from_object( obj ) ); } else { - jarr.throw_error( "array element is neither string nor object." ); + entry.throw_error( "array element is neither string nor object." ); } } diff --git a/src/item_factory.h b/src/item_factory.h index 947bdbff6f182..e4c1ba2121369 100644 --- a/src/item_factory.h +++ b/src/item_factory.h @@ -86,7 +86,7 @@ class Item_factory /** * Callback for the init system (@ref DynamicDataLoader), loads an item group definitions. * @param jsobj The json object to load from. - * @throw std::string if the json object contains invalid data. + * @throw JsonError if the json object contains invalid data. */ void load_item_group( const JsonObject &jsobj ); /** @@ -99,7 +99,7 @@ class Item_factory * @param group_id The ident of the item that is to be loaded. * @param subtype The type of the item group, either "collection", "distribution" or "old" * ("old" is a distribution, too). - * @throw std::string if the json object contains invalid data. + * @throw JsonError if the json object contains invalid data. */ void load_item_group( const JsonObject &jsobj, const Group_tag &group_id, const std::string &subtype ); @@ -121,7 +121,7 @@ class Item_factory * Note that each entry in the array has to be a JSON object. The other function above * can also load data from arrays of strings, where the strings are item or group ids. */ - void load_item_group( JsonArray &entries, const Group_tag &group_id, bool is_collection, + void load_item_group( const JsonArray &entries, const Group_tag &group_id, bool is_collection, int ammo_chance, int magazine_chance ); /** * Get the item group object. Returns null if the item group does not exists. @@ -148,7 +148,7 @@ class Item_factory * These function load different instances of itype objects from json. * The loaded item types are stored and can be accessed through @ref find_template. * @param jo The json object to load data from. - * @throw std::string if the json object contains invalid data. + * @throw JsonError if the json object contains invalid data. */ /*@{*/ void load_ammo( const JsonObject &jo, const std::string &src ); diff --git a/src/item_group.cpp b/src/item_group.cpp index 9dbb4421086f5..086ac150471e6 100644 --- a/src/item_group.cpp +++ b/src/item_group.cpp @@ -588,22 +588,22 @@ static Group_tag get_unique_group_id() } } -Group_tag item_group::load_item_group( JsonIn &stream, const std::string &default_subtype ) +Group_tag item_group::load_item_group( const JsonValue &value, const std::string &default_subtype ) { - if( stream.test_string() ) { - return stream.get_string(); - } else if( stream.test_object() ) { + if( value.test_string() ) { + return value.get_string(); + } else if( value.test_object() ) { const Group_tag group = get_unique_group_id(); - JsonObject jo = stream.get_object(); + JsonObject jo = value.get_object(); const std::string subtype = jo.get_string( "subtype", default_subtype ); item_controller->load_item_group( jo, group, subtype ); return group; - } else if( stream.test_array() ) { + } else if( value.test_array() ) { const Group_tag group = get_unique_group_id(); - JsonArray jarr = stream.get_array(); + JsonArray jarr = value.get_array(); // load_item_group needs a bool, invalid subtypes are unexpected and most likely errors // from the caller of this function. if( default_subtype != "collection" && default_subtype != "distribution" ) { @@ -613,7 +613,7 @@ Group_tag item_group::load_item_group( JsonIn &stream, const std::string &defaul return group; } else { - stream.error( "invalid item group, must be string (group id) or object/array (the group data)" ); + value.throw_error( "invalid item group, must be string (group id) or object/array (the group data)" ); // stream.error always throws, this is here to prevent a warning return Group_tag{}; } diff --git a/src/item_group.h b/src/item_group.h index f38f38cdf7cba..7e1c72f74f94e 100644 --- a/src/item_group.h +++ b/src/item_group.h @@ -16,7 +16,7 @@ struct itype; using Item_tag = std::string; using Group_tag = std::string; class JsonObject; -class JsonIn; +class JsonValue; class time_point; namespace item_group @@ -79,23 +79,23 @@ void load_item_group( const JsonObject &jsobj, const Group_tag &group_id, /** * Get an item group id and (optionally) load an inlined item group. * - * If the next value in the JSON stream is string, it's assumed to be an item group id and it's + * If the value is string, it's assumed to be an item group id and it's * returned directly. * - * If the next value is a JSON object, it is loaded as item group. The group will be given a + * If the value is a JSON object, it is loaded as item group. The group will be given a * unique id (if the JSON object contains an id, it is ignored) and that id will be returned. * If the JSON object does not contain a subtype, the given default is used. * - * If the next value is a JSON array, it is loaded as item group: the default_subtype will be + * If the value is a JSON array, it is loaded as item group: the default_subtype will be * used as subtype of the new item group and the array is loaded like the "entries" array of * a item group definition (see format of item groups). * * @param stream Stream to load from * @param default_subtype If an inlined item group is loaded this is used as the default * subtype. It must be either "distribution" or "collection". See @ref Item_group. - * @throw std::string as usual for JSON errors, including invalid input values. + * @throw JsonError as usual for JSON errors, including invalid input values. */ -Group_tag load_item_group( JsonIn &stream, const std::string &default_subtype ); +Group_tag load_item_group( const JsonValue &value, const std::string &default_subtype ); } // namespace item_group /** diff --git a/src/iuse.cpp b/src/iuse.cpp index 2afdf3a168e75..75f14e3a937d7 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -395,10 +395,10 @@ static int alcohol( player &p, const item &it, const int strength ) { // Weaker characters are cheap drunks /** @EFFECT_STR_MAX reduces drunkenness duration */ - time_duration duration = alc_strength( strength, 34_minutes, 68_minutes, - 90_minutes ) - ( alc_strength( strength, 36_seconds, 1_minutes, 72_seconds ) * p.str_max ); + time_duration duration = alc_strength( strength, 22_minutes, 34_minutes, + 45_minutes ) - ( alc_strength( strength, 36_seconds, 1_minutes, 72_seconds ) * p.str_max ); if( p.has_trait( trait_ALCMET ) ) { - duration = alc_strength( strength, 9_minutes, 18_minutes, 25_minutes ) - ( alc_strength( strength, + duration = alc_strength( strength, 6_minutes, 14_minutes, 18_minutes ) - ( alc_strength( strength, 36_seconds, 1_minutes, 1_minutes ) * p.str_max ); // Metabolizing the booze improves the nutritional value; // might not be healthy, and still causes Thirst problems, though @@ -406,9 +406,9 @@ static int alcohol( player &p, const item &it, const int strength ) // Metabolizing it cancels out the depressant p.mod_stim( abs( it.get_comestible() ? it.get_comestible()->stim : 0 ) ); } else if( p.has_trait( trait_TOLERANCE ) ) { - duration -= alc_strength( strength, 12_minutes, 30_minutes, 45_minutes ); + duration -= alc_strength( strength, 9_minutes, 16_minutes, 24_minutes ); } else if( p.has_trait( trait_LIGHTWEIGHT ) ) { - duration += alc_strength( strength, 12_minutes, 30_minutes, 45_minutes ); + duration += alc_strength( strength, 9_minutes, 16_minutes, 24_minutes ); } p.add_effect( effect_drunk, duration ); return it.type->charges_to_use(); @@ -4356,6 +4356,7 @@ int iuse::portable_game( player *p, item *it, bool, const tripoint & ) as_m.entries.emplace_back( 3, true, '3', _( "Sokoban" ) ); as_m.entries.emplace_back( 4, true, '4', _( "Minesweeper" ) ); as_m.entries.emplace_back( 5, true, '5', _( "Lights on!" ) ); + as_m.entries.emplace_back( 6, true, '6', _( "Play anything for a while" ) ); as_m.query(); switch( as_m.ret ) { @@ -4374,6 +4375,9 @@ int iuse::portable_game( player *p, item *it, bool, const tripoint & ) case 5: loaded_software = "lightson_game"; break; + case 6: + loaded_software = "null"; + break; default: //Cancel return 0; @@ -4383,8 +4387,12 @@ int iuse::portable_game( player *p, item *it, bool, const tripoint & ) const int moves = to_moves( 15_minutes ); p->add_msg_if_player( _( "You play on your %s for a while." ), it->tname() ); + if( loaded_software == "null" ) { + p->assign_activity( activity_id( "ACT_GENERIC_GAME" ), to_moves( 1_hours ), -1, + p->get_item_position( it ), "gaming" ); + return it->type->charges_to_use(); + } p->assign_activity( activity_id( "ACT_GAME" ), moves, -1, p->get_item_position( it ), "gaming" ); - std::map game_data; game_data.clear(); int game_score = 0; diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index 2961ca35ef39f..7bc6b7605700a 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -137,9 +137,8 @@ void iuse_transform::load( const JsonObject &obj ) } obj.read( "target_charges", ammo_qty ); if( obj.has_array( "rand_target_charges" ) ) { - JsonArray jarr = obj.get_array( "rand_target_charges" ); - while( jarr.has_more() ) { - random_ammo_qty.push_back( jarr.next_int() ); + for( const int charge : obj.get_array( "rand_target_charges" ) ) { + random_ammo_qty.push_back( charge ); } if( random_ammo_qty.size() < 2 ) { obj.throw_error( "You must specify two or more values to choose between", "rand_target_charges" ); @@ -616,9 +615,7 @@ void consume_drug_iuse::load( const JsonObject &obj ) obj.read( "tools_needed", tools_needed ); if( obj.has_array( "effects" ) ) { - JsonArray jsarr = obj.get_array( "effects" ); - while( jsarr.has_more() ) { - JsonObject e = jsarr.next_object(); + for( const JsonObject &e : obj.get_array( "effects" ) ) { effects.push_back( load_effect_data( e ) ); } } @@ -626,9 +623,7 @@ void consume_drug_iuse::load( const JsonObject &obj ) obj.read( "fields_produced", fields_produced ); obj.read( "moves", moves ); - auto arr = obj.get_array( "vitamins" ); - while( arr.has_more() ) { - auto vit = arr.next_array(); + for( JsonArray vit : obj.get_array( "vitamins" ) ) { auto lo = vit.get_int( 1 ); auto hi = vit.size() >= 3 ? vit.get_int( 2 ) : lo; vitamins.emplace( vitamin_id( vit.get_string( 0 ) ), std::make_pair( lo, hi ) ); @@ -1152,15 +1147,14 @@ void reveal_map_actor::load( const JsonObject &obj ) { radius = obj.get_int( "radius" ); message = obj.get_string( "message" ); - JsonArray jarr = obj.get_array( "terrain" ); std::string ter; ot_match_type ter_match_type; - while( jarr.has_more() ) { - if( jarr.test_string() ) { - ter = jarr.next_string(); + for( const JsonValue &entry : obj.get_array( "terrain" ) ) { + if( entry.test_string() ) { + ter = entry.get_string(); ter_match_type = ot_match_type::contains; } else { - JsonObject jo = jarr.next_object(); + JsonObject jo = entry.get_object(); ter = jo.get_string( "om_terrain" ); ter_match_type = jo.get_enum_value( jo.get_string( "om_terrain_match_type", "CONTAINS" ), ot_match_type::contains ); @@ -2835,9 +2829,8 @@ int ammobelt_actor::use( player &p, item &, bool, const tripoint & ) const void repair_item_actor::load( const JsonObject &obj ) { // Mandatory: - JsonArray jarr = obj.get_array( "materials" ); - while( jarr.has_more() ) { - materials.emplace( jarr.next_string() ); + for( const std::string &line : obj.get_array( "materials" ) ) { + materials.emplace( line ); } // TODO: Make skill non-mandatory while still erroring on invalid skill @@ -3419,9 +3412,7 @@ void heal_actor::load( const JsonObject &obj ) long_action = obj.get_bool( "long_action", false ); if( obj.has_array( "effects" ) ) { - JsonArray jsarr = obj.get_array( "effects" ); - while( jsarr.has_more() ) { - JsonObject e = jsarr.next_object(); + for( const JsonObject &e : obj.get_array( "effects" ) ) { effects.push_back( load_effect_data( e ) ); } } @@ -4475,13 +4466,11 @@ std::unique_ptr weigh_self_actor::clone() const void sew_advanced_actor::load( const JsonObject &obj ) { // Mandatory: - JsonArray jarr = obj.get_array( "materials" ); - while( jarr.has_more() ) { - materials.emplace( jarr.next_string() ); + for( const std::string &line : obj.get_array( "materials" ) ) { + materials.emplace( line ); } - jarr = obj.get_array( "clothing_mods" ); - while( jarr.has_more() ) { - clothing_mods.push_back( clothing_mod_id( jarr.next_string() ) ); + for( const std::string &line : obj.get_array( "clothing_mods" ) ) { + clothing_mods.push_back( clothing_mod_id( line ) ); } // TODO: Make skill non-mandatory while still erroring on invalid skill diff --git a/src/json.cpp b/src/json.cpp index c53fc7276fc5b..02a6592fa97ca 100644 --- a/src/json.cpp +++ b/src/json.cpp @@ -321,20 +321,18 @@ JsonArray JsonObject::get_array( const std::string &name ) const std::vector JsonObject::get_int_array( const std::string &name ) const { - JsonArray ja = get_array( name ); std::vector ret; - while( ja.has_more() ) { - ret.push_back( ja.next_int() ); + for( const int entry : get_array( name ) ) { + ret.push_back( entry ); } return ret; } std::vector JsonObject::get_string_array( const std::string &name ) const { - JsonArray ja = get_array( name ); std::vector ret; - while( ja.has_more() ) { - ret.push_back( ja.next_string() ); + for( const std::string &entry : get_array( name ) ) { + ret.push_back( entry ); } return ret; } @@ -699,9 +697,8 @@ bool JsonArray::has_object( const size_t i ) const void add_array_to_set( std::set &s, const JsonObject &json, const std::string &name ) { - JsonArray jarr = json.get_array( name ); - while( jarr.has_more() ) { - s.insert( jarr.next_string() ); + for( const std::string &line : json.get_array( name ) ) { + s.insert( line ); } } @@ -1888,3 +1885,13 @@ JsonIn &JsonValue::seek() const jsin_.seek( pos_ ); return jsin_; } + +JsonValue JsonObject::get_member( const std::string &name ) const +{ + const auto iter = positions.find( name ); + if( !jsin || iter == positions.end() ) { + throw_error( "requested non-existing member \"" + name + "\"" ); + } + visited_members.insert( name ); + return JsonValue( *jsin, iter->second ); +} diff --git a/src/json.h b/src/json.h index 43b3170287768..259077859d27c 100644 --- a/src/json.h +++ b/src/json.h @@ -35,6 +35,7 @@ class JsonObject; class JsonArray; class JsonSerializer; class JsonDeserializer; +class JsonValue; template class string_id; @@ -836,6 +837,7 @@ class JsonObject [[noreturn]] void throw_error( std::string err, const std::string &name ) const; // seek to a value and return a pointer to the JsonIn (member must exist) JsonIn *get_raw( const std::string &name ) const; + JsonValue get_member( const std::string &name ) const; // values by name // variants with no fallback throw an error if the name is not found. @@ -910,8 +912,6 @@ class JsonObject std::string line_number() const; // for occasional use only }; -class JsonValue; - /* JsonArray * ========= * @@ -1114,6 +1114,25 @@ class JsonValue return seek().read( t ); } + bool test_string() const { + return seek().test_string(); + } + bool test_int() const { + return seek().test_int(); + } + bool test_bool() const { + return seek().test_bool(); + } + bool test_float() const { + return seek().test_float(); + } + bool test_object() const { + return seek().test_object(); + } + bool test_array() const { + return seek().test_array(); + } + void throw_error( const std::string &err ) const { seek().error( err ); } diff --git a/src/magic.cpp b/src/magic.cpp index 19d0a5ace96dc..16bad5b8fbdc2 100644 --- a/src/magic.cpp +++ b/src/magic.cpp @@ -103,6 +103,7 @@ std::string enum_to_string( spell_flag data ) case spell_flag::RANDOM_DURATION: return "RANDOM_DURATION"; case spell_flag::RANDOM_TARGET: return "RANDOM_TARGET"; case spell_flag::MUTATE_TRAIT: return "MUTATE_TRAIT"; + case spell_flag::PAIN_NORESIST: return "PAIN_NORESIST"; case spell_flag::WONDER: return "WONDER"; case spell_flag::LAST: break; } diff --git a/src/magic.h b/src/magic.h index 35d28d6e08526..f8e3b5dcc4ecc 100644 --- a/src/magic.h +++ b/src/magic.h @@ -51,6 +51,7 @@ enum spell_flag { RANDOM_TARGET, // picks a random valid target within your range instead of normal behavior. MUTATE_TRAIT, // overrides the mutate spell_effect to use a specific trait_id instead of a category WONDER, // instead of casting each of the extra_spells, it picks N of them and casts them (where N is std::min( damage(), number_of_spells )) + PAIN_NORESIST, // pain altering spells can't be resisted (like with the deadened trait) LAST }; diff --git a/src/magic_enchantment.cpp b/src/magic_enchantment.cpp index e654109134787..efd7c246167ce 100644 --- a/src/magic_enchantment.cpp +++ b/src/magic_enchantment.cpp @@ -200,16 +200,12 @@ void enchantment::load( const JsonObject &jo, const std::string & ) if( jo.has_object( "intermittent_activation" ) ) { JsonObject jobj = jo.get_object( "intermittent_activation" ); - JsonArray jarray = jo.get_array( "effects" ); - while( jarray.has_more() ) { - JsonObject effect_obj; + for( const JsonObject &effect_obj : jo.get_array( "effects" ) ) { time_duration dur = read_from_json_string( *effect_obj.get_raw( "frequency" ), time_duration::units ); if( effect_obj.has_array( "spell_effects" ) ) { - JsonArray jarray = effect_obj.get_array( "spell_effects" ); - while( jarray.has_more() ) { + for( const JsonObject &fake_spell_obj : effect_obj.get_array( "spell_effects" ) ) { fake_spell fake; - JsonObject fake_spell_obj = jarray.next_object(); fake.load( fake_spell_obj ); add_activation( dur, fake ); } @@ -227,9 +223,7 @@ void enchantment::load( const JsonObject &jo, const std::string & ) "ALWAYS" ) ); if( jo.has_array( "values" ) ) { - JsonArray jarray = jo.get_array( "values" ); - while( jarray.has_more() ) { - JsonObject value_obj = jarray.next_object(); + for( const JsonObject &value_obj : jo.get_array( "values" ) ) { const enchantment::mod value = io::string_to_enum( value_obj.get_string( "value" ) ); const int add = value_obj.get_int( "add", 0 ); const double mult = value_obj.get_float( "multiply", 0.0 ); diff --git a/src/magic_spell_effect.cpp b/src/magic_spell_effect.cpp index 23168b0037f72..496190e6e67bb 100644 --- a/src/magic_spell_effect.cpp +++ b/src/magic_spell_effect.cpp @@ -698,7 +698,11 @@ void spell_effect::recover_energy( const spell &sp, Creature &caster, const trip } } else if( energy_source == "PAIN" ) { // pain is backwards - p->mod_pain_noresist( -healing ); + if( sp.has_flag( PAIN_NORESIST ) ) { + p->mod_pain_noresist( -healing ); + } else { + p->mod_pain( -healing ); + } } else if( energy_source == "HEALTH" ) { p->mod_healthy( healing ); } else { diff --git a/src/magic_ter_fur_transform.cpp b/src/magic_ter_fur_transform.cpp index 0dc1adc256b8d..5099e95bdddae 100644 --- a/src/magic_ter_fur_transform.cpp +++ b/src/magic_ter_fur_transform.cpp @@ -55,13 +55,12 @@ static void load_transform_results( const JsonObject &jsi, const std::string &js list.add( T( jsi.get_string( json_key ) ), 1 ); return; } - JsonArray jarr = jsi.get_array( json_key ); - while( jarr.has_more() ) { - if( jarr.test_array() ) { - JsonArray inner = jarr.next_array(); + for( const JsonValue &entry : jsi.get_array( json_key ) ) { + if( entry.test_array() ) { + JsonArray inner = entry.get_array(); list.add( T( inner.get_string( 0 ) ), inner.get_int( 1 ) ); } else { - list.add( T( jarr.next_string() ), 1 ); + list.add( T( entry.get_string() ), 1 ); } } } diff --git a/src/map.cpp b/src/map.cpp index e705bd8135dcc..bb7a51c724f4e 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -4380,7 +4380,9 @@ void map::process_items( const bool active, map::map_process_func processor, process_items_in_vehicles( *current_submap, pos.z, processor, signal ); } } - for( const tripoint &abs_pos : submaps_with_active_items ) { + // Making a copy, in case the original variable gets modified during `process_items_in_submap` + const std::set submaps_with_active_items_copy = submaps_with_active_items; + for( const tripoint &abs_pos : submaps_with_active_items_copy ) { const tripoint local_pos = abs_pos - abs_sub.xy(); submap *const current_submap = get_submap_at_grid( local_pos ); if( !active || !current_submap->active_items.empty() ) { diff --git a/src/map_extras.cpp b/src/map_extras.cpp index a72fd0f2340ff..600fefc3ff262 100644 --- a/src/map_extras.cpp +++ b/src/map_extras.cpp @@ -2796,6 +2796,55 @@ void check_consistency() extras.check(); } +void debug_spawn_test() +{ + uilist mx_menu; + std::vector mx_names; + for( std::pair ®ion_extra : + region_settings_map["default"].region_extras ) { + mx_menu.addentry( -1, true, -1, region_extra.first ); + mx_names.push_back( region_extra.first ); + } + + mx_menu.text = _( "Test which map extra list?" ); + while( true ) { + mx_menu.query(); + const int index = mx_menu.ret; + if( index >= static_cast( mx_names.size() ) || index < 0 ) { + break; + } + + std::map results; + for( size_t a = 0; a < 32400; a++ ) { + map_extras ex = region_settings_map["default"].region_extras[mx_names[index]]; + if( ex.chance > 0 && one_in( ex.chance ) ) { + std::string *extra = ex.values.pick(); + if( extra == nullptr ) { + results[_( "none" )]++; + } else { + results[*( ex.values.pick() )]++; + } + } else { + results[_( "none" )]++; + } + } + + std::multimap sorted_results; + for( std::pair &e : results ) { + sorted_results.insert( std::pair( e.second, e.first ) ); + } + uilist results_menu; + results_menu.text = _( "Result of 32400 selections:" ); + for( std::pair &r : sorted_results ) { + std::ostringstream buffer; + buffer << r.first << " x " << r.second << "\n"; + results_menu.entries.emplace_back( static_cast( results_menu.entries.size() ), true, -2, + buffer.str() ); + } + results_menu.query(); + } +} + } // namespace MapExtras void map_extra::load( const JsonObject &jo, const std::string & ) diff --git a/src/map_extras.h b/src/map_extras.h index ab05be3b13d9c..a079fa5c33fc9 100644 --- a/src/map_extras.h +++ b/src/map_extras.h @@ -66,6 +66,8 @@ void apply_function( const std::string &id, map &m, const tripoint &abs_sub ); void load( const JsonObject &jo, const std::string &src ); void check_consistency(); +void debug_spawn_test(); + /// This function provides access to all loaded map extras. const generic_factory &mapExtraFactory(); diff --git a/src/mapdata.cpp b/src/mapdata.cpp index 616a16da7ea7e..7cf26bedd0215 100644 --- a/src/mapdata.cpp +++ b/src/mapdata.cpp @@ -239,8 +239,7 @@ bool map_bash_info::load( const JsonObject &jsobj, const std::string &member, bo } if( j.has_member( "items" ) ) { - JsonIn &stream = *j.get_raw( "items" ); - drop_group = item_group::load_item_group( stream, "collection" ); + drop_group = item_group::load_item_group( j.get_member( "items" ), "collection" ); } else { drop_group = "EMPTY_GROUP"; } @@ -270,8 +269,7 @@ bool map_deconstruct_info::load( const JsonObject &jsobj, const std::string &mem can_do = true; deconstruct_above = j.get_bool( "deconstruct_above", false ); - JsonIn &stream = *j.get_raw( "items" ); - drop_group = item_group::load_item_group( stream, "collection" ); + drop_group = item_group::load_item_group( j.get_member( "items" ), "collection" ); return true; } diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 936b58b8d34fe..01d2b47de9e5d 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -577,7 +577,7 @@ int jmapgen_int::get() const * Turn json gobbldigook into machine friendly gobbldigook, for applying * basic map 'set' functions, optionally based on one_in(chance) or repeat value */ -void mapgen_function_json_base::setup_setmap( JsonArray &parray ) +void mapgen_function_json_base::setup_setmap( const JsonArray &parray ) { std::string tmpval; std::map setmap_opmap; @@ -590,8 +590,7 @@ void mapgen_function_json_base::setup_setmap( JsonArray &parray ) jmapgen_setmap_op tmpop; int setmap_optype = 0; - while( parray.has_more() ) { - JsonObject pjo = parray.next_object(); + for( const JsonObject &pjo : parray ) { if( pjo.read( "point", tmpval ) ) { setmap_optype = JMAPGEN_SETMAP_OPTYPE_POINT; } else if( pjo.read( "set", tmpval ) ) { @@ -1165,16 +1164,15 @@ class jmapgen_monster : public jmapgen_piece return; } } else if( jsi.has_array( "monster" ) ) { - JsonArray jarr = jsi.get_array( "monster" ); - while( jarr.has_more() ) { + for( const JsonValue &entry : jsi.get_array( "monster" ) ) { mtype_id id; int weight = 100; - if( jarr.test_array() ) { - JsonArray inner = jarr.next_array(); + if( entry.test_array() ) { + JsonArray inner = entry.get_array(); id = mtype_id( inner.get_string( 0 ) ); weight = inner.get_int( 1 ); } else { - id = mtype_id( jarr.next_string() ); + id = mtype_id( entry.get_string() ); } if( !id.is_valid() ) { set_mapgen_defer( jsi, "monster", "no such monster" ); @@ -1641,13 +1639,12 @@ class jmapgen_zone : public jmapgen_piece static void load_weighted_entries( const JsonObject &jsi, const std::string &json_key, weighted_int_list &list ) { - JsonArray jarr = jsi.get_array( json_key ); - while( jarr.has_more() ) { - if( jarr.test_array() ) { - JsonArray inner = jarr.next_array(); + for( const JsonValue &entry : jsi.get_array( json_key ) ) { + if( entry.test_array() ) { + JsonArray inner = entry.get_array(); list.add( inner.get_string( 0 ), inner.get_int( 1 ) ); } else { - list.add( jarr.next_string(), 100 ); + list.add( entry.get_string(), 100 ); } } } @@ -1883,17 +1880,16 @@ void load_place_mapings_string( const JsonObject &pjo, const std::string &key, } else if( pjo.has_object( key ) ) { load_place_mapings( pjo.get_object( key ), vect ); } else { - JsonArray jarr = pjo.get_array( key ); - while( jarr.has_more() ) { - if( jarr.test_string() ) { + for( const JsonValue &entry : pjo.get_array( key ) ) { + if( entry.test_string() ) { try { - vect.push_back( make_shared_fast( jarr.next_string() ) ); + vect.push_back( make_shared_fast( entry.get_string() ) ); } catch( const std::runtime_error &err ) { // Using the json object here adds nice formatting and context information - jarr.throw_error( err.what() ); + entry.throw_error( err.what() ); } } else { - load_place_mapings( jarr.next_object(), vect ); + load_place_mapings( entry.get_object(), vect ); } } } @@ -1911,21 +1907,20 @@ void load_place_mapings_alternatively( const JsonObject &pjo, const std::string load_place_mapings_string( pjo, key, vect ); } else { auto alter = make_shared_fast< jmapgen_alternativly >(); - JsonArray jarr = pjo.get_array( key ); - while( jarr.has_more() ) { - if( jarr.test_string() ) { + for( const JsonValue &entry : pjo.get_array( key ) ) { + if( entry.test_string() ) { try { - alter->alternatives.emplace_back( jarr.next_string() ); + alter->alternatives.emplace_back( entry.get_string() ); } catch( const std::runtime_error &err ) { // Using the json object here adds nice formatting and context information - jarr.throw_error( err.what() ); + entry.throw_error( err.what() ); } - } else if( jarr.test_object() ) { - JsonObject jsi = jarr.next_object(); + } else if( entry.test_object() ) { + JsonObject jsi = entry.get_object(); alter->alternatives.emplace_back( jsi ); - } else if( jarr.test_array() ) { + } else if( entry.test_array() ) { // If this is an array, it means it is an entry followed by a desired total count of instances. - JsonArray piece_and_count_jarr = jarr.next_array(); + JsonArray piece_and_count_jarr = entry.get_array(); if( piece_and_count_jarr.size() != 2 ) { piece_and_count_jarr.throw_error( "Array must have exactly two entries: the object, then the count." ); } @@ -2308,8 +2303,7 @@ bool mapgen_function_json_base::setup_common( const JsonObject &jo ) } if( jo.has_array( "set" ) ) { - parray = jo.get_array( "set" ); - setup_setmap( parray ); + setup_setmap( jo.get_array( "set" ) ); } // "add" is deprecated in favor of "place_item", but kept to support mods diff --git a/src/mapgen.h b/src/mapgen.h index e21be63201c30..d76980a3cef42 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -290,7 +290,7 @@ class mapgen_function_json_base void setup_common(); bool setup_common( const JsonObject &jo ); - void setup_setmap( JsonArray &parray ); + void setup_setmap( const JsonArray &parray ); // Returns true if the mapgen qualifies at this point already virtual bool setup_internal( const JsonObject &jo ) = 0; virtual void setup_setmap_internal() { } diff --git a/src/mattack_actors.cpp b/src/mattack_actors.cpp index 7114931720c2e..ab1f8bb3704ea 100644 --- a/src/mattack_actors.cpp +++ b/src/mattack_actors.cpp @@ -214,8 +214,7 @@ void melee_actor::load_internal( const JsonObject &obj, const std::string & ) { // Optional: if( obj.has_array( "damage_max_instance" ) ) { - JsonArray arr = obj.get_array( "damage_max_instance" ); - damage_max_instance = load_damage_instance( arr ); + damage_max_instance = load_damage_instance( obj.get_array( "damage_max_instance" ) ); } else if( obj.has_object( "damage_max_instance" ) ) { damage_max_instance = load_damage_instance( obj ); } diff --git a/src/mission.h b/src/mission.h index 15595e6decf56..e8adfb13dc748 100644 --- a/src/mission.h +++ b/src/mission.h @@ -172,7 +172,8 @@ tripoint target_om_ter_random( const std::string &omter, int reveal_rad, mission bool must_see, int range, tripoint loc = overmap::invalid_tripoint ); void set_reveal( const std::string &terrain, std::vector> &funcs ); -void set_reveal_any( JsonArray &ja, std::vector> &funcs ); +void set_reveal_any( const JsonArray &ja, + std::vector> &funcs ); mission_target_params parse_mission_om_target( const JsonObject &jo ); cata::optional assign_mission_target( const mission_target_params ¶ms ); tripoint get_om_terrain_pos( const mission_target_params ¶ms ); diff --git a/src/mission_util.cpp b/src/mission_util.cpp index 19c9308d661bd..105ec3306d78d 100644 --- a/src/mission_util.cpp +++ b/src/mission_util.cpp @@ -423,12 +423,11 @@ void mission_util::set_reveal( const std::string &terrain, funcs.emplace_back( mission_func ); } -void mission_util::set_reveal_any( JsonArray &ja, +void mission_util::set_reveal_any( const JsonArray &ja, std::vector> &funcs ) { std::vector terrains; - while( ja.has_more() ) { - std::string terrain = ja.next_string(); + for( const std::string &terrain : ja ) { terrains.push_back( terrain ); } const auto mission_func = [ terrains ]( mission * miss ) { @@ -486,8 +485,7 @@ bool mission_util::load_funcs( const JsonObject &jo, const std::string target_terrain = jo.get_string( "reveal_om_ter" ); set_reveal( target_terrain, funcs ); } else if( jo.has_array( "reveal_om_ter" ) ) { - JsonArray target_terrain = jo.get_array( "reveal_om_ter" ); - set_reveal_any( target_terrain, funcs ); + set_reveal_any( jo.get_array( "reveal_om_ter" ), funcs ); } else if( jo.has_object( "assign_mission_target" ) ) { JsonObject mission_target = jo.get_object( "assign_mission_target" ); set_assign_om_target( mission_target, funcs ); diff --git a/src/mod_manager.h b/src/mod_manager.h index 5722324fa76ad..d83ce12f037ff 100644 --- a/src/mod_manager.h +++ b/src/mod_manager.h @@ -141,8 +141,7 @@ class mod_manager /** * Load mod info from a json object. Put the loaded modinfo * directly into @ref mod_map. - * @throws std::string on all kind of errors. The string - * contains the error message. + * @throws JsonError on all kind of errors. */ void load_modfile( const JsonObject &jo, const std::string &path ); diff --git a/src/monattack.cpp b/src/monattack.cpp index eb1cc5e891535..5c0af3f8b1283 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -738,6 +738,7 @@ bool mattack::pull_metal_weapon( monster *z ) // Wielded steel or iron items except for built-in things like bionic claws or monomolecular blade if( !foe->weapon.has_flag( "NO_UNWIELD" ) && ( foe->weapon.made_of( material_id( "iron" ) ) || + foe->weapon.made_of( material_id( "hardsteel" ) ) || foe->weapon.made_of( material_id( "steel" ) ) || foe->weapon.made_of( material_id( "budget_steel" ) ) ) ) { int wp_skill = foe->get_skill_level( skill_melee ); @@ -753,6 +754,9 @@ bool mattack::pull_metal_weapon( monster *z ) target->add_msg_player_or_npc( m_type, _( "%s is pulled away from your hands!" ), _( "%s is pulled away from 's hands!" ), foe->weapon.tname() ); z->add_item( foe->remove_weapon() ); + if( foe->has_activity( activity_id( "ACT_RELOAD" ) ) ) { + foe->cancel_activity(); + } } else { target->add_msg_player_or_npc( m_type, _( "The %s unsuccessfully attempts to pull your weapon away." ), diff --git a/src/monstergenerator.cpp b/src/monstergenerator.cpp index 6aebf2d8783ed..a03e930232131 100644 --- a/src/monstergenerator.cpp +++ b/src/monstergenerator.cpp @@ -679,8 +679,7 @@ void mtype::load( const JsonObject &jo, const std::string &src ) // TODO: make this work with `was_loaded` if( jo.has_array( "melee_damage" ) ) { - JsonArray arr = jo.get_array( "melee_damage" ); - melee_damage = load_damage_instance( arr ); + melee_damage = load_damage_instance( jo.get_array( "melee_damage" ) ); } else if( jo.has_object( "melee_damage" ) ) { melee_damage = load_damage_instance( jo ); } @@ -698,8 +697,7 @@ void mtype::load( const JsonObject &jo, const std::string &src ) } if( jo.has_member( "death_drops" ) ) { - JsonIn &stream = *jo.get_raw( "death_drops" ); - death_drops = item_group::load_item_group( stream, "distribution" ); + death_drops = item_group::load_item_group( jo.get_member( "death_drops" ), "distribution" ); } assign( jo, "harvest", harvest ); @@ -1024,14 +1022,13 @@ void mtype::add_special_attacks( const JsonObject &jo, const std::string &member return; } - JsonArray outer = jo.get_array( member ); - while( outer.has_more() ) { - if( outer.test_array() ) { - add_special_attack( outer.next_array(), src ); - } else if( outer.test_object() ) { - add_special_attack( outer.next_object(), src ); + for( const JsonValue &entry : jo.get_array( member ) ) { + if( entry.test_array() ) { + add_special_attack( entry.get_array(), src ); + } else if( entry.test_object() ) { + add_special_attack( entry.get_object(), src ); } else { - outer.throw_error( "array element is neither array nor object." ); + entry.throw_error( "array element is neither array nor object." ); } } } diff --git a/src/mutation.h b/src/mutation.h index 40d27df15ab01..b1a42c201ab32 100644 --- a/src/mutation.h +++ b/src/mutation.h @@ -316,7 +316,7 @@ struct mutation_branch { * Callback for the init system (@ref DynamicDataLoader), loads a trait * group definitions. * @param jsobj The json object to load from. - * @throw std::string if the json object contains invalid data. + * @throw JsonError if the json object contains invalid data. */ static void load_trait_group( const JsonObject &jsobj ); @@ -332,7 +332,7 @@ struct mutation_branch { * @param gid The ID of the group that is to be loaded. * @param subtype The type of the trait group, either "collection", "distribution" or "old" * (i.e. the old list-based format, `[ ["TRAIT", 100] ]`). - * @throw std::string if the json object contains invalid data. + * @throw JsonError if the json object contains invalid data. */ static void load_trait_group( const JsonObject &jsobj, const trait_group::Trait_group_tag &gid, const std::string &subtype ); @@ -355,7 +355,7 @@ struct mutation_branch { * Note that each entry in the array has to be a JSON object. The other function above * can also load data from arrays of strings, where the strings are item or group ids. */ - static void load_trait_group( JsonArray &entries, const trait_group::Trait_group_tag &gid, + static void load_trait_group( const JsonArray &entries, const trait_group::Trait_group_tag &gid, bool is_collection ); /** diff --git a/src/mutation_data.cpp b/src/mutation_data.cpp index 9adbc6a75eaac..8aaf3c4abac5c 100644 --- a/src/mutation_data.cpp +++ b/src/mutation_data.cpp @@ -215,16 +215,14 @@ static mut_attack load_mutation_attack( const JsonObject &jo ) jo.read( "chance", ret.chance ); if( jo.has_array( "base_damage" ) ) { - JsonArray jo_dam = jo.get_array( "base_damage" ); - ret.base_damage = load_damage_instance( jo_dam ); + ret.base_damage = load_damage_instance( jo.get_array( "base_damage" ) ); } else if( jo.has_object( "base_damage" ) ) { JsonObject jo_dam = jo.get_object( "base_damage" ); ret.base_damage = load_damage_instance( jo_dam ); } if( jo.has_array( "strength_damage" ) ) { - JsonArray jo_dam = jo.get_array( "strength_damage" ); - ret.strength_damage = load_damage_instance( jo_dam ); + ret.strength_damage = load_damage_instance( jo.get_array( "strength_damage" ) ); } else if( jo.has_object( "strength_damage" ) ) { JsonObject jo_dam = jo.get_object( "strength_damage" ); ret.strength_damage = load_damage_instance( jo_dam ); @@ -639,21 +637,21 @@ static Trait_group &make_group_or_throw( const trait_group::Trait_group_tag &gid return *found->second; } -void mutation_branch::load_trait_group( JsonArray &entries, const trait_group::Trait_group_tag &gid, - const bool is_collection ) +void mutation_branch::load_trait_group( const JsonArray &entries, + const trait_group::Trait_group_tag &gid, const bool is_collection ) { Trait_group &tg = make_group_or_throw( gid, is_collection ); - while( entries.has_more() ) { + for( const JsonValue &entry : entries ) { // Backwards-compatibility with old format ["TRAIT", 100] - if( entries.test_array() ) { - JsonArray subarr = entries.next_array(); + if( entry.test_array() ) { + JsonArray subarr = entry.get_array(); trait_id id( subarr.get_string( 0 ) ); tg.add_entry( std::make_unique( id, subarr.get_int( 1 ) ) ); // Otherwise load new format {"trait": ... } or {"group": ...} } else { - JsonObject subobj = entries.next_object(); + JsonObject subobj = entry.get_object(); add_entry( tg, subobj ); } } @@ -684,29 +682,28 @@ void mutation_branch::load_trait_group( const JsonObject &jsobj, } } if( jsobj.has_member( "traits" ) ) { - JsonArray traits = jsobj.get_array( "traits" ); - while( traits.has_more() ) { - if( traits.test_string() ) { - tg.add_trait_entry( trait_id( traits.next_string() ), 100 ); - } else if( traits.test_array() ) { - JsonArray subtrait = traits.next_array(); + for( const JsonValue &entry : jsobj.get_array( "traits" ) ) { + if( entry.test_string() ) { + tg.add_trait_entry( trait_id( entry.get_string() ), 100 ); + } else if( entry.test_array() ) { + JsonArray subtrait = entry.get_array(); tg.add_trait_entry( trait_id( subtrait.get_string( 0 ) ), subtrait.get_int( 1 ) ); } else { - JsonObject subobj = traits.next_object(); + JsonObject subobj = entry.get_object(); add_entry( tg, subobj ); } } } if( jsobj.has_member( "groups" ) ) { - JsonArray traits = jsobj.get_array( "groups" ); - while( traits.has_more() ) { - if( traits.test_string() ) { - tg.add_group_entry( trait_group::Trait_group_tag( traits.next_string() ), 100 ); - } else if( traits.test_array() ) { - JsonArray subtrait = traits.next_array(); - tg.add_group_entry( trait_group::Trait_group_tag( traits.get_string( 0 ) ), subtrait.get_int( 1 ) ); + for( const JsonValue &entry : jsobj.get_array( "groups" ) ) { + if( entry.test_string() ) { + tg.add_group_entry( trait_group::Trait_group_tag( entry.get_string() ), 100 ); + } else if( entry.test_array() ) { + JsonArray subtrait = entry.get_array(); + tg.add_group_entry( trait_group::Trait_group_tag( subtrait.get_string( 0 ) ), + subtrait.get_int( 1 ) ); } else { - JsonObject subobj = traits.next_object(); + JsonObject subobj = entry.get_object(); add_entry( tg, subobj ); } } @@ -729,8 +726,7 @@ void mutation_branch::add_entry( Trait_group &tg, const JsonObject &obj ) if( ptr ) { Trait_group &tg2 = dynamic_cast( *ptr ); - while( jarr.has_more() ) { - JsonObject job2 = jarr.next_object(); + for( const JsonObject &job2 : jarr ) { add_entry( tg2, job2 ); } tg.add_entry( std::move( ptr ) ); diff --git a/src/npc_class.cpp b/src/npc_class.cpp index 7ad7c54a0bb30..949ca3871001a 100644 --- a/src/npc_class.cpp +++ b/src/npc_class.cpp @@ -247,8 +247,8 @@ void npc_class::load( const JsonObject &jo, const std::string & ) optional( jo, was_loaded, "carry_override", carry_override ); optional( jo, was_loaded, "weapon_override", weapon_override ); - if( jo.has_array( "traits" ) ) { - traits = trait_group::load_trait_group( *jo.get_raw( "traits" ), "collection" ); + if( jo.has_member( "traits" ) ) { + traits = trait_group::load_trait_group( jo.get_member( "traits" ), "collection" ); } if( jo.has_array( "spells" ) ) { diff --git a/src/npctalk.cpp b/src/npctalk.cpp index e3c3deb9a7b68..454c47dd500a3 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -2676,13 +2676,12 @@ void talk_effect_t::load_effect( const JsonObject &jo ) JsonObject sub_effect = jo.get_object( member_name ); parse_sub_effect( sub_effect ); } else if( jo.has_array( member_name ) ) { - JsonArray ja = jo.get_array( member_name ); - while( ja.has_more() ) { - if( ja.test_string() ) { - const std::string type = ja.next_string(); + for( const JsonValue &entry : jo.get_array( member_name ) ) { + if( entry.test_string() ) { + const std::string type = entry.get_string(); parse_string_effect( type, jo ); - } else if( ja.test_object() ) { - JsonObject sub_effect = ja.next_object(); + } else if( entry.test_object() ) { + JsonObject sub_effect = entry.get_object(); parse_sub_effect( sub_effect ); } else { jo.throw_error( "invalid effect array syntax", member_name ); @@ -2869,16 +2868,15 @@ dynamic_line_t::dynamic_line_t( const JsonObject &jo ) { if( jo.has_member( "and" ) ) { std::vector lines; - JsonArray ja = jo.get_array( "and" ); - while( ja.has_more() ) { - if( ja.test_string() ) { - lines.emplace_back( ja.next_string() ); - } else if( ja.test_array() ) { - lines.emplace_back( ja.next_array() ); - } else if( ja.test_object() ) { - lines.emplace_back( ja.next_object() ); + for( const JsonValue &entry : jo.get_array( "and" ) ) { + if( entry.test_string() ) { + lines.emplace_back( entry.get_string() ); + } else if( entry.test_array() ) { + lines.emplace_back( entry.get_array() ); + } else if( entry.test_object() ) { + lines.emplace_back( entry.get_object() ); } else { - ja.throw_error( "invalid format: must be string, array or object" ); + entry.throw_error( "invalid format: must be string, array or object" ); } } function = [lines]( const dialogue & d ) { @@ -2950,15 +2948,15 @@ dynamic_line_t::dynamic_line_t( const JsonObject &jo ) dynamic_line_t::dynamic_line_t( JsonArray ja ) { std::vector lines; - while( ja.has_more() ) { - if( ja.test_string() ) { - lines.emplace_back( ja.next_string() ); - } else if( ja.test_array() ) { - lines.emplace_back( ja.next_array() ); - } else if( ja.test_object() ) { - lines.emplace_back( ja.next_object() ); + for( const JsonValue &entry : ja ) { + if( entry.test_string() ) { + lines.emplace_back( entry.get_string() ); + } else if( entry.test_array() ) { + lines.emplace_back( entry.get_array() ); + } else if( entry.test_object() ) { + lines.emplace_back( entry.get_object() ); } else { - ja.throw_error( "invalid format: must be string, array or object" ); + entry.throw_error( "invalid format: must be string, array or object" ); } } function = [lines]( const dialogue & d ) { diff --git a/src/npctalk_funcs.cpp b/src/npctalk_funcs.cpp index fddad96c87ac2..58ca3f7cfd612 100644 --- a/src/npctalk_funcs.cpp +++ b/src/npctalk_funcs.cpp @@ -914,11 +914,14 @@ void talk_function::start_training( npc &p ) // quicker to learn with instruction as opposed to books. // if this is a known spell, then there is a set time to gain some exp. // if player doesnt know this spell, then the NPC will teach all of it - // which takes as long as it takes. + // which takes max 6 hours, min 3 hours. + // TODO: a system for NPCs to train new stuff in bits and pieces + // and remember the progress. if( knows ) { time = 1_hours; } else { - time = time_duration::from_seconds( g->u.magic.time_to_learn_spell( g->u, sp_id ) / 2 ); + time = time_duration::from_seconds( clamp( g->u.magic.time_to_learn_spell( g->u, sp_id ) / 50, 7200, + 21600 ) ); } } else { debugmsg( "start_training with no valid skill or style set" ); @@ -931,10 +934,11 @@ void talk_function::start_training( npc &p ) } else if( !npc_trading::pay_npc( p, cost ) ) { return; } - player_activity act = player_activity( activity_id( "ACT_TRAIN" ), to_turns( time ) * 100, + player_activity act = player_activity( activity_id( "ACT_TRAIN" ), to_moves( time ), p.getID().get_value(), 0, name ); act.values.push_back( expert_multiplier ); g->u.assign_activity( act ); + p.add_effect( effect_asked_to_train, 6_hours ); } diff --git a/src/overmap_ui.cpp b/src/overmap_ui.cpp index a293bb01cd995..47f5577928f83 100644 --- a/src/overmap_ui.cpp +++ b/src/overmap_ui.cpp @@ -1429,12 +1429,21 @@ static tripoint display( const tripoint &orig, const draw_data_t &data = draw_da curs.y = p.y; } } else if( action == "CHOOSE_DESTINATION" ) { + bool in_road_vehicle = g->u.in_vehicle && g->u.controlling_vehicle; + const optional_vpart_position vp = g->m.veh_at( g->u.pos() ); + bool in_boat = false; + if( vp && in_road_vehicle ) { + vehicle &veh = vp->vehicle(); + in_boat = veh.can_float() && veh.is_watercraft() && veh.is_in_water(); + if( in_boat ) { + in_road_vehicle = false; + } + } const tripoint player_omt_pos = g->u.global_omt_location(); if( !g->u.omt_path.empty() && g->u.omt_path.front() == curs ) { if( query_yn( _( "Travel to this point?" ) ) ) { // renew the path incase of a leftover dangling path point - g->u.omt_path = overmap_buffer.get_npc_path( player_omt_pos, curs, g->u.in_vehicle && - g->u.controlling_vehicle ); + g->u.omt_path = overmap_buffer.get_npc_path( player_omt_pos, curs, in_road_vehicle, in_boat ); if( g->u.in_vehicle && g->u.controlling_vehicle ) { vehicle *player_veh = veh_pointer_or_null( g->m.veh_at( g->u.pos() ) ); player_veh->omt_path = g->u.omt_path; @@ -1450,8 +1459,7 @@ static tripoint display( const tripoint &orig, const draw_data_t &data = draw_da if( curs == player_omt_pos ) { g->u.omt_path.clear(); } else { - g->u.omt_path = overmap_buffer.get_npc_path( player_omt_pos, curs, g->u.in_vehicle && - g->u.controlling_vehicle ); + g->u.omt_path = overmap_buffer.get_npc_path( player_omt_pos, curs, in_road_vehicle, in_boat ); } } else if( action == "TOGGLE_BLINKING" ) { uistate.overmap_blinking = !uistate.overmap_blinking; diff --git a/src/overmapbuffer.cpp b/src/overmapbuffer.cpp index 13a98ced83887..ec2bc9d205830 100644 --- a/src/overmapbuffer.cpp +++ b/src/overmapbuffer.cpp @@ -667,7 +667,7 @@ bool overmapbuffer::reveal( const tripoint ¢er, int radius, } std::vector overmapbuffer::get_npc_path( const tripoint &src, const tripoint &dest, - bool road_only ) + bool road_only, bool do_boat ) { std::vector path; static const int RADIUS = 4; // Maximal radius of search (in overmaps) @@ -697,8 +697,12 @@ std::vector overmapbuffer::get_npc_path( const tripoint &src, const tr !is_ot_match( "road_nesw_manhole", oter, ot_match_type::type ) ) ) { return pf::rejected; } + if( do_boat && ( !is_river_or_lake( oter ) || + is_ot_match( "bridge", oter, ot_match_type::type ) ) ) { + return pf::rejected; + } if( is_ot_match( "empty_rock", oter, ot_match_type::type ) || - is_ot_match( "open_air", oter, ot_match_type::type ) || oter->is_lake() ) { + is_ot_match( "open_air", oter, ot_match_type::type ) || ( !do_boat && oter->is_lake() ) ) { return pf::rejected; } else if( is_ot_match( "forest", oter, ot_match_type::type ) ) { travel_cost = 10; @@ -708,8 +712,8 @@ std::vector overmapbuffer::get_npc_path( const tripoint &src, const tr is_ot_match( "bridge", oter, ot_match_type::type ) || is_ot_match( "road_nesw_manhole", oter, ot_match_type::type ) ) { travel_cost = 1; - } else if( is_river( oter ) ) { - travel_cost = 20; + } else if( is_river_or_lake( oter ) ) { + travel_cost = do_boat ? 1 : 20; } res += travel_cost; res += manhattan_dist( finish, cur.pos ); diff --git a/src/overmapbuffer.h b/src/overmapbuffer.h index 04a5eaafb8bb8..07fc3482ab88e 100644 --- a/src/overmapbuffer.h +++ b/src/overmapbuffer.h @@ -302,7 +302,7 @@ class overmapbuffer bool reveal( const tripoint ¢er, int radius, const std::function &filter ); std::vector get_npc_path( const tripoint &src, const tripoint &dest, - bool road_only = false ); + bool road_only = false, bool do_boat = false ); bool reveal_route( const tripoint &source, const tripoint &dest, int radius = 0, bool road_only = false ); /** diff --git a/src/profession.cpp b/src/profession.cpp index ef58e88775e93..2ec55f98be56a 100644 --- a/src/profession.cpp +++ b/src/profession.cpp @@ -196,19 +196,19 @@ void profession::load( const JsonObject &jo, const std::string & ) optional( items_obj, was_loaded, "both", legacy_starting_items, item_reader {} ); } if( items_obj.has_object( "both" ) ) { - _starting_items = item_group::load_item_group( *items_obj.get_raw( "both" ), "collection" ); + _starting_items = item_group::load_item_group( items_obj.get_member( "both" ), "collection" ); } if( items_obj.has_array( "male" ) ) { optional( items_obj, was_loaded, "male", legacy_starting_items_male, item_reader {} ); } if( items_obj.has_object( "male" ) ) { - _starting_items_male = item_group::load_item_group( *items_obj.get_raw( "male" ), "collection" ); + _starting_items_male = item_group::load_item_group( items_obj.get_member( "male" ), "collection" ); } if( items_obj.has_array( "female" ) ) { optional( items_obj, was_loaded, "female", legacy_starting_items_female, item_reader {} ); } if( items_obj.has_object( "female" ) ) { - _starting_items_female = item_group::load_item_group( *items_obj.get_raw( "female" ), + _starting_items_female = item_group::load_item_group( items_obj.get_member( "female" ), "collection" ); } } diff --git a/src/regional_settings.cpp b/src/regional_settings.cpp index 24a72990e289e..0b90d3c203ea5 100644 --- a/src/regional_settings.cpp +++ b/src/regional_settings.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -760,10 +761,24 @@ void groundcover_extra::finalize() // FIXME: return bool for failure } if( wtotal > 1000000 ) { - debugmsg( "plant coverage total exceeds 100%%" ); + std::stringstream ss; + for( auto it = percent_str.begin(); it != percent_str.end(); ++it ) { + if( it != percent_str.begin() ) { + ss << '+'; + } + ss << it->second; + } + debugmsg( "plant coverage total (%s=%de-4) exceeds 100%%", ss.str(), wtotal ); } if( btotal > 1000000 ) { - debugmsg( "boosted plant coverage total exceeds 100%%" ); + std::stringstream ss; + for( auto it = boosted_percent_str.begin(); it != boosted_percent_str.end(); ++it ) { + if( it != boosted_percent_str.begin() ) { + ss << '+'; + } + ss << it->second; + } + debugmsg( "boosted plant coverage total (%s=%de-4) exceeds 100%%", ss.str(), btotal ); } tf_id.furn = f_null; diff --git a/src/requirements.cpp b/src/requirements.cpp index 27e0060b921c4..d1500ee9fd6b9 100644 --- a/src/requirements.cpp +++ b/src/requirements.cpp @@ -156,9 +156,9 @@ std::string item_comp::to_string( const int batch, const int avail ) const } } -void quality_requirement::load( JsonArray &jsarr ) +void quality_requirement::load( const JsonValue &value ) { - JsonObject quality_data = jsarr.next_object(); + const JsonObject quality_data = value.get_object(); type = quality_id( quality_data.get_string( "id" ) ); level = quality_data.get_int( "level", 1 ); count = quality_data.get_int( "amount", 1 ); @@ -168,27 +168,27 @@ void quality_requirement::load( JsonArray &jsarr ) // Note: level is not checked, negative values and 0 are allow, see butchering quality. } -void tool_comp::load( JsonArray &ja ) +void tool_comp::load( const JsonValue &value ) { - if( ja.test_string() ) { + if( value.test_string() ) { // constructions uses this format: [ "tool", ... ] - type = ja.next_string(); + type = value.get_string(); count = -1; } else { - JsonArray comp = ja.next_array(); + JsonArray comp = value.get_array(); type = comp.get_string( 0 ); count = comp.get_int( 1 ); requirement = comp.size() > 2 && comp.get_string( 2 ) == "LIST"; } if( count == 0 ) { - ja.throw_error( "tool count must not be 0" ); + value.throw_error( "tool count must not be 0" ); } // Note: negative count means charges (of the tool) should be consumed } -void item_comp::load( JsonArray &ja ) +void item_comp::load( const JsonValue &value ) { - JsonArray comp = ja.next_array(); + JsonArray comp = value.get_array(); type = comp.get_string( 0 ); count = comp.get_int( 1 ); size_t handled = 2; @@ -201,20 +201,19 @@ void item_comp::load( JsonArray &ja ) } } if( count <= 0 ) { - ja.throw_error( "item count must be a positive number" ); + value.throw_error( "item count must be a positive number" ); } } template -void requirement_data::load_obj_list( JsonArray &jsarr, std::vector< std::vector > &objs ) +void requirement_data::load_obj_list( const JsonArray &jsarr, std::vector< std::vector > &objs ) { - while( jsarr.has_more() ) { - if( jsarr.test_array() ) { + for( const JsonValue &entry : jsarr ) { + if( entry.test_array() ) { std::vector choices; - JsonArray ja = jsarr.next_array(); - while( ja.has_more() ) { + for( const JsonValue &subentry : entry.get_array() ) { choices.push_back( T() ); - choices.back().load( ja ); + choices.back().load( subentry ); } if( !choices.empty() ) { objs.push_back( choices ); @@ -223,7 +222,7 @@ void requirement_data::load_obj_list( JsonArray &jsarr, std::vector< std::vector // tool qualities don't normally use a list of alternatives // each quality is mandatory. objs.push_back( std::vector( 1 ) ); - objs.back().back().load( jsarr ); + objs.back().back().load( entry ); } } } @@ -268,12 +267,9 @@ void requirement_data::load_requirement( const JsonObject &jsobj, const requirem { requirement_data req; - JsonArray jsarr = jsobj.get_array( "components" ); - requirement_data::load_obj_list( jsarr, req.components ); - jsarr = jsobj.get_array( "qualities" ); - requirement_data::load_obj_list( jsarr, req.qualities ); - jsarr = jsobj.get_array( "tools" ); - requirement_data::load_obj_list( jsarr, req.tools ); + load_obj_list( jsobj.get_array( "components" ), req.components ); + load_obj_list( jsobj.get_array( "qualities" ), req.qualities ); + load_obj_list( jsobj.get_array( "tools" ), req.tools ); if( !id.is_null() ) { req.id_ = id; diff --git a/src/requirements.h b/src/requirements.h index 452558e2273e0..7fbf2a84c84ac 100644 --- a/src/requirements.h +++ b/src/requirements.h @@ -14,6 +14,7 @@ #include "type_id.h" class nc_color; +class JsonValue; class JsonObject; class JsonArray; class JsonIn; @@ -76,7 +77,7 @@ struct tool_comp : public component { tool_comp() = default; tool_comp( const itype_id &TYPE, int COUNT ) : component( TYPE, COUNT ) { } - void load( JsonArray &ja ); + void load( const JsonValue &value ); bool has( const inventory &crafting_inv, const std::function &filter, int batch = 1, std::function visitor = std::function() ) const; std::string to_string( int batch = 1, int avail = 0 ) const; @@ -92,7 +93,7 @@ struct item_comp : public component { item_comp() = default; item_comp( const itype_id &TYPE, int COUNT ) : component( TYPE, COUNT ) { } - void load( JsonArray &ja ); + void load( const JsonValue &value ); bool has( const inventory &crafting_inv, const std::function &filter, int batch = 1, std::function visitor = std::function() ) const; std::string to_string( int batch = 1, int avail = 0 ) const; @@ -114,7 +115,7 @@ struct quality_requirement { quality_requirement( const quality_id &TYPE, int COUNT, int LEVEL ) : type( TYPE ), count( COUNT ), level( LEVEL ) { } - void load( JsonArray &jsarr ); + void load( const JsonValue &value ); bool has( const inventory &crafting_inv, const std::function &filter, int = 0, std::function visitor = std::function() ) const; std::string to_string( int batch = 1, int avail = 0 ) const; @@ -142,8 +143,8 @@ struct quality_requirement { * * Requirements (item_comp, tool_comp, quality_requirement) must have those * functions: - * Load from the next entry of the json array: - * void load(JsonArray &jarr); + * Load from an entry of a json array: + * void load(const JsonValue &value); * Check whether the player has fulfills the requirement with this crafting * inventory (or by mutation): * bool has(const inventory &crafting_inv) const; @@ -326,7 +327,7 @@ struct requirement_data { template static bool any_marked_available( const std::vector &comps ); template - static void load_obj_list( JsonArray &jsarr, std::vector< std::vector > &objs ); + static void load_obj_list( const JsonArray &jsarr, std::vector< std::vector > &objs ); template static const T *find_by_type( const std::vector< std::vector > &vec, const ID &type ); }; diff --git a/src/savegame_json.cpp b/src/savegame_json.cpp index 4629e0ea02a3f..47dbe2971818f 100644 --- a/src/savegame_json.cpp +++ b/src/savegame_json.cpp @@ -1826,20 +1826,18 @@ void monster::load( const JsonObject &data ) // sp_timeout indicates an old save, prior to the special_attacks refactor if( data.has_array( "sp_timeout" ) ) { JsonArray parray = data.get_array( "sp_timeout" ); - if( !parray.empty() ) { - int index = 0; - int ptimeout = 0; - while( parray.has_more() && index < static_cast( type->special_attacks_names.size() ) ) { - if( parray.read_next( ptimeout ) ) { - // assume timeouts saved in same order as current monsters.json listing - const std::string &aname = type->special_attacks_names[index++]; - auto &entry = special_attacks[aname]; - if( ptimeout >= 0 ) { - entry.cooldown = ptimeout; - } else { // -1 means disabled, unclear what <-1 values mean in old saves - entry.cooldown = type->special_attacks.at( aname )->cooldown; - entry.enabled = false; - } + size_t index = 0; + int ptimeout = 0; + while( parray.has_more() && index < type->special_attacks_names.size() ) { + if( parray.read_next( ptimeout ) ) { + // assume timeouts saved in same order as current monsters.json listing + const std::string &aname = type->special_attacks_names[index++]; + auto &entry = special_attacks[aname]; + if( ptimeout >= 0 ) { + entry.cooldown = ptimeout; + } else { // -1 means disabled, unclear what <-1 values mean in old saves + entry.cooldown = type->special_attacks.at( aname )->cooldown; + entry.enabled = false; } } } diff --git a/src/text_snippets.cpp b/src/text_snippets.cpp index 77702961c2293..86cfb0bee09dc 100644 --- a/src/text_snippets.cpp +++ b/src/text_snippets.cpp @@ -18,28 +18,27 @@ void snippet_library::load_snippet( const JsonObject &jsobj ) hash_to_id_migration = cata::nullopt; const std::string category = jsobj.get_string( "category" ); if( jsobj.has_array( "text" ) ) { - JsonArray jarr = jsobj.get_array( "text" ); - add_snippets_from_json( category, jarr ); + add_snippets_from_json( category, jsobj.get_array( "text" ) ); } else { add_snippet_from_json( category, jsobj ); } } -void snippet_library::add_snippets_from_json( const std::string &category, JsonArray &jarr ) +void snippet_library::add_snippets_from_json( const std::string &category, const JsonArray &jarr ) { if( hash_to_id_migration.has_value() ) { debugmsg( "snippet_library::add_snippets_from_json called after snippet_library::migrate_hash_to_id." ); } hash_to_id_migration = cata::nullopt; - while( jarr.has_more() ) { - if( jarr.test_string() ) { + for( const JsonValue &entry : jarr ) { + if( entry.test_string() ) { translation text; - if( !jarr.read_next( text ) ) { - jarr.throw_error( "Error reading snippet from JSON array" ); + if( !entry.read( text ) ) { + entry.throw_error( "Error reading snippet from JSON array" ); } snippets_by_category[category].no_id.emplace_back( text ); } else { - JsonObject jo = jarr.next_object(); + JsonObject jo = entry.get_object(); add_snippet_from_json( category, jo ); } } diff --git a/src/text_snippets.h b/src/text_snippets.h index f20dd03b6c380..91d062efd4946 100644 --- a/src/text_snippets.h +++ b/src/text_snippets.h @@ -24,7 +24,7 @@ class snippet_library * Entries in the array can be simple strings, or json objects (for the * later see add_snippet_from_json). */ - void add_snippets_from_json( const std::string &category, JsonArray &jarr ); + void add_snippets_from_json( const std::string &category, const JsonArray &jarr ); /** * Load a single snippet text from the json object. The object should have * a "text" member with the text of the snippet. diff --git a/src/trait_group.cpp b/src/trait_group.cpp index da028ca39a8b1..578f65e3c7ef7 100644 --- a/src/trait_group.cpp +++ b/src/trait_group.cpp @@ -50,31 +50,31 @@ static Trait_group_tag get_unique_trait_group_id() } } -Trait_group_tag trait_group::load_trait_group( JsonIn &stream, const std::string &default_subtype ) +Trait_group_tag trait_group::load_trait_group( const JsonValue &value, + const std::string &default_subtype ) { - if( stream.test_string() ) { - return Trait_group_tag( stream.get_string() ); - } else if( stream.test_object() ) { + if( value.test_string() ) { + return Trait_group_tag( value.get_string() ); + } else if( value.test_object() ) { const Trait_group_tag group = get_unique_trait_group_id(); - JsonObject jo = stream.get_object(); + JsonObject jo = value.get_object(); const std::string subtype = jo.get_string( "subtype", default_subtype ); mutation_branch::load_trait_group( jo, group, subtype ); return group; - } else if( stream.test_array() ) { + } else if( value.test_array() ) { const Trait_group_tag group = get_unique_trait_group_id(); - JsonArray jarr = stream.get_array(); if( default_subtype != "collection" && default_subtype != "distribution" ) { - jarr.throw_error( "invalid subtype for trait group" ); + value.throw_error( "invalid subtype for trait group" ); } - mutation_branch::load_trait_group( jarr, group, default_subtype == "collection" ); + mutation_branch::load_trait_group( value.get_array(), group, default_subtype == "collection" ); return group; } else { - stream.error( "invalid trait group, must be string (group id) or object/array (the group data)" ); + value.throw_error( "invalid trait group, must be string (group id) or object/array (the group data)" ); return Trait_group_tag{}; } } diff --git a/src/trait_group.h b/src/trait_group.h index 4744814629e54..cb2dd1bd4c24c 100644 --- a/src/trait_group.h +++ b/src/trait_group.h @@ -12,6 +12,7 @@ class JsonObject; class JsonIn; class Trait_group; +class JsonValue; namespace trait_group { @@ -38,23 +39,22 @@ void load_trait_group( const JsonObject &jsobj, const Trait_group_tag &gid, /** * Get a trait group ID and optionally load an inlined trait group. * - * If the next value in the JSON stream is string, it's assumed to be a trait group id and it's + * If the value is string, it's assumed to be a trait group id and it's * returned directly. * - * If the next value is a JSON object, it is loaded as a trait group. The group will be given a + * If the value is a JSON object, it is loaded as a trait group. The group will be given a * unique id (if the JSON object contains an id, it is ignored) and that id will be returned. * If the JSON object does not contain a subtype, the given default is used. * - * If the next value is a JSON array, it is loaded as a trait group: the default_subtype will be + * If the value is a JSON array, it is loaded as a trait group: the default_subtype will be * used as subtype of the new trait group and the array is loaded like the "entries" array of * a trait group definition (see format of trait groups). * - * @param stream Stream to load from * @param default_subtype If an inlined trait group is loaded this is used as the default * subtype. It must be either "distribution" or "collection". See @ref Trait_group. - * @throw std::string as usual for JSON errors, including invalid input values. + * @throw JsonError as usual for JSON errors, including invalid input values. */ -Trait_group_tag load_trait_group( JsonIn &stream, const std::string &default_subtype ); +Trait_group_tag load_trait_group( const JsonValue &value, const std::string &default_subtype ); /** * Show a debug menu for testing trait groups. diff --git a/src/trap.cpp b/src/trap.cpp index ead593c7ec56c..651619e1c69cb 100644 --- a/src/trap.cpp +++ b/src/trap.cpp @@ -120,18 +120,17 @@ void trap::load( const JsonObject &jo, const std::string & ) optional( jo, was_loaded, "comfort", comfort, 0 ); optional( jo, was_loaded, "floor_bedding_warmth", floor_bedding_warmth, 0 ); assign( jo, "trigger_weight", trigger_weight ); - JsonArray ja = jo.get_array( "drops" ); - while( ja.has_more() ) { + for( const JsonValue &entry : jo.get_array( "drops" ) ) { std::string item_type; int quantity = 0; int charges = 0; - if( ja.test_object() ) { - JsonObject jc = ja.next_object(); + if( entry.test_object() ) { + JsonObject jc = entry.get_object(); item_type = jc.get_string( "item" ); quantity = jc.get_int( "quantity", 1 ); charges = jc.get_int( "charges", 1 ); } else { - item_type = ja.next_string(); + item_type = entry.get_string(); quantity = 1; charges = 1; } @@ -153,13 +152,12 @@ void trap::load( const JsonObject &jo, const std::string & ) vehicle_data.sound_variant = jv.get_string( "sound_variant", "" ); vehicle_data.spawn_items.clear(); if( jv.has_array( "spawn_items" ) ) { - JsonArray ja = jv.get_array( "spawn_items" ); - while( ja.has_more() ) { - if( ja.test_object() ) { - JsonObject joitm = ja.next_object(); + for( const JsonValue &entry : jv.get_array( "spawn_items" ) ) { + if( entry.test_object() ) { + JsonObject joitm = entry.get_object(); vehicle_data.spawn_items.emplace_back( joitm.get_string( "id" ), joitm.get_float( "chance" ) ); } else { - vehicle_data.spawn_items.emplace_back( ja.next_string(), 1.0 ); + vehicle_data.spawn_items.emplace_back( entry.get_string(), 1.0 ); } } } diff --git a/src/trap.h b/src/trap.h index c5b075f7cc398..c8e61e96bf25e 100644 --- a/src/trap.h +++ b/src/trap.h @@ -229,7 +229,7 @@ struct trap { */ /** * Loads the trap and adds it to the trapmap, and the traplist. - * @throw std::string if the json is invalid as usual. + * @throw JsonError if the json is invalid as usual. */ static void load_trap( const JsonObject &jo, const std::string &src ); /** diff --git a/src/uistate.h b/src/uistate.h index 293101cd36624..16e823f3d2120 100644 --- a/src/uistate.h +++ b/src/uistate.h @@ -206,9 +206,9 @@ class uistatedata } // viewing vehicle cargo if( jo.has_array( "adv_inv_in_vehicle" ) ) { - auto ja = jo.get_array( "adv_inv_in_vehicle" ); - for( size_t i = 0; ja.has_more(); ++i ) { - adv_inv_in_vehicle[i] = ja.next_bool(); + const JsonArray ja = jo.get_array( "adv_inv_in_vehicle" ); + for( size_t i = 0; i < adv_inv_in_vehicle.size() && i < ja.size(); ++i ) { + adv_inv_in_vehicle[i] = ja.get_bool( i ); } } // filter strings @@ -256,11 +256,10 @@ class uistatedata jo.read( "list_item_priority_active", list_item_priority_active ); for( const JsonMember &member : jo.get_object( "input_history" ) ) { - JsonArray ja = member.get_array(); std::vector &v = gethistory( member.name() ); v.clear(); - while( ja.has_more() ) { - v.push_back( ja.next_string() ); + for( const std::string &line : member.get_array() ) { + v.push_back( line ); } } // fetch list_item settings from input_history diff --git a/src/veh_type.cpp b/src/veh_type.cpp index 8151b2c5de948..6d62cfdcb1be9 100644 --- a/src/veh_type.cpp +++ b/src/veh_type.cpp @@ -388,8 +388,7 @@ void vpart_info::load( const JsonObject &jo, const std::string &src ) } if( jo.has_member( "breaks_into" ) ) { - JsonIn &stream = *jo.get_raw( "breaks_into" ); - def.breaks_into_group = item_group::load_item_group( stream, "collection" ); + def.breaks_into_group = item_group::load_item_group( jo.get_member( "breaks_into" ), "collection" ); } auto qual = jo.get_array( "qualities" ); @@ -946,13 +945,12 @@ void vehicle_prototype::load( const JsonObject &jo ) if( part.has_string( "part" ) ) { add_part_obj( part, pos ); } else if( part.has_array( "parts" ) ) { - JsonArray subparts = part.get_array( "parts" ); - while( subparts.has_more() ) { - if( subparts.test_string() ) { - std::string part_name = subparts.next_string(); + for( const JsonValue &entry : part.get_array( "parts" ) ) { + if( entry.test_string() ) { + std::string part_name = entry.get_string(); add_part_string( part_name, pos ); } else { - JsonObject subpart = subparts.next_object(); + JsonObject subpart = entry.get_object(); add_part_obj( subpart, pos ); } } @@ -978,9 +976,8 @@ void vehicle_prototype::load( const JsonObject &jo ) if( spawn_info.has_array( "items" ) ) { //Array of items that all spawn together (i.e. jack+tire) - JsonArray item_group = spawn_info.get_array( "items" ); - while( item_group.has_more() ) { - next_spawn.item_ids.push_back( item_group.next_string() ); + for( const std::string &line : spawn_info.get_array( "items" ) ) { + next_spawn.item_ids.push_back( line ); } } else if( spawn_info.has_string( "items" ) ) { //Treat single item as array @@ -988,9 +985,8 @@ void vehicle_prototype::load( const JsonObject &jo ) } if( spawn_info.has_array( "item_groups" ) ) { //Pick from a group of items, just like map::place_items - JsonArray item_group_names = spawn_info.get_array( "item_groups" ); - while( item_group_names.has_more() ) { - next_spawn.item_groups.push_back( item_group_names.next_string() ); + for( const std::string &line : spawn_info.get_array( "item_groups" ) ) { + next_spawn.item_groups.push_back( line ); } } else if( spawn_info.has_string( "item_groups" ) ) { next_spawn.item_groups.push_back( spawn_info.get_string( "item_groups" ) ); diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 9c31a94431647..f1bd9c620a858 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -735,6 +735,9 @@ std::set vehicle::immediate_path( int rotate ) void vehicle::stop_autodriving() { + if( !is_autodriving && !is_patrolling && !is_following ){ + return; + } if( velocity > 0 ) { if( is_patrolling || is_following ) { autodrive( 0, 10 ); diff --git a/src/vehicle_move.cpp b/src/vehicle_move.cpp index f5b9c9147896b..f59a8117a45a6 100644 --- a/src/vehicle_move.cpp +++ b/src/vehicle_move.cpp @@ -544,7 +544,7 @@ veh_collision vehicle::part_collision( int part, const tripoint &p, // Hit nothing or we aren't actually hitting return ret; } - + stop_autodriving(); // Calculate mass AFTER checking for collision // because it involves iterating over all cargo const float mass = to_kilogram( total_mass() );