diff --git a/.clang-tidy b/.clang-tidy index 6a17e66ee1428..c99681aa461fd 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -29,7 +29,6 @@ readability-*,\ -cert-msc51-cpp,\ -misc-non-private-member-variables-in-classes,\ -modernize-avoid-c-arrays,\ --modernize-deprecated-headers,\ -modernize-pass-by-value,\ -modernize-return-braced-init-list,\ -modernize-use-auto,\ diff --git a/CMakeLists.txt b/CMakeLists.txt index 09fc85a064f61..435e421c9e24e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -224,7 +224,7 @@ ELSE() -Woverloaded-virtual \ -Wpedantic") IF(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") - SET(CATA_WARNINGS "$(CATA_WARNINGS) -Wsuggest-override") + SET(CATA_WARNINGS "${CATA_WARNINGS} -Wsuggest-override") ENDIF(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") # Compact the whitespace in the warning string string(REGEX REPLACE "[\t ]+" " " CATA_WARNINGS "${CATA_WARNINGS}") diff --git a/android/.gitignore b/android/.gitignore index d7a510e5a97e4..79469f4e55cbd 100644 --- a/android/.gitignore +++ b/android/.gitignore @@ -1,4 +1,5 @@ !config/ +!deps*.zip *.iml .cxx .DS_Store diff --git a/android/app/build.gradle b/android/app/build.gradle index 823bc72081301..0feeba630773e 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -37,8 +37,10 @@ if (keystorePropertiesFile.exists()) { def njobs = getProperty("j") def localize = getProperty("localize").toBoolean() -def abi32 = getProperty("abi32").toBoolean() -def abi64 = getProperty("abi64").toBoolean() +def abi_arm_32 = getProperty("abi_arm_32").toBoolean() +def abi_arm_64 = getProperty("abi_arm_64").toBoolean() +def abi_x86_32 = getProperty("abi_x86_32").toBoolean() +def abi_x86_64 = getProperty("abi_x86_64").toBoolean() def deps = getProperty("deps") def override_version = getProperty("override_version") def version_header_path = getProperty("version_header_path") @@ -52,8 +54,8 @@ println("Using minSdkVersion: $override_minSdkVersion") println("Using targetSdkVersion: $override_targetSdkVersion") println("Using ndkBuildAppPlatform: $override_ndkBuildAppPlatform") -if (!abi32 && !abi64) { - throw new GradleException("Both `abi32` and `abi64` properties are set to false") +if (!abi_arm_32 && !abi_arm_64 && !abi_x86_32 && !abi_x86_64) { + throw new GradleException("All supported ABI properties are set to false!") } if (!file(deps).exists()) { throw new GradleException("Dependencies file does not exist:" + deps) @@ -154,12 +156,18 @@ android { // Resets the list of ABIs that Gradle should create APKs for to none. reset() // Specifies a list of ABIs that Gradle should create APKs for. - if (abi32) { + if (abi_arm_32) { include "armeabi-v7a" } - if (abi64) { + if (abi_arm_64) { include "arm64-v8a" } + if (abi_x86_32) { + include "x86" + } + if (abi_x86_64) { + include "x86_64" + } // Specifies that we do not want to also generate a universal APK that includes all ABIs. universalApk false } diff --git a/android/app/deps.zip b/android/app/deps.zip index 75b4d2f68a635..81e9f5697a0c8 100644 Binary files a/android/app/deps.zip and b/android/app/deps.zip differ diff --git a/android/app/deps_debug.zip b/android/app/deps_debug.zip new file mode 100644 index 0000000000000..8958923cbfb52 Binary files /dev/null and b/android/app/deps_debug.zip differ diff --git a/android/gradle.properties b/android/gradle.properties index 80b12331f351b..8fb7fc2b1cdef 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -24,13 +24,21 @@ j=2 # You can override this from the command line by passing "-Plocalize=#" localize=true -# This property controls whether to build 32 bit ABI -# You can override this from the command line by passing "-Pabi32=#" -abi32=true +# This property controls whether to build arm 32 bit ABI +# You can override this from the command line by passing "-Pabi_arm_32=#" +abi_arm_32=true -# This property controls whether to build 64 bit ABI -# You can override this from the command line by passing "-Pabi64=#" -abi64=true +# This property controls whether to build arm 64 bit ABI +# You can override this from the command line by passing "-Pabi_arm_64=#" +abi_arm_64=true + +# This property controls whether to build x86 32 bit ABI +# You can override this from the command line by passing "-Pabi_x86_32=#" +abi_x86_32=false + +# This property controls whether to build x86 64 bit ABI +# You can override this from the command line by passing "-Pabi_x86_64=#" +abi_x86_64=false # This property controls which dependencies file to use # You can override this from the command line by passing "-Pdeps=#" diff --git a/data/json/harvest.json b/data/json/harvest.json index f9f7b6e869272..b1797d8d28962 100644 --- a/data/json/harvest.json +++ b/data/json/harvest.json @@ -401,10 +401,10 @@ "type": "harvest", "message": "You laboriously dissect the colossal insect.", "entries": [ - { "drop": "meat", "base_num": [ 40, 55 ], "scale_num": [ 0.5, 0.7 ], "max": 80, "type": "flesh" }, + { "drop": "mutant_meat", "base_num": [ 40, 55 ], "scale_num": [ 0.5, 0.7 ], "max": 80, "type": "flesh" }, { "drop": "acidchitin_piece", "base_num": [ 2, 6 ], "scale_num": [ 0.3, 0.6 ], "max": 10, "type": "bone" }, { "drop": "sweetbread", "base_num": [ 3, 4 ], "scale_num": [ 0.4, 0.6 ], "max": 8, "type": "offal" }, - { "drop": "fat", "base_num": [ 5, 8 ], "scale_num": [ 0.6, 0.8 ], "max": 18, "type": "flesh" } + { "drop": "mutant_fat", "base_num": [ 5, 8 ], "scale_num": [ 0.6, 0.8 ], "max": 18, "type": "flesh" } ] }, { @@ -421,8 +421,8 @@ "id": "arachnid_acid", "type": "harvest", "entries": [ - { "drop": "meat_tainted", "type": "flesh", "mass_ratio": 0.33 }, - { "drop": "fat", "type": "flesh", "mass_ratio": 0.04 }, + { "drop": "mutant_meat", "type": "flesh", "mass_ratio": 0.33 }, + { "drop": "mutant_fat", "type": "flesh", "mass_ratio": 0.04 }, { "drop": "sinew", "type": "bone", "mass_ratio": 0.01 }, { "drop": "acidchitin_piece", "type": "bone", "mass_ratio": 0.1 } ] diff --git a/data/json/itemgroups/SUS/evac_shelter.json b/data/json/itemgroups/SUS/evac_shelter.json index bd7f9d562f9e9..67739a044b844 100644 --- a/data/json/itemgroups/SUS/evac_shelter.json +++ b/data/json/itemgroups/SUS/evac_shelter.json @@ -3,7 +3,7 @@ "id": "SUS_evac_shelter_locker", "type": "item_group", "//": "SUS item groups are collections that contain a reasonable realistic distribution of items that might spawn in a given storage furniture.", - "//2": "Each locker contains by spec one jacket, one blanket, one gas mask, a flashlight, a plastic bowl and utensils, a lighter, and two bottles of water. Not every locker is fully stocked.", + "//2": "Each locker contains by spec one jacket, one blanket, one gas mask, a flashlight, a whistle, a plastic bowl and utensils, a lighter, and two bottles of water. Not every locker is fully stocked.", "subtype": "collection", "entries": [ { "item": "evac_pamphlet", "prob": 99 }, @@ -13,6 +13,7 @@ { "item": "flashlight", "prob": 50 }, { "item": "light_disposable_cell", "prob": 10 }, { "item": "lighter", "prob": 20 }, + { "item": "whistle", "prob": 70 }, { "item": "water_clean", "count": [ 1, 2 ], "prob": 80 }, { "item": "protein_bar_evac", "count": [ 2, 3 ] }, { @@ -83,7 +84,8 @@ { "item": "1st_aid", "count": [ 1, 3 ], "prob": 65 }, { "item": "two_way_radio", "prob": 65 }, { "item": "light_disposable_cell", "count": [ 2, 4 ], "prob": 65 }, - { "item": "electric_lantern", "prob": 35 } + { "item": "electric_lantern", "prob": 35 }, + { "item": "barometer", "prob": 8 } ], "prob": 10 }, @@ -92,7 +94,8 @@ { "item": "detergent", "count": [ 0, 2 ] }, { "item": "brush", "prob": 85 }, { "item": "bleach", "prob": 45 }, - { "item": "ammonia", "prob": 15 } + { "item": "ammonia", "prob": 15 }, + { "item": "vinegar", "prob": 10 } ], "prob": 15 }, @@ -121,6 +124,7 @@ "distribution": [ { "collection": [ + { "item": "folding_poncho", "count": [ 1, 10 ], "prob": 60 }, { "item": "emer_blanket", "count": [ 1, 10 ], "prob": 60 }, { "item": "jacket_evac", "count": [ 1, 10 ], "prob": 50 } ], @@ -139,7 +143,8 @@ { "item": "extinguisher", "prob": 50 }, { "item": "1st_aid", "prob": 5 }, { "item": "two_way_radio", "prob": 25 }, - { "item": "electric_lantern", "prob": 5 } + { "item": "electric_lantern", "prob": 5 }, + { "item": "wearable_light", "prob": 5 } ], "prob": 10 }, @@ -163,6 +168,7 @@ { "item": "box_small", "prob": 5 }, { "item": "bag_plastic", "prob": 5 }, { "item": "bowl_plastic", "prob": 5 }, + { "item": "vitamins", "prob": 5 }, { "item": "can_food_unsealed", "count": [ 1, 30 ], "prob": 90 }, { "item": "can_opener", "prob": 90 } ], @@ -184,6 +190,7 @@ { "item": "brush", "prob": 90 }, { "item": "bleach", "prob": 45 }, { "item": "ammonia", "prob": 25 }, + { "item": "mirror", "prob": 12 }, { "item": "1st_aid", "prob": 60 }, { "item": "paper", "count": [ 1, 3 ] }, { "item": "evac_pamphlet", "prob": 10 } diff --git a/data/json/items/ammo.json b/data/json/items/ammo.json index b9b0370f9b004..68f1e8197dc57 100644 --- a/data/json/items/ammo.json +++ b/data/json/items/ammo.json @@ -483,7 +483,7 @@ "id": "22_casing_new", "category": "spare_parts", "price": 100, - "name": "unused .22 casing", + "name": { "str": "unused .22 casing" }, "symbol": "=", "color": "yellow", "description": "An unfired, like-new .22 round casing, with the primer still intact.", diff --git a/data/json/items/ammo/20x66mm.json b/data/json/items/ammo/20x66mm.json index cd8f9a9b51e76..441073c0b458c 100644 --- a/data/json/items/ammo/20x66mm.json +++ b/data/json/items/ammo/20x66mm.json @@ -3,7 +3,7 @@ "id": "20x66_beanbag", "copy-from": "20x66_shot", "type": "AMMO", - "name": "20x66mm beanbag", + "name": { "str": "20x66mm beanbag" }, "description": "20x66mm caseless shotgun rounds, sublethal beanbag type. Proprietary ammunition for Rivtech shotguns. Being caseless rounds, these cannot be disassembled or reloaded.", "price": 8000, "price_postapoc": 25000, @@ -15,7 +15,7 @@ "id": "20x66_bootleg_flechette", "copy-from": "20x66_flechette", "type": "AMMO", - "name": "20x66mm flechette, handmade", + "name": { "str": "20x66mm flechette, handmade", "str_pl": "20x66mm flechettes, handmade" }, "description": "Handcrafted bootleg duplicates of Rivtech 20x66mm caseless flechette rounds. Being caseless rounds, these cannot be disassembled or reloaded.", "proportional": { "price": 0.7, "damage": 0.9, "dispersion": 1.1 }, "extend": { "effects": [ "RECYCLED" ] }, @@ -25,7 +25,7 @@ "id": "20x66_bootleg_shot", "copy-from": "20x66_shot", "type": "AMMO", - "name": "20x66mm buckshot, handmade", + "name": { "str": "20x66mm buckshot, handmade" }, "description": "Handcrafted bootleg duplicates of Rivtech 20x66mm caseless buckshot rounds. Being caseless rounds, these cannot be disassembled or reloaded.", "proportional": { "price": 0.7, "damage": 0.9, "dispersion": 1.1 }, "extend": { "effects": [ "RECYCLED" ] }, @@ -35,7 +35,7 @@ "id": "20x66_bootleg_slug", "copy-from": "20x66_slug", "type": "AMMO", - "name": "20x66mm slug, handmade", + "name": { "str": "20x66mm slug, handmade", "str_pl": "20x66mm slugs, handmade" }, "description": "Handcrafted bootleg duplicates of Rivtech 20x66mm caseless solid projectile rounds. Being caseless rounds, these cannot be disassembled or reloaded.", "proportional": { "price": 0.7, "damage": 0.9, "dispersion": 1.1 }, "extend": { "effects": [ "RECYCLED" ] }, @@ -45,7 +45,7 @@ "id": "20x66_exp", "copy-from": "20x66_shot", "type": "AMMO", - "name": "20x66mm explosive", + "name": { "str": "20x66mm explosive" }, "description": "20x66mm caseless shotgun rounds, explosive projectile type. Proprietary ammunition for Rivtech shotguns. Being caseless rounds, these cannot be disassembled or reloaded.", "price": 10000, "price_postapoc": 80000, @@ -59,7 +59,7 @@ "id": "20x66_flare", "copy-from": "20x66_shot", "type": "AMMO", - "name": "20x66mm flare", + "name": { "str": "20x66mm flare" }, "description": "20x66mm caseless shotgun rounds, signal flare type. Proprietary ammunition for Rivtech shotguns. Being caseless rounds, these cannot be disassembled or reloaded.", "price": 5000, "price_postapoc": 20000, @@ -75,7 +75,7 @@ "id": "20x66_flechette", "copy-from": "20x66_shot", "type": "AMMO", - "name": "20x66mm flechette", + "name": { "str": "20x66mm flechette" }, "description": "20x66mm caseless shotgun rounds, flechette type. Proprietary ammunition for Rivtech shotguns. Being caseless rounds, these cannot be disassembled or reloaded.", "price": 4000, "price_postapoc": 55000, @@ -86,7 +86,7 @@ "id": "20x66_frag", "copy-from": "20x66_slug", "type": "AMMO", - "name": "20x66mm frag", + "name": { "str": "20x66mm frag" }, "description": "20x66mm caseless shotgun rounds, explosive fragmentation type. Proprietary ammunition for Rivtech shotguns. Being caseless rounds, these cannot be disassembled or reloaded.", "price": 7800, "price_postapoc": 90000, @@ -98,7 +98,7 @@ "id": "20x66_inc", "copy-from": "20x66_shot", "type": "AMMO", - "name": "20x66mm incendiary", + "name": { "str": "20x66mm incendiary" }, "description": "20x66mm caseless shotgun rounds, incendiary type. Proprietary ammunition for Rivtech shotguns. Being caseless rounds, these cannot be disassembled or reloaded.", "price": 10500, "price_postapoc": 100000, @@ -108,7 +108,7 @@ { "id": "20x66_shot", "type": "AMMO", - "name": "20x66mm buckshot", + "name": { "str": "20x66mm buckshot" }, "//": "2.5x the Generic Rate of $1/shot", "description": "20x66mm caseless shotgun rounds, buckshot type. Proprietary ammunition for Rivtech shotguns. Being caseless rounds, these cannot be disassembled or reloaded.", "weight": "56 g", @@ -130,7 +130,7 @@ "id": "20x66_slug", "copy-from": "20x66_shot", "type": "AMMO", - "name": "20x66mm slug", + "name": { "str": "20x66mm slug" }, "description": "20x66mm caseless shotgun rounds, solid projectile type. Proprietary ammunition for Rivtech shotguns. Being caseless rounds, these cannot be disassembled or reloaded.", "price": 1500, "price_postapoc": 9000, diff --git a/data/json/items/ammo/22.json b/data/json/items/ammo/22.json index c7956feb66841..cb7288309746d 100644 --- a/data/json/items/ammo/22.json +++ b/data/json/items/ammo/22.json @@ -3,7 +3,7 @@ "id": "22_cb", "copy-from": "22_lr", "type": "AMMO", - "name": ".22 CB", + "name": { "str": ".22 CB" }, "description": "The .22 Conical Ball is a variety of .22 ammunition that propels its bullet using a primer instead of gunpowder. The end result is a subsonic round that is so weak as to be nearly useless given your predicament.", "price": 100, "price_postapoc": 1800, @@ -17,14 +17,14 @@ "id": "22_fmj", "copy-from": "22_lr", "type": "AMMO", - "name": ".22 FMJ", + "name": { "str": ".22 FMJ" }, "description": ".22 Long Rifle ammunition with 30gr FMJ bullets. The .22LR round is extremely weak with very low stopping power, short range, and negligible recoil. It is most useful for rifle training, and hunting small animals.", "relative": { "damage": -1, "pierce": 2 } }, { "id": "22_lr", "type": "AMMO", - "name": ".22 LR", + "name": { "str": ".22 LR" }, "description": ".22 Long Rifle ammunition with 40gr unjacketed bullets. The .22LR round is extremely weak with very low stopping power, short range, and negligible recoil. It is most useful for rifle training, and hunting small animals.", "weight": "3 g", "volume": "250 ml", @@ -47,7 +47,7 @@ "id": "22_ratshot", "copy-from": "22_lr", "type": "AMMO", - "name": ".22 rat-shot", + "name": { "str": ".22 rat-shot" }, "description": "A .22 caliber cartridge loaded with very small pieces of shot contained within a fragmenting plastic capsule. It has an extremely short range and penetration ability, but it can hit targets with greater ease.", "count": 100, "dispersion": 0, diff --git a/data/json/items/ammo/223.json b/data/json/items/ammo/223.json index 1fc70c2b873c5..1c86f3b30d2b9 100644 --- a/data/json/items/ammo/223.json +++ b/data/json/items/ammo/223.json @@ -2,7 +2,7 @@ { "id": "223", "type": "AMMO", - "name": ".223 Remington", + "name": { "str": ".223 Remington" }, "description": ".223 Remington ammunition with 36gr JHP bullets. The .223 round has been very popular with civilian shooters for almost a century, finding use in a wide variety of weapons. It generates lower pressure than 5.56 NATO leading to slightly decreased accuracy and recoil.", "weight": "12 g", "volume": "250 ml", diff --git a/data/json/items/ammo/270win.json b/data/json/items/ammo/270win.json index 2aba414b5f4d2..f2d4fe85bfbf8 100644 --- a/data/json/items/ammo/270win.json +++ b/data/json/items/ammo/270win.json @@ -2,7 +2,7 @@ { "id": "270win_jsp", "type": "AMMO", - "name": ".270 Winchester JSP", + "name": { "str": ".270 Winchester JSP" }, "description": ".270 Winchester ammunition with 130gr soft point bullets. The .270 round was not initially successful, but over a few decades it became one of the most popular rifle cartridges for hunting and silhouette shooting. It is a powerful round capable of taking down large targets with ease.", "weight": "20 g", "volume": "250 ml", diff --git a/data/json/items/ammo/3006.json b/data/json/items/ammo/3006.json index d8de3d439abbd..cfbd5640fd075 100644 --- a/data/json/items/ammo/3006.json +++ b/data/json/items/ammo/3006.json @@ -2,7 +2,7 @@ { "id": "3006", "type": "AMMO", - "name": ".30-06 Springfield", + "name": { "str": ".30-06 Springfield" }, "description": ".30-06 Springfield rounds with 165gr soft point bullets. The .30-06 cartridge has excellent accuracy, range, and stopping power making it popular with hunters and snipers for well over a century.", "weight": "20 g", "volume": "250 ml", @@ -26,7 +26,7 @@ "id": "3006_incendiary", "copy-from": "3006", "type": "AMMO", - "name": ".30-06 M14A1 tracer", + "name": { "str": ".30-06 M14A1 tracer" }, "description": "Armor piercing incendiary .30-06 M14A1 ammunition containing tracer rounds to help keep the weapon they are fired from on target. It penetrates all but the strongest body armor with ease.", "extend": { "effects": [ "INCENDIARY" ] } }, @@ -34,7 +34,7 @@ "id": "3006fmj", "copy-from": "3006", "type": "AMMO", - "name": ".30-06 M2 AP", + "name": { "str": ".30-06 M2 AP" }, "description": "Armor piercing .30-06 M2 ammunition with 168gr FMJ bullets. It is an extremely powerful and accurate cartridge but pays for its armor penetration abilities with lowered damage.", "relative": { "damage": -4, "pierce": 8 } }, diff --git a/data/json/items/ammo/40x46mm.json b/data/json/items/ammo/40x46mm.json index b960c554a2ed4..964a7fc979085 100644 --- a/data/json/items/ammo/40x46mm.json +++ b/data/json/items/ammo/40x46mm.json @@ -107,6 +107,17 @@ "recoil": 1000, "casing": "40x46mm_m118_casing" }, + { + "id": "40x46mm_sponge", + "copy-from": "40x46mm_grenade", + "type": "AMMO", + "name": "40x46mm sponge", + "description": "A 40mm sponge round that delivers strong impact on target, causing pain and disorientation. May still injure or kill.", + "price": 5000, + "price_postapoc": 10000, + "damage": 5, + "extend": { "effects": [ "BEANBAG" ] } + }, { "id": "40x46mm_slug_m199", "copy-from": "40x46mm_grenade", diff --git a/data/json/items/corpses/inactive_bots.json b/data/json/items/corpses/inactive_bots.json index d3feaee1bf9e0..5cd3290d511f7 100644 --- a/data/json/items/corpses/inactive_bots.json +++ b/data/json/items/corpses/inactive_bots.json @@ -269,6 +269,28 @@ "skill2": "computer" } }, + { + "id": "bot_turret_riot", + "type": "TOOL", + "name": "inactive riot control turret", + "description": "This is an inactive riot control turret. Using this item involves loading the unit with the factory-loaded beanbag rounds in your inventory (if you wish to divide your ammunition, set aside whatever beanbag rounds you do NOT want to give the turret) turning it on, and placing it on the ground, where it will attach itself. If programmed successfully the turret will then identify you as a friendly, and attack all enemies with its riot control gun.", + "weight": "125000 g", + "volume": "60 L", + "price": 200500, + "to_hit": -3, + "bashing": 8, + "material": [ "steel", "plastic" ], + "symbol": ";", + "color": "red", + "use_action": { + "type": "place_monster", + "monster_id": "mon_turret_riot", + "difficulty": 6, + "moves": 100, + "skill1": "electronics", + "skill2": "computer" + } + }, { "id": "bot_turret", "type": "TOOL", diff --git a/data/json/items/generic.json b/data/json/items/generic.json index b7094d6e3251f..2d53f6fd5c1da 100644 --- a/data/json/items/generic.json +++ b/data/json/items/generic.json @@ -2403,6 +2403,19 @@ "volume": "750 ml", "flags": [ "SLEEP_AID" ] }, + { + "type": "GENERIC", + "id": "teddy_bear", + "symbol": "o", + "color": "brown", + "name": "teddy bear", + "description": "A mass produced plush teddy bear. It is wearing a little red tshirt but no pants.", + "price": 200, + "material": [ "cotton" ], + "weight": "444 g", + "volume": "850 ml", + "flags": [ "SLEEP_AID" ] + }, { "type": "GENERIC", "id": "money_bundle", @@ -2959,20 +2972,29 @@ "description": "A broken turret. Much less threatening now that it's laid limp on solid ground. Could be gutted for parts.", "price": 1000, "material": [ "steel", "plastic" ], - "weight": "62650 g", + "weight": "72650 g", "volume": "30 L", "bashing": 4, "cutting": 4, "to_hit": -3, "flags": [ "TRADER_AVOID", "NO_REPAIR" ] }, + { + "type": "GENERIC", + "id": "broken_turret_riot", + "symbol": ",", + "color": "blue", + "name": "broken riot control turret", + "description": "A broken riot control turret. Much less threatening now that it's laid limp on solid ground. Could be gutted for parts.", + "copy-from": "broken_turret" + }, { "type": "GENERIC", "id": "broken_turret_rifle", "symbol": ",", "color": "green", "name": "broken M249 autonomous CROWS II", - "weight": "70000 g", + "weight": "75 kg", "copy-from": "broken_turret" }, { @@ -2981,7 +3003,7 @@ "symbol": ",", "color": "green", "name": "broken M240 autonomous CROWS II", - "weight": "70000 g", + "weight": "75 kg", "copy-from": "broken_turret" }, { @@ -2990,7 +3012,7 @@ "symbol": ",", "color": "green", "name": "broken M2 autonomous CROWS II", - "weight": "100000 g", + "weight": "100 kg", "copy-from": "broken_turret" }, { @@ -2999,7 +3021,7 @@ "symbol": ",", "color": "green", "name": "broken laser turret", - "weight": "110000 g", + "weight": "110 kg", "copy-from": "broken_turret" }, { @@ -3012,8 +3034,8 @@ "description": "A broken secubot, with its casing broken and fluid drained. Could be gutted for parts.", "price": 1000, "material": [ "steel", "plastic" ], - "weight": "100000 g", - "volume": "65000 ml", + "weight": "100 kg", + "volume": "65 L", "bashing": 4, "cutting": 4, "to_hit": -3, @@ -3029,8 +3051,8 @@ "description": "A broken TALON UGV, with its casing broken and fluid drained. Could be gutted for parts.", "price": 1000, "material": [ "steel", "plastic" ], - "weight": "100000 g", - "volume": "65000 ml", + "weight": "100 kg", + "volume": "65 L", "bashing": 4, "cutting": 4, "to_hit": -3, diff --git a/data/json/items/gun/40x46mm.json b/data/json/items/gun/40x46mm.json index 719fdc01c7942..94faf1a491058 100644 --- a/data/json/items/gun/40x46mm.json +++ b/data/json/items/gun/40x46mm.json @@ -148,5 +148,28 @@ "clip_size": 3, "modes": [ [ "DEFAULT", "single", 1, "NPC_AVOID" ], [ "MULTI", "multi", 3, [ "NPC_AVOID", "SIMULTANEOUS" ] ] ], "proportional": { "weight": 1.5, "volume": 1.8, "price": 2 } + }, + { + "id": "pseudo_m203", + "copy-from": "launcher_base", + "looks_like": "m203", + "type": "GUN", + "name": "M203 array", + "description": "Six M203 grenade launchers for use on an automated 40mm turret.", + "weight": "8200 g", + "volume": "4 L", + "price": 250000, + "to_hit": -1, + "bashing": 14, + "material": "steel", + "ammo": "40x46mm", + "range": 30, + "ranged_damage": 1, + "dispersion": 300, + "durability": 10, + "reload": 400, + "modes": [ [ "DEFAULT", "semi-auto", 1, "NPC_AVOID" ] ], + "clip_size": 16, + "flags": [ "MOUNTED_GUN" ] } ] diff --git a/data/json/items/gun/9mm.json b/data/json/items/gun/9mm.json index 274a0b74924df..3fa05b1022a2d 100644 --- a/data/json/items/gun/9mm.json +++ b/data/json/items/gun/9mm.json @@ -344,20 +344,20 @@ "copy-from": "pistol_base", "looks_like": "glock_17", "type": "GUN", - "name": "Beretta M9", - "description": "A very popular 9x19mm pistol, the M9 has been the standard issue sidearm of the US army since 1985.", - "weight": "590 g", - "volume": "500 ml", + "name": "Beretta M9A1", + "description": "An iconic 9x19mm pistol, the M9 was the standard issue sidearm of US armed force from 1985 only until recently. It was formerly popular amongst law enforcement before the advent of commercially available polymer-framed handguns and the FBI's adoption of .40S&W.", + "weight": "961 g", + "volume": "528 ml", "price": 65000, "to_hit": -2, "bashing": 8, - "material": [ "steel", "plastic" ], + "material": [ "steel", "aluminum" ], "symbol": "(", "color": "dark_gray", "ammo": "9mm", "range": 1, "dispersion": 480, - "durability": 6, + "durability": 7, "min_cycle_recoil": 450, "magazine_well": 1, "magazines": [ [ "9mm", [ "m9mag", "m9bigmag" ] ] ] diff --git a/data/json/items/gun/shot.json b/data/json/items/gun/shot.json index d9466e90d208e..ca70ed0ea790c 100644 --- a/data/json/items/gun/shot.json +++ b/data/json/items/gun/shot.json @@ -127,6 +127,7 @@ "clip_size": 8, "valid_mod_locations": [ [ "accessories", 2 ], + [ "mechanism", 4 ], [ "sling", 1 ], [ "barrel", 1 ], [ "rail mount", 1 ], @@ -209,9 +210,12 @@ [ "accessories", 2 ], [ "sling", 1 ], [ "barrel", 1 ], + [ "grip mount", 1 ], + [ "stock mount", 1 ], [ "rail mount", 1 ], [ "loading port", 1 ], [ "brass catcher", 1 ], + [ "mechanism", 4 ], [ "sights", 1 ], [ "underbarrel mount", 1 ] ], @@ -297,7 +301,7 @@ "copy-from": "remington_870", "type": "GUN", "name": "Remington 870 MCS", - "description": "This Remington 870 Modular Combat system shotgun is currently setup for breaching operations, with a 10 inch barrel and no stock. It is small enough to carry as a secondary weapon, specifically to pop open any pesky doors you might come across. The grip's design makes for controllable yet unpleasant recoil, and the barrel lacks any sights.", + "description": "This Remington 870 Modular Combat System shotgun is currently setup for breaching operations, with a 10 inch barrel and no stock. It is small enough to carry as a secondary weapon, specifically to pop open any pesky doors you might come across. The grip's design makes for controllable yet unpleasant recoil, and the barrel lacks any sights.", "weight": "2812 g", "volume": "1427 ml", "looks_like": "remington_870", @@ -316,7 +320,6 @@ [ "bore", 1 ], [ "brass catcher", 1 ], [ "grip", 1 ], - [ "grip mount", 1 ], [ "loading port", 1 ], [ "mechanism", 4 ], [ "rail mount", 1 ], @@ -364,6 +367,8 @@ [ "sling", 1 ], [ "brass catcher", 1 ], [ "barrel", 1 ], + [ "stock", 1 ], + [ "mechanism", 4 ], [ "rail mount", 1 ], [ "loading port", 1 ], [ "sights mount", 1 ], diff --git a/data/json/mapgen/hazardous_waste_sarcophagus.json b/data/json/mapgen/hazardous_waste_sarcophagus.json new file mode 100644 index 0000000000000..b94baa72cb922 --- /dev/null +++ b/data/json/mapgen/hazardous_waste_sarcophagus.json @@ -0,0 +1,324 @@ +[ + { + "type": "mapgen", + "method": "json", + "om_terrain": [ [ "haz_sar_1_2", "haz_sar_1_1" ], [ "haz_sar_1_4", "haz_sar_1_3" ] ], + "weight": 10, + "object": { + "rows": [ + " :::::::::::::::: ", + " :::::::::::::::: ", + " :::::::::::::::: ", + " ffffffffffffffffffffffffffffffff:::::::|www- ", + " f ,,,,,,,,,,,,,,,,,,,,,, f:::::::wcdcw ", + " f ,,:::::::::;:::::::::, v f:::::::+.C6w ", + " f ,,:::::::::;:::::::::, |LLLLLLL--+--ff ", + " f ,,:::::::::;:::::::::,,,,,,,,:::::::,,,, f ", + " f ,,::::::::::::::::::::::::::::::::::,,,, f ", + " f ,,::::::::::::::::::::::::::::::::::, f ", + " f ,,::::::::::::::::::::::::::::::::::, f ", + " f ,,::::::::::::::::::::::::::::::::::, f ", + " f ,,::::;::::;::::;::::,,,,,,,,:::::::, f ", + " f ,,::::;::::;::::;::::,,,,,,,,:::::::, f ", + " f ,,::::;::::;::::;::::,,|-+-|-LLLLLLL-| f ", + " f ,,::::;::::;::::;::::,,|4.6|~~~~~~~~~| f ", + " f ,,,,,,,,,,,,,,,,,,,,,,,|4..`~~~~~~~~~| f ", + " f ,,,,,,,,,,,,,,,,,,,,,,,|4..`~~~~~~~~l| f ", + " f |-000--000-0*0|000-000| |4..`~~~~~~~~l| f ", + " f |dddrFFddcW..2|2..Fddd| |s..|~~~~~~~~l| f ", + " f 0dC.....Cc....*....dCr| |4..?~~~~~~~~~| f ", + " f 0............a|b...d..| |4..|~~~~~~~~4| f ", + " f 0..C...|*-|-*-|b......| |4..`::::::::4| f ", + " f |rddd1p|.l|&.s|a36561p| |s..`~~~~~~~~4| f ", + " f |-000--|--|---|-------| |4..`~~~~~~~~~| f ", + " f |4.6|6~~~~~~~~| f ", + " f ////////////////////+///LLLLLLL/// f ", + " f /////////////////////.//6~~~~~~~./// f ", + " f //.......................~~~~~~~~..// f ", + " f //.......||||............~~~~~~~~~..// f ", + " f //........|EE.......A....~~~~~~~~~~..// f ", + " f //...S....|EE......AA...~~~~~~~~~~~.9// f ", + " f //...P....|e.|.....AA..~~~~~~~~~~~~.9// f ", + " f //.``P``...............~~~~~~~~~~~~.9// f ", + " f //.`$$$`.......AAA.....~~~~~~~~~~~~.9// f ", + " f //.`$$$`6......AA......~~~~~~~~~~~~.9// f ", + " f //.`$$$`...............~~~~~~~~~~~~..// f ", + " f //.`$$$`...............~~~~~~~~~~~~..// f ", + " f //.``P``.|G|...........SS6~~~~~~~~~..// f ", + " f //...PPPPPPPPPPPPPPPPPPSS~~~~~~~~~~..// f ", + " f //......|G|..............~~~~~~~~~.// f ", + " f //.........V.V.V...........7788..// f ", + " f ///////////////////////////////// f ", + " f /////////////////////////////// f ", + " f f ", + " f f ", + " ffffffffffffffffffffffffffffffffffffffffffffff ", + " " + ], + "terrain": { + " ": [ + [ "t_grass", 20 ], + [ "t_grass_dead", 3 ], + [ "t_grass_tall", 5 ], + [ "t_grass_long", 3 ], + [ "t_dirt", 5 ], + [ "t_shrub", 2 ], + [ "t_tree", 1 ] + ], + "f": "t_chainfence", + "|": "t_wall", + "-": "t_wall", + "/": "t_concrete_wall", + "+": "t_door_locked", + "*": "t_door_c", + "?": "t_door_locked_alarm", + "w": "t_window_alarm", + "0": [ [ "t_curtains", 10 ], [ "t_window_open", 3 ], [ "t_window_domestic", 5 ] ], + ",": "t_sidewalk", + ":": "t_pavement", + ";": "t_pavement_y", + "1": "t_floor", + "2": "t_floor", + "3": "t_floor", + "4": "t_floor", + "5": "t_console", + "6": "t_console_broken", + "7": "t_floor", + "8": "t_floor", + "9": "t_floor", + "&": "t_floor", + "$": "t_sewage", + ".": "t_floor", + "a": "t_floor", + "b": "t_floor", + "r": "t_floor", + "F": "t_floor", + "c": "t_floor", + "C": "t_floor", + "d": "t_floor", + "l": "t_floor", + "p": "t_floor", + "A": "t_floor", + "P": "t_sewage_pipe", + "S": "t_sewage_pump", + "G": "t_grate", + "E": "t_elevator", + "e": "t_elevator_control_off", + "s": "t_floor", + "v": "t_dirt", + "V": "t_vat", + "L": "t_door_metal_locked", + "W": "t_water_dispenser", + "~": "t_thconc_floor", + "`": "t_wall_glass" + }, + "furniture": { + "1": "f_shredder", + "2": "f_rack_coat", + "3": "f_server", + "4": "f_utility_shelf", + "7": "f_locker", + "8": "f_utility_shelf", + "9": "f_utility_shelf", + "a": "f_air_conditioner", + "b": "f_bookcase", + "r": "f_trashcan", + "F": "f_filing_cabinet", + "A": "f_crate_c", + "c": "f_counter", + "C": "f_chair", + "d": "f_desk", + "l": "f_locker", + "p": [ "f_indoor_plant", "f_indoor_plant_y" ], + "s": "f_sink", + "v": "f_vent_pipe" + }, + "toilets": { "&": { } }, + "items": { + "2": { "item": "coat_rack", "chance": 60, "repeat": 2 }, + "4": { "item": "toxic_dump_equipment", "chance": 85, "repeat": [ 1, 2 ] }, + "7": { "item": "tools_common", "chance": 85, "repeat": [ 1, 2 ] }, + "8": { "item": "tools_common", "chance": 85, "repeat": [ 1, 2 ] }, + "9": { "item": "cleaning", "chance": 85, "repeat": [ 1, 2 ] }, + "r": { "item": "trash_cart", "chance": 50 }, + "d": { "item": "office", "chance": 50 }, + "c": { "item": "office_supplies", "chance": 60 }, + "b": { "item": "lab_bookshelves", "chance": 60, "repeat": 2 }, + "l": { "item": "cleaning", "chance": 85, "repeat": 2 }, + "F": { "item": "office_paper", "chance": 50 } + }, + "place_item": [ { "item": "id_military", "x": 22, "y": 20 }, { "item": "cleansuit", "x": 28, "y": 24 } ], + "set": [ { "square": "radiation", "amount": [ 10, 30 ], "x": 0, "y": 0, "x2": 47, "y2": 47 } ], + "place_monster": [ + { "monster": "mon_hazmatbot", "x": 36, "y": 20 }, + { "monster": "mon_hazmatbot", "x": 13, "y": 29 }, + { "monster": "mon_hazmatbot", "x": 26, "y": 37 }, + { "monster": "mon_hazmatbot", "x": 22, "y": 29 } + ], + "//": "There is 4th security reminder with name 'Security Reminder [1058]' and action 'sr4_mess'. Add it when our computer UI will support more than 9 options.", + "computers": { + "5": { + "name": "SRCF Security Terminal", + "security": 5, + "options": [ + { "name": "Security Reminder [1055]", "action": "sr1_mess" }, + { "name": "Security Reminder [1056]", "action": "sr2_mess" }, + { "name": "Security Reminder [1057]", "action": "sr3_mess" }, + { "name": "EPA: Report All Potential Containment Breaches [3873643]", "action": "srcf_1_mess" }, + { "name": "SRCF: Internal Memo, EPA [2918024]", "action": "srcf_2_mess" }, + { "name": "CDC: Internal Memo, Standby [2918115]", "action": "srcf_3_mess" }, + { "name": "USARMY: SEAL SRCF [987167]", "action": "srcf_seal_order" }, + { "name": "COMMAND: REACTIVATE ELEVATOR", "action": "srcf_elevator" }, + { "name": "COMMAND: SEAL SRCF [4423]", "action": "srcf_seal" } + ], + "failures": [ { "action": "alarm" } ] + } + }, + "place_vehicles": [ { "vehicle": "military_cargo_truck", "x": 37, "y": 35, "chance": 25, "status": 1, "rotation": 90, "fuel": 40 } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ [ "haz_sar_b_2", "haz_sar_b_1" ], [ "haz_sar_b_4", "haz_sar_b_3" ] ], + "weight": 10, + "object": { + "rows": [ + "###|-------------------|-------------------|####", + "###|~~~~~~~~~~~~~~~~~~~|~~~~~~~~~~~~~~~~~~~|####", + "###|~~~~~~~~~~~~~~~~~~~|~~~~~~~~~~~~~~~~~~~|####", + "###|~~~~~~~~~~~~~~~~~~~|~~~~~~~~~~~~~~~~~~~|####", + "###|~~~~~~~~~~~~~~~~~~~|~~~~~~~~~~~~~~~~~~~|####", + "###|~~~~~~~~~~~~~~~~~~~|~~~~~~~~~~~~~~~~~~~|####", + "###|~~~~~~~~~~~~~~~~~~~|~~~~~~~~~~~~~~~~~~~|####", + "###|~~~~~~~~~~~~~~~~~~~|~~~~~~~~~~~~~~~~~~~|####", + "###|----|~~~~~~~~~|----|----|~~~~~~~~~|----|####", + "########|--LLLLL--|#########|--LLLLL--|#########", + "####### ^ ### #### ^###########", + "###### ###########", + "#### ############", + "### #|---------|", + "# |~~~~~~~~~|", + "## L~~~~~~~~~|", + "## L~~~~~~~~~|", + "# L~~~~~~~~~|", + "## L~~~~~~~~~|", + "### L~~~~~~~~~|", + "## ^|~~~~~~~~~|", + "### #|---------|", + "#### |+%%-| #############", + "#### |....| ^ #############", + "####|-%%%%-|-%%+|-|-LLLLL-| #|---------|", + "####|a....8|a....W|^.....a| |~~~~~~~~~|", + "####|.c5c..*......*.......| L~~~~~~~~~|", + "####|.cC..F|...|--|......8| L~~~~~~~~~|", + "####|.c....%...|99|......8| L~~~~~~~~~|", + "####|......%...+..|......8| L~~~~~~~~~|", + "####|l...C.%...|--|-L-|---| L~~~~~~~~~|", + "####|l.Fddd|...*EE|l..|#### ^|~~~~~~~~~|", + "####|-|----|...*EE|l..|#### #|---------|", + "######|....*...|e||-+-|## ############", + "######|&rsa|...|-|## ### #############", + "######|----|---|#### ##############", + "################### ###############", + "#####|----------|# |----------|####", + "#####|~~~~~~~~~~|^ |~~~~~~~~~~|####", + "#####|~~~~~~~~~~L L~~~~~~~~~~|####", + "#####|~~~~~~~~~~L L~~~~~~~~~~|####", + "#####|~~~~~~~~~~L L~~~~~~~~~~|####", + "#####|~~~~~~~~~~L L~~~~~~~~~~|####", + "#####|~~~~~~~~~~L L~~~~~~~~~~|####", + "#####|~~~~~~~~~~| ^|~~~~~~~~~~|####", + "#####|----------| ###|----------|####", + "####################### ## ####################", + "################################################" + ], + "terrain": { + " ": "t_rock_floor", + ".": "t_metal_floor", + "&": "t_metal_floor", + "a": "t_metal_floor", + "l": "t_metal_floor", + "s": "t_metal_floor", + "r": "t_metal_floor", + "c": "t_metal_floor", + "C": "t_metal_floor", + "d": "t_metal_floor", + "8": "t_metal_floor", + "9": "t_metal_floor", + "F": "t_metal_floor", + "|": "t_concrete_wall", + "-": "t_concrete_wall", + "+": "t_door_metal_c", + "*": "t_door_metal_c", + "L": "t_door_metal_locked", + "#": "t_rock", + "^": "t_gates_control_concrete", + "%": "t_reinforced_glass", + "E": "t_elevator", + "e": "t_elevator_control_off", + "5": "t_console", + "W": "t_water_dispenser", + "~": [ [ "t_sewage", 55 ], [ "t_dirtfloor", 25 ], [ "t_dirtmound", 20 ] ] + }, + "furniture": { + "s": "f_sink", + "r": "f_trashcan", + "d": "f_desk", + "c": "f_counter", + "C": "f_chair", + "l": "f_locker", + "8": "f_utility_shelf", + "9": "f_utility_shelf", + "a": "f_air_conditioner", + "F": "f_filing_cabinet", + "~": [ [ "f_null", 50 ], [ "f_wreckage", 50 ] ] + }, + "toilets": { "&": { } }, + "items": { + "8": { "item": "mechanics", "chance": 60, "repeat": [ 1, 2 ] }, + "9": { "item": "sewage_plant", "chance": 60, "repeat": [ 1, 2 ] }, + "r": { "item": "trash_cart", "chance": 50 }, + "d": { "item": "office", "chance": 50 }, + "c": { "item": "office_supplies", "chance": 60 }, + "l": { "item": "cleaning", "chance": 60, "repeat": 2 }, + "F": { "item": "office_paper", "chance": 50 }, + " ": { "item": "corpse_and_science", "chance": 1 }, + "~": [ { "item": "trash", "chance": 50 }, { "item": "sewer", "chance": 50 }, { "item": "nanomaterials", "chance": 3 } ] + }, + "place_item": [ { "item": "sarcophagus_access_code", "x": 20, "y": 31 } ], + "set": [ { "square": "radiation", "amount": [ 10, 70 ], "x": 0, "y": 0, "x2": 47, "y2": 47 } ], + "monster": { " ": { "monster": "mon_zombie", "chance": 10 } }, + "monsters": { "~": { "monster": "GROUP_VANILLA", "chance": 20, "density": 0.1 } }, + "computers": { + "5": { + "name": "SRCF Security Terminal", + "security": 5, + "options": [ + { "name": "Security Reminder [1055]", "action": "sr1_mess" }, + { "name": "Security Reminder [1056]", "action": "sr2_mess" }, + { "name": "Security Reminder [1057]", "action": "sr3_mess" }, + { "name": "Security Reminder [1058]", "action": "sr4_mess" }, + { "name": "EPA: Report All Potential Containment Breaches [3873643]", "action": "srcf_1_mess" }, + { "name": "SRCF: Internal Memo, EPA [2918024]", "action": "srcf_2_mess" }, + { "name": "CDC: Internal Memo, Standby [2918115]", "action": "srcf_3_mess" }, + { "name": "USARMY: SEAL SRCF [987167]", "action": "srcf_seal_order" }, + { "name": "COMMAND: REACTIVATE ELEVATOR", "action": "srcf_elevator" } + ], + "failures": [ { "action": "alarm" } ] + } + } + } + }, + { + "id": "corpse_and_science", + "type": "item_group", + "subtype": "collection", + "entries": [ { "item": "corpse_generic_human", "prob": 100 }, { "group": "science", "prob": 100 } ] + }, + { + "id": "nanomaterials", + "type": "item_group", + "entries": [ { "item": "nanomaterial", "prob": 100 } ] + } +] diff --git a/data/json/mapgen/house/house_inner_garden.json b/data/json/mapgen/house/house_inner_garden.json new file mode 100644 index 0000000000000..ba19c5dd67965 --- /dev/null +++ b/data/json/mapgen/house/house_inner_garden.json @@ -0,0 +1,114 @@ +[ + { + "type": "mapgen", + "method": "json", + "om_terrain": "house_inner_garden", + "object": { + "fill_ter": "t_floor", + "rows": [ + "...$..GssMMMMMMMMsssss..", + ".$.....ssM......Msssssu.", + ".......ssM.....##xxxxx%#", + ".#MMM##8]#8#8#8#~~~~~~u#", + ".#888#E #5 #~~~~~~~#", + "^#yay##8]# #~~~~~~##", + "##4 #~~~~~~N#", + "#h #~~~~~~U#", + "## #~~~~~~U#", + ".# +~~~~~~U#", + ".# y y8]888#8#88#8##", + ".###iL## #8sssssssssss#.", + ".p#n 8s#3..3..sFs#.", + ".M#K JA ]s.......sFs#.", + ".^#QllJA 8s#......sFs#.", + "######## #8sSsssssssss#.", + "#y + y8]#8]#8]8888#.", + "o 6 #R + 1 #.", + "o #R #++#HLH #.", + "#O ##+#Wg#### #.", + "#######j ####j + #.", + ".....^#t d#dd t# #OOOO#.", + "......###o#o###########.", + "........................" + ], + "palettes": [ "house_w_foundation_palette" ], + "terrain": { "8": "t_wall_glass", "#": "t_rock_wall", "]": "t_door_glass_c", "%": "t_wall_w" }, + "furniture": { "a": "f_displaycase" }, + "place_vehicles": [ + { "vehicle": "showroom_small_vehicles", "x": 17, "y": 5, "rotation": 270, "chance": 20, "status": 0 }, + { "vehicle": "showroom_small_vehicles", "x": 19, "y": 5, "rotation": 270, "chance": 20, "status": 0 } + ], + "items": { + "E": { "item": "coat_rack", "chance": 30, "repeat": [ 1, 4 ] }, + "G": { "item": "mail", "chance": 30, "repeat": [ 2, 5 ] }, + "a": { "item": "art", "chance": 100 }, + "n": [ + { "item": "SUS_dishes", "chance": 100 }, + { "item": "SUS_silverware", "chance": 100 }, + { "item": "SUS_kitchen_sink", "chance": 100 } + ], + "Q": [ { "item": "SUS_cookware", "chance": 100 }, { "item": "SUS_spice_collection", "chance": 100 } ], + "K": [ + { "item": "SUS_utensils", "chance": 100 }, + { "item": "SUS_knife_drawer", "chance": 100 }, + { "item": "SUS_junk_drawer", "chance": 100 }, + { "item": "SUS_appliances_cupboard", "chance": 100 } + ], + "J": [ { "item": "SUS_breakfast_cupboard", "chance": 100 }, { "item": "SUS_coffee_cupboard", "chance": 100 } ], + "l": { "item": "SUS_fridge", "chance": 100 }, + "i": { "item": "SUS_oven", "chance": 100 } + }, + "nested": { + "1": { "chunks": [ [ "bedroom_4x4_adult_1_E", 20 ] ] }, + "3": { "chunks": [ [ "garden_3x3_1", 50 ], [ "garden_3x3_2", 33 ], [ "garden_3x3_3", 33 ] ] }, + "4": { "chunks": [ [ "diningroom_5x5_N_S", 50 ], [ "diningroom_6x6_N_S_1A", 50 ] ] }, + "5": { + "chunks": [ + [ "livingroom_5x5_N_1", 20 ], + [ "livingroom_5x5_S_1", 20 ], + [ "livingroom_5x5_E_1", 20 ], + [ "livingroom_5x5_E_2", 20 ], + [ "livingroom_5x5_W_1", 20 ] + ] + }, + "6": { "chunks": [ [ "bonus_room_3x3_S_6", 40 ], [ "bonus_room_3x3_S_5", 20 ], [ "bonus_room_3x3_S_7", 40 ] ] } + } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "house_inner_garden_roof", + "object": { + "fill_ter": "t_shingle_flat_roof", + "rows": [ + " ", + " ", + " --------|", + " ---------------.......|", + " |................ooo..|", + " |.....................|", + "5|................ooo.A|", + "|~.....................|", + "||................ooo..|", + " |.....................|", + " |..........22222222223|", + " |..........3 ", + " |..&.......3 ", + " |..........3 ", + " |..........3 ", + "||..........3 ", + "|...........22222222222 ", + "|.....................| ", + "|.....................| ", + "|................... .| ", + "-------...............| ", + " 5..&............| ", + " ----------------- ", + " " + ], + "palettes": [ "roof_palette" ], + "terrain": { ".": "t_shingle_flat_roof" } + } + } +] diff --git a/data/json/mapgen/missile_silo.json b/data/json/mapgen/missile_silo.json index 806f9e52595b1..a71acf5036f8d 100644 --- a/data/json/mapgen/missile_silo.json +++ b/data/json/mapgen/missile_silo.json @@ -509,7 +509,7 @@ "access_denied": "ERROR! Access denied! Unauthorized access will be met with lethal force!", "security": 10, "failures": [ { "action": "alarm" }, { "action": "damage" }, { "action": "secubots" } ], - "options": [ { "name": "Launch Missile", "action": "miss_launch" }, { "name": "Disarm Missile", "action": "miss_disarm" } ] + "options": [ { "name": "Disarm Missile", "action": "miss_disarm" } ] } }, "place_graffiti": [ { "text": "Warning! Automatic security measures engaged due to the lockdown order!", "x": 17, "y": 20 } ], diff --git a/data/json/mapgen/office_tower_2.json b/data/json/mapgen/office_tower_2.json index 326fd9515730f..1dfe16498d816 100644 --- a/data/json/mapgen/office_tower_2.json +++ b/data/json/mapgen/office_tower_2.json @@ -229,7 +229,7 @@ ], "place_monsters": [ { "monster": "GROUP_OFFICE_TOWER_2", "x": [ 7, 21 ], "y": [ 13, 21 ], "chance": 2, "repeat": [ 1 ] } ], "place_monster": [ { "monster": "mon_zombie_scientist", "x": [ 7, 21 ], "y": [ 4, 10 ], "repeat": [ 1, 3 ] } ], - "monster": { "7": { "monster": "mon_turret_rifle" } } + "monster": { "7": { "monster": "mon_turret_riot" } } } }, { diff --git a/data/json/mapgen/prison_1.json b/data/json/mapgen/prison_1.json index eb91104628b0c..7f227c2e24a23 100644 --- a/data/json/mapgen/prison_1.json +++ b/data/json/mapgen/prison_1.json @@ -178,11 +178,11 @@ "place_item": [ { "item": "visions_solitude", "x": 16, "y": 108, "amount": 1 } ], "place_monsters": [ { "monster": "GROUP_ZOMBIE_PRISON", "x": [ 15, 20 ], "y": [ 34, 37 ], "repeat": [ 1, 2 ], "density": 0.2 }, - { "monster": "GROUP_ROBOT_SECUBOT", "x": [ 15, 20 ], "y": [ 39, 42 ], "density": 0.1 }, + { "monster": "GROUP_TURRET_RIOT", "x": [ 15, 20 ], "y": [ 39, 42 ], "density": 0.1 }, { "monster": "GROUP_ZOMBIE_PRISON", "x": [ 15, 20 ], "y": [ 44, 37 ], "repeat": [ 1, 2 ], "density": 0.2 }, - { "monster": "GROUP_ROBOT_SECUBOT", "x": [ 32, 39 ], "y": [ 39, 42 ], "density": 0.1 }, + { "monster": "GROUP_TURRET_RIOT", "x": [ 32, 39 ], "y": [ 39, 42 ], "density": 0.1 }, { "monster": "GROUP_ZOMBIE_PRISON", "x": [ 51, 56 ], "y": [ 34, 37 ], "repeat": [ 1, 2 ], "density": 0.2 }, - { "monster": "GROUP_ROBOT_SECUBOT", "x": [ 51, 56 ], "y": [ 39, 42 ], "density": 0.1 }, + { "monster": "GROUP_TURRET_RIOT", "x": [ 51, 56 ], "y": [ 39, 42 ], "density": 0.1 }, { "monster": "GROUP_ZOMBIE_PRISON", "x": [ 51, 56 ], "y": [ 44, 37 ], "repeat": [ 1, 2 ], "density": 0.2 }, { "monster": "GROUP_ROBOT_EYEBOT", "x": [ 24, 47 ], "y": [ 0, 13 ], "density": 0.1 }, { "monster": "GROUP_ROBOT_EYEBOT", "x": [ 27, 44 ], "y": [ 52, 60 ], "density": 0.1 }, @@ -253,7 +253,7 @@ }, "place_monsters": [ { "monster": "GROUP_ZOMBIE_COP", "x": [ 35, 38 ], "y": [ 2, 7 ], "density": 0.2 } ], "monster": { - "7": { "monster": "mon_turret_rifle" }, + "7": { "monster": "mon_turret_riot" }, "Z": { "monster": "mon_zombie_prisoner" }, "C": { "monster": "mon_broken_cyborg" } } @@ -474,7 +474,7 @@ }, "place_monster": [ { "monster": "mon_zombie_hulk", "x": 45, "y": 3 }, - { "monster": "mon_secubot", "x": 90, "y": 37 }, + { "monster": "mon_turret_riot", "x": 90, "y": 37 }, { "monster": "mon_zombie_brute", "x": 60, "y": 56 } ], "place_graffiti": [ { "text": "Dufresne was here", "x": 19, "y": 22 } ], diff --git a/data/json/monstergroups/monstergroups.json b/data/json/monstergroups/monstergroups.json index c6e8fed4a2478..4e1ab1dc23224 100644 --- a/data/json/monstergroups/monstergroups.json +++ b/data/json/monstergroups/monstergroups.json @@ -4261,7 +4261,6 @@ { "monster": "mon_zombie_technician", "freq": 50, "cost_multiplier": 3 }, { "monster": "mon_zombie_static", "freq": 50, "cost_multiplier": 3 }, { "monster": "mon_zombie_brute_shocker", "freq": 10, "cost_multiplier": 5 }, - { "monster": "mon_chickenbot", "freq": 1, "cost_multiplier": 50 }, { "monster": "mon_zombie_hulk", "freq": 1, "cost_multiplier": 50 }, { "monster": "mon_skeleton_hulk", "freq": 1, "cost_multiplier": 50 } ] @@ -4351,27 +4350,6 @@ "default": "mon_spider_web", "monsters": [ ] }, - { - "type": "monstergroup", - "name": "GROUP_ROBOT", - "default": "mon_manhack", - "monsters": [ - { "monster": "mon_skitterbot", "freq": 220, "cost_multiplier": 0 }, - { "monster": "mon_secubot", "freq": 150, "cost_multiplier": 0 }, - { "monster": "mon_talon_m202a1", "freq": 75, "cost_multiplier": 0 }, - { "monster": "mon_copbot", "freq": 0, "cost_multiplier": 0 }, - { "monster": "mon_molebot", "freq": 40, "cost_multiplier": 0 }, - { "monster": "mon_tripod", "freq": 110, "cost_multiplier": 0 }, - { "monster": "mon_chickenbot", "freq": 60, "cost_multiplier": 0 }, - { "monster": "mon_tankbot", "freq": 20, "cost_multiplier": 0 } - ] - }, - { - "type": "monstergroup", - "name": "GROUP_TURRET", - "default": "mon_turret_rifle", - "monsters": [ { "monster": "mon_turret_bmg", "freq": 50, "cost_multiplier": 2 } ] - }, { "type": "monstergroup", "name": "GROUP_POLICE", @@ -5083,18 +5061,6 @@ { "monster": "mon_dog_zombie_cop", "freq": 50, "cost_multiplier": 2, "pack_size": [ 1, 2 ] } ] }, - { - "type": "monstergroup", - "name": "GROUP_ROBOT_EYEBOT", - "default": "mon_eyebot", - "monsters": [ { "monster": "mon_eyebot", "freq": 100, "cost_multiplier": 0 } ] - }, - { - "type": "monstergroup", - "name": "GROUP_ROBOT_SECUBOT", - "default": "mon_secubot", - "monsters": [ { "monster": "mon_secubot", "freq": 100, "cost_multiplier": 0 } ] - }, { "type": "monstergroup", "name": "GROUP_PARK_ANIMAL", @@ -5318,12 +5284,6 @@ "default": "mon_dark_wyrm", "monsters": [ { "monster": "mon_dark_wyrm", "freq": 40, "cost_multiplier": 1 } ] }, - { - "name": "GROUP_HAZMATBOT", - "type": "monstergroup", - "default": "mon_hazmatbot", - "monsters": [ { "monster": "mon_hazmatbot", "freq": 40, "cost_multiplier": 1 } ] - }, { "name": "GROUP_STRAY_DOGS", "type": "monstergroup", diff --git a/data/json/monstergroups/robots.json b/data/json/monstergroups/robots.json new file mode 100644 index 0000000000000..d4cbf677275ba --- /dev/null +++ b/data/json/monstergroups/robots.json @@ -0,0 +1,44 @@ +[ + { + "type": "monstergroup", + "name": "GROUP_ROBOT", + "default": "mon_manhack", + "monsters": [ + { "monster": "mon_skitterbot", "freq": 220, "cost_multiplier": 0 }, + { "monster": "mon_secubot", "freq": 150, "cost_multiplier": 0 }, + { "monster": "mon_talon_m202a1", "freq": 75, "cost_multiplier": 0 }, + { "monster": "mon_copbot", "freq": 0, "cost_multiplier": 0 }, + { "monster": "mon_molebot", "freq": 40, "cost_multiplier": 0 } + ] + }, + { + "type": "monstergroup", + "name": "GROUP_TURRET", + "default": "mon_turret_rifle", + "monsters": [ { "monster": "mon_turret_bmg", "freq": 50, "cost_multiplier": 2 } ] + }, + { + "name": "GROUP_HAZMATBOT", + "type": "monstergroup", + "default": "mon_hazmatbot", + "monsters": [ { "monster": "mon_hazmatbot", "freq": 40, "cost_multiplier": 1 } ] + }, + { + "type": "monstergroup", + "name": "GROUP_ROBOT_EYEBOT", + "default": "mon_eyebot", + "monsters": [ { "monster": "mon_eyebot", "freq": 100, "cost_multiplier": 0 } ] + }, + { + "type": "monstergroup", + "name": "GROUP_ROBOT_SECUBOT", + "default": "mon_secubot", + "monsters": [ { "monster": "mon_secubot", "freq": 100, "cost_multiplier": 0 } ] + }, + { + "type": "monstergroup", + "name": "GROUP_TURRET_RIOT", + "default": "mon_turret_riot", + "monsters": [ { "monster": "mon_turret_riot", "freq": 100, "cost_multiplier": 0 } ] + } +] diff --git a/data/json/monsters/turrets.json b/data/json/monsters/turrets.json index 53e1695944207..8f09ae297886f 100644 --- a/data/json/monsters/turrets.json +++ b/data/json/monsters/turrets.json @@ -225,5 +225,55 @@ "death_drops": { }, "death_function": [ "BROKEN" ], "flags": [ "SEES", "NOHEAD", "ELECTRONIC", "IMMOBILE", "NO_BREATHE", "DROPS_AMMO" ] + }, + { + "id": "mon_turret_riot", + "type": "MONSTER", + "name": "riot control platform", + "description": "These six-wheeled riot control platforms were widely publicized a few years before the cataclysm as a new semi-autonomous device that could fire less-lethal rounds with far more accuracy than a human, ensuring safer hits against a target's limbs. They were quickly adopted by prisons and inner city police forces, where they demonstrated that 'less lethal' is not the same as 'non-lethal'. In the days before the cataclysm, massive stockrooms of the things were put into circulation. On the bright side, although it shoots autonomously, it requires a human operator to relocate, so it's not so mobile anymore.", + "default_faction": "cop_bot", + "looks_like": "mon_turret", + "species": [ "ROBOT" ], + "diff": 20, + "volume": "62500 ml", + "weight": 172000, + "hp": 30, + "speed": 100, + "material": [ "steel" ], + "symbol": "2", + "color": "blue", + "aggression": 50, + "morale": 100, + "anger_triggers": [ "PLAYER_CLOSE", "HURT", "FRIEND_ATTACKED", "FRIEND_DIED" ], + "armor_bash": 14, + "armor_cut": 16, + "vision_day": 50, + "vision_night": 3, + "revert_to_itype": "bot_turret_riot", + "starting_ammo": { "40x46mm_sponge": 100 }, + "special_attacks": [ + { + "//": "For later: needs the ability to preferentially target legs and arms", + "type": "gun", + "cooldown": 1, + "move_cost": 150, + "gun_type": "pseudo_m203", + "ammo_type": "40x46mm_sponge", + "fake_skills": [ [ "gun", 8 ], [ "rifle", 8 ] ], + "fake_dex": 12, + "ranges": [ [ 0, 30, "DEFAULT" ] ], + "require_targeting_npc": true, + "require_targeting_monster": true, + "laser_lock": false, + "targeting_cost": 200, + "targeting_timeout_extend": -10, + "targeting_sound": "\"Universal curfew is in effect. Please return to your home. This unit is authorized to open fire.\"", + "targeting_volume": 50, + "no_ammo_sound": "a chk!" + } + ], + "death_drops": { }, + "death_function": [ "BROKEN" ], + "flags": [ "SEES", "NOHEAD", "ELECTRONIC", "IMMOBILE", "NO_BREATHE", "DROPS_AMMO" ] } ] diff --git a/data/json/mutations/mutations.json b/data/json/mutations/mutations.json index 2da69b6758c03..26c235393844e 100644 --- a/data/json/mutations/mutations.json +++ b/data/json/mutations/mutations.json @@ -724,8 +724,9 @@ "id": "PRETTY", "name": "Pretty", "points": 1, + "visibility": 1, "ugliness": -2, - "description": "You are a sight to behold. NPCs who care about such things will react more kindly to you.", + "description": "You are a sight to behold. People who care about such things will react more kindly to you.", "starting_trait": true, "category": [ "ALPHA", "FELINE", "LUPINE" ], "cancels": [ "UGLY", "DEFORMED", "DEFORMED2", "DEFORMED3" ], @@ -1258,8 +1259,9 @@ "id": "UGLY", "name": "Ugly", "points": -1, + "visibility": 1, "ugliness": 2, - "description": "You're not much to look at. NPCs who care about such things will react poorly to you.", + "description": "You're not much to look at. People who care about such things will react poorly to you.", "starting_trait": true, "cancels": [ "PRETTY", "BEAUTIFUL", "BEAUTIFUL2", "BEAUTIFUL3" ], "changes_to": [ "DEFORMED" ], @@ -4421,7 +4423,7 @@ "id": "BEAUTIFUL", "name": "Beautiful", "points": 2, - "visibility": -4, + "visibility": 4, "ugliness": -4, "description": "You're a real head-turner. Some people will react well to your appearance, and most people have an easier time trusting you.", "cancels": [ "UGLY", "DEFORMED", "DEFORMED2", "DEFORMED3" ], @@ -4433,7 +4435,7 @@ "id": "BEAUTIFUL2", "name": "Very Beautiful", "points": 3, - "visibility": -7, + "visibility": 7, "ugliness": -7, "description": "You are a vision of beauty. Some people will react very well to your looks, and most people will trust you immediately.", "cancels": [ "UGLY", "DEFORMED", "DEFORMED2", "DEFORMED3" ], @@ -4445,7 +4447,7 @@ "id": "BEAUTIFUL3", "name": "Glorious", "points": 4, - "visibility": -10, + "visibility": 10, "ugliness": -10, "description": "You are incredibly beautiful. People cannot help themselves due to your charms, and will do whatever they can to please you.", "cancels": [ "UGLY", "DEFORMED", "DEFORMED2", "DEFORMED3" ], @@ -5051,7 +5053,7 @@ "points": -2, "visibility": 10, "ugliness": 10, - "description": "Your flesh is a pleasing gel-like consistency. Your bodily functions seem to be moving around, and your leg-equivalents flow comfortably.", + "description": "Your flesh is a pleasing gel-like consistency. Your bodily functions seem to be moving around, and your leg-equivalents flow comfortably - if a little slower than your old meat-legs.", "purifiable": false, "leads_to": [ "INT_SLIME", "PER_SLIME" ], "prereqs": [ "VISCOUS" ], diff --git a/data/json/npcs/missiondef.json b/data/json/npcs/missiondef.json index c41032e0b92be..11dd9ab86df8c 100644 --- a/data/json/npcs/missiondef.json +++ b/data/json/npcs/missiondef.json @@ -8,10 +8,10 @@ "value": 50000, "start": { "effect": [ "follow", { "u_buy_item": "sarcophagus_access_code" } ], - "assign_mission_target": { "om_terrain": "haz_sar", "om_special": "Hazardous Waste Sarcophagus", "reveal_radius": 3 } + "assign_mission_target": { "om_terrain": "haz_sar_1_1", "om_special": "Hazardous Waste Sarcophagus", "reveal_radius": 3 } }, "origins": [ "ORIGIN_SECONDARY" ], - "destination": "haz_sar_b1", + "destination": "haz_sar_b_1", "dialogue": { "describe": "You wouldn't believe what I found...", "offer": "Holy hell, the crash you recovered the black box from wasn't as old as I thought. Check this out, it was on its approach to pick up a team sent to secure and destroy something called a 'Hazardous Waste Sarcophagus' in the middle of nowhere. If the bird never picked up the team then we may still have a chance to meet up with them. It includes an access code for the elevator and an encoded message for the team leader, I guess. If we want to join up with what remains of the government then now may be our only chance.", diff --git a/data/json/obsolete_terrains.json b/data/json/obsolete_terrains.json index 02b8fb9278261..9f500f559f41f 100644 --- a/data/json/obsolete_terrains.json +++ b/data/json/obsolete_terrains.json @@ -270,6 +270,10 @@ "dairy_farm_SE", "megastore", "megastore_entrance", + "haz_sar_entrance", + "haz_sar", + "haz_sar_entrance_b1", + "haz_sar_b1", "house_base_north", "house_base_south", "house_base_east", diff --git a/data/json/overmap/map_extras.json b/data/json/overmap/map_extras.json index bad3eb720a600..9bf619d283ff8 100644 --- a/data/json/overmap/map_extras.json +++ b/data/json/overmap/map_extras.json @@ -81,7 +81,7 @@ "type": "map_extra", "name": "Roadblock (Bandits)", "description": "This road is blocked by bandits.", - "generator": { "generator_method": "map_extra_function", "generator_id": "mx_roadblock" }, + "generator": { "generator_method": "map_extra_function", "generator_id": "mx_bandits_block" }, "sym": "x", "color": "yellow", "autonote": true diff --git a/data/json/overmap/multitile_city_buildings.json b/data/json/overmap/multitile_city_buildings.json index bdabbc119972f..d39f219c916f1 100644 --- a/data/json/overmap/multitile_city_buildings.json +++ b/data/json/overmap/multitile_city_buildings.json @@ -76,6 +76,15 @@ { "point": [ 0, 0, -1 ], "overmap": "basement" } ] }, + { + "type": "city_building", + "id": "house_inner_garden", + "locations": [ "land" ], + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "house_inner_garden_north" }, + { "point": [ 0, 0, 1 ], "overmap": "house_inner_garden_roof_north" } + ] + }, { "type": "city_building", "id": "s_electronics", diff --git a/data/json/overmap/overmap_special/specials.json b/data/json/overmap/overmap_special/specials.json index da119bace153a..e122084ec5da7 100644 --- a/data/json/overmap/overmap_special/specials.json +++ b/data/json/overmap/overmap_special/specials.json @@ -1089,14 +1089,14 @@ "id": "Hazardous Waste Sarcophagus", "overmaps": [ { "point": [ 1, -1, 0 ], "overmap": "road_end_north" }, - { "point": [ 0, 0, 0 ], "overmap": "haz_sar_north" }, - { "point": [ 1, 0, 0 ], "overmap": "haz_sar_entrance_north" }, - { "point": [ 0, 1, 0 ], "overmap": "haz_sar_north" }, - { "point": [ 1, 1, 0 ], "overmap": "haz_sar_north" }, - { "point": [ 0, 0, -2 ], "overmap": "haz_sar_b1_north" }, - { "point": [ 1, 0, -2 ], "overmap": "haz_sar_entrance_b1_north" }, - { "point": [ 0, 1, -2 ], "overmap": "haz_sar_b1_north" }, - { "point": [ 1, 1, -2 ], "overmap": "haz_sar_b1_north" } + { "point": [ 1, 0, 0 ], "overmap": "haz_sar_1_1_north" }, + { "point": [ 0, 0, 0 ], "overmap": "haz_sar_1_2_north" }, + { "point": [ 1, 1, 0 ], "overmap": "haz_sar_1_3_north" }, + { "point": [ 0, 1, 0 ], "overmap": "haz_sar_1_4_north" }, + { "point": [ 1, 0, -2 ], "overmap": "haz_sar_b_1_north" }, + { "point": [ 0, 0, -2 ], "overmap": "haz_sar_b_2_north" }, + { "point": [ 1, 1, -2 ], "overmap": "haz_sar_b_3_north" }, + { "point": [ 0, 1, -2 ], "overmap": "haz_sar_b_4_north" } ], "connections": [ { "point": [ 1, -1, 0 ] } ], "locations": [ "land" ], diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_residential.json b/data/json/overmap/overmap_terrain/overmap_terrain_residential.json index 742df73bf684c..70aa81386b929 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_residential.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_residential.json @@ -468,6 +468,23 @@ "see_cost": 2, "mondensity": 2 }, + { + "type": "overmap_terrain", + "id": "house_inner_garden", + "name": "house", + "copy-from": "generic_city_building", + "color": "light_green", + "see_cost": 2, + "flags": [ "SIDEWALK", "GENERIC_LOOT" ] + }, + { + "type": "overmap_terrain", + "id": "house_inner_garden_roof", + "name": "house", + "copy-from": "generic_city_building", + "color": "light_green", + "see_cost": 2 + }, { "type": "overmap_terrain", "id": "house_w_1", diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_waste_junk.json b/data/json/overmap/overmap_terrain/overmap_terrain_waste_junk.json index b504798207ef7..5bab968600498 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_waste_junk.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_waste_junk.json @@ -100,6 +100,78 @@ "see_cost": 2, "flags": [ "RISK_HIGH" ] }, + { + "type": "overmap_terrain", + "id": "haz_sar_1_1", + "name": "hazardous waste sarcophagus", + "sym": "X", + "color": "pink", + "see_cost": 5, + "flags": [ "RISK_HIGH" ] + }, + { + "type": "overmap_terrain", + "id": "haz_sar_1_2", + "name": "hazardous waste sarcophagus", + "sym": "X", + "color": "pink", + "see_cost": 5, + "flags": [ "RISK_HIGH" ] + }, + { + "type": "overmap_terrain", + "id": "haz_sar_1_3", + "name": "hazardous waste sarcophagus", + "sym": "X", + "color": "pink", + "see_cost": 5, + "flags": [ "RISK_HIGH" ] + }, + { + "type": "overmap_terrain", + "id": "haz_sar_1_4", + "name": "hazardous waste sarcophagus", + "sym": "X", + "color": "pink", + "see_cost": 5, + "flags": [ "RISK_HIGH" ] + }, + { + "type": "overmap_terrain", + "id": "haz_sar_b_1", + "name": "hazardous waste sarcophagus", + "sym": "X", + "color": "pink", + "see_cost": 5, + "flags": [ "RISK_HIGH" ] + }, + { + "type": "overmap_terrain", + "id": "haz_sar_b_2", + "name": "hazardous waste sarcophagus", + "sym": "X", + "color": "pink", + "see_cost": 5, + "flags": [ "RISK_HIGH" ] + }, + { + "type": "overmap_terrain", + "id": "haz_sar_b_3", + "name": "hazardous waste sarcophagus", + "sym": "X", + "color": "pink", + "see_cost": 5, + "flags": [ "RISK_HIGH" ] + }, + { + "type": "overmap_terrain", + "id": "haz_sar_b_4", + "name": "hazardous waste sarcophagus", + "sym": "X", + "color": "pink", + "see_cost": 5, + "flags": [ "RISK_HIGH" ] + }, { "type": "overmap_terrain", "id": "haz_sar_entrance", diff --git a/data/json/recipes/armor/pets_horse.json b/data/json/recipes/armor/pets_horse.json index fb9d27f30aabf..a020d119a8d9d 100644 --- a/data/json/recipes/armor/pets_horse.json +++ b/data/json/recipes/armor/pets_horse.json @@ -164,5 +164,16 @@ "autolearn": true, "qualities": [ { "id": "SEW", "level": 1 }, { "id": "CUT", "level": 1 } ], "components": [ [ [ "duct_tape", 350 ] ], [ [ "bag_plastic", 70 ] ], [ [ "rag", 70 ] ] ] + }, + { + "result": "saddlebag", + "type": "recipe", + "category": "CC_ANIMALS", + "subcategory": "CSC_ANIMALS_EQUINE STORAGE", + "skills_required": [ "tailor", 4 ], + "time": "120 m", + "autolearn": true, + "using": [ [ "sewing_standard", 40 ] ], + "components": [ [ [ "leather", 12 ], [ "tanned_hide", 3 ] ] ] } ] diff --git a/data/json/recipes/recipe_deconstruction.json b/data/json/recipes/recipe_deconstruction.json index b89569ee42f51..adc4107a8ccf1 100644 --- a/data/json/recipes/recipe_deconstruction.json +++ b/data/json/recipes/recipe_deconstruction.json @@ -731,7 +731,7 @@ "result": "broken_turret", "type": "uncraft", "skill_used": "electronics", - "difficulty": 3, + "difficulty": 4, "time": "1 h", "using": [ [ "soldering_standard", 10 ] ], "qualities": [ { "id": "SCREW", "level": 1 } ], @@ -752,7 +752,7 @@ "result": "broken_turret_rifle", "type": "uncraft", "skill_used": "electronics", - "difficulty": 3, + "difficulty": 4, "time": "1 h", "using": [ [ "soldering_standard", 10 ] ], "qualities": [ { "id": "SCREW", "level": 1 } ], @@ -773,7 +773,7 @@ "result": "broken_crows_m240", "type": "uncraft", "skill_used": "electronics", - "difficulty": 3, + "difficulty": 4, "time": "1 h", "using": [ [ "soldering_standard", 10 ] ], "qualities": [ { "id": "SCREW", "level": 1 } ], @@ -794,7 +794,7 @@ "result": "broken_turret_bmg", "type": "uncraft", "skill_used": "electronics", - "difficulty": 3, + "difficulty": 4, "time": "1 h", "using": [ [ "soldering_standard", 10 ] ], "qualities": [ { "id": "SCREW", "level": 1 } ], @@ -811,11 +811,34 @@ [ [ "turret_chassis", 1 ] ] ] }, + { + "result": "broken_turret_riot", + "type": "uncraft", + "skill_used": "electronics", + "difficulty": 4, + "time": "1 h", + "using": [ [ "soldering_standard", 10 ] ], + "qualities": [ { "id": "SCREW", "level": 1 } ], + "components": [ + [ [ "ai_module", 1 ] ], + [ [ "gun_module", 1 ] ], + [ [ "targeting_module", 1 ] ], + [ [ "identification_module", 1 ] ], + [ [ "sensor_module", 1 ] ], + [ [ "m203", 16 ] ], + [ [ "small_storage_battery", 1 ] ], + [ [ "power_supply", 3 ] ], + [ [ "antenna", 1 ] ], + [ [ "robot_controls", 1 ] ], + [ [ "omni_wheel", 1 ] ], + [ [ "copbot_chassis", 1 ] ] + ] + }, { "result": "broken_laserturret", "type": "uncraft", "skill_used": "electronics", - "difficulty": 3, + "difficulty": 4, "time": "1 h", "using": [ [ "soldering_standard", 10 ] ], "qualities": [ { "id": "SCREW", "level": 1 } ], diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index f2a50a7ee7b30..05ccdf0e30cd8 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -3757,7 +3757,7 @@ ], [ [ "tomato", 1 ], [ "irradiated_tomato", 1 ], [ "can_tomato", 1 ] ], [ [ "meat_red", 1, "LIST" ], [ "dry_meat", 1 ], [ "can_chicken", 1 ] ], - [ [ "sauce_red", 1 ], [ "curry_powder", 4 ] ] + [ [ "curry_powder", 4 ], [ "chilly-p", 4 ] ] ] }, { @@ -3794,7 +3794,7 @@ [ "dry_rice", 1 ] ], [ [ "tomato", 1 ], [ "irradiated_tomato", 1 ], [ "can_tomato", 1 ] ], - [ [ "sauce_red", 1 ], [ "curry_powder", 4 ] ] + [ [ "curry_powder", 4 ], [ "chilly-p", 4 ] ] ] }, { @@ -3824,7 +3824,7 @@ [ [ "tomato", 1 ], [ "irradiated_tomato", 1 ], [ "can_tomato", 1 ] ], [ [ "meat_red", 1, "LIST" ], [ "dry_meat", 1 ], [ "can_chicken", 1 ] ], [ [ "can_beans", 1 ], [ "raw_beans", 1 ], [ "dry_beans", 1 ] ], - [ [ "sauce_red", 1 ], [ "chilly-p", 2 ], [ "chili_pepper", 1 ] ] + [ [ "chilly-p", 2 ], [ "chili_pepper", 1 ] ] ] }, { @@ -3850,7 +3850,15 @@ [ "mushroom_cooked", 2 ], [ "dry_veggy", 2 ] ], - [ [ "sauce_pesto", 1 ], [ "sauce_red", 1 ], [ "seasoning_italian", 5 ], [ "wild_herbs", 10 ] ], + [ + [ "sauce_pesto", 1 ], + [ "sauce_red", 1 ], + [ "seasoning_italian", 5 ], + [ "wild_herbs", 10 ], + [ "tomato", 1 ], + [ "irradiated_tomato", 1 ], + [ "can_tomato", 1 ] + ], [ [ "water", 1 ], [ "water_clean", 1 ] ] ] }, @@ -4963,9 +4971,9 @@ "qualities": [ { "id": "CUT", "level": 1 }, { "id": "COOK", "level": 2 } ], "tools": [ [ [ "surface_heat", 10, "LIST" ] ] ], "components": [ - [ [ "sausage", 2 ], [ "sausage_cooked", 2 ], [ "bratwurst_sausage", 2 ] ], - [ [ "curry_powder", 20 ] ], - [ [ "ketchup", 4 ] ] + [ [ "sausage", 1 ], [ "sausage_cooked", 1 ], [ "bratwurst_sausage", 2 ] ], + [ [ "curry_powder", 10 ], [ "chilly-p", 10 ] ], + [ [ "ketchup", 2 ] ] ] }, { diff --git a/data/json/recipes/recipe_obsolete.json b/data/json/recipes/recipe_obsolete.json index 0187e7a5bd164..1a73a32837b27 100644 --- a/data/json/recipes/recipe_obsolete.json +++ b/data/json/recipes/recipe_obsolete.json @@ -1803,6 +1803,11 @@ "result": "small_relicuncraft", "obsolete": true }, + { + "type": "recipe", + "result": "rock_pot", + "obsolete": true + }, { "type": "recipe", "result": "small_storage_battery", diff --git a/data/json/recipes/recipe_others.json b/data/json/recipes/recipe_others.json index 621eddfe76e6b..33b11df9bd465 100644 --- a/data/json/recipes/recipe_others.json +++ b/data/json/recipes/recipe_others.json @@ -740,19 +740,6 @@ "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ [ [ "stick", 1 ], [ "2x4", 1 ] ] ] }, - { - "type": "recipe", - "result": "rock_pot", - "category": "CC_OTHER", - "subcategory": "CSC_OTHER_TOOLS", - "skill_used": "survival", - "skills_required": [ "cooking", 1 ], - "difficulty": 2, - "time": "20 m", - "autolearn": true, - "qualities": [ { "id": "HAMMER", "level": 1 } ], - "components": [ [ [ "rock", 3 ] ], [ [ "cordage", 1, "LIST" ] ] ] - }, { "type": "recipe", "result": "primitive_shovel", diff --git a/data/json/recipes/recipes.json b/data/json/recipes/recipes.json index fb3253a91441e..9d4b990aff556 100644 --- a/data/json/recipes/recipes.json +++ b/data/json/recipes/recipes.json @@ -103,7 +103,7 @@ { "type": "recipe_category", "id": "CC_ANIMALS", - "recipe_subcategories": [ "CSC_ALL", "CSC_ANIMALS_CANINE ARMOR", "CSC_ANIMALS_EQUINE ARMOR" ] + "recipe_subcategories": [ "CSC_ALL", "CSC_ANIMALS_CANINE ARMOR", "CSC_ANIMALS_EQUINE ARMOR", "CSC_ANIMALS_EQUINE STORAGE" ] }, { "type": "recipe_category", diff --git a/data/json/regional_map_settings.json b/data/json/regional_map_settings.json index b958b7ac3dc94..1f8cb793d1ab8 100644 --- a/data/json/regional_map_settings.json +++ b/data/json/regional_map_settings.json @@ -546,6 +546,7 @@ "house_w_4": 40, "house_w_5": 40, "house_w_6": 40, + "house_inner_garden": 40, "emptyresidentiallot": 20, "apartments_con_new": 10, "apartments_mod_new": 10, diff --git a/data/mods/mapspecials_demo/missile_silo/silo_utrc_03.json b/data/mods/mapspecials_demo/missile_silo/silo_utrc_03.json index 74823c79930f2..ec72d86cdf2fe 100644 --- a/data/mods/mapspecials_demo/missile_silo/silo_utrc_03.json +++ b/data/mods/mapspecials_demo/missile_silo/silo_utrc_03.json @@ -39,7 +39,7 @@ "7": { "name": "Missile Control", "access_denied": "ERROR! Access denied! Unauthorized access will be met with lethal force!", - "options": [ { "name": "Launch Missile", "action": "miss_launch" }, { "name": "Disarm Missile", "action": "miss_disarm" } ], + "options": [ { "name": "Disarm Missile", "action": "miss_disarm" } ], "failures": [ { "action": "secubots" }, { "action": "damage" } ] } } diff --git a/doc/DEVELOPER_TOOLING.md b/doc/DEVELOPER_TOOLING.md index 3c50ab19cf580..ae2f14f195809 100644 --- a/doc/DEVELOPER_TOOLING.md +++ b/doc/DEVELOPER_TOOLING.md @@ -263,7 +263,7 @@ to avoid compiler errors. python3 /clang-tools-extra/clang-tidy/tool/run-clang-tidy.py \ -clang-tidy-binary=build/tools/clang-tidy-plugin/CataAnalyzerPlugin.exe \ -p=build "\.cpp$" \ - -extra-arg=-target -extra-arg=x86_64-pc-windows-gnu -extra-arg=-pthread -extra-arg=-DSDL_DISABLE_ANALYZE_MACROS \ + -extra-arg=-target -extra-arg=x86_64-pc-windows-gnu -extra-arg=-pthread -extra-arg=-DSDL_DISABLE_ANALYZE_MACROS -extra-arg=-Wno-unknown-warning-option \ -extra-arg=-isystem -extra-arg=/clang/lib/Headers ``` diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 7e062ca18366f..28680eae87992 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -6,6 +6,7 @@ Use the `Home` key to return to the top. - [File descriptions](#file-descriptions) * [`data/json/`](#datajson) * [`data/json/items/`](#datajsonitems) + + [`data/json/items/comestibles`](#datajsonitemscomestibles) * [`data/json/requirements/`](#datajsonrequirements) * [`data/json/vehicles/`](#datajsonvehicles) - [Generic properties and formatting](#generic-properties-and-formatting) @@ -160,7 +161,7 @@ Use the `Home` key to return to the top. This document describes the contents of the json files used in Cataclysm: Dark days ahead. You are probably reading this if you want to add or change content of Catacysm: Dark days ahead and need to learn more about what to find where and what each file and property does. # File descriptions -Here's a quick summary of what each of the JSON files contain, broken down by folder. +Here's a quick summary of what each of the JSON files contain, broken down by folder. This list is not comprehensive, but covers the broad strokes. ## `data/json/` @@ -259,6 +260,8 @@ See below for specifics on the various items | tools.json | tools and items that can be (a)ctivated | vehicle_parts.json | components of vehicles when they aren't on the vehicle +### `data/json/items/comestibles` + ## `data/json/requirements/` Standard components and tools for crafting @@ -483,6 +486,12 @@ The syntax listed here is still valid. | `specific_heat_solid` | Specific heat of a material when frozen (J/(g K)). Default 2.108. | `latent_heat` | Latent heat of fusion for a material (J/g). Default 334. | `freeze_point` | Freezing point of this material (F). Default 32 F ( 0 C ). +| `edible` | Optional boolean. Default is false. +| `rotting` | Optional boolean. Default is false. +| `soft` | Optional boolean. Default is false. +| `reinforces` | Optional boolean. Default is false. + +There are six -resist parameters: acid, bash, chip, cut, elec, and fire. These are integer values; the default is 0 and they can be negative to take more damage. ```C++ { diff --git a/src/avatar.cpp b/src/avatar.cpp index d89c4b3cad279..52e4191142c33 100644 --- a/src/avatar.cpp +++ b/src/avatar.cpp @@ -1,7 +1,7 @@ #include "avatar.h" -#include -#include +#include +#include #include #include #include diff --git a/src/avatar.h b/src/avatar.h index 92eda70fc169c..341df17c8f5ce 100644 --- a/src/avatar.h +++ b/src/avatar.h @@ -2,7 +2,7 @@ #ifndef AVATAR_H #define AVATAR_H -#include +#include #include #include #include diff --git a/src/avatar_action.cpp b/src/avatar_action.cpp index 3243d03bc5e94..0bb4f6b0549e2 100644 --- a/src/avatar_action.cpp +++ b/src/avatar_action.cpp @@ -1,6 +1,6 @@ #include "avatar_action.h" -#include +#include #include #include #include @@ -1018,9 +1018,7 @@ void avatar_action::plthrow( avatar &you, item_location loc, } // you must wield the item to throw it if( !you.is_wielding( *orig ) ) { - if( you.wield( *orig ) ) { - orig = &you.weapon; - } else { + if( !you.wield( *orig ) ) { return; } } diff --git a/src/avatar_action.h b/src/avatar_action.h index a4e8aa06f6611..df18173e592d6 100644 --- a/src/avatar_action.h +++ b/src/avatar_action.h @@ -2,7 +2,7 @@ #ifndef AVATAR_ACTION_H #define AVATAR_ACTION_H -#include +#include #include "optional.h" #include "point.h" diff --git a/src/behavior.cpp b/src/behavior.cpp index 2208bc873040c..2d911d16fe5b1 100644 --- a/src/behavior.cpp +++ b/src/behavior.cpp @@ -1,6 +1,6 @@ #include "behavior.h" -#include +#include #include #include #include diff --git a/src/cata_algo.h b/src/cata_algo.h index 7337246f30217..ef284136f9c87 100644 --- a/src/cata_algo.h +++ b/src/cata_algo.h @@ -3,9 +3,13 @@ #define CATA_ALGO_H #include +#include +#include +#include +#include #include -namespace algo +namespace cata { /** @@ -41,6 +45,82 @@ void sort_by_rating( Iterator begin, Iterator end, RatingFunction rating_func ) } ); } -} // namespace algo +// Implementation detail of below find_cycles +// This explores one branch of the given graph depth-first +template +void find_cycles_impl( + const std::unordered_map> &edges, + const T &v, + std::unordered_set &visited, + std::unordered_map &on_current_branch, + std::vector> &result ) +{ + bool new_vertex = visited.insert( v ).second; + + if( !new_vertex ) { + return; + } + auto it = edges.find( v ); + if( it == edges.end() ) { + return; + } + + for( const T &next_v : it->second ) { + if( next_v == v ) { + // Trivial self-loop + result.push_back( { v } ); + continue; + } + auto previous_match = on_current_branch.find( next_v ); + if( previous_match != on_current_branch.end() ) { + // We have looped back to somewhere along the branch we took to + // reach this vertex, so reconstruct the loop and save it. + std::vector loop; + T on_path = v; + while( true ) { + loop.push_back( on_path ); + if( on_path == next_v ) { + break; + } + on_path = on_current_branch[on_path]; + } + std::reverse( loop.begin(), loop.end() ); + result.push_back( loop ); + } else { + on_current_branch.emplace( next_v, v ); + find_cycles_impl( edges, next_v, visited, on_current_branch, result ); + on_current_branch.erase( next_v ); + } + } +} + +// Find and return a list of all cycles in a directed graph. +// Each T defines a vertex. +// For a vertex a, edges[a] is a list of all the vertices connected by edges +// from a. +// It is acceptable for some vertex keys to be missing from the edges map, if +// those vertices have no out-edges. +// Complexity should be O(V+E) +// Based on https://www.geeksforgeeks.org/detect-cycle-in-a-graph/ +template +std::vector> find_cycles( const std::unordered_map> &edges ) +{ + std::unordered_set visited; + std::unordered_map on_current_branch; + std::vector> result; + + for( const auto &p : edges ) { + const T &root = p.first; + + on_current_branch.emplace( root, root ); + find_cycles_impl( edges, root, visited, on_current_branch, result ); + on_current_branch.erase( root ); + assert( on_current_branch.empty() ); + } + + return result; +} + +} // namespace cata #endif // CATA_ALGO_H diff --git a/src/cata_tiles.cpp b/src/cata_tiles.cpp index 766eccacfd0ef..9562a0d95d826 100644 --- a/src/cata_tiles.cpp +++ b/src/cata_tiles.cpp @@ -1353,10 +1353,13 @@ void cata_tiles::draw( const point &dest, const tripoint ¢er, int width, int would_apply_vision_effects( g->m.get_visibility( ch.visibility_cache[np.x][np.y], cache ) ); } //calling draw to memorize everything. - draw_terrain( p, lighting, height_3d, invisible ); - draw_furniture( p, lighting, height_3d, invisible ); - draw_trap( p, lighting, height_3d, invisible ); - draw_vpart( p, lighting, height_3d, invisible ); + if( g->m.check_seen_cache( p ) ) { + draw_terrain( p, lighting, height_3d, invisible ); + draw_furniture( p, lighting, height_3d, invisible ); + draw_trap( p, lighting, height_3d, invisible ); + draw_vpart( p, lighting, height_3d, invisible ); + g->m.check_and_set_seen_cache( p ); + } } } @@ -2176,7 +2179,7 @@ bool cata_tiles::draw_terrain( const tripoint &p, const lit_level ll, int &heigh // do something to get other terrain orientation values } const std::string &tname = t.id().str(); - if( g->m.check_and_set_seen_cache( p ) ) { + if( g->m.check_seen_cache( p ) ) { g->u.memorize_tile( g->m.getabs( p ), tname, subtile, rotation ); } // draw the actual terrain if there's no override @@ -2340,7 +2343,7 @@ bool cata_tiles::draw_furniture( const tripoint &p, const lit_level ll, int &hei int rotation = 0; get_tile_values( f, neighborhood, subtile, rotation ); const std::string &fname = f.id().str(); - if( g->m.check_and_set_seen_cache( p ) ) { + if( g->m.check_seen_cache( p ) ) { g->u.memorize_tile( g->m.getabs( p ), fname, subtile, rotation ); } // draw the actual furniture if there's no override @@ -2414,7 +2417,7 @@ bool cata_tiles::draw_trap( const tripoint &p, const lit_level ll, int &height_3 int rotation = 0; get_tile_values( tr, neighborhood, subtile, rotation ); const std::string trname = tr.id().str(); - if( g->m.check_and_set_seen_cache( p ) ) { + if( g->m.check_seen_cache( p ) ) { g->u.memorize_tile( g->m.getabs( p ), trname, subtile, rotation ); } // draw the actual trap if there's no override @@ -2580,7 +2583,7 @@ bool cata_tiles::draw_vpart( const tripoint &p, lit_level ll, int &height_3d, const int rotation = veh.face.dir(); const std::string vpname = "vp_" + vp_id.str(); if( !veh.forward_velocity() && !veh.player_in_control( g->u ) && - g->m.check_and_set_seen_cache( p ) ) { + g->m.check_seen_cache( p ) ) { g->u.memorize_tile( g->m.getabs( p ), vpname, subtile, rotation ); } if( !overridden ) { diff --git a/src/character.cpp b/src/character.cpp index f8c0af9416e00..aceba9460129c 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -1,6 +1,6 @@ #include "character.h" -#include +#include #include #include #include diff --git a/src/clzones.h b/src/clzones.h index 9c5bd5e44153e..db3485286b61b 100644 --- a/src/clzones.h +++ b/src/clzones.h @@ -2,7 +2,7 @@ #ifndef CLZONES_H #define CLZONES_H -#include +#include #include #include #include diff --git a/src/computer.cpp b/src/computer.cpp index 75a31cc48c3f1..ec996580a8aee 100644 --- a/src/computer.cpp +++ b/src/computer.cpp @@ -320,6 +320,7 @@ std::string computer::save_data() const void computer::load_data( const std::string &data ) { + static const std::set blacklisted_options = {{ "Launch_Missile" }}; options.clear(); failures.clear(); @@ -340,7 +341,9 @@ void computer::load_data( const std::string &data ) int tmpsec; dump >> tmpname >> tmpaction >> tmpsec; - + if( blacklisted_options.find( tmpname ) != blacklisted_options.end() ) { + continue; + } add_option( string_replace( tmpname, "_", " " ), static_cast( tmpaction ), tmpsec ); } @@ -631,69 +634,8 @@ void computer::activate_function( computer_action action ) } break; - case COMPACT_MISS_LAUNCH: { - // Target Acquisition. - tripoint target = ui::omap::choose_point( 0 ); - if( target == overmap::invalid_tripoint ) { - add_msg( m_info, _( "Target acquisition canceled." ) ); - return; - } - - // TODO: Z - target.z = 0; - - if( query_yn( _( "Confirm nuclear missile launch." ) ) ) { - add_msg( m_info, _( "Nuclear missile launched!" ) ); - //Remove the option to fire another missile. - options.clear(); - } else { - add_msg( m_info, _( "Nuclear missile launch aborted." ) ); - return; - } - g->refresh_all(); - - //Put some smoke gas and explosions at the nuke location. - const tripoint nuke_location = { g->u.pos() - point( 12, 0 ) }; - for( const auto &loc : g->m.points_in_radius( nuke_location, 5, 0 ) ) { - if( one_in( 4 ) ) { - g->m.add_field( loc, fd_smoke, rng( 1, 9 ) ); - } - } - - //Only explode once. But make it large. - explosion_handler::explosion( nuke_location, 2000, 0.7, true ); - - //...ERASE MISSILE, OPEN SILO, DISABLE COMPUTER - // For each level between here and the surface, remove the missile - for( int level = g->get_levz(); level <= 0; level++ ) { - map tmpmap; - tmpmap.load( tripoint( g->get_levx(), g->get_levy(), level ), false ); - - if( level < 0 ) { - tmpmap.translate( t_missile, t_hole ); - } else { - tmpmap.translate( t_metal_floor, t_hole ); - } - tmpmap.save(); - } - - const oter_id oter = overmap_buffer.ter( target ); - g->events().send( oter ); - for( const tripoint &p : g->m.points_in_radius( target, 2 ) ) { - // give it a nice rounded shape - if( !( p.x == target.x - 2 && p.y == target.y - 2 ) && - !( p.x == target.x - 2 && p.y == target.y + 2 ) && - !( p.x == target.x + 2 && p.y == target.y - 2 ) && - !( p.x == target.x + 2 && p.y == target.y + 2 ) ) { - // TODO: other Z-levels. - explosion_handler::nuke( tripoint( p.xy(), 0 ) ); - } - } - - activate_failure( COMPFAIL_SHUTDOWN ); - } - break; - + case COMPACT_OBSOLETE: + break; case COMPACT_MISS_DISARM: // TODO: stop the nuke from creating radioactive clouds. if( query_yn( _( "Disarm missile." ) ) ) { @@ -1659,21 +1601,7 @@ void computer::print_newline() wprintz( w_terminal, c_green, "\n" ); } -computer_option computer_option::from_json( const JsonObject &jo ) -{ - std::string name = jo.get_string( "name" ); - computer_action action = computer_action_from_string( jo.get_string( "action" ) ); - int sec = jo.get_int( "security", 0 ); - return computer_option( name, action, sec ); -} - -computer_failure computer_failure::from_json( const JsonObject &jo ) -{ - computer_failure_type type = computer_failure_type_from_string( jo.get_string( "action" ) ); - return computer_failure( type ); -} - -computer_action computer_action_from_string( const std::string &str ) +static computer_action computer_action_from_string( const std::string &str ) { static const std::map actions = {{ { "null", COMPACT_NULL }, @@ -1694,7 +1622,6 @@ computer_action computer_action_from_string( const std::string &str ) { "maps", COMPACT_MAPS }, { "map_sewer", COMPACT_MAP_SEWER }, { "map_subway", COMPACT_MAP_SUBWAY }, - { "miss_launch", COMPACT_MISS_LAUNCH }, { "miss_disarm", COMPACT_MISS_DISARM }, { "list_bionics", COMPACT_LIST_BIONICS }, { "elevator_on", COMPACT_ELEVATOR_ON }, @@ -1738,7 +1665,7 @@ computer_action computer_action_from_string( const std::string &str ) return COMPACT_NULL; } -computer_failure_type computer_failure_type_from_string( const std::string &str ) +static computer_failure_type computer_failure_type_from_string( const std::string &str ) { static const std::map fails = {{ { "null", COMPFAIL_NULL }, @@ -1763,3 +1690,16 @@ computer_failure_type computer_failure_type_from_string( const std::string &str debugmsg( "Invalid computer failure %s", str ); return COMPFAIL_NULL; } +computer_option computer_option::from_json( const JsonObject &jo ) +{ + std::string name = jo.get_string( "name" ); + computer_action action = computer_action_from_string( jo.get_string( "action" ) ); + int sec = jo.get_int( "security", 0 ); + return computer_option( name, action, sec ); +} + +computer_failure computer_failure::from_json( const JsonObject &jo ) +{ + computer_failure_type type = computer_failure_type_from_string( jo.get_string( "action" ) ); + return computer_failure( type ); +} diff --git a/src/computer.h b/src/computer.h index 7419244068b87..e9852549e24a0 100644 --- a/src/computer.h +++ b/src/computer.h @@ -29,7 +29,7 @@ enum computer_action { COMPACT_MAPS, COMPACT_MAP_SEWER, COMPACT_MAP_SUBWAY, - COMPACT_MISS_LAUNCH, + COMPACT_OBSOLETE, // No longer used COMPACT_MISS_DISARM, COMPACT_LIST_BIONICS, COMPACT_ELEVATOR_ON, @@ -66,7 +66,6 @@ enum computer_action { COMPACT_RADIO_ARCHIVE, NUM_COMPUTER_ACTIONS }; - // Don't change those! They must stay in this specific order! // TODO: Remove this enum enum computer_failure_type { @@ -84,10 +83,6 @@ enum computer_failure_type { NUM_COMPUTER_FAILURES }; -// TODO: Turn the enum into id, get rid of this -computer_action computer_action_from_string( const std::string &str ); -computer_failure_type computer_failure_type_from_string( const std::string &str ); - struct computer_option { std::string name; computer_action action; diff --git a/src/construction_category.h b/src/construction_category.h index 21619a84fcd48..acf944a3328fd 100644 --- a/src/construction_category.h +++ b/src/construction_category.h @@ -2,7 +2,7 @@ #ifndef CONSTRUCTION_CATEGORY_H #define CONSTRUCTION_CATEGORY_H -#include +#include #include #include diff --git a/src/consumption.cpp b/src/consumption.cpp index cd1c12f8b93f2..08ea0258df406 100644 --- a/src/consumption.cpp +++ b/src/consumption.cpp @@ -23,6 +23,8 @@ #include "morale_types.h" #include "mutation.h" #include "options.h" +#include "recipe.h" +#include "recipe_dictionary.h" #include "stomach.h" #include "string_formatter.h" #include "translations.h" @@ -96,20 +98,24 @@ int player::stomach_capacity() const } // TODO: Move pizza scraping here. -static int compute_default_effective_kcal( const item &comest, const player &p ) +static int compute_default_effective_kcal( const item &comest, const player &p, + const cata::flat_set &extra_flags = {} ) { static const trait_id trait_CARNIVORE( "CARNIVORE" ); static const trait_id trait_GIZZARD( "GIZZARD" ); static const trait_id trait_SAPROPHAGE( "SAPROPHAGE" ); static const std::string flag_CARNIVORE_OK( "CARNIVORE_OK" ); - assert( comest.get_comestible() ); + if( !comest.get_comestible() ) { + return 0; + } // As float to avoid rounding too many times float kcal = comest.get_comestible()->default_nutrition.kcal; // Many raw foods give less calories, as your body has expends more energy digesting them. - if( comest.has_flag( "RAW" ) && !comest.has_flag( "COOKED" ) ) { + bool cooked = comest.has_flag( "COOKED" ) || extra_flags.count( "COOKED" ); + if( comest.has_flag( "RAW" ) && !cooked ) { kcal *= 0.75f; } @@ -145,7 +151,9 @@ static int compute_default_effective_kcal( const item &comest, const player &p ) static std::map compute_default_effective_vitamins( const item &it, const player &p ) { - assert( it.get_comestible() ); + if( !it.get_comestible() ) { + return {}; + } std::map res = it.get_comestible()->default_nutrition.vitamins; @@ -173,9 +181,9 @@ static std::map compute_default_effective_vitamins( // Calculate the effective nutrients for a given item, taking // into account player traits but not item components. static nutrients compute_default_effective_nutrients( const item &comest, - const player &p ) + const player &p, const cata::flat_set &extra_flags = {} ) { - return { compute_default_effective_kcal( comest, p ), + return { compute_default_effective_kcal( comest, p, extra_flags ), compute_default_effective_vitamins( comest, p ) }; } @@ -207,6 +215,114 @@ nutrients player::compute_effective_nutrients( const item &comest ) const } } +// Calculate range of nutrients obtainable for a given item when crafted via +// the given recipe +std::pair player::compute_nutrient_range( + const item &comest, const recipe_id &recipe_i, + const cata::flat_set &extra_flags ) const +{ + if( !comest.is_comestible() ) { + return {}; + } + + // if item has components, will derive calories from that instead. + if( comest.has_flag( "NUTRIENT_OVERRIDE" ) ) { + nutrients result = compute_default_effective_nutrients( comest, *this ); + return { result, result }; + } + + nutrients tally_min; + nutrients tally_max; + + const recipe &rec = *recipe_i; + + cata::flat_set our_extra_flags = extra_flags; + + if( rec.hot_result() ) { + our_extra_flags.insert( "COOKED" ); + } + + const requirement_data requirements = rec.requirements(); + const requirement_data::alter_item_comp_vector &component_requirements = + requirements.get_components(); + + for( const std::vector &component_options : component_requirements ) { + nutrients this_min; + nutrients this_max; + bool first = true; + for( const item_comp &component_option : component_options ) { + std::pair component_option_range = + compute_nutrient_range( component_option.type, our_extra_flags ); + component_option_range.first *= component_option.count; + component_option_range.second *= component_option.count; + + if( first ) { + std::tie( this_min, this_max ) = component_option_range; + first = false; + } else { + this_min.min_in_place( component_option_range.first ); + this_max.max_in_place( component_option_range.second ); + } + } + tally_min += this_min; + tally_max += this_max; + } + + for( const std::pair &byproduct : rec.byproducts ) { + item byproduct_it( byproduct.first, calendar::turn, byproduct.second ); + nutrients byproduct_nutr = compute_default_effective_nutrients( byproduct_it, *this ); + tally_min -= byproduct_nutr; + tally_max -= byproduct_nutr; + } + + int charges = comest.count(); + return { tally_min / charges, tally_max / charges }; +} + +// Calculate the range of nturients possible for a given item across all +// possible recipes +std::pair player::compute_nutrient_range( + const itype_id &comest_id, const cata::flat_set &extra_flags ) const +{ + const itype *comest = item::find_type( comest_id ); + if( !comest->comestible ) { + return {}; + } + + item comest_it( comest, calendar::turn, 1 ); + // The default nutrients are always a possibility + nutrients min_nutr = compute_default_effective_nutrients( comest_it, *this, extra_flags ); + + if( comest->item_tags.count( "NUTRIENT_OVERRIDE" ) || + recipe_dict.is_item_on_loop( comest->get_id() ) ) { + return { min_nutr, min_nutr }; + } + + nutrients max_nutr = min_nutr; + + for( const recipe_id &rec : comest->recipes ) { + nutrients this_min; + nutrients this_max; + + item result_it = rec->create_result(); + if( result_it.contents.size() == 1 ) { + const item alt_result = result_it.contents.front(); + if( alt_result.typeId() == comest_it.typeId() ) { + result_it = alt_result; + } + } + if( result_it.typeId() != comest_it.typeId() ) { + debugmsg( "When creating recipe result expected %s, got %s\n", + comest_it.typeId(), result_it.typeId() ); + } + std::tie( this_min, this_max ) = compute_nutrient_range( result_it, rec, extra_flags ); + min_nutr.min_in_place( this_min ); + max_nutr.max_in_place( this_max ); + } + + return { min_nutr, max_nutr }; +} + int player::nutrition_for( const item &comest ) const { return compute_effective_nutrients( comest ).kcal / islot_comestible::kcal_per_nutr; diff --git a/src/craft_command.cpp b/src/craft_command.cpp index 8e43f6aebc60d..73018b9fdae28 100644 --- a/src/craft_command.cpp +++ b/src/craft_command.cpp @@ -1,6 +1,6 @@ #include "craft_command.h" -#include +#include #include #include #include diff --git a/src/crafting_gui.cpp b/src/crafting_gui.cpp index ca4bf9e5d0850..41c7f84b3ee10 100644 --- a/src/crafting_gui.cpp +++ b/src/crafting_gui.cpp @@ -607,17 +607,10 @@ const recipe *select_crafting_recipe( int &batch_size ) if( last_recipe != current[line] ) { last_recipe = current[line]; tmp = current[line]->create_result(); + tmp.set_var( "recipe_exemplar", last_recipe->ident().str() ); } tmp.info( true, thisItem, count ); - // If it's food that can have variable nutrition, add disclaimer. - // Hidden if the user is attempting to page through components. - if( ( tmp.is_food_container() || tmp.is_food() ) && !tmp.has_flag( "NUTRIENT_OVERRIDE" ) && - display_mode == 0 ) { - ypos += fold_and_print( w_data, point( xpos + 2, ypos ), pane - 2, c_light_gray, - _( "Shown nutrition is estimated, varying with chosen ingredients." ) ); - } - //color needs to be preserved in case part of the previous page was cut off nc_color stored_color = col; if( display_mode > 1 ) { diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index 85f9f02830f8b..a5442c61ed99e 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -1,8 +1,8 @@ #include "debug_menu.h" // IWYU pragma: no_include -#include -#include +#include +#include #include #include #include @@ -67,7 +67,7 @@ #include "artifact.h" #include "vpart_position.h" #include "rng.h" -#include "signal.h" +#include #include "magic.h" #include "bodypart.h" #include "calendar.h" diff --git a/src/event.cpp b/src/event.cpp index a026dc7ade4a8..c0daa07ac241d 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -54,7 +54,6 @@ std::string enum_to_string( event_type data ) case event_type::game_start: return "game_start"; case event_type::installs_cbm: return "installs_cbm"; case event_type::installs_faulty_cbm: return "installs_faulty_cbm"; - case event_type::launches_nuke: return "launches_nuke"; case event_type::learns_martial_art: return "learns_martial_art"; case event_type::loses_addiction: return "loses_addiction"; case event_type::npc_becomes_hostile: return "npc_becomes_hostile"; @@ -92,7 +91,7 @@ constexpr std::array, constexpr std::array, event_spec_character::fields.size()> event_spec_character::fields; -static_assert( static_cast( event_type::num_event_types ) == 62, +static_assert( static_cast( event_type::num_event_types ) == 61, "This static_assert is a reminder to add a definition below when you add a new " "event_type. If your event_spec specialization inherits from another struct for " "its fields definition then you probably don't need a definition here." ); @@ -129,7 +128,6 @@ DEFINE_EVENT_FIELDS( game_over ) DEFINE_EVENT_FIELDS( game_start ) DEFINE_EVENT_FIELDS( installs_cbm ) DEFINE_EVENT_FIELDS( installs_faulty_cbm ) -DEFINE_EVENT_FIELDS( launches_nuke ) DEFINE_EVENT_FIELDS( learns_martial_art ) DEFINE_EVENT_FIELDS( loses_addiction ) DEFINE_EVENT_FIELDS( npc_becomes_hostile ) diff --git a/src/event.h b/src/event.h index 661089d71ae2d..9720143303469 100644 --- a/src/event.h +++ b/src/event.h @@ -64,7 +64,6 @@ enum class event_type { game_start, installs_cbm, installs_faulty_cbm, - launches_nuke, learns_martial_art, loses_addiction, npc_becomes_hostile, @@ -134,7 +133,7 @@ struct event_spec_character { }; }; -static_assert( static_cast( event_type::num_event_types ) == 62, +static_assert( static_cast( event_type::num_event_types ) == 61, "This static_assert is to remind you to add a specialization for your new " "event_type below" ); @@ -433,14 +432,6 @@ struct event_spec { }; }; -template<> -struct event_spec { - static constexpr std::array, 1> fields = {{ - { "target_terrain", cata_variant_type::oter_id }, - } - }; -}; - template<> struct event_spec { static constexpr std::array, 2> fields = {{ diff --git a/src/explosion.cpp b/src/explosion.cpp index d40de90657602..f723f10d31bd8 100644 --- a/src/explosion.cpp +++ b/src/explosion.cpp @@ -825,35 +825,6 @@ void resonance_cascade( const tripoint &p ) } } -void nuke( const tripoint &p ) -{ - // TODO: nukes hit above surface, not critter = 0 - // TODO: Z - tripoint p_surface( p.xy(), 0 ); - tinymap tmpmap; - tmpmap.load( omt_to_sm_copy( p_surface ), false ); - tripoint dest( 0, 0, p.z ); - int &i = dest.x; - int &j = dest.y; - for( i = 0; i < SEEX * 2; i++ ) { - for( j = 0; j < SEEY * 2; j++ ) { - if( !one_in( 10 ) ) { - tmpmap.make_rubble( dest, f_rubble_rock, true, t_dirt, true ); - } - if( one_in( 3 ) ) { - tmpmap.add_field( dest, fd_nuke_gas, 3 ); - } - tmpmap.adjust_radiation( dest, rng( 20, 80 ) ); - } - } - tmpmap.save(); - overmap_buffer.ter_set( p_surface, oter_id( "crater" ) ); - // Kill any npcs on that omap location. - for( const auto &npc : overmap_buffer.get_npcs_near_omt( p_surface, 0 ) ) { - npc->marked_for_death = true; - } -} - } // namespace explosion_handler // This is only ever used to zero the cloud values, which is what makes it work. diff --git a/src/explosion.h b/src/explosion.h index 8a70066dfb3cd..18897b2024d6d 100644 --- a/src/explosion.h +++ b/src/explosion.h @@ -54,8 +54,6 @@ void resonance_cascade( const tripoint &p ); void scrambler_blast( const tripoint &p ); /** Triggers an EMP blast at p. */ void emp_blast( const tripoint &p ); -/** Nuke the area at p - global overmap terrain coordinates! */ -void nuke( const tripoint &p ); // shockwave applies knockback to all targets within radius of p // parameters force, stun, and dam_mult are passed to knockback() // ignore_player determines if player is affected, useful for bionic, etc. diff --git a/src/faction.cpp b/src/faction.cpp index 20c45c6040206..428a7afe4f463 100644 --- a/src/faction.cpp +++ b/src/faction.cpp @@ -1,6 +1,6 @@ #include "faction.h" -#include +#include #include #include #include diff --git a/src/field_type.h b/src/field_type.h index 38ebeaf7dac30..bc11a7d4e9e40 100644 --- a/src/field_type.h +++ b/src/field_type.h @@ -2,8 +2,8 @@ #ifndef FIELD_TYPE_H #define FIELD_TYPE_H -#include -#include +#include +#include #include #include #include diff --git a/src/game.cpp b/src/game.cpp index 9974bb5fb9d1f..2032b72754951 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1,7 +1,7 @@ #include "game.h" -#include -#include +#include +#include #include #include #include @@ -1173,22 +1173,35 @@ bool game::cleanup_at_end() bool queryReset = false; if( get_option( "WORLD_END" ) == "query" ) { - uilist smenu; - smenu.allow_cancel = false; - smenu.addentry( 0, true, 'k', "%s", _( "Keep world" ) ); - smenu.addentry( 1, true, 'r', "%s", _( "Reset world" ) ); - smenu.addentry( 2, true, 'd', "%s", _( "Delete world" ) ); - smenu.query(); - - switch( smenu.ret ) { - case 0: - break; - case 1: - queryReset = true; - break; - case 2: - queryDelete = true; - break; + bool decided = false; + std::string buffer = _( "Warning: NPC interactions and some other global flags " + "will not all reset when starting a new character in an " + "already-played world. This can lead to some strange " + "behavior.\n\n" + "Are you sure you wish to keep this world?" + ); + + while( !decided ) { + uilist smenu; + smenu.allow_cancel = false; + smenu.addentry( 0, true, 'r', "%s", _( "Reset world" ) ); + smenu.addentry( 1, true, 'd', "%s", _( "Delete world" ) ); + smenu.addentry( 2, true, 'k', "%s", _( "Keep world" ) ); + smenu.query(); + + switch( smenu.ret ) { + case 0: + queryReset = true; + decided = true; + break; + case 1: + queryDelete = true; + decided = true; + break; + case 2: + decided = query_yn( buffer ); + break; + } } } diff --git a/src/game_inventory.cpp b/src/game_inventory.cpp index 9e12d92f2c4f3..812aa3f5c484b 100644 --- a/src/game_inventory.cpp +++ b/src/game_inventory.cpp @@ -1,6 +1,6 @@ #include "game_inventory.h" -#include +#include #include #include #include diff --git a/src/generic_factory.h b/src/generic_factory.h index 0ac1ca1f84141..20b080d997190 100644 --- a/src/generic_factory.h +++ b/src/generic_factory.h @@ -833,6 +833,38 @@ class auto_flags_reader : public generic_typed_reader; +class volume_reader : public generic_typed_reader +{ + public: + bool operator()( const JsonObject &jo, const std::string &member_name, + units::volume &member, bool /* was_loaded */ ) const { + if( !jo.has_member( member_name ) ) { + return false; + } + member = read_from_json_string( *jo.get_raw( member_name ), units::volume_units ); + return true; + } + units::volume get_next( JsonIn &jin ) const { + return read_from_json_string( jin, units::volume_units ); + } +}; + +class mass_reader : public generic_typed_reader +{ + public: + bool operator()( const JsonObject &jo, const std::string &member_name, + units::mass &member, bool /* was_loaded */ ) const { + if( !jo.has_member( member_name ) ) { + return false; + } + member = read_from_json_string( *jo.get_raw( member_name ), units::mass_units ); + return true; + } + units::mass get_next( JsonIn &jin ) const { + return read_from_json_string( jin, units::mass_units ); + } +}; + /** * Uses a map (unordered or standard) to convert strings from JSON to some other type * (the mapped type of the map: `C::mapped_type`). It works for all mapped types, not just enums. diff --git a/src/handle_liquid.cpp b/src/handle_liquid.cpp index 58d75755b5814..cfdad43df3832 100644 --- a/src/handle_liquid.cpp +++ b/src/handle_liquid.cpp @@ -1,7 +1,7 @@ #include "handle_liquid.h" -#include -#include +#include +#include #include #include #include diff --git a/src/iexamine.cpp b/src/iexamine.cpp index 1cfe3eb6450cf..204d4a4ed327b 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -1161,7 +1161,7 @@ void iexamine::slot_machine( player &p, const tripoint & ) add_msg( m_info, _( "You need $%d to play." ), price ); break; } - if( !query_yn( _( played ? "Play again for $%d?" : "Insert $%d?" ), price ) ) { + if( !query_yn( played ? _( "Play again for $%d?" ) : _( "Insert $%d?" ), price ) ) { break; } p.cash -= cents( price ); diff --git a/src/inventory_ui.h b/src/inventory_ui.h index 2faa88ef67bca..5d5105bc77c3d 100644 --- a/src/inventory_ui.h +++ b/src/inventory_ui.h @@ -2,7 +2,7 @@ #ifndef INVENTORY_UI_H #define INVENTORY_UI_H -#include +#include #include #include #include diff --git a/src/item.cpp b/src/item.cpp index 7a1e28e066a03..0569205198a34 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1322,12 +1322,38 @@ void item::med_info( const item *med_item, std::vector &info, const it void item::food_info( const item *food_item, std::vector &info, const iteminfo_query *parts, int batch, bool debug ) const { - const nutrients nutr = g->u.compute_effective_nutrients( *food_item ); + nutrients min_nutr; + nutrients max_nutr; + + std::string recipe_exemplar = get_var( "recipe_exemplar", "" ); + if( recipe_exemplar.empty() ) { + min_nutr = max_nutr = g->u.compute_effective_nutrients( *food_item ); + } else { + std::tie( min_nutr, max_nutr ) = + g->u.compute_nutrient_range( *food_item, recipe_id( recipe_exemplar ) ); + } + + bool show_nutr = parts->test( iteminfo_parts::FOOD_NUTRITION ) || + parts->test( iteminfo_parts::FOOD_VITAMINS ); + if( min_nutr != max_nutr && show_nutr ) { + info.emplace_back( + "FOOD", _( "Nutrition will vary with chosen ingredients." ) ); + if( recipe_dict.is_item_on_loop( food_item->typeId() ) ) { + info.emplace_back( + "FOOD", _( "Nutrition range cannot be calculated accurately due to " + "recipe loops." ) ); + } + } + const std::string space = " "; - if( nutr.kcal != 0 || food_item->get_comestible()->quench != 0 ) { + if( max_nutr.kcal != 0 || food_item->get_comestible()->quench != 0 ) { if( parts->test( iteminfo_parts::FOOD_NUTRITION ) ) { info.push_back( iteminfo( "FOOD", _( "Calories (kcal): " ), - "", iteminfo::no_newline, nutr.kcal ) ); + "", iteminfo::no_newline, min_nutr.kcal ) ); + if( max_nutr.kcal != min_nutr.kcal ) { + info.push_back( iteminfo( "FOOD", _( "-" ), + "", iteminfo::no_newline, max_nutr.kcal ) ); + } } if( parts->test( iteminfo_parts::FOOD_QUENCH ) ) { info.push_back( iteminfo( "FOOD", space + _( "Quench: " ), @@ -1351,30 +1377,34 @@ void item::food_info( const item *food_item, std::vector &info, info.push_back( iteminfo( "FOOD", _( "Smells like: " ) + food_item->corpse->nname() ) ); } - const std::string required_vits = enumerate_as_string( - nutr.vitamins.begin(), - nutr.vitamins.end(), - []( const std::pair &v ) { + auto format_vitamin = [&]( const std::pair &v, bool display_vitamins ) { + const bool is_vitamin = v.first->type() == vitamin_type::VITAMIN; // only display vitamins that we actually require - return ( g->u.vitamin_rate( v.first ) > 0_turns && v.second != 0 && - v.first->type() == vitamin_type::VITAMIN && !v.first->has_flag( "NO_DISPLAY" ) ) ? - string_format( "%s (%i%%)", v.first.obj().name(), - static_cast( v.second * g->u.vitamin_rate( v.first ) / - 1_days * 100 ) ) : - std::string(); + if( g->u.vitamin_rate( v.first ) == 0_turns || v.second == 0 || + display_vitamins != is_vitamin || v.first->has_flag( "NO_DISPLAY" ) ) { + return std::string(); + } + const double multiplier = g->u.vitamin_rate( v.first ) / 1_days * 100; + const int min_value = min_nutr.get_vitamin( v.first ); + const int max_value = v.second; + const int min_rda = lround( min_value * multiplier ); + const int max_rda = lround( max_value * multiplier ); + const std::string format = min_rda == max_rda ? "%s (%i%%)" : "%s (%i-%i%%)"; + return string_format( format, v.first->name(), min_value, max_value ); + }; + + const std::string required_vits = enumerate_as_string( + max_nutr.vitamins.begin(), + max_nutr.vitamins.end(), + [&]( const std::pair &v ) { + return format_vitamin( v, true ); } ); const std::string effect_vits = enumerate_as_string( - nutr.vitamins.begin(), - nutr.vitamins.end(), - []( const std::pair &v ) { - // only display vitamins that we actually require - return ( g->u.vitamin_rate( v.first ) > 0_turns && v.second != 0 && - v.first->type() != vitamin_type::VITAMIN && !v.first->has_flag( "NO_DISPLAY" ) ) ? - string_format( "%s (%i%%)", v.first.obj().name(), - static_cast( v.second * g->u.vitamin_rate( v.first ) / - 1_days * 100 ) ) : - std::string(); + max_nutr.vitamins.begin(), + max_nutr.vitamins.end(), + [&]( const std::pair &v ) { + return format_vitamin( v, false ); } ); if( !required_vits.empty() && parts->test( iteminfo_parts::FOOD_VITAMINS ) ) { diff --git a/src/item.h b/src/item.h index 6daece3776d93..f0ac233d5ef52 100644 --- a/src/item.h +++ b/src/item.h @@ -2,7 +2,7 @@ #ifndef ITEM_H #define ITEM_H -#include +#include #include #include #include diff --git a/src/item_factory.cpp b/src/item_factory.cpp index 11695c5389478..513e76b70619b 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -440,6 +440,19 @@ void Item_factory::finalize() finalize_pre( *e.second ); finalize_post( *e.second ); } + + // for each item register all (non-obsolete) potential recipes + for( const std::pair &p : recipe_dict ) { + const recipe &rec = p.second; + if( rec.obsolete || rec.will_be_blacklisted() ) { + continue; + } + const itype_id &result = rec.result(); + auto it = m_templates.find( result ); + if( it != m_templates.end() ) { + it->second.recipes.push_back( p.first ); + } + } } void Item_factory::finalize_item_blacklist() diff --git a/src/itype.h b/src/itype.h index 2dc035a840237..40a2c6186ce42 100644 --- a/src/itype.h +++ b/src/itype.h @@ -965,6 +965,9 @@ struct itype { /** What items can be used to repair this item? @see Item_factory::finalize */ std::set repair; + /** What recipes can make this item */ + std::vector recipes; + /** What faults (if any) can occur */ std::set faults; diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index 7bc6b7605700a..8594c832bdde4 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -2566,13 +2566,21 @@ int holster_actor::use( player &p, item &it, bool, const tripoint & ) const return string_format( _( "Draw %s" ), elem.display_name() ); } ); + item *internal_item = nullptr; if( opts.size() > 1 ) { - const int ret = uilist( string_format( _( "Use %s" ), it.tname() ), opts ); + int ret = uilist( string_format( _( "Use %s" ), it.tname() ), opts ); if( ret < 0 ) { pos = -2; } else { pos += ret; + if( opts.size() != it.contents.size() ) { + ret--; + } + auto iter = std::next( it.contents.begin(), ret ); + internal_item = &*iter; } + } else { + internal_item = &it.contents.front(); } if( pos < -1 ) { @@ -2583,13 +2591,13 @@ int holster_actor::use( player &p, item &it, bool, const tripoint & ) const if( pos >= 0 ) { // worn holsters ignore penalty effects (e.g. GRABBED) when determining number of moves to consume if( p.is_worn( it ) ) { - p.wield_contents( it, pos, false, draw_cost ); + p.wield_contents( it, internal_item, false, draw_cost ); } else { - p.wield_contents( it, pos ); + p.wield_contents( it, internal_item ); } } else { - auto loc = game_menus::inv::holster( p, it ); + item_location loc = game_menus::inv::holster( p, it ); if( !loc ) { p.add_msg_if_player( _( "Never mind." ) ); diff --git a/src/magic.cpp b/src/magic.cpp index 16bad5b8fbdc2..47ad78291b9f8 100644 --- a/src/magic.cpp +++ b/src/magic.cpp @@ -1,6 +1,6 @@ #include "magic.h" -#include +#include #include #include #include diff --git a/src/magic.h b/src/magic.h index f8e3b5dcc4ecc..d57ef3d6e6bae 100644 --- a/src/magic.h +++ b/src/magic.h @@ -2,7 +2,7 @@ #ifndef MAGIC_H #define MAGIC_H -#include +#include #include #include #include diff --git a/src/magic_spell_effect.cpp b/src/magic_spell_effect.cpp index 1159b3f4d8458..c6fac1357fcf4 100644 --- a/src/magic_spell_effect.cpp +++ b/src/magic_spell_effect.cpp @@ -1,6 +1,6 @@ -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/src/magic_teleporter_list.cpp b/src/magic_teleporter_list.cpp index b93f72c870cf2..d6f2a3df7aa4c 100644 --- a/src/magic_teleporter_list.cpp +++ b/src/magic_teleporter_list.cpp @@ -1,6 +1,6 @@ #include "magic_teleporter_list.h" -#include +#include #include #include #include diff --git a/src/main.cpp b/src/main.cpp index 21536165ad805..8da3f3577441b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,7 +19,7 @@ #if defined(_WIN32) #include "platform_win.h" #else -#include +#include #endif #include "color.h" #include "crash.h" diff --git a/src/map.h b/src/map.h index c2a1ff55baef2..65a89eb8d3c65 100644 --- a/src/map.h +++ b/src/map.h @@ -265,6 +265,11 @@ class map } } + bool check_seen_cache( const tripoint &p ) const { + std::bitset &memory_seen_cache = + get_cache( p.z ).map_memory_seen_cache; + return !memory_seen_cache[ static_cast( p.x + p.y * MAPSIZE_Y ) ]; + } bool check_and_set_seen_cache( const tripoint &p ) const { std::bitset &memory_seen_cache = get_cache( p.z ).map_memory_seen_cache; @@ -1534,7 +1539,6 @@ class map void draw_temple( mapgendata &dat ); void draw_mine( mapgendata &dat ); void draw_spiral( mapgendata &dat ); - void draw_sarcophagus( mapgendata &dat ); void draw_fema( mapgendata &dat ); void draw_anthill( mapgendata &dat ); void draw_slimepit( mapgendata &dat ); diff --git a/src/map_extras.cpp b/src/map_extras.cpp index bf02a4b81d6e8..7d0ebc50994a5 100644 --- a/src/map_extras.cpp +++ b/src/map_extras.cpp @@ -108,6 +108,7 @@ static const mtype_id mon_dispatch( "mon_dispatch" ); static const mtype_id mon_tankbot( "mon_tankbot" ); static const mtype_id mon_turret_bmg( "mon_turret_bmg" ); static const mtype_id mon_turret_rifle( "mon_turret_rifle" ); +static const mtype_id mon_turret_riot( "mon_turret_riot" ); static const mtype_id mon_zombie_spitter( "mon_zombie_spitter" ); static const mtype_id mon_zombie_soldier( "mon_zombie_soldier" ); static const mtype_id mon_zombie_military_pilot( "mon_zombie_military_pilot" ); @@ -525,14 +526,16 @@ static void mx_roadblock( map &m, const tripoint &abs_sub ) const bool road_at_east = is_ot_match( "road", east, ot_match_type::type ); const auto spawn_turret = [&]( int x, int y ) { - if( one_in( 2 ) ) { + if( one_in( 3 ) ) { m.add_spawn( mon_turret_bmg, 1, point( x, y ) ); - } else { + } else if( one_in( 2 ) ) { m.add_spawn( mon_turret_rifle, 1, point( x, y ) ); + } else { + m.add_spawn( mon_turret_riot, 1, point( x, y ) ); } }; bool mil = false; - if( one_in( 3 ) ) { + if( one_in( 6 ) ) { mil = true; } if( mil ) { //Military doesn't joke around with their barricades! @@ -573,14 +576,21 @@ static void mx_roadblock( map &m, const tripoint &abs_sub ) } } - if( one_in( 3 ) ) { // Chicken delivery - m.add_vehicle( vgroup_id( "military_vehicles" ), tripoint( 12, SEEY * 2 - 7, abs_sub.z ), 0, 70, - -1 ); - m.add_spawn( mon_chickenbot, 1, point( 12, 12 ) ); - } else if( one_in( 2 ) ) { // TAAANK + if( one_in( 2 ) ) { // The truck's wrecked...with fuel. Explosive barrel? - m.add_vehicle( vproto_id( "military_cargo_truck" ), point( 12, SEEY * 2 - 8 ), 0, 70, -1 ); - m.add_spawn( mon_tankbot, 1, point( 12, 12 ) ); + m.add_vehicle( vproto_id( "military_cargo_truck" ), point( 12, SEEY * 2 - 12 ), 0, 70, -1 ); + if( road_at_north ) { + spawn_turret( 12, 6 ); + } + if( road_at_east ) { + spawn_turret( 18, 12 ); + } + if( road_at_south ) { + spawn_turret( 12, 18 ); + } + if( road_at_west ) { + spawn_turret( 6, 12 ); + } } else { // Vehicle & turrets m.add_vehicle( vgroup_id( "military_vehicles" ), tripoint( 12, SEEY * 2 - 10, abs_sub.z ), 0, 70, -1 ); @@ -616,22 +626,22 @@ static void mx_roadblock( map &m, const tripoint &abs_sub ) if( road_at_north ) { line_furn( &m, f_barricade_road, 4, 3, 10, 3 ); line_furn( &m, f_barricade_road, 13, 3, 19, 3 ); - m.add_spawn( mon_turret_rifle, 1, point( 12, 1 ) ); + m.add_spawn( mon_turret_riot, 1, point( 12, 1 ) ); } if( road_at_east ) { line_furn( &m, f_barricade_road, SEEX * 2 - 3, 4, SEEX * 2 - 3, 10 ); line_furn( &m, f_barricade_road, SEEX * 2 - 3, 13, SEEX * 2 - 3, 19 ); - m.add_spawn( mon_turret_rifle, 1, point( SEEX * 2 - 1, 12 ) ); + m.add_spawn( mon_turret_riot, 1, point( SEEX * 2 - 1, 12 ) ); } if( road_at_south ) { line_furn( &m, f_barricade_road, 4, SEEY * 2 - 3, 10, SEEY * 2 - 3 ); line_furn( &m, f_barricade_road, 13, SEEY * 2 - 3, 19, SEEY * 2 - 3 ); - m.add_spawn( mon_turret_rifle, 1, point( 12, SEEY * 2 - 1 ) ); + m.add_spawn( mon_turret_riot, 1, point( 12, SEEY * 2 - 1 ) ); } if( road_at_west ) { line_furn( &m, f_barricade_road, 3, 4, 3, 10 ); line_furn( &m, f_barricade_road, 3, 13, 3, 19 ); - m.add_spawn( mon_turret_rifle, 1, point( 1, 12 ) ); + m.add_spawn( mon_turret_riot, 1, point( 1, 12 ) ); } m.add_vehicle( vproto_id( "policecar" ), point( 8, 6 ), 20 ); @@ -2740,14 +2750,13 @@ void apply_function( const string_id &id, map &m, const tripoint &abs break; } case map_extra_method::mapgen: { - tripoint over( abs_sub ); - sm_to_omt( over ); - mapgendata dat( over, m, 0.0f, calendar::turn, nullptr ); + mapgendata dat( sm_to_omt_copy( abs_sub ), m, 0.0f, calendar::turn, nullptr ); run_mapgen_func( extra.generator_id, dat ); break; } case map_extra_method::update_mapgen: { - run_mapgen_update_func( extra.generator_id, sm_to_omt_copy( abs_sub ) ); + mapgendata dat( sm_to_omt_copy( abs_sub ), m, 0.0f, calendar::start_of_cataclysm, nullptr ); + run_mapgen_update_func( extra.generator_id, dat ); break; } case map_extra_method::null: diff --git a/src/map_extras.h b/src/map_extras.h index a079fa5c33fc9..fe92449cce025 100644 --- a/src/map_extras.h +++ b/src/map_extras.h @@ -2,7 +2,7 @@ #ifndef MAP_EXTRAS_H #define MAP_EXTRAS_H -#include +#include #include #include diff --git a/src/mapdata.cpp b/src/mapdata.cpp index 7cf26bedd0215..51908adb959e0 100644 --- a/src/mapdata.cpp +++ b/src/mapdata.cpp @@ -1255,7 +1255,7 @@ void furn_t::load( const JsonObject &jo, const std::string &src ) optional( jo, was_loaded, "bonus_fire_warmth_feet", bonus_fire_warmth_feet, 300 ); optional( jo, was_loaded, "keg_capacity", keg_capacity, legacy_volume_reader, 0_ml ); mandatory( jo, was_loaded, "required_str", move_str_req ); - assign( jo, "max_volume", max_volume, src == "dda" ); + optional( jo, was_loaded, "max_volume", max_volume, volume_reader(), DEFAULT_MAX_VOLUME_IN_SQUARE ); optional( jo, was_loaded, "crafting_pseudo_item", crafting_pseudo_item, "" ); optional( jo, was_loaded, "deployed_item", deployed_item ); load_symbol( jo ); diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 8af82206d208c..dcb2210f5c8c9 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -1,6 +1,6 @@ #include "mapgen.h" -#include +#include #include #include #include @@ -2728,8 +2728,6 @@ void map::draw_map( mapgendata &dat ) if( is_ot_match( "slimepit", terrain_type, ot_match_type::prefix ) || is_ot_match( "slime_pit", terrain_type, ot_match_type::prefix ) ) { draw_slimepit( dat ); - } else if( is_ot_match( "haz_sar", terrain_type, ot_match_type::prefix ) ) { - draw_sarcophagus( dat ); } else if( is_ot_match( "triffid", terrain_type, ot_match_type::prefix ) ) { draw_triffid( dat ); } else if( is_ot_match( "office", terrain_type, ot_match_type::prefix ) ) { @@ -5136,582 +5134,6 @@ void map::draw_spiral( mapgendata &dat ) } } -void map::draw_sarcophagus( mapgendata &dat ) -{ - const oter_id &terrain_type = dat.terrain_type(); - computer *tmpcomp = nullptr; - - const auto ter_key = mapf::ter_bind( "R 1 & V C G 5 % Q E , _ r X f F V H 6 x $ ^ . - | " - "# t + = D w T S e o h c d l s !", t_elevator_control_off, - t_sewage_pipe, t_sewage_pump, t_vat, t_floor, t_grate, - t_wall_glass, t_wall_glass, t_sewage, t_elevator, - t_pavement_y, t_pavement, t_floor, t_door_metal_locked, - t_chainfence, t_chainfence, t_wall_glass, t_wall_glass, - t_console, t_console_broken, t_shrub, t_floor, t_floor, - t_wall, t_wall, t_rock, t_floor, t_door_c, - t_door_locked_alarm, t_door_locked, t_window, t_floor, - t_floor, t_floor, t_floor, t_floor, t_floor, t_floor, - t_floor, t_sidewalk, t_thconc_floor ); - const auto fur_key = mapf::furn_bind( "R 1 & V C G 5 % Q E , _ r X f F V H 6 x $ ^ . - | " - "# t + = D w T S e o h c d l s !", f_null, f_null, - f_null, f_null, f_crate_c, f_null, f_null, f_null, - f_null, f_null, f_null, f_null, f_rack, f_null, f_null, - f_null, f_null, f_null, f_null, f_null, f_null, - f_indoor_plant, f_null, f_null, f_null, f_null, f_table, - f_null, f_null, f_null, f_null, f_toilet, f_sink, - f_fridge, f_bookcase, f_chair, f_counter, f_desk, - f_locker, f_null, f_null ); - const auto b_ter_key = mapf::ter_bind( "= + E & 6 H V c h d r M _ $ | - # . , l S T", - t_door_metal_c, t_door_metal_o, t_elevator, - t_elevator_control_off, t_console, t_reinforced_glass, - t_reinforced_glass, t_floor, t_floor, t_floor, t_floor, - t_gates_control_concrete, t_sewage, t_door_metal_locked, - t_concrete_wall, t_concrete_wall, t_rock, t_rock_floor, - t_metal_floor, t_floor, t_floor, t_floor ); - const auto b_fur_key = mapf::furn_bind( "= + E & 6 H V c h d r M _ $ | - # . , l S T", f_null, - f_null, f_null, f_null, f_null, f_null, f_null, - f_counter, f_chair, f_desk, f_rack, f_null, f_null, - f_null, f_null, f_null, f_null, f_null, f_null, - f_locker, f_sink, f_toilet ); - - // Convenience function because this big block of hardcoded mapgen does a LOT of overmap terrain - // comparisons and it gets very verbose. What would be better is to convert all this to JSON mapgen. - const auto match = []( const oter_id & oterid, const std::string & oterstr ) { - return is_ot_match( oterstr, oterid, ot_match_type::type ); - }; - - if( match( terrain_type, "haz_sar_entrance" ) ) { - // Init to grass & dirt; - dat.fill_groundcover(); - mapf::formatted_set_simple( this, 0, 0, - " f |_________%..S| |.\n" - " f |!!!!!!!!!|..r| |.\n" - " f |!!!!!!!!!|..r| |.\n" - " f |l!!!!!!!!=..r| |c\n" - " f |l!!!!!!!!|..S| |w\n" - " f |l!!!!!!!!%..r|sss\n" - " f |!!!!!!!!!%..r|sss\n" - " f |!!!!!!!!!%..r|ss_\n" - " f |!!!!!!!!!|x..|ss_\n" - " f |-XXXXXXX-|-D-|ss_\n" - " f s_______ssssssss_\n" - " f s_______ssssssss_\n" - " f s________________\n" - " f s________________\n" - " f s________________\n" - " f ssss________________\n" - " f ssss_______ssssssss_\n" - " fF|-D-|XXXXXXX- s_\n" - " wxh.D_______f s_\n" - " wcdcw_______f ss\n" - " |www|_______fFFFFFFFF\n" - " _______ \n" - " _______ \n" - " _______ \n", ter_key, fur_key ); - spawn_item( point( 19, 3 ), "cleansuit" ); - place_items( "office", 80, point( 4, 19 ), point( 6, 19 ), false, calendar::start_of_cataclysm ); - place_items( "cleaning", 90, point( 7, 3 ), point( 7, 5 ), false, calendar::start_of_cataclysm ); - place_items( "toxic_dump_equipment", 85, point( 19, 1 ), point( 19, 3 ), false, - calendar::start_of_cataclysm ); - place_items( "toxic_dump_equipment", 85, point( 19, 5 ), point( 19, 7 ), false, - calendar::start_of_cataclysm ); - place_spawns( GROUP_HAZMATBOT, 2, point( 10, 5 ), point( 10, 5 ), 1, true ); - //lazy radiation mapping - for( int x = 0; x < SEEX * 2; x++ ) { - for( int y = 0; y < SEEY * 2; y++ ) { - adjust_radiation( point( x, y ), rng( 10, 30 ) ); - } - } - if( match( dat.north(), "haz_sar" ) && match( dat.west(), "haz_sar" ) ) { - rotate( 3 ); - } else if( match( dat.north(), "haz_sar" ) && match( dat.east(), "haz_sar" ) ) { - rotate( 0 ); - } else if( match( dat.south(), "haz_sar" ) && match( dat.east(), "haz_sar" ) ) { - rotate( 1 ); - } else if( match( dat.west(), "haz_sar" ) && match( dat.south(), "haz_sar" ) ) { - rotate( 2 ); - } - } else if( match( terrain_type, "haz_sar" ) ) { - dat.fill_groundcover(); - if( ( match( dat.south(), "haz_sar_entrance" ) && match( dat.east(), "haz_sar" ) ) || - ( match( dat.north(), "haz_sar" ) && match( dat.east(), "haz_sar_entrance" ) ) || - ( match( dat.west(), "haz_sar" ) && match( dat.north(), "haz_sar_entrance" ) ) || - ( match( dat.south(), "haz_sar" ) && match( dat.west(), "haz_sar_entrance" ) ) ) { - mapf::formatted_set_simple( this, 0, 0, - " \n" - " fFFFFFFFFFFFFFFFFFFFFFF\n" - " f \n" - " f \n" - " f #################\n" - " f ##################\n" - " f ##...llrr..........\n" - " f ##..!!!!!!!!!.......\n" - " f ##..!!!!!!!!!&&&1111\n" - " f ##..!!!!!!!!x&&&....\n" - " f ##..!!!!!!!!!!!!....\n" - " f ##r.!!!!!!!!!!!!....\n" - " f ##r.!!!!!!!!!!!!....\n" - " f ##r.!!!!!!!!!!!!....\n" - " f ##r.!!!!!!!!!!!!..CC\n" - " f ##..!!!!!!!!!!!...CC\n" - " f ##..!!!!!!!!!!....C.\n" - " f ##..!!!!!!!!!.......\n" - " f ##..!!!!!!!!........\n" - " f ###.!!!!!!!x##.#####\n" - " f ####XXXXXXX###+#####\n" - " f ##!!!!!!!!x|x.r| \n" - " f |!!!!!!!!!%..r| |-\n" - " f |!!!!!!!!!%..r| |^\n", ter_key, fur_key ); - spawn_item( point( 19, 22 ), "cleansuit" ); - place_items( "cleaning", 85, point( 6, 11 ), point( 6, 14 ), false, calendar::start_of_cataclysm ); - place_items( "tools_common", 85, point( 10, 6 ), point( 13, 6 ), false, - calendar::start_of_cataclysm ); - place_items( "toxic_dump_equipment", 85, point( 22, 14 ), point( 23, 15 ), false, - calendar::start_of_cataclysm ); - place_spawns( GROUP_HAZMATBOT, 2, point( 22, 12 ), point( 22, 12 ), 1, true ); - place_spawns( GROUP_HAZMATBOT, 2, point( 23, 18 ), point( 23, 18 ), 1, true ); - //lazy radiation mapping - for( int x = 0; x < SEEX * 2; x++ ) { - for( int y = 0; y < SEEY * 2; y++ ) { - adjust_radiation( point( x, y ), rng( 10, 30 ) ); - } - } - if( match( dat.west(), "haz_sar_entrance" ) ) { - rotate( 1 ); - if( x_in_y( 1, 4 ) ) { - add_vehicle( vproto_id( "military_cargo_truck" ), point( 10, 11 ), 0 ); - } - } else if( match( dat.north(), "haz_sar_entrance" ) ) { - rotate( 2 ); - if( x_in_y( 1, 4 ) ) { - add_vehicle( vproto_id( "military_cargo_truck" ), point( 12, 10 ), 90 ); - } - } else if( match( dat.east(), "haz_sar_entrance" ) ) { - rotate( 3 ); - if( x_in_y( 1, 4 ) ) { - add_vehicle( vproto_id( "military_cargo_truck" ), point( 13, 12 ), 180 ); - } - } else if( x_in_y( 1, 4 ) ) { - add_vehicle( vproto_id( "military_cargo_truck" ), point( 11, 13 ), 270 ); - } - - } else if( ( match( dat.west(), "haz_sar_entrance" ) && match( dat.north(), "haz_sar" ) ) || - ( match( dat.north(), "haz_sar_entrance" ) && match( dat.east(), "haz_sar" ) ) || - ( match( dat.west(), "haz_sar" ) && match( dat.south(), "haz_sar_entrance" ) ) || - ( match( dat.south(), "haz_sar" ) && match( dat.east(), "haz_sar_entrance" ) ) ) { - mapf::formatted_set_simple( this, 0, 0, - "......|-+-|-+|...h..w f \n" - ".c....|.............w f \n" - "hd....+....ch.....hdw f \n" - "cc....|....cdd...ddd| f \n" - "ww-www|w+w-www--www-| f \n" - "ssssssssssssssssssss f \n" - "ssssssssssssssssssss f \n" - "___,____,____,____ss f \n" - "___,____,____,____ss f \n" - "___,____,____,____ss f \n" - "___,____,____,____ss f \n" - "___,____,____,____ss f \n" - "__________________ss f \n" - "__________________ss f \n" - "__________________ss f \n" - "__________________ss f \n" - "________,_________ss f \n" - "________,_________ss f \n" - "________,_________ss f \n" - "ssssssssssssssssssss f \n" - "FFFFFFFFFFFFFFFFFFFFFFf \n" - " \n" - " \n" - " \n", ter_key, fur_key ); - spawn_item( point( 1, 2 ), "id_military" ); - place_items( "office", 85, point_south_east, point( 1, 3 ), false, calendar::start_of_cataclysm ); - place_items( "office", 85, point( 11, 3 ), point( 13, 3 ), false, calendar::start_of_cataclysm ); - place_items( "office", 85, point( 17, 3 ), point( 19, 3 ), false, calendar::start_of_cataclysm ); - //lazy radiation mapping - for( int x = 0; x < SEEX * 2; x++ ) { - for( int y = 0; y < SEEY * 2; y++ ) { - adjust_radiation( point( x, y ), rng( 10, 30 ) ); - } - } - if( match( dat.north(), "haz_sar_entrance" ) ) { - rotate( 1 ); - } - if( match( dat.east(), "haz_sar_entrance" ) ) { - rotate( 2 ); - } - if( match( dat.south(), "haz_sar_entrance" ) ) { - rotate( 3 ); - } - } else { - mapf::formatted_set_simple( this, 0, 0, - " \n" - "FFFFFFFFFFFFFFFFFFFFFFf \n" - " f \n" - " f \n" - "################ f \n" - "################# f \n" - ".V.V.V..........## f \n" - ".......|G|.......## f \n" - "11111111111111...## f \n" - ".......|G|.%515%.## f \n" - "...........%QQQ%.## f \n" - "..CC......x%QQQ%.## f \n" - ".CCC.......%QQQ%.## f \n" - "...........%QQQ%.## f \n" - ".....|.R|..%515%.## f \n" - "......EE|....1...## f \n" - "......EE|....&...## f \n" - ".....---|.......## f \n" - "...............## f \n" - "################ f \n" - "############### f \n" - " f \n" - "------|---|--|---www| f \n" - ".x6x..|S.T|l.|^.ddd.| f \n", ter_key, fur_key ); - place_items( "office", 85, point( 16, 23 ), point( 18, 23 ), false, calendar::start_of_cataclysm ); - place_items( "cleaning", 85, point( 11, 23 ), point( 12, 23 ), false, - calendar::start_of_cataclysm ); - place_items( "robots", 90, point( 2, 11 ), point( 3, 11 ), false, calendar::start_of_cataclysm ); - // TODO: change to monster group - place_spawns( GROUP_HAZMATBOT, 2, point( 7, 10 ), point( 7, 10 ), 1, true ); - place_spawns( GROUP_HAZMATBOT, 2, point( 11, 16 ), point( 11, 16 ), 1, true ); - //lazy radiation mapping - for( int x = 0; x < SEEX * 2; x++ ) { - for( int y = 0; y < SEEY * 2; y++ ) { - adjust_radiation( point( x, y ), rng( 10, 30 ) ); - } - } - tmpcomp = add_computer( tripoint( 2, 23, abs_sub.z ), _( "SRCF Security Terminal" ), 0 ); - tmpcomp->add_option( _( "Security Reminder [1055]" ), COMPACT_SR1_MESS, 0 ); - tmpcomp->add_option( _( "Security Reminder [1056]" ), COMPACT_SR2_MESS, 0 ); - tmpcomp->add_option( _( "Security Reminder [1057]" ), COMPACT_SR3_MESS, 0 ); - //tmpcomp->add_option(_("Security Reminder [1058]"), COMPACT_SR4_MESS, 0); limited to 9 computer options - tmpcomp->add_option( _( "EPA: Report All Potential Containment Breaches [3873643]" ), - COMPACT_SRCF_1_MESS, 2 ); - tmpcomp->add_option( _( "SRCF: Internal Memo, EPA [2918024]" ), COMPACT_SRCF_2_MESS, 2 ); - tmpcomp->add_option( _( "CDC: Internal Memo, Standby [2918115]" ), COMPACT_SRCF_3_MESS, 2 ); - tmpcomp->add_option( _( "USARMY: SEAL SRCF [987167]" ), COMPACT_SRCF_SEAL_ORDER, 4 ); - tmpcomp->add_option( _( "COMMAND: REACTIVATE ELEVATOR" ), COMPACT_SRCF_ELEVATOR, 0 ); - tmpcomp->add_option( _( "COMMAND: SEAL SRCF [4423]" ), COMPACT_SRCF_SEAL, 5 ); - tmpcomp->add_failure( COMPFAIL_ALARM ); - if( match( dat.west(), "haz_sar" ) && match( dat.north(), "haz_sar" ) ) { - rotate( 1 ); - } - if( match( dat.east(), "haz_sar" ) && match( dat.north(), "haz_sar" ) ) { - rotate( 2 ); - } - if( match( dat.east(), "haz_sar" ) && match( dat.south(), "haz_sar" ) ) { - rotate( 3 ); - } - } - } else if( match( terrain_type, "haz_sar_entrance_b1" ) ) { - // Init to grass & dirt; - dat.fill_groundcover(); - mapf::formatted_set_simple( this, 0, 0, - "#############...........\n" - "#############...........\n" - "|---------|#............\n" - "|_________|M............\n" - "|_________$.............\n" - "|_________$.............\n" - "|_________$.............\n" - "|_________$.............\n" - "|_________$.............\n" - "|_________|.............\n" - "|---------|#............\n" - "############............\n" - "###########.............\n" - "###########M......####..\n" - "#########|--$$$$$--|####\n" - "####|----|_________|----\n" - "####|___________________\n" - "####|___________________\n" - "####|___________________\n" - "####|___________________\n" - "####|___________________\n" - "####|___________________\n" - "####|___________________\n" - "####|-------------------\n", b_ter_key, b_fur_key ); - for( int i = 0; i < SEEX * 2; i++ ) { - for( int j = 0; j < SEEY * 2; j++ ) { - if( this->ter( point( i, j ) ) == t_rock_floor ) { - if( one_in( 250 ) ) { - add_item( point( i, j ), item::make_corpse() ); - place_items( "science", 70, point( i, j ), point( i, j ), true, calendar::start_of_cataclysm ); - } - place_spawns( GROUP_PLAIN, 80, point( i, j ), point( i, j ), 1, true ); - } - if( this->ter( point( i, j ) ) != t_metal_floor ) { - adjust_radiation( point( i, j ), rng( 10, 70 ) ); - } - if( this->ter( point( i, j ) ) == t_sewage ) { - if( one_in( 2 ) ) { - ter_set( point( i, j ), t_dirtfloor ); - } - if( one_in( 4 ) ) { - ter_set( point( i, j ), t_dirtmound ); - } - if( one_in( 2 ) ) { - make_rubble( tripoint( i, j, abs_sub.z ), f_wreckage, true ); - } - place_items( "trash", 50, point( i, j ), point( i, j ), false, calendar::start_of_cataclysm ); - place_items( "sewer", 50, point( i, j ), point( i, j ), false, calendar::start_of_cataclysm ); - if( one_in( 40 ) ) { - spawn_item( point( i, j ), "nanomaterial", 1, 5 ); - } - place_spawns( GROUP_VANILLA, 5, point( i, j ), point( i, j ), 1, true ); - } - } - } - if( match( dat.north(), "haz_sar_b1" ) && match( dat.west(), "haz_sar_b1" ) ) { - rotate( 3 ); - } else if( match( dat.north(), "haz_sar_b1" ) && match( dat.east(), "haz_sar_b1" ) ) { - rotate( 0 ); - } else if( match( dat.south(), "haz_sar_b1" ) && match( dat.east(), "haz_sar_b1" ) ) { - rotate( 1 ); - } else if( match( dat.west(), "haz_sar_b1" ) && match( dat.south(), "haz_sar_b1" ) ) { - rotate( 2 ); - } - } else if( match( terrain_type, "haz_sar_b1" ) ) { - dat.fill_groundcover(); - if( ( match( dat.south(), "haz_sar_entrance_b1" ) && match( dat.east(), "haz_sar_b1" ) ) || - ( match( dat.north(), "haz_sar_b1" ) && match( dat.east(), "haz_sar_entrance_b1" ) ) || - ( match( dat.west(), "haz_sar_b1" ) && match( dat.north(), "haz_sar_entrance_b1" ) ) || - ( match( dat.south(), "haz_sar_b1" ) && match( dat.west(), "haz_sar_entrance_b1" ) ) ) { - mapf::formatted_set_simple( this, 0, 0, - "########################\n" - "####################.##.\n" - "####|----------|###.....\n" - "####|__________|M.......\n" - "####|__________$........\n" - "####|__________$........\n" - "####|__________$........\n" - "####|__________$........\n" - "####|__________$........\n" - "####|__________|........\n" - "####|----------|........\n" - "###############.........\n" - "##############..........\n" - "#############...........\n" - "############...........#\n" - "|---------|#.........###\n" - "|_________|M.........###\n" - "|_________$..........|--\n" - "|_________$..........|r,\n" - "|_________$..........|r,\n" - "|_________$..........|r,\n" - "|_________$..........|,,\n" - "|_________|..........|,,\n" - "|---------|#.........|-$\n", b_ter_key, b_fur_key ); - for( int i = 0; i < SEEX * 2; i++ ) { - for( int j = 0; j < SEEY * 2; j++ ) { - if( this->furn( point( i, j ) ) == f_rack ) { - place_items( "mechanics", 60, point( i, j ), point( i, j ), false, calendar::start_of_cataclysm ); - } - if( this->ter( point( i, j ) ) == t_rock_floor ) { - if( one_in( 250 ) ) { - add_item( point( i, j ), item::make_corpse() ); - place_items( "science", 70, point( i, j ), point( i, j ), true, calendar::start_of_cataclysm ); - } else { - place_spawns( GROUP_PLAIN, 1, point( i, j ), point( i, j ), 1, true ); - } - } - if( this->ter( point( i, j ) ) != t_metal_floor ) { - adjust_radiation( point( i, j ), rng( 10, 70 ) ); - } - if( this->ter( point( i, j ) ) == t_sewage ) { - if( one_in( 2 ) ) { - ter_set( point( i, j ), t_dirtfloor ); - } - if( one_in( 4 ) ) { - ter_set( point( i, j ), t_dirtmound ); - } - if( one_in( 2 ) ) { - make_rubble( tripoint( i, j, abs_sub.z ), f_wreckage, true ); - } - place_items( "trash", 50, point( i, j ), point( i, j ), false, calendar::start_of_cataclysm ); - place_items( "sewer", 50, point( i, j ), point( i, j ), false, calendar::start_of_cataclysm ); - if( one_in( 40 ) ) { - spawn_item( point( i, j ), "nanomaterial", 1, 5 ); - } - place_spawns( GROUP_VANILLA, 5, point( i, j ), point( i, j ), 1, true ); - } - } - } - if( match( dat.west(), "haz_sar_entrance_b1" ) ) { - rotate( 1 ); - } else if( match( dat.north(), "haz_sar_entrance_b1" ) ) { - rotate( 2 ); - } else if( match( dat.east(), "haz_sar_entrance_b1" ) ) { - rotate( 3 ); - } - } else if( ( match( dat.west(), "haz_sar_entrance_b1" ) && match( dat.north(), "haz_sar_b1" ) ) || - ( match( dat.north(), "haz_sar_entrance_b1" ) && match( dat.east(), "haz_sar_b1" ) ) || - ( match( dat.west(), "haz_sar_b1" ) && match( dat.south(), "haz_sar_entrance_b1" ) ) || - ( match( dat.south(), "haz_sar_b1" ) && match( dat.east(), "haz_sar_entrance_b1" ) ) ) { - mapf::formatted_set_simple( this, 0, 0, - "....M..|,,,,|........###\n" - ".......|-HH=|.........##\n" - ".....................###\n" - "......................##\n" - ".......................#\n" - "......................##\n" - ".......................#\n" - "......................##\n" - "......................##\n" - ".......................#\n" - ".....................###\n" - "....................####\n" - "..................######\n" - "###....M.........#######\n" - "#####|--$$$$$--|########\n" - "|----|_________|----|###\n" - "|___________________|###\n" - "|___________________|###\n" - "|___________________|###\n" - "|___________________|###\n" - "|___________________|###\n" - "|___________________|###\n" - "|___________________|###\n" - "|-------------------|###\n", b_ter_key, b_fur_key ); - for( int i = 0; i < SEEX * 2; i++ ) { - for( int j = 0; j < SEEY * 2; j++ ) { - if( this->ter( point( i, j ) ) == t_rock_floor ) { - if( one_in( 250 ) ) { - add_item( point( i, j ), item::make_corpse() ); - place_items( "science", 70, point( i, j ), point( i, j ), true, calendar::start_of_cataclysm ); - } - place_spawns( GROUP_PLAIN, 80, point( i, j ), point( i, j ), 1, true ); - } - if( this->ter( point( i, j ) ) != t_metal_floor ) { - adjust_radiation( point( i, j ), rng( 10, 70 ) ); - } - if( this->ter( point( i, j ) ) == t_sewage ) { - if( one_in( 2 ) ) { - ter_set( point( i, j ), t_dirtfloor ); - } - if( one_in( 4 ) ) { - ter_set( point( i, j ), t_dirtmound ); - } - if( one_in( 2 ) ) { - make_rubble( tripoint( i, j, abs_sub.z ), f_wreckage, true ); - } - place_items( "trash", 50, point( i, j ), point( i, j ), false, calendar::start_of_cataclysm ); - place_items( "sewer", 50, point( i, j ), point( i, j ), false, calendar::start_of_cataclysm ); - if( one_in( 20 ) ) { - spawn_item( point( i, j ), "nanomaterial", 1, 5 ); - } - place_spawns( GROUP_VANILLA, 5, point( i, j ), point( i, j ), 1, true ); - } - } - } - if( match( dat.north(), "haz_sar_entrance_b1" ) ) { - rotate( 1 ); - } - if( match( dat.east(), "haz_sar_entrance_b1" ) ) { - rotate( 2 ); - } - if( match( dat.south(), "haz_sar_entrance_b1" ) ) { - rotate( 3 ); - } - } else { - mapf::formatted_set_simple( this, 0, 0, - "########################\n" - ".#######################\n" - "...#..#|----------|#####\n" - ".......|__________|#####\n" - ".......$__________|#####\n" - ".......$__________|#####\n" - ".......$__________|#####\n" - ".......$__________|#####\n" - ".......$__________|#####\n" - "......M|__________|#####\n" - "......#|----------|#####\n" - ".....###################\n" - "....####|---|----|######\n" - "###.##|-|,,,|,S,T|######\n" - "#|-=-||&|,,,+,,,,|######\n" - "#|,,l|EE+,,,|----|-|####\n" - "#|,,l|EE+,,,|ddd,,l|####\n" - "-|-$-|--|,,,V,h,,,l|####\n" - ",,,,,|,,=,,,V,,,,,,|####\n" - ",,,,,|rr|,,,V,,,,c,|####\n" - ",,,,,|--|,,,|,,,hc,|####\n" - ",,,,,+,,,,,,+,,c6c,|####\n" - ",,,,M|,,,,,,|r,,,,,|####\n" - "$$$$-|-|=HH-|-HHHH-|####\n", b_ter_key, b_fur_key ); - spawn_item( point( 3, 16 ), "sarcophagus_access_code" ); - for( int i = 0; i < SEEX * 2; i++ ) { - for( int j = 0; j < SEEY * 2; j++ ) { - if( this->furn( point( i, j ) ) == f_locker ) { - place_items( "cleaning", 60, point( i, j ), point( i, j ), false, calendar::start_of_cataclysm ); - } - if( this->furn( point( i, j ) ) == f_desk ) { - place_items( "cubical_office", 60, point( i, j ), point( i, j ), false, - calendar::start_of_cataclysm ); - } - if( this->furn( point( i, j ) ) == f_rack ) { - place_items( "sewage_plant", 60, point( i, j ), point( i, j ), false, - calendar::start_of_cataclysm ); - } - if( this->ter( point( i, j ) ) == t_rock_floor ) { - if( one_in( 250 ) ) { - add_item( point( i, j ), item::make_corpse() ); - place_items( "science", 70, point( i, j ), point( i, j ), true, calendar::start_of_cataclysm ); - } - place_spawns( GROUP_PLAIN, 80, point( i, j ), point( i, j ), 1, true ); - } - if( this->ter( point( i, j ) ) != t_metal_floor ) { - adjust_radiation( point( i, j ), rng( 10, 70 ) ); - } - if( this->ter( point( i, j ) ) == t_sewage ) { - if( one_in( 2 ) ) { - ter_set( point( i, j ), t_dirtfloor ); - } - if( one_in( 4 ) ) { - ter_set( point( i, j ), t_dirtmound ); - } - if( one_in( 2 ) ) { - make_rubble( tripoint( i, j, abs_sub.z ), f_wreckage, true ); - } - place_items( "trash", 50, point( i, j ), point( i, j ), false, calendar::start_of_cataclysm ); - place_items( "sewer", 50, point( i, j ), point( i, j ), false, calendar::start_of_cataclysm ); - if( one_in( 40 ) ) { - spawn_item( point( i, j ), "nanomaterial", 1, 5 ); - } - place_spawns( GROUP_VANILLA, 5, point( i, j ), point( i, j ), 1, true ); - } - } - } - tmpcomp = add_computer( tripoint( 16, 21, abs_sub.z ), - _( "SRCF Security Terminal" ), 0 ); - tmpcomp->add_option( _( "Security Reminder [1055]" ), COMPACT_SR1_MESS, 0 ); - tmpcomp->add_option( _( "Security Reminder [1056]" ), COMPACT_SR2_MESS, 0 ); - tmpcomp->add_option( _( "Security Reminder [1057]" ), COMPACT_SR3_MESS, 0 ); - //tmpcomp->add_option(_("Security Reminder [1058]"), COMPACT_SR4_MESS, 0); limited to 9 computer options - tmpcomp->add_option( _( "EPA: Report All Potential Containment Breaches [3873643]" ), - COMPACT_SRCF_1_MESS, 2 ); - tmpcomp->add_option( _( "SRCF: Internal Memo, EPA [2918024]" ), - COMPACT_SRCF_2_MESS, 2 ); - tmpcomp->add_option( _( "CDC: Internal Memo, Standby [2918115]" ), - COMPACT_SRCF_3_MESS, 2 ); - tmpcomp->add_option( _( "USARMY: SEAL SRCF [987167]" ), COMPACT_SRCF_SEAL_ORDER, 4 ); - tmpcomp->add_option( _( "COMMAND: REACTIVATE ELEVATOR" ), COMPACT_SRCF_ELEVATOR, 0 ); - tmpcomp->add_failure( COMPFAIL_ALARM ); - if( match( dat.west(), "haz_sar_b1" ) && match( dat.north(), "haz_sar_b1" ) ) { - rotate( 1 ); - } - if( match( dat.east(), "haz_sar_b1" ) && match( dat.north(), "haz_sar_b1" ) ) { - rotate( 2 ); - } - if( match( dat.east(), "haz_sar_b1" ) && match( dat.south(), "haz_sar_b1" ) ) { - rotate( 3 ); - } - } - } -} - void map::draw_fema( mapgendata &dat ) { const oter_id &terrain_type = dat.terrain_type(); @@ -7752,31 +7174,37 @@ bool update_mapgen_function_json::update_map( const tripoint &omt_pos, const poi mapgendata md( omt_pos, update_tmap, 0.0f, calendar::start_of_cataclysm, miss ); - // If the existing map is rotated, we need to rotate it back to the north - // orientation before applying our updates. - const int rotation = oter_get_rotation( overmap_buffer.ter( omt_pos ) ); - if( rotation > 0 ) { - md.m.rotate( rotation, true ); - } - - const bool applied = update_map( md, offset, verify ); - - // If we rotated the map before applying updates, we now need to rotate - // it back to where we found it. - if( rotation ) { - md.m.rotate( 4 - rotation, true ); - } - - if( applied ) { - md.m.save(); - } - - return applied; + return update_map( md, offset, verify ); } bool update_mapgen_function_json::update_map( mapgendata &md, const point &offset, const bool verify ) const { + class rotation_guard + { + public: + rotation_guard( const mapgendata &md ) + : md( md ), rotation( oter_get_rotation( md.terrain_type() ) ) { + // If the existing map is rotated, we need to rotate it back to the north + // orientation before applying our updates. + if( rotation != 0 ) { + md.m.rotate( rotation, true ); + } + } + + ~rotation_guard() { + // If we rotated the map before applying updates, we now need to rotate + // it back to where we found it. + if( rotation != 0 ) { + md.m.rotate( 4 - rotation, true ); + } + } + private: + const mapgendata &md; + const int rotation; + }; + rotation_guard rot( md ); + for( auto &elem : setmap_points ) { if( verify && elem.has_vehicle_collision( md, offset ) ) { return false; @@ -7831,6 +7259,16 @@ bool run_mapgen_update_func( const std::string &update_mapgen_id, const tripoint return update_function->second[0]->update_map( omt_pos, point_zero, miss, cancel_on_collision ); } +bool run_mapgen_update_func( const std::string &update_mapgen_id, mapgendata &dat, + const bool cancel_on_collision ) +{ + const auto update_function = update_mapgen.find( update_mapgen_id ); + if( update_function == update_mapgen.end() || update_function->second.empty() ) { + return false; + } + return update_function->second[0]->update_map( dat, point_zero, cancel_on_collision ); +} + std::pair, std::map> get_changed_ids_from_update( const std::string &update_mapgen_id ) { diff --git a/src/mapgen_functions.h b/src/mapgen_functions.h index fb2994bac3233..9d23b552bca77 100644 --- a/src/mapgen_functions.h +++ b/src/mapgen_functions.h @@ -86,6 +86,8 @@ void place_stairs( mapgendata &dat ); mapgen_update_func add_mapgen_update_func( const JsonObject &jo, bool &defer ); bool run_mapgen_update_func( const std::string &update_mapgen_id, const tripoint &omt_pos, mission *miss = nullptr, bool cancel_on_collision = true ); +bool run_mapgen_update_func( const std::string &update_mapgen_id, mapgendata &dat, + bool cancel_on_collision = true ); bool run_mapgen_func( const std::string &mapgen_id, mapgendata &dat ); std::pair, std::map> get_changed_ids_from_update( const std::string &update_mapgen_id ); diff --git a/src/memorial_logger.cpp b/src/memorial_logger.cpp index d2a2095daaaf8..598115af3e5e1 100644 --- a/src/memorial_logger.cpp +++ b/src/memorial_logger.cpp @@ -878,14 +878,6 @@ void memorial_logger::notify( const cata::event &e ) } break; } - case event_type::launches_nuke: { - oter_id oter = e.get( "target_terrain" ); - //~ %s is terrain name - add( pgettext( "memorial_male", "Launched a nuke at a %s." ), - pgettext( "memorial_female", "Launched a nuke at a %s." ), - oter->get_name() ); - break; - } case event_type::learns_martial_art: { character_id ch = e.get( "character" ); if( ch == g->u.getID() ) { diff --git a/src/monattack.cpp b/src/monattack.cpp index 5c0af3f8b1283..e4d5a863f55aa 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -1,6 +1,6 @@ #include "monattack.h" -#include +#include #include #include #include diff --git a/src/npcmove.cpp b/src/npcmove.cpp index bb5afdfad4814..b08ee25201ded 100644 --- a/src/npcmove.cpp +++ b/src/npcmove.cpp @@ -2600,7 +2600,7 @@ void npc::move_away_from( const std::vector &spheres, bool no_bashing ) return g->m.passable( elem ); } ); - algo::sort_by_rating( escape_points.begin(), escape_points.end(), [&]( const tripoint & elem ) { + cata::sort_by_rating( escape_points.begin(), escape_points.end(), [&]( const tripoint & elem ) { const int danger = std::accumulate( spheres.begin(), spheres.end(), 0, [&]( const int sum, const sphere & s ) { return sum + std::max( s.radius - rl_dist( elem, s.center ), 0 ); diff --git a/src/npctalk_funcs.cpp b/src/npctalk_funcs.cpp index 98c558ab77600..a4a48b01995d6 100644 --- a/src/npctalk_funcs.cpp +++ b/src/npctalk_funcs.cpp @@ -372,7 +372,7 @@ void talk_function::assign_camp( npc &p ) void talk_function::stop_guard( npc &p ) { - if( p.mission != NPC_MISSION_GUARD_ALLY && p.mission != NPC_MISSION_ASSIGNED_CAMP ) { + if( !p.is_player_ally() ) { p.set_attitude( NPCATT_NULL ); p.set_mission( NPC_MISSION_NULL ); return; @@ -766,6 +766,7 @@ void talk_function::leave( npc &p ) if( new_solo_fac ) { new_solo_fac->known_by_u = true; } + p.chatbin.first_topic = "TALK_STRANGER_NEUTRAL"; p.set_attitude( NPCATT_NULL ); } diff --git a/src/npctrade.cpp b/src/npctrade.cpp index f2f33c4bf76ca..2f7e6c1c6cd34 100644 --- a/src/npctrade.cpp +++ b/src/npctrade.cpp @@ -1,6 +1,6 @@ #include "npctrade.h" -#include +#include #include #include #include diff --git a/src/npctrade.h b/src/npctrade.h index 1413656975fde..2ba4aa91cc0f3 100644 --- a/src/npctrade.h +++ b/src/npctrade.h @@ -2,7 +2,7 @@ #ifndef NPCTRADE_H #define NPCTRADE_H -#include +#include #include #include #include diff --git a/src/options.cpp b/src/options.cpp index b5e6f20971bb1..7131ef7e88121 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -1940,9 +1940,9 @@ void options_manager::add_options_world_default() add( "WORLD_END", "world_default", translate_marker( "World end handling" ), translate_marker( "Handling of game world when last character dies." ), { - { "keep", translate_marker( "Keep" ) }, { "reset", translate_marker( "Reset" ) }, - { "delete", translate_marker( "Delete" ) }, { "query", translate_marker( "Query" ) } - }, "keep" + { "reset", translate_marker( "Reset" ) }, { "delete", translate_marker( "Delete" ) }, + { "query", translate_marker( "Query" ) }, { "keep", translate_marker( "Keep" ) } + }, "reset" ); mOptionsSort["world_default"]++; @@ -2691,6 +2691,7 @@ std::string options_manager::show( bool ingame, const bool world_options_only ) // keybinding screen erased the internal borders of main menu, restore it: draw_borders_internal( w_options_header, mapLines ); } else if( action == "QUIT" ) { + catacurses::clear(); catacurses::refresh(); break; } diff --git a/src/output.cpp b/src/output.cpp index ef614fe5b395c..e36ee01f5f4fc 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -1,6 +1,6 @@ #include "output.h" -#include +#include #include #include #include diff --git a/src/overmap.cpp b/src/overmap.cpp index 4fe9cd01b2259..a87882c4e145a 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -726,10 +726,10 @@ bool oter_t::is_hardcoded() const "ants_lab_stairs", "fema", "fema_entrance", - "haz_sar", - "haz_sar_b1", - "haz_sar_entrance", - "haz_sar_entrance_b1", + "haz_sar", // remove after 0.E. + "haz_sar_b1", // remove after 0.E. + "haz_sar_entrance", // remove after 0.E. + "haz_sar_entrance_b1", // remove after 0.E. "ice_lab", "ice_lab_stairs", "ice_lab_core", diff --git a/src/pixel_minimap.cpp b/src/pixel_minimap.cpp index 6a00d83ee5584..2c9b59f5fa387 100644 --- a/src/pixel_minimap.cpp +++ b/src/pixel_minimap.cpp @@ -23,13 +23,13 @@ #include #include -#include +#include #include #include #include #include #include -#include +#include #include #include diff --git a/src/player.cpp b/src/player.cpp index b197d4d7a293c..f4aae4b9a3969 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -1923,7 +1923,7 @@ void player::apply_damage( Creature *source, body_part hurt, int dam, const bool g->events().send( getID(), dam_to_bodypart ); if( hp_cur[hurtpart] <= 0 && ( source == nullptr || !source->is_hallucination() ) ) { - if( !weapon.is_null() && !can_wield( weapon ).success() ) { + if( !weapon.is_null() && can_unwield( weapon ).success() ) { put_into_vehicle_or_drop( *this, item_drop_reason::tumbling, { weapon } ); i_rem( &weapon ); } @@ -6300,32 +6300,35 @@ std::string player::weapname( unsigned int truncate ) const } } -bool player::wield_contents( item &container, int pos, bool penalties, int base_cost ) +bool player::wield_contents( item &container, item *internal_item, bool penalties, int base_cost ) { // if index not specified and container has multiple items then ask the player to choose one - if( pos < 0 ) { + if( internal_item == nullptr ) { std::vector opts; std::transform( container.contents.begin(), container.contents.end(), std::back_inserter( opts ), []( const item & elem ) { return elem.display_name(); } ); if( opts.size() > 1 ) { - pos = uilist( _( "Wield what?" ), opts ); + int pos = uilist( _( "Wield what?" ), opts ); if( pos < 0 ) { return false; } } else { - pos = 0; + internal_item = &container.contents.front(); } } - if( pos >= static_cast( container.contents.size() ) ) { + const bool has = std::any_of( container.contents.begin(), + container.contents.end(), [internal_item]( const item & it ) { + return internal_item == ⁢ + } ); + if( !has ) { debugmsg( "Tried to wield non-existent item from container (player::wield_contents)" ); return false; } - auto target = std::next( container.contents.begin(), pos ); - const auto ret = can_wield( *target ); + const ret_val ret = can_wield( *internal_item ); if( !ret.success() ) { add_msg_if_player( m_info, "%s", ret.c_str() ); return false; @@ -6340,8 +6343,10 @@ bool player::wield_contents( item &container, int pos, bool penalties, int base_ inv.unsort(); } - weapon = std::move( *target ); - container.contents.erase( target ); + weapon = std::move( *internal_item ); + container.contents.remove_if( [internal_item]( const item & it ) { + return internal_item == ⁢ + } ); container.on_contents_changed(); inv.update_invlet( weapon ); diff --git a/src/player.h b/src/player.h index f00d97b9904d7..47eefb8e821fa 100644 --- a/src/player.h +++ b/src/player.h @@ -671,6 +671,14 @@ class player : public Character /** Get calorie & vitamin contents for a comestible, taking into * account player traits */ nutrients compute_effective_nutrients( const item & ) const; + /** Get range of possible nutrient content, for a particular recipe, + * depending on choice of ingredients */ + std::pair compute_nutrient_range( + const item &, const recipe_id &, + const cata::flat_set &extra_flags = {} ) const; + /** Same, but across arbitrary recipes */ + std::pair compute_nutrient_range( + const itype_id &, const cata::flat_set &extra_flags = {} ) const; /** Get vitamin usage rate (minutes per unit) accounting for bionics, mutations and effects */ time_duration vitamin_rate( const vitamin_id &vit ) const; @@ -813,7 +821,7 @@ class player : public Character * @param penalties Whether item volume and temporary effects (e.g. GRABBED, DOWNED) should be considered. * @param base_cost Cost due to storage type. */ - bool wield_contents( item &container, int pos = 0, bool penalties = true, + bool wield_contents( item &container, item *internal_item = nullptr, bool penalties = true, int base_cost = INVENTORY_HANDLING_PENALTY ); /** * Stores an item inside another consuming moves proportional to weapon skill and volume diff --git a/src/recipe.cpp b/src/recipe.cpp index 23979151f4f80..c17b6d77a9260 100644 --- a/src/recipe.cpp +++ b/src/recipe.cpp @@ -483,6 +483,23 @@ std::string recipe::result_name() const return name; } +bool recipe::will_be_blacklisted() const +{ + if( requirements_.is_blacklisted() ) { + return true; + } + + auto any_is_blacklisted = []( const std::vector> &reqs ) { + auto req_is_blacklisted = []( const std::pair &req ) { + return req.first->is_blacklisted(); + }; + + return std::any_of( reqs.begin(), reqs.end(), req_is_blacklisted ); + }; + + return any_is_blacklisted( reqs_internal ) || any_is_blacklisted( reqs_external ); +} + std::function recipe::get_component_filter() const { const item result = create_result(); diff --git a/src/recipe.h b/src/recipe.h index ea75db9f922a5..c5170b370e963 100644 --- a/src/recipe.h +++ b/src/recipe.h @@ -62,6 +62,10 @@ class recipe return requirements_.is_blacklisted(); } + // Slower equivalent of is_blacklisted that needs to be used before + // recipe finalization happens + bool will_be_blacklisted() const; + std::function get_component_filter() const; /** Prevent this recipe from ever being added to the player's learned recipies ( used for special NPC crafting ) */ diff --git a/src/recipe_dictionary.cpp b/src/recipe_dictionary.cpp index 81c6c951f919b..68efd587926c7 100644 --- a/src/recipe_dictionary.cpp +++ b/src/recipe_dictionary.cpp @@ -5,6 +5,7 @@ #include #include +#include "cata_algo.h" #include "cata_utility.h" #include "init.h" #include "item.h" @@ -332,6 +333,11 @@ std::map::const_iterator recipe_dictionary::end() const return recipes.end(); } +bool recipe_dictionary::is_item_on_loop( const itype_id &i ) const +{ + return items_on_loops.count( i ); +} + void recipe_dictionary::finalize_internal( std::map &obj ) { for( auto &elem : obj ) { @@ -357,6 +363,49 @@ void recipe_dictionary::finalize_internal( std::map &obj ) } ); } +void recipe_dictionary::find_items_on_loops() +{ + // Check for infinite recipe loops in food (which are problematic for + // nutrient calculations). + // + // Start by building a directed graph of itypes to potential components of + // those itypes. + items_on_loops.clear(); + std::unordered_map> potential_components_of; + for( const itype *i : item_controller->all() ) { + if( !i->comestible || i->item_tags.count( "NUTRIENT_OVERRIDE" ) ) { + continue; + } + std::vector &potential_components = potential_components_of[i->get_id()]; + for( const recipe_id &rec : i->recipes ) { + const requirement_data requirements = rec->requirements(); + const requirement_data::alter_item_comp_vector &component_requirements = + requirements.get_components(); + + for( const std::vector &component_options : component_requirements ) { + for( const item_comp &component_option : component_options ) { + potential_components.push_back( component_option.type ); + } + } + } + } + + // Now check that graph for loops + std::vector> loops = cata::find_cycles( potential_components_of ); + for( const std::vector &loop : loops ) { + std::string error_message = + "loop in comestible recipes detected: " + loop.back(); + for( const itype_id &i : loop ) { + error_message += " -> " + i; + items_on_loops.insert( i ); + } + error_message += ". Such loops can be broken by either removing or altering " + "recipes or marking one of the items involved with the NUTRIENT_OVERRIDE " + "flag"; + debugmsg( error_message ); + } +} + void recipe_dictionary::finalize() { DynamicDataLoader::get_instance().load_deferred( deferred ); @@ -416,6 +465,8 @@ void recipe_dictionary::finalize() recipe_dict.blueprints.insert( &e.second ); } } + + recipe_dict.find_items_on_loops(); } void recipe_dictionary::reset() @@ -424,6 +475,7 @@ void recipe_dictionary::reset() recipe_dict.autolearn.clear(); recipe_dict.recipes.clear(); recipe_dict.uncraft.clear(); + recipe_dict.items_on_loops.clear(); } void recipe_dictionary::delete_if( const std::function &pred ) diff --git a/src/recipe_dictionary.h b/src/recipe_dictionary.h index dcd0bafaaf1c0..9e9ab4ee6d8f6 100644 --- a/src/recipe_dictionary.h +++ b/src/recipe_dictionary.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "recipe.h" @@ -39,6 +40,8 @@ class recipe_dictionary std::map::const_iterator begin() const; std::map::const_iterator end() const; + bool is_item_on_loop( const itype_id & ) const; + /** Returns disassembly recipe (or null recipe if no match) */ static const recipe &get_uncraft( const itype_id &id ); @@ -63,8 +66,10 @@ class recipe_dictionary std::map uncraft; std::set autolearn; std::set blueprints; + std::unordered_set items_on_loops; static void finalize_internal( std::map &obj ); + void find_items_on_loops(); }; extern recipe_dictionary recipe_dict; diff --git a/src/requirements.cpp b/src/requirements.cpp index e5ec728320727..3563635cbca89 100644 --- a/src/requirements.cpp +++ b/src/requirements.cpp @@ -1,6 +1,6 @@ #include "requirements.h" -#include +#include #include #include #include diff --git a/src/rng.cpp b/src/rng.cpp index 8acab811637a2..63a643e183d54 100644 --- a/src/rng.cpp +++ b/src/rng.cpp @@ -1,6 +1,6 @@ #include "rng.h" -#include +#include #include #include diff --git a/src/savegame.cpp b/src/savegame.cpp index d2083f5c9bd4e..fa4d81e7ddeb1 100644 --- a/src/savegame.cpp +++ b/src/savegame.cpp @@ -706,7 +706,7 @@ void overmap::convert_terrain( const std::unordered_map & old.compare( 0, 5, "cabin" ) == 0 || old.compare( 0, 5, "pond_" ) == 0 || old.compare( 0, 6, "bandit" ) == 0 || - old.compare( 0, 7, "haz_sar" ) == 0 || + old.compare( 0, 7, "haz_sar" ) == 0 || // remove after 0.E. old.compare( 0, 7, "shelter" ) == 0 || old.compare( 0, 8, "campsite" ) == 0 || old.compare( 0, 9, "pwr_large" ) == 0 || diff --git a/src/savegame_json.cpp b/src/savegame_json.cpp index 36d0685edf2b4..3545b43368581 100644 --- a/src/savegame_json.cpp +++ b/src/savegame_json.cpp @@ -5,7 +5,7 @@ #include "npc_favor.h" // IWYU pragma: associated #include "pldata.h" // IWYU pragma: associated -#include +#include #include #include #include diff --git a/src/sdl_utils.cpp b/src/sdl_utils.cpp index cdd776328baae..3b47c1b557009 100644 --- a/src/sdl_utils.cpp +++ b/src/sdl_utils.cpp @@ -2,7 +2,7 @@ #include "sdl_utils.h" -#include +#include #include #include "color.h" diff --git a/src/sdltiles.cpp b/src/sdltiles.cpp index ee4dd5f1d09f1..bdb00e4d0372b 100644 --- a/src/sdltiles.cpp +++ b/src/sdltiles.cpp @@ -3,7 +3,7 @@ #include "sdltiles.h" // IWYU pragma: associated #include "cursesdef.h" // IWYU pragma: associated -#include +#include #include #include #include diff --git a/src/stomach.cpp b/src/stomach.cpp index f6cd607dd4393..59717ca597e33 100644 --- a/src/stomach.cpp +++ b/src/stomach.cpp @@ -7,6 +7,62 @@ #include "units.h" #include "game.h" #include "itype.h" +#include "vitamin.h" + +void nutrients::min_in_place( const nutrients &r ) +{ + kcal = std::min( kcal, r.kcal ); + for( const std::pair &vit_pair : vitamin::all() ) { + const vitamin_id &vit = vit_pair.first; + int other = r.get_vitamin( vit ); + if( other == 0 ) { + vitamins.erase( vit ); + } else { + auto our_vit = vitamins.find( vit ); + if( our_vit != vitamins.end() ) { + our_vit->second = std::min( our_vit->second, other ); + } + } + } +} + +void nutrients::max_in_place( const nutrients &r ) +{ + kcal = std::max( kcal, r.kcal ); + for( const std::pair &vit_pair : vitamin::all() ) { + const vitamin_id &vit = vit_pair.first; + int other = r.get_vitamin( vit ); + if( other != 0 ) { + int &val = vitamins[vit]; + val = std::max( val, other ); + } + } +} + +int nutrients::get_vitamin( const vitamin_id &vit ) const +{ + auto it = vitamins.find( vit ); + if( it == vitamins.end() ) { + return 0; + } + return it->second; +} + +bool nutrients::operator==( const nutrients &r ) const +{ + if( kcal != r.kcal ) { + return false; + } + // Can't just use vitamins == r.vitamins, because there might be zero + // entries in the map, which need to compare equal to missing entries. + for( const std::pair &vit_pair : vitamin::all() ) { + const vitamin_id &vit = vit_pair.first; + if( get_vitamin( vit ) != r.get_vitamin( vit ) ) { + return false; + } + } + return true; +} nutrients &nutrients::operator+=( const nutrients &r ) { diff --git a/src/stomach.h b/src/stomach.h index c2ac702b86096..dc24efee8f0ba 100644 --- a/src/stomach.h +++ b/src/stomach.h @@ -19,6 +19,18 @@ struct nutrients { /** vitamins potentially provided by this comestible (if any) */ std::map vitamins; + /** Replace the values here with the minimum (or maximum) of themselves and the corresponding + * values taken from r. */ + void min_in_place( const nutrients &r ); + void max_in_place( const nutrients &r ); + + int get_vitamin( const vitamin_id & ) const; + + bool operator==( const nutrients &r ) const; + bool operator!=( const nutrients &r ) const { + return !( *this == r ); + } + nutrients &operator+=( const nutrients &r ); nutrients &operator-=( const nutrients &r ); nutrients &operator*=( int r ); diff --git a/src/string_input_popup.h b/src/string_input_popup.h index f8124aa849fa8..e1914e34f8215 100644 --- a/src/string_input_popup.h +++ b/src/string_input_popup.h @@ -2,7 +2,7 @@ #ifndef STRING_INPUT_POPUP_H #define STRING_INPUT_POPUP_H -#include +#include #include #include #include diff --git a/src/teleport.cpp b/src/teleport.cpp index 7a63eb5b025e0..c9be878b80af8 100644 --- a/src/teleport.cpp +++ b/src/teleport.cpp @@ -22,7 +22,7 @@ bool teleport::teleport( Creature &critter, int min_distance, int max_distance, const bool c_is_u = p != nullptr && p == &g->u; int tries = 0; tripoint origin = critter.pos(); - tripoint new_pos; + tripoint new_pos = origin; //The teleportee is dimensionally anchored so nothing happens if( p && ( p->worn_with_flag( "DIMENSIONAL_ANCHOR" ) || p->has_effect_with_flag( "DIMENSIONAL_ANCHOR" ) ) ) { diff --git a/src/ui.cpp b/src/ui.cpp index 13d86ab4a2d1c..7b2bedc127ea5 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -1,6 +1,6 @@ #include "ui.h" -#include +#include #include #include #include diff --git a/src/units.cpp b/src/units.cpp new file mode 100644 index 0000000000000..a2122749dded9 --- /dev/null +++ b/src/units.cpp @@ -0,0 +1,27 @@ +#include "json.h" +#include "units.h" + +namespace units +{ +template<> +void volume::serialize( JsonOut &jsout ) const +{ + if( value_ % 1000 == 0 ) { + jsout.write( string_format( "%d L", value_ ) ); + } else { + jsout.write( string_format( "%d ml", value_ ) ); + } +} + +template<> +void mass::serialize( JsonOut &jsout ) const +{ + if( value_ % 1000000 == 0 ) { + jsout.write( string_format( "%d kg", value_ ) ); + } else if( value_ % 1000 == 0 ) { + jsout.write( string_format( "%d g", value_ ) ); + } else { + jsout.write( string_format( "%d mg", value_ ) ); + } +} +} // namespace units diff --git a/src/units.h b/src/units.h index a25930a05b3cb..f4ae0898fb734 100644 --- a/src/units.h +++ b/src/units.h @@ -656,6 +656,11 @@ static const std::vector> money_units = { { { "kUSD", 1_kUSD }, } }; +static const std::vector> volume_units = { { + { "ml", 1_ml }, + { "L", 1_liter } + } +}; } // namespace units template diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index 6880d44cae343..1b43684991eae 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -486,6 +486,7 @@ WORLDPTR worldfactory::pick_world( bool show_prompt ) const std::string action = ctxt.handle_input(); if( action == "QUIT" ) { + catacurses::clear(); catacurses::refresh(); break; } else if( !world_pages[selpage].empty() && action == "DOWN" ) { @@ -757,6 +758,7 @@ void worldfactory::show_active_world_mods( const std::vector &world_mods } } else if( action == "QUIT" || action == "CONFIRM" ) { + catacurses::clear(); catacurses::refresh(); break; } @@ -1164,6 +1166,7 @@ int worldfactory::show_worldgen_tab_confirm( const catacurses::window &win, WORL if( !valid_worldname( world->world_name ) ) { continue; } + catacurses::clear(); catacurses::refresh(); return 1; } @@ -1171,6 +1174,7 @@ int worldfactory::show_worldgen_tab_confirm( const catacurses::window &win, WORL // erase entire window to avoid overlapping of query with possible popup about invalid worldname werase( w_confirmation ); wrefresh( w_confirmation ); + catacurses::clear(); catacurses::refresh(); if( valid_worldname( worldname ) ) { diff --git a/tests/algo_test.cpp b/tests/algo_test.cpp new file mode 100644 index 0000000000000..14ba445c960f4 --- /dev/null +++ b/tests/algo_test.cpp @@ -0,0 +1,48 @@ +#define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER + +#include "cata_algo.h" + +#include "catch/catch.hpp" + +static void check_cycle_finding( std::unordered_map> &g, + std::vector> &expected ) +{ + CAPTURE( g ); + std::vector> loops = cata::find_cycles( g ); + // Canonicalize the list of loops by rotating each to be lexicographically + // least and then sorting. + for( std::vector &loop : loops ) { + auto min = std::min_element( loop.begin(), loop.end() ); + std::rotate( loop.begin(), min, loop.end() ); + } + std::sort( loops.begin(), loops.end() ); + CHECK( loops == expected ); +} + + +TEST_CASE( "find_cycles_small" ) +{ + std::unordered_map> g = { + { 0, { 1 } }, + { 1, { 0 } }, + }; + std::vector> expected = { + { 0, 1 }, + }; + check_cycle_finding( g, expected ); +} +TEST_CASE( "find_cycles" ) +{ + std::unordered_map> g = { + { 0, { 0, 1 } }, + { 1, { 0, 2, 3, 17 } }, + { 2, { 1 } }, + { 3, {} }, + }; + std::vector> expected = { + { 0 }, + { 0, 1 }, + { 1, 2 }, + }; + check_cycle_finding( g, expected ); +} diff --git a/tests/bionics_test.cpp b/tests/bionics_test.cpp index 03cad7b9cef50..573d84a3e6d92 100644 --- a/tests/bionics_test.cpp +++ b/tests/bionics_test.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include #include #include diff --git a/tests/colony_test.cpp b/tests/colony_test.cpp index e2ae8f0f6ad5a..ba774b6983c7d 100644 --- a/tests/colony_test.cpp +++ b/tests/colony_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include // std::find #include // std::greater #include // std::move diff --git a/tests/comestible_tests.cpp b/tests/comestible_tests.cpp index 1c99a77137e97..a18d06a17d55a 100644 --- a/tests/comestible_tests.cpp +++ b/tests/comestible_tests.cpp @@ -1,11 +1,13 @@ -#include +#include #include #include #include #include #include +#include "avatar.h" #include "catch/catch.hpp" +#include "game.h" #include "itype.h" #include "recipe_dictionary.h" #include "recipe.h" @@ -108,7 +110,7 @@ static item food_or_food_container( const item &it ) return it.is_food_container() ? it.contents.front() : it; } -TEST_CASE( "recipe_permutations" ) +TEST_CASE( "recipe_permutations", "[recipe]" ) { // Are these tests failing? Here's how to fix that: // If the average is over the upper bound, you need to increase the calories for the item @@ -155,3 +157,20 @@ TEST_CASE( "recipe_permutations" ) } } } + +TEST_CASE( "cooked_veggies_get_correct_calorie_prediction", "[recipe]" ) +{ + // This test verifies that predicted calorie ranges properly take into + // account the "RAW"/"COOKED" flags. + const item veggy_wild_cooked( "veggy_wild_cooked" ); + const recipe_id veggy_wild_cooked_recipe( "veggy_wild_cooked" ); + + const avatar &u = g->u; + + nutrients default_nutrition = u.compute_effective_nutrients( veggy_wild_cooked ); + std::pair predicted_nutrition = + u.compute_nutrient_range( veggy_wild_cooked, veggy_wild_cooked_recipe ); + + CHECK( default_nutrition.kcal == predicted_nutrition.first.kcal ); + CHECK( default_nutrition.kcal == predicted_nutrition.second.kcal ); +} diff --git a/tests/crafting_test.cpp b/tests/crafting_test.cpp index 88991a8acd950..a3ec63c051d9a 100644 --- a/tests/crafting_test.cpp +++ b/tests/crafting_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/tests/creature_test.cpp b/tests/creature_test.cpp index 257066ac1af26..62d3f27d4554c 100644 --- a/tests/creature_test.cpp +++ b/tests/creature_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/tests/fake_messages.cpp b/tests/fake_messages.cpp index 480f7ebea20d4..6bca667a402d7 100644 --- a/tests/fake_messages.cpp +++ b/tests/fake_messages.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/tests/health_test.cpp b/tests/health_test.cpp index f835d002e5c24..698dad13bfc7f 100644 --- a/tests/health_test.cpp +++ b/tests/health_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/tests/invlet_test.cpp b/tests/invlet_test.cpp index 3119a59d654a9..bcf9b48aa64d7 100644 --- a/tests/invlet_test.cpp +++ b/tests/invlet_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index ffa2434c47404..46a1e4ea495e1 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -57,6 +57,7 @@ TEST_CASE( "gun_lists_default_ammo", "[item][iteminfo]" ) "--\n" "Gun is not loaded, so stats below assume the default ammo: wooden broadhead arrow\n" ); } + TEST_CASE( "gun_damage_multiplier_not_integer", "[item][iteminfo]" ) { iteminfo_query q( { iteminfo_parts::GUN_DAMAGE, iteminfo_parts::GUN_DAMAGE_AMMOPROP, @@ -67,3 +68,34 @@ TEST_CASE( "gun_damage_multiplier_not_integer", "[item][iteminfo]" ) "--\n" "Damage: 18*1.25 = 22\n" ); } + +TEST_CASE( "nutrients_in_regular_item", "[item][iteminfo]" ) +{ + iteminfo_query q( { iteminfo_parts::FOOD_NUTRITION, iteminfo_parts::FOOD_VITAMINS, + iteminfo_parts::FOOD_QUENCH + } ); + item i( "icecream" ); + iteminfo_test( + i, q, + "--\n" + "Calories (kcal): 325 " + "Quench: 0\n" + "Vitamins (RDA): Calcium (9%), Vitamin A (9%), and Vitamin B12 (11%)\n" ); +} + +TEST_CASE( "nutrient_ranges_for_recipe_exemplars", "[item][iteminfo]" ) +{ + iteminfo_query q( { iteminfo_parts::FOOD_NUTRITION, iteminfo_parts::FOOD_VITAMINS, + iteminfo_parts::FOOD_QUENCH + } ); + item i( "icecream" ); + i.set_var( "recipe_exemplar", "icecream" ); + iteminfo_test( + i, q, + "--\n" + "Nutrition will vary with chosen ingredients.\n" + "Calories (kcal): 317-" + "469 Quench: 0\n" + "Vitamins (RDA): Calcium (7-28%), Iron (0-83%), " + "Vitamin A (3-11%), Vitamin B12 (2-6%), and Vitamin C (1-85%)\n" ); +} diff --git a/tests/iuse_test.cpp b/tests/iuse_test.cpp index 3cb25a3aba25b..c7963425ffc80 100644 --- a/tests/iuse_test.cpp +++ b/tests/iuse_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/tests/line_test.cpp b/tests/line_test.cpp index f7dc61528ce4e..f2f2481e9cdc7 100644 --- a/tests/line_test.cpp +++ b/tests/line_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/tests/map_memory.cpp b/tests/map_memory.cpp index 21f43811b122a..26e01337fbd3c 100644 --- a/tests/map_memory.cpp +++ b/tests/map_memory.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/tests/math_functions.cpp b/tests/math_functions.cpp index c3c3d8846401f..2ba62a55ff289 100644 --- a/tests/math_functions.cpp +++ b/tests/math_functions.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/tests/melee_test.cpp b/tests/melee_test.cpp index 09bc0ca573648..0f03f85dc7fa4 100644 --- a/tests/melee_test.cpp +++ b/tests/melee_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/tests/memorial_test.cpp b/tests/memorial_test.cpp index b51a9dca3edee..2ab932db43d2c 100644 --- a/tests/memorial_test.cpp +++ b/tests/memorial_test.cpp @@ -184,9 +184,6 @@ TEST_CASE( "memorials" ) check_memorial( m, b, "Installed bad bionic: Alarm System.", ch, cbm ); - check_memorial( - m, b, "Launched a nuke at a garage.", oter_id( "s_garage_north" ) ); - check_memorial( m, b, "Learned Aikido.", ch, matype_id( "style_aikido" ) ); diff --git a/tests/monster_test.cpp b/tests/monster_test.cpp index c3b4427b322b6..d655a7ee41665 100644 --- a/tests/monster_test.cpp +++ b/tests/monster_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/tests/npc_talk_test.cpp b/tests/npc_talk_test.cpp index 95030b3ed27ea..c59e1c55a223c 100644 --- a/tests/npc_talk_test.cpp +++ b/tests/npc_talk_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/tests/npc_test.cpp b/tests/npc_test.cpp index 2b4d53105576a..2988840121c43 100644 --- a/tests/npc_test.cpp +++ b/tests/npc_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/tests/reloading_test.cpp b/tests/reloading_test.cpp index 292b15dbcd229..47c02e4aa4cb0 100644 --- a/tests/reloading_test.cpp +++ b/tests/reloading_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/tests/rot_test.cpp b/tests/rot_test.cpp index 8e1f874af3bff..8a172751aaca5 100644 --- a/tests/rot_test.cpp +++ b/tests/rot_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/tests/stomach_contents_tests.cpp b/tests/stomach_contents_tests.cpp index 7c13bc8e6c7da..89d86403380b0 100644 --- a/tests/stomach_contents_tests.cpp +++ b/tests/stomach_contents_tests.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include "avatar.h" diff --git a/tests/string_formatter_test.cpp b/tests/string_formatter_test.cpp index 0c2e043d1cad5..001a83c06e95d 100644 --- a/tests/string_formatter_test.cpp +++ b/tests/string_formatter_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/tests/temperature_test.cpp b/tests/temperature_test.cpp index cf1629f0c0bea..773a01ea61b8a 100644 --- a/tests/temperature_test.cpp +++ b/tests/temperature_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/tests/test_main.cpp b/tests/test_main.cpp index 65d7d2db73153..446426bb7f92c 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -13,9 +13,9 @@ #endif // _GLIBCXX_DEBUG #define CATCH_CONFIG_RUNNER -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/tests/vehicle_drag.cpp b/tests/vehicle_drag.cpp index 6ff2a3abe5e55..34600c61708aa 100644 --- a/tests/vehicle_drag.cpp +++ b/tests/vehicle_drag.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/tests/vehicle_efficiency.cpp b/tests/vehicle_efficiency.cpp index 9017a17cd9506..e45c978e21c2c 100644 --- a/tests/vehicle_efficiency.cpp +++ b/tests/vehicle_efficiency.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include #include #include diff --git a/tests/vision_test.cpp b/tests/vision_test.cpp index bf9c86a7407c4..41abaddd4cf26 100644 --- a/tests/vision_test.cpp +++ b/tests/vision_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/tests/wield_times_test.cpp b/tests/wield_times_test.cpp index fd5d4a7667769..2d16fd1efa5cc 100644 --- a/tests/wield_times_test.cpp +++ b/tests/wield_times_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include